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.
220 lines
6.6 KiB
220 lines
6.6 KiB
/* |
|
* https://github.com/morethanwords/tweb |
|
* Copyright (C) 2019-2021 Eduard Kuzmenko |
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE |
|
*/ |
|
|
|
import {horizontalMenu} from './horizontalMenu'; |
|
import TransitionSlider from './transition'; |
|
import appNavigationController, {NavigationItem} from './appNavigationController'; |
|
import SliderSuperTab, {SliderSuperTabConstructable} from './sliderTab'; |
|
import indexOfAndSplice from '../helpers/array/indexOfAndSplice'; |
|
import safeAssign from '../helpers/object/safeAssign'; |
|
import {AppManagers} from '../lib/appManagers/managers'; |
|
import {getMiddleware, MiddlewareHelper} from '../helpers/middleware'; |
|
import {MaybePromise} from '../types'; |
|
|
|
const TRANSITION_TIME = 250; |
|
|
|
export {SliderSuperTab}; |
|
|
|
export default class SidebarSlider { |
|
protected _selectTab: ReturnType<typeof horizontalMenu>; |
|
protected historyTabIds: (number | SliderSuperTab)[] = []; // * key is any, since right sidebar is ugly nowz |
|
protected tabsContainer: HTMLElement; |
|
public sidebarEl: HTMLElement; |
|
protected tabs: Map<any, SliderSuperTab>; // * key is any, since right sidebar is ugly now |
|
private canHideFirst = false; |
|
private navigationType: NavigationItem['type']; |
|
protected managers: AppManagers; |
|
protected middlewareHelper: MiddlewareHelper; |
|
public onOpenTab: () => MaybePromise<void>; |
|
|
|
constructor(options: { |
|
sidebarEl: SidebarSlider['sidebarEl'], |
|
tabs?: SidebarSlider['tabs'], |
|
canHideFirst?: SidebarSlider['canHideFirst'], |
|
navigationType: SidebarSlider['navigationType'] |
|
}) { |
|
safeAssign(this, options); |
|
|
|
this.tabs ??= new Map(); |
|
|
|
this.tabsContainer = this.sidebarEl.querySelector('.sidebar-slider'); |
|
this._selectTab = TransitionSlider({ |
|
content: this.tabsContainer, |
|
type: 'navigation', |
|
transitionTime: TRANSITION_TIME |
|
}); |
|
if(!this.canHideFirst) { |
|
this._selectTab(0); |
|
} |
|
|
|
this.middlewareHelper = getMiddleware(); |
|
|
|
// Array.from(this.sidebarEl.querySelectorAll('.sidebar-close-button') as any as HTMLElement[]).forEach((el) => { |
|
// attachClickEvent(el, this.onCloseBtnClick); |
|
// }); |
|
} |
|
|
|
public getMiddleware() { |
|
return this.middlewareHelper.get(); |
|
} |
|
|
|
public onCloseBtnClick = () => { |
|
const item = appNavigationController.findItemByType(this.navigationType); |
|
if(item) { |
|
appNavigationController.back(this.navigationType); |
|
} else if(this.historyTabIds.length) { |
|
this.closeTab(this.historyTabIds[this.historyTabIds.length - 1]); |
|
} |
|
// this.closeTab(); |
|
}; |
|
|
|
public closeTab = (id?: number | SliderSuperTab, animate?: boolean, isNavigation?: boolean) => { |
|
if(id !== undefined && this.historyTabIds[this.historyTabIds.length - 1] !== id) { |
|
this.removeTabFromHistory(id); |
|
return false; |
|
} |
|
|
|
// console.log('sidebar-close-button click:', this.historyTabIDs); |
|
const closingId = this.historyTabIds.pop(); // pop current |
|
this.onCloseTab(closingId, animate, isNavigation); |
|
|
|
const tab = this.historyTabIds[this.historyTabIds.length - 1]; |
|
this._selectTab(tab !== undefined ? (tab instanceof SliderSuperTab ? tab.container : tab) : (this.canHideFirst ? -1 : 0), animate); |
|
return true; |
|
}; |
|
|
|
public async selectTab(id: number | SliderSuperTab) { |
|
/* if(id instanceof SliderSuperTab) { |
|
id = id.id; |
|
} */ |
|
|
|
if(this.historyTabIds[this.historyTabIds.length - 1] === id) { |
|
return false; |
|
} |
|
|
|
const tab: SliderSuperTab = id instanceof SliderSuperTab ? id : this.tabs.get(id); |
|
this.onOpenTab && await this.onOpenTab(); |
|
|
|
if(tab) { |
|
// @ts-ignore |
|
tab.onOpen?.(); |
|
|
|
// @ts-ignore |
|
if(tab.onOpenAfterTimeout) { |
|
setTimeout(() => { |
|
// @ts-ignore |
|
tab.onOpenAfterTimeout(); |
|
}, TRANSITION_TIME); |
|
} |
|
} |
|
|
|
const navigationItem: NavigationItem = { |
|
type: this.navigationType, |
|
onPop: (canAnimate) => { |
|
if(tab.isConfirmationNeededOnClose) { |
|
const result = tab.isConfirmationNeededOnClose(); |
|
if(result) { |
|
Promise.resolve(result).then(() => { |
|
appNavigationController.removeItem(navigationItem); |
|
this.closeTab(undefined, undefined, true); |
|
}); |
|
|
|
return false; |
|
} |
|
} |
|
|
|
this.closeTab(undefined, canAnimate, true); |
|
return true; |
|
} |
|
}; |
|
|
|
// if(!this.canHideFirst || this.historyTabIds.length) { |
|
appNavigationController.pushItem(navigationItem); |
|
// } |
|
|
|
this.historyTabIds.push(id); |
|
this._selectTab(id instanceof SliderSuperTab ? id.container : id); |
|
return true; |
|
} |
|
|
|
public removeTabFromHistory(id: number | SliderSuperTab) { |
|
indexOfAndSplice(this.historyTabIds, id); |
|
this.onCloseTab(id, undefined); |
|
} |
|
|
|
public sliceTabsUntilTab(tabConstructor: SliderSuperTabConstructable, preserveTab: SliderSuperTab) { |
|
for(let i = this.historyTabIds.length - 1; i >= 0; --i) { |
|
const tab = this.historyTabIds[i]; |
|
if(tab === preserveTab) continue; |
|
else if(tab instanceof tabConstructor) { |
|
break; |
|
} |
|
|
|
this.removeTabFromHistory(tab); |
|
// appNavigationController.removeByType(this.navigationType, true); |
|
} |
|
} |
|
|
|
public getTab<T extends SliderSuperTab>(tabConstructor: SliderSuperTabConstructable<T>) { |
|
return this.historyTabIds.find((t) => t instanceof tabConstructor) as T; |
|
} |
|
|
|
public getHistory() { |
|
return this.historyTabIds; |
|
} |
|
|
|
public isTabExists(tabConstructor: SliderSuperTabConstructable) { |
|
return !!this.getTab(tabConstructor); |
|
} |
|
|
|
protected onCloseTab(id: number | SliderSuperTab, animate: boolean, isNavigation?: boolean) { |
|
if(!isNavigation) { |
|
appNavigationController.removeByType(this.navigationType, true); |
|
} |
|
|
|
const tab: SliderSuperTab = id instanceof SliderSuperTab ? id : this.tabs.get(id); |
|
if(tab) { |
|
try { |
|
// @ts-ignore |
|
tab.onClose?.(); |
|
} catch(err) { |
|
console.error('tab onClose error', tab); |
|
} |
|
|
|
// @ts-ignore |
|
if(tab.onCloseAfterTimeout) { |
|
setTimeout(() => { |
|
// @ts-ignore |
|
tab.onCloseAfterTimeout(); |
|
}, TRANSITION_TIME + 30); |
|
} |
|
} |
|
} |
|
|
|
public addTab(tab: SliderSuperTab) { |
|
if(!tab.container.parentElement) { |
|
this.tabsContainer.append(tab.container); |
|
|
|
if(tab.closeBtn) { |
|
tab.closeBtn.addEventListener('click', this.onCloseBtnClick); |
|
} |
|
} |
|
} |
|
|
|
public deleteTab(tab: SliderSuperTab) { |
|
this.tabs.delete(tab); |
|
} |
|
|
|
public createTab<T extends SliderSuperTab>( |
|
ctor: SliderSuperTabConstructable<T>, |
|
destroyable = true, |
|
doNotAppend?: boolean |
|
) { |
|
const tab = new ctor(doNotAppend ? undefined : this, destroyable); |
|
tab.managers = this.managers; |
|
return tab; |
|
} |
|
}
|
|
|