templates/vitekit/__/vite-template-main/js/files/functions.ts
2026-04-12 21:03:18 +03:00

793 lines
34 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { IBreakpoint, IMediaQueryItem, IMediaQueryResult, IMobile } from '../types'
/* Проверка мобильного браузера */
export const isMobile: IMobile = {
Android(): RegExpMatchArray | null {
return navigator.userAgent.match(/Android/i)
},
BlackBerry(): RegExpMatchArray | null {
return navigator.userAgent.match(/BlackBerry/i)
},
iOS(): RegExpMatchArray | null {
return navigator.userAgent.match(/iPhone|iPad|iPod/i)
},
Opera(): RegExpMatchArray | null {
return navigator.userAgent.match(/Opera Mini/i)
},
Windows(): RegExpMatchArray | null {
return navigator.userAgent.match(/IEMobile/i)
},
any(): boolean {
return Boolean(
isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()
)
},
}
/* Добавление класса touch для HTML если браузер мобильный */
export function addTouchClass(): void {
if (isMobile.any()) {
document.documentElement.classList.add('touch')
}
}
// Добавление loaded для HTML после полной загрузки страницы
export function addLoadedClass(): void {
if (!document.documentElement.classList.contains('loading')) {
window.addEventListener('load', () => {
setTimeout(() => {
document.documentElement.classList.add('loaded')
}, 0)
})
}
}
// Получение хеша в адресе сайта
export function getHash(): string | undefined {
if (location.hash) {
return location.hash.replace('#', '')
}
return undefined
}
// Указание хеша в адресе сайта
export function setHash(hash: string): void {
const newHash = hash ? `#${hash}` : window.location.href.split('#')[0]
history.pushState('', '', newHash)
}
// Учет плавающей панели на мобильных устройствах при 100vh
export function fullVHfix(): void {
const fullScreens = document.querySelectorAll<HTMLElement>('[data-fullscreen]')
if (fullScreens.length && isMobile.any()) {
const fixHeight = (): void => {
const vh = window.innerHeight * 0.01
document.documentElement.style.setProperty('--vh', `${vh}px`)
}
fixHeight()
window.addEventListener('resize', fixHeight)
}
}
// Вспомогательные модули плавного раскрытия и закрытия объекта ======================================================================================================================================================================
export function _slideUp(target: HTMLElement, duration: number = 500, showmore: number = 0): void {
if (!target.classList.contains('_slide')) {
target.classList.add('_slide')
target.style.transitionProperty = 'height, margin, padding'
target.style.transitionDuration = `${duration}ms`
target.style.height = `${target.offsetHeight}px`
void target.offsetHeight
target.style.overflow = 'hidden'
target.style.height = showmore ? `${showmore}px` : '0'
target.style.paddingTop = '0'
target.style.paddingBottom = '0'
target.style.marginTop = '0'
target.style.marginBottom = '0'
window.setTimeout(() => {
target.hidden = !showmore
if (!showmore) {
target.style.removeProperty('height')
target.style.removeProperty('overflow')
}
target.style.removeProperty('padding-top')
target.style.removeProperty('padding-bottom')
target.style.removeProperty('margin-top')
target.style.removeProperty('margin-bottom')
target.style.removeProperty('transition-duration')
target.style.removeProperty('transition-property')
target.classList.remove('_slide')
// Создаем событие
document.dispatchEvent(
new CustomEvent('slideUpDone', {
detail: {
target,
},
})
)
}, duration)
}
}
export function _slideDown(target: HTMLElement, duration: number = 500, showmore: number = 0): void {
if (!target.classList.contains('_slide')) {
target.classList.add('_slide')
target.hidden = false
if (showmore) {
target.style.removeProperty('height')
}
const height = target.offsetHeight
target.style.overflow = 'hidden'
target.style.height = showmore ? `${showmore}px` : '0'
target.style.paddingTop = '0'
target.style.paddingBottom = '0'
target.style.marginTop = '0'
target.style.marginBottom = '0'
void target.offsetHeight
target.style.transitionProperty = 'height, margin, padding'
target.style.transitionDuration = `${duration}ms`
target.style.height = `${height}px`
target.style.removeProperty('padding-top')
target.style.removeProperty('padding-bottom')
target.style.removeProperty('margin-top')
target.style.removeProperty('margin-bottom')
window.setTimeout(() => {
target.style.removeProperty('height')
target.style.removeProperty('overflow')
target.style.removeProperty('transition-duration')
target.style.removeProperty('transition-property')
target.classList.remove('_slide')
// Создаем событие
document.dispatchEvent(
new CustomEvent('slideDownDone', {
detail: {
target,
},
})
)
}, duration)
}
}
export function _slideToggle(target: HTMLElement, duration: number = 500): void {
if (target.hidden) {
return _slideDown(target, duration)
} else {
return _slideUp(target, duration)
}
}
// Вспомогательные модули блокировки прокрутки и скачка ====================================================================================================================================================================================================================================================================================
// eslint-disable-next-line import/no-mutable-exports
export let bodyLockStatus = true
export function bodyUnlock(delay: number = 500) {
const body = document.querySelector<HTMLBodyElement>('body')!
if (bodyLockStatus) {
const lockPadding = document.querySelectorAll<HTMLElement>('[data-lp]')
setTimeout(() => {
for (let index = 0; index < lockPadding.length; index++) {
const el = lockPadding[index]
el.style.paddingRight = '0'
}
body.style.paddingRight = '0'
document.documentElement.classList.remove('lock')
}, delay)
bodyLockStatus = false
setTimeout(() => {
bodyLockStatus = true
}, delay)
}
}
export function bodyLock(delay: number = 500) {
const body = document.querySelector<HTMLBodyElement>('body')
if (bodyLockStatus) {
const lockPadding = document.querySelectorAll<HTMLElement>('[data-lp]')
for (let index = 0; index < lockPadding.length; index++) {
const el = lockPadding[index]
el.style.paddingRight = `${window.innerWidth - document.querySelector<HTMLElement>('.wrapper')!.offsetWidth}px`
}
body!.style.paddingRight = `${window.innerWidth - document.querySelector<HTMLElement>('.wrapper')!.offsetWidth}px`
document.documentElement.classList.add('lock')
bodyLockStatus = false
setTimeout(() => {
bodyLockStatus = true
}, delay)
}
}
export function bodyLockToggle(delay: number = 500) {
if (document.documentElement.classList.contains('lock')) {
bodyUnlock(delay)
} else {
bodyLock(delay)
}
}
// Модуль работы со спойлерами =======================================================================================================================================================================================================================
export function spoilers(): void {
const spoilersArray = document.querySelectorAll<HTMLElement>('[data-spoilers]')
if (spoilersArray.length > 0) {
// Получение обычных спойлеров
const spoilersRegular = Array.from(spoilersArray).filter((item) => {
return !item.dataset.spoilers?.split(',')[0]
})
const setSpoilerAction = (e: Event): void => {
const el = e.target as HTMLElement
const spoilerTitle = el.closest('[data-spoiler]') as HTMLElement | null
if (spoilerTitle) {
const spoilersBlock = spoilerTitle.closest('[data-spoilers]') as HTMLElement
const oneSpoiler = spoilersBlock.hasAttribute('data-one-spoiler')
const spoilerSpeed = spoilersBlock.dataset.spoilersSpeed
? Number.parseInt(spoilersBlock.dataset.spoilersSpeed)
: 500
if (!spoilersBlock.querySelectorAll('._slide').length) {
if (oneSpoiler && !spoilerTitle.classList.contains('_spoiler-active')) {
hideSpoilersBody(spoilersBlock)
}
spoilerTitle.classList.toggle('_spoiler-active')
const nextElement = spoilerTitle.nextElementSibling as HTMLElement
if (nextElement) {
_slideToggle(nextElement, spoilerSpeed)
}
}
}
}
// Инициализация
const initSpoilers = (spoilersArray: HTMLElement[], matchMedia: MediaQueryList | false = false): void => {
spoilersArray.forEach((spoilersBlock) => {
if (matchMedia && 'item' in spoilersBlock) {
spoilersBlock = (spoilersBlock as unknown as IBreakpoint).item
}
if ((matchMedia as MediaQueryList)?.matches || !matchMedia) {
spoilersBlock.classList.add('_spoiler-init')
initSpoilerBody(spoilersBlock)
spoilersBlock.addEventListener('click', setSpoilerAction)
} else {
spoilersBlock.classList.remove('_spoiler-init')
initSpoilerBody(spoilersBlock, false)
spoilersBlock.removeEventListener('click', setSpoilerAction)
}
})
}
// Работа с контентом
const initSpoilerBody = (spoilersBlock: HTMLElement, hideSpoilerBody = true): void => {
const spoilerTitlesNodeList = spoilersBlock.querySelectorAll<HTMLElement>('[data-spoiler]')
const spoilerTitles = Array.from(spoilerTitlesNodeList).filter((item) => {
return item.closest('[data-spoilers]') === spoilersBlock
})
if (spoilerTitles.length) {
spoilerTitles.forEach((spoilerTitle) => {
if (hideSpoilerBody) {
spoilerTitle.removeAttribute('tabindex')
if (!spoilerTitle.classList.contains('_spoiler-active')) {
const nextElement = spoilerTitle.nextElementSibling as HTMLElement
if (nextElement) {
nextElement.hidden = true
}
}
} else {
spoilerTitle.setAttribute('tabindex', '-1')
const nextElement = spoilerTitle.nextElementSibling as HTMLElement
if (nextElement) {
nextElement.hidden = false
}
}
})
}
}
// Инициализация обычных спойлеров
if (spoilersRegular.length) {
initSpoilers(spoilersRegular, false)
}
// Получение спойлеров с медиа запросами
const mdQueriesArray = dataMediaQueries(spoilersArray, 'spoilers')
if (mdQueriesArray && mdQueriesArray.length) {
mdQueriesArray.forEach((mdQueriesItem) => {
mdQueriesItem.matchMedia.addEventListener('change', () => {
initSpoilers(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
initSpoilers(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
}
const hideSpoilersBody = (spoilersBlock: HTMLElement): void => {
const spoilerActiveTitle = spoilersBlock.querySelector<HTMLElement>('[data-spoiler]._spoiler-active')
const spoilerSpeed = spoilersBlock.dataset.spoilersSpeed
? Number.parseInt(spoilersBlock.dataset.spoilersSpeed)
: 500
if (spoilerActiveTitle && !spoilersBlock.querySelectorAll('._slide').length) {
spoilerActiveTitle.classList.remove('_spoiler-active')
const nextElement = spoilerActiveTitle.nextElementSibling as HTMLElement
if (nextElement) {
_slideUp(nextElement, spoilerSpeed)
}
}
}
// Закрытие при клике вне спойлера
const spoilersClose = document.querySelectorAll<HTMLElement>('[data-spoiler-close]')
if (spoilersClose.length) {
document.addEventListener('click', (e: MouseEvent) => {
const el = e.target as HTMLElement
if (!el.closest('[data-spoilers]')) {
spoilersClose.forEach((spoilerClose) => {
const spoilersBlock = spoilerClose.closest('[data-spoilers]') as HTMLElement | null
if (spoilersBlock?.classList.contains('_spoiler-init')) {
const spoilerSpeed = spoilersBlock.dataset.spoilersSpeed
? Number.parseInt(spoilersBlock.dataset.spoilersSpeed)
: 500
spoilerClose.classList.remove('_spoiler-active')
const nextElement = spoilerClose.nextElementSibling as HTMLElement
if (nextElement) {
_slideUp(nextElement, spoilerSpeed)
}
}
})
}
})
}
}
}
// Модуль работы с табами =======================================================================================================================================================================================================================
export function tabs(): void {
const tabs = document.querySelectorAll<HTMLElement>('[data-tabs]')
let tabsActiveHash: string[] = []
if (tabs.length > 0) {
const hash = getHash()
if (hash && hash.startsWith('tab-')) {
tabsActiveHash = hash.replace('tab-', '').split('-')
}
Array.from(tabs).forEach((tabsBlock, index) => {
if (tabsBlock.getAttribute('data-tabs') === 'hover') {
tabsBlock.addEventListener('mouseover', setTabsAction)
} else {
tabsBlock.addEventListener('click', setTabsAction)
}
tabsBlock.classList.add('_tab-init')
tabsBlock.setAttribute('data-tabs-index', String(index))
initTabs(tabsBlock)
})
// Получение спойлеров с медиа запросами
const mdQueriesArray = dataMediaQueries(tabs, 'tabs')
if (mdQueriesArray && mdQueriesArray.length) {
mdQueriesArray.forEach((mdQueriesItem) => {
// Событие
mdQueriesItem.matchMedia.addEventListener('change', () => {
setTitlePosition(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
setTitlePosition(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
}
}
function setTitlePosition(tabsMediaArray: HTMLElement[], matchMedia: MediaQueryList): void {
tabsMediaArray.forEach((tabsMediaItem) => {
const tabsTitles = tabsMediaItem.querySelector<HTMLElement>('[data-tabs-titles]')
const tabsTitleItemsNodeList = tabsMediaItem.querySelectorAll<HTMLElement>('[data-tabs-title]')
const tabsContent = tabsMediaItem.querySelector<HTMLElement>('[data-tabs-body]')
const tabsContentItemsNodeList = tabsMediaItem.querySelectorAll<HTMLElement>('[data-tabs-item]')
if (!tabsTitles || !tabsContent) {
return
}
const tabsTitleItems = Array.from(tabsTitleItemsNodeList).filter((item) => {
return item.closest('[data-tabs]') === tabsMediaItem
})
const tabsContentItems = Array.from(tabsContentItemsNodeList).filter((item) => {
return item.closest('[data-tabs]') === tabsMediaItem
})
tabsContentItems.forEach((tabsContentItem, index) => {
if (matchMedia.matches) {
tabsContent.append(tabsTitleItems[index])
tabsContent.append(tabsContentItem)
tabsMediaItem.classList.add('_tab-spoiler')
} else {
tabsTitles.append(tabsTitleItems[index])
tabsMediaItem.classList.remove('_tab-spoiler')
}
})
})
}
// Работа с контентом
function initTabs(tabsBlock: HTMLElement): void {
const tabsTitlesNodeList = tabsBlock.querySelectorAll<HTMLElement>('[data-tabs-titles]>*')
const tabsContentNodeList = tabsBlock.querySelectorAll<HTMLElement>('[data-tabs-body]>*')
const tabsBlockIndex = tabsBlock.dataset.tabsIndex
const tabsActiveHashBlock = tabsActiveHash[0] === tabsBlockIndex
if (tabsActiveHashBlock) {
const tabsActiveTitle = tabsBlock.querySelector<HTMLElement>('[data-tabs-titles]>._tab-active')
if (tabsActiveTitle) {
tabsActiveTitle.classList.remove('_tab-active')
}
}
if (tabsContentNodeList.length) {
const tabsContent = Array.from(tabsContentNodeList).filter((item) => {
return item.closest('[data-tabs]') === tabsBlock
})
const tabsTitles = Array.from(tabsTitlesNodeList).filter((item) => {
return item.closest('[data-tabs]') === tabsBlock
})
tabsContent.forEach((tabsContentItem, index) => {
if (tabsTitles[index]) {
tabsTitles[index].setAttribute('data-tabs-title', '')
tabsContentItem.setAttribute('data-tabs-item', '')
if (tabsActiveHashBlock && index === Number.parseInt(tabsActiveHash[1])) {
tabsTitles[index].classList.add('_tab-active')
}
tabsContentItem.hidden = !tabsTitles[index].classList.contains('_tab-active')
}
})
}
}
function setTabsStatus(tabsBlock: HTMLElement): void {
const tabsTitles = Array.from(tabsBlock.querySelectorAll<HTMLElement>('[data-tabs-title]'))
const tabsContent = Array.from(tabsBlock.querySelectorAll<HTMLElement>('[data-tabs-item]'))
const tabsBlockIndex = tabsBlock.dataset.tabsIndex
function isTabsAnimate(tabsBlock: HTMLElement): number | false {
if (tabsBlock.hasAttribute('data-tabs-animate')) {
return tabsBlock.dataset.tabsAnimate ? Number.parseInt(tabsBlock.dataset.tabsAnimate) : 500
}
return false
}
const tabsBlockAnimate = isTabsAnimate(tabsBlock)
if (tabsContent.length > 0) {
const isHash = tabsBlock.hasAttribute('data-tabs-hash')
tabsContent.forEach((tabsContentItem, index) => {
const tabTitle = tabsTitles[index]
if (!tabTitle) {
return
}
if (tabTitle.classList.contains('_tab-active')) {
if (tabsBlockAnimate) {
_slideDown(tabsContentItem, tabsBlockAnimate)
} else {
tabsContentItem.hidden = false
}
if (isHash && !tabsContentItem.closest('.popup')) {
setHash(`tab-${tabsBlockIndex}-${index}`)
}
} else {
if (tabsBlockAnimate) {
_slideUp(tabsContentItem, tabsBlockAnimate)
} else {
tabsContentItem.hidden = true
}
}
})
}
}
function setTabsAction(e: Event): void {
const el = e.target as HTMLElement
const tabTitle = el.closest('[data-tabs-title]') as HTMLElement | null
if (tabTitle) {
const tabsBlock = tabTitle.closest('[data-tabs]') as HTMLElement | null
if (tabsBlock && !tabTitle.classList.contains('_tab-active') && !tabsBlock.querySelector('._slide')) {
const tabActiveTitle = tabsBlock.querySelector<HTMLElement>('[data-tabs-title]._tab-active')
if (tabActiveTitle) {
tabActiveTitle.classList.remove('_tab-active')
}
tabTitle.classList.add('_tab-active')
setTabsStatus(tabsBlock)
}
e.preventDefault()
}
}
}
// Обработка медиа запросов из атрибутов
export function dataMediaQueries(array: NodeListOf<HTMLElement>, dataSetValue: string): IMediaQueryResult[] {
// Получение объектов с медиа запросами
const media = Array.from(array).filter((item) => {
const dataset = item.dataset[dataSetValue]
return dataset ? dataset.split(',')[0] : false
})
// Инициализация объектов с медиа запросами
if (media.length) {
const breakpointsArray: IBreakpoint[] = []
media.forEach((item) => {
const params = item.dataset[dataSetValue]
if (!params) {
return
}
const paramsArray = params.split(',')
breakpointsArray.push({
value: paramsArray[0],
type: paramsArray[1] ? paramsArray[1].trim() : 'max',
item,
})
})
// Получаем уникальные брейкпоинты
const mdQueries = uniqArray(
breakpointsArray.map((item) => {
return `(${item.type}-width: ${item.value}px),${item.value},${item.type}`
})
)
return mdQueries.map((breakpoint): IMediaQueryResult => {
const [query, value, type] = breakpoint.split(',')
const matchMedia = window.matchMedia(query)
const itemsArray = breakpointsArray
.filter((item) => {
return item.value === value && item.type === type
})
.map((item) => {
return item.item
})
return {
itemsArray,
matchMedia,
}
})
}
return []
}
// Модуль работы с меню (бургер) =======================================================================================================================================================================================================================
export function menuInit(): void {
if (document.querySelector<HTMLElement>('[data-menu-button]')) {
document.addEventListener('click', (e: MouseEvent) => {
const target = e.target as HTMLElement
if (bodyLockStatus && target.closest('[data-menu-button]')) {
bodyLockToggle()
document.documentElement.classList.toggle('menu-open')
}
})
}
}
export function menuOpen() {
bodyLock()
document.documentElement.classList.add('menu-open')
}
export function menuClose() {
bodyUnlock()
document.documentElement.classList.remove('menu-open')
}
// Модуль "показать еще" =======================================================================================================================================================================================================================
export function showMore(): void {
window.addEventListener('load', () => {
const showMoreBlocks = document.querySelectorAll<HTMLElement>('[data-showmore]')
let showMoreBlocksRegular: HTMLElement[] = []
let mdQueriesArray: IMediaQueryItem[] | undefined
if (showMoreBlocks.length) {
// Получение обычных объектов
showMoreBlocksRegular = Array.from(showMoreBlocks).filter((item) => {
return !item.dataset.showmoreMedia
})
// Инициализация обычных объектов
if (showMoreBlocksRegular.length) {
initItems(showMoreBlocksRegular, false)
}
document.addEventListener('click', showMoreActions)
window.addEventListener('resize', showMoreActions)
// Получение объектов с медиа запросами
mdQueriesArray = dataMediaQueries(showMoreBlocks, 'showmoreMedia')
if (mdQueriesArray && mdQueriesArray.length) {
mdQueriesArray.forEach((mdQueriesItem) => {
// Событие
mdQueriesItem.matchMedia.addEventListener('change', () => {
initItems(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
})
initItemsMedia(mdQueriesArray)
}
}
function initItemsMedia(mdQueriesArray: IMediaQueryItem[]): void {
mdQueriesArray.forEach((mdQueriesItem) => {
initItems(mdQueriesItem.itemsArray, mdQueriesItem.matchMedia)
})
}
function initItems(showMoreBlocks: HTMLElement[], matchMedia: MediaQueryList | false): void {
showMoreBlocks.forEach((showMoreBlock) => {
initItem(showMoreBlock, matchMedia)
})
}
function initItem(showMoreBlock: HTMLElement, matchMedia: MediaQueryList | false = false): void {
showMoreBlock =
matchMedia && 'item' in showMoreBlock ? (showMoreBlock as unknown as IBreakpoint).item : showMoreBlock
if ((matchMedia as MediaQueryList)?.matches || !matchMedia) {
const showMoreContent = showMoreBlock.querySelector<HTMLElement>('[data-showmore-content]')
const showMoreButton = showMoreBlock.querySelector<HTMLElement>('[data-showmore-button]')
if (!showMoreContent || !showMoreButton) {
return
}
const hiddenHeight = getHeight(showMoreBlock, showMoreContent)
if (hiddenHeight < getOriginalHeight(showMoreContent)) {
_slideUp(showMoreContent, 0, hiddenHeight)
showMoreButton.hidden = false
} else {
_slideDown(showMoreContent, 0, hiddenHeight)
showMoreButton.hidden = true
}
}
}
function getHeight(showMoreBlock: HTMLElement, showMoreContent: HTMLElement) {
let hiddenHeight = 0
const showMoreType = showMoreBlock.dataset.showmore ? showMoreBlock.dataset.showmore : 'size'
if (showMoreType === 'items') {
const showMoreTypeValue = showMoreContent.dataset.showmoreContent
? showMoreContent.dataset.showmoreContent
: 3
const showMoreItems = showMoreContent.children
for (
let index = 0;
index < Number.parseInt(showMoreTypeValue as string) && index < showMoreItems.length;
index++
) {
const showMoreItem = showMoreItems[index]
hiddenHeight += (showMoreItem as HTMLElement).offsetHeight
}
} else {
const showMoreTypeValue = showMoreContent.dataset.showmoreContent
? showMoreContent.dataset.showmoreContent
: 150
hiddenHeight = Number.parseInt(showMoreTypeValue as string)
}
return hiddenHeight
}
function getOriginalHeight(showMoreContent: HTMLElement) {
let parentHidden: HTMLElement | null = null
const hiddenHeight = showMoreContent.offsetHeight
showMoreContent.style.removeProperty('height')
if (showMoreContent.closest(`[hidden]`)) {
parentHidden = showMoreContent.closest(`[hidden]`) as HTMLElement
parentHidden.hidden = false
}
const originalHeight = showMoreContent.offsetHeight
if (parentHidden) {
parentHidden.hidden = true
}
showMoreContent.style.height = `${hiddenHeight}px`
return originalHeight
}
function showMoreActions(e: Event): void {
const targetEvent = e.target as HTMLElement
const targetType = e.type
if (targetType === 'click') {
if (targetEvent.closest('[data-showmore-button]')) {
const showMoreButton = targetEvent.closest('[data-showmore-button]') as HTMLElement
const showMoreBlock = showMoreButton.closest('[data-showmore]') as HTMLElement
const showMoreContent = showMoreBlock.querySelector<HTMLElement>('[data-showmore-content]')
if (!showMoreContent) {
return
}
const showMoreSpeed = showMoreBlock.dataset.showmoreButton
? Number.parseInt(showMoreBlock.dataset.showmoreButton as string)
: 500
const hiddenHeight = getHeight(showMoreBlock, showMoreContent)
if (!showMoreContent.classList.contains('_slide')) {
showMoreBlock.classList.contains('_showmore-active')
? _slideUp(showMoreContent, showMoreSpeed, hiddenHeight)
: _slideDown(showMoreContent, showMoreSpeed, hiddenHeight)
showMoreBlock.classList.toggle('_showmore-active')
}
}
} else if (targetType === 'resize') {
if (showMoreBlocksRegular.length) {
initItems(showMoreBlocksRegular, false)
}
if (mdQueriesArray && mdQueriesArray.length) {
initItemsMedia(mdQueriesArray)
}
}
}
})
}
// ================================================================================================================================================================================================================================================================================================================
// Прочие полезные функции ================================================================================================================================================================================================================================================================================================================
// ================================================================================================================================================================================================================================================================================================================
// FLS (Full Logging System)
export function FLS(message: string): void {
setTimeout(() => {
if (window.FLS) {
// eslint-disable-next-line no-console
console.log(message)
}
}, 0)
}
// Получить цифры из строки
export function getDigFromString(item: string): number {
return Number.parseInt(item.replace(/\D/g, ''))
}
// Форматирование цифр типа 100 000 000
export function getDigFormat(item: number | string): string {
return item.toString().replace(/(\d)(?=(?:\d\d\d)+(?:\D|$))/g, '$1 ')
}
// Убрать класс из всех элементов массива
export function removeClasses(array: HTMLElement[], className: string): void {
for (let i = 0; i < array.length; i++) {
array[i].classList.remove(className)
}
}
// Уникализация массива
export function uniqArray<T>(array: T[]): T[] {
return array.filter((item, index, self) => {
return self.indexOf(item) === index
})
}
// Функция получения индекса внутри родителя
export function indexInParent(parent: Element, element: Element): number {
const array = Array.prototype.slice.call(parent.children)
return Array.prototype.indexOf.call(array, element)
}
// Функция проверяет, скрыт ли объект
export function isHidden(el: HTMLElement): boolean {
return el.offsetParent === null
}