Telegram Web K with changes to work inside I2P
https://web.telegram.i2p/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.5 KiB
139 lines
4.5 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import {TransitionSlider} from './transition'; |
|
import {ScrollableX} from './scrollable'; |
|
import rootScope from '../lib/rootScope'; |
|
import {fastRaf} from '../helpers/schedulers'; |
|
import {FocusDirection} from '../helpers/fastSmoothScroll'; |
|
import findUpAsChild from '../helpers/dom/findUpAsChild'; |
|
import whichChild from '../helpers/dom/whichChild'; |
|
import ListenerSetter from '../helpers/listenerSetter'; |
|
import {attachClickEvent} from '../helpers/dom/clickEvent'; |
|
|
|
export function horizontalMenu( |
|
tabs: HTMLElement, |
|
content: HTMLElement, |
|
onClick?: (id: number, tabContent: HTMLDivElement, animate: boolean) => void | boolean | Promise<void | boolean>, |
|
onTransitionEnd?: () => void, |
|
transitionTime = 250, |
|
scrollableX?: ScrollableX, |
|
listenerSetter?: ListenerSetter |
|
) { |
|
const selectTab = TransitionSlider(content, tabs || content.dataset.animation === 'tabs' ? 'tabs' : 'navigation', transitionTime, onTransitionEnd, undefined, listenerSetter); |
|
|
|
if(!tabs) { |
|
return selectTab; |
|
} |
|
|
|
const proxy = new Proxy(selectTab, { |
|
apply: (target, that, args) => { |
|
const id = +args[0]; |
|
const animate = args[1] !== undefined ? args[1] : true; |
|
|
|
const el = (tabs.querySelector(`[data-tab="${id}"]`) || tabs.children[id]) as HTMLElement; |
|
selectTarget(el, id, animate); |
|
} |
|
}); |
|
|
|
const selectTarget = async(target: HTMLElement, id: number, animate = true) => { |
|
const tabContent = content.children[id] as HTMLDivElement; |
|
|
|
if(onClick) { |
|
const result1 = onClick(id, tabContent, animate); |
|
const canChange = result1 instanceof Promise ? await result1 : result1; |
|
if(canChange !== undefined && !canChange) { |
|
return; |
|
} |
|
} |
|
|
|
if(scrollableX) { |
|
scrollableX.scrollIntoViewNew({ |
|
element: target.parentElement.children[id] as HTMLElement, |
|
position: 'center', |
|
forceDirection: animate ? undefined : FocusDirection.Static, |
|
forceDuration: transitionTime, |
|
axis: 'x' |
|
}); |
|
} |
|
|
|
if(!rootScope.settings.animationsEnabled) { |
|
animate = false; |
|
} |
|
|
|
const prevId = selectTab.prevId(); |
|
if(target.classList.contains('active') || id === prevId) { |
|
return false; |
|
} |
|
|
|
const mutateCallback = animate ? fastRaf : (cb: () => void) => cb(); |
|
|
|
const prev = tabs.querySelector(tagName.toLowerCase() + '.active') as HTMLElement; |
|
if(prev) { |
|
mutateCallback(() => { |
|
prev.classList.remove('active'); |
|
}); |
|
} |
|
|
|
// a great stripe from Jolly Cobra |
|
if(useStripe && prevId !== -1 && animate) { |
|
mutateCallback(() => { |
|
const indicator = target.querySelector('i')!; |
|
const currentIndicator = target.parentElement.children[prevId].querySelector('i')!; |
|
|
|
currentIndicator.classList.remove('animate'); |
|
indicator.classList.remove('animate'); |
|
|
|
// We move and resize our indicator so it repeats the position and size of the previous one. |
|
const shiftLeft = currentIndicator.parentElement.parentElement.offsetLeft - indicator.parentElement.parentElement.offsetLeft; |
|
const scaleFactor = currentIndicator.clientWidth / indicator.clientWidth; |
|
indicator.style.transform = `translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`; |
|
|
|
// console.log(`translate3d(${shiftLeft}px, 0, 0) scale3d(${scaleFactor}, 1, 1)`); |
|
|
|
fastRaf(() => { |
|
// Now we remove the transform to let it animate to its own position and size. |
|
indicator.classList.add('animate'); |
|
indicator.style.transform = 'none'; |
|
}); |
|
}); |
|
} |
|
|
|
mutateCallback(() => { |
|
target.classList.add('active'); |
|
}); |
|
|
|
selectTab(id, animate); |
|
}; |
|
|
|
const useStripe = !tabs.classList.contains('no-stripe'); |
|
|
|
// const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI'; |
|
const tagName = tabs.firstElementChild.tagName; |
|
attachClickEvent(tabs, (e) => { |
|
let target = e.target as HTMLElement; |
|
|
|
target = findUpAsChild(target, tabs); |
|
|
|
// console.log('tabs click:', target); |
|
|
|
if(!target) return false; |
|
|
|
let id: number; |
|
if(target.dataset.tab) { |
|
id = +target.dataset.tab; |
|
if(id === -1) { |
|
return false; |
|
} |
|
} else { |
|
id = whichChild(target); |
|
} |
|
|
|
selectTarget(target, id); |
|
}, {listenerSetter}); |
|
|
|
return proxy; |
|
}
|
|
|