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.
 
 
 
 
 

361 lines
11 KiB

import { whichChild, findUpTag } from "../lib/utils";
import Config from "../lib/config";
let rippleClickID = 0;
export function ripple(elem: HTMLElement, callback: (id: number) => Promise<boolean | void> = () => Promise.resolve(), onEnd: (id: number) => void = null) {
let r = document.createElement('div');
r.classList.add('c-ripple');
elem.append(r);
elem.addEventListener('mousedown', (e) => {
if(elem.dataset.ripple == '0') {
return false;
}
let startTime = Date.now();
let span = document.createElement('span');
let clickID = rippleClickID++;
console.log('ripple mousedown');
let handler = () => {
let elapsedTime = Date.now() - startTime;
if(elapsedTime < 700) {
let delay = Math.max(700 - elapsedTime, 350);
setTimeout(() => span.classList.add('hiding'), Math.max(delay - 350, 0));
setTimeout(() => {
//console.log('ripple elapsedTime total pre-remove:', Date.now() - startTime);
span.remove();
if(onEnd) onEnd(clickID);
}, delay);
} else {
span.classList.add('hiding');
setTimeout(() => {
//console.log('ripple elapsedTime total pre-remove:', Date.now() - startTime);
span.remove();
if(onEnd) onEnd(clickID);
}, 350);
}
};
callback && callback(clickID);
/* callback().then((bad) => {
if(bad) {
span.remove();
return;
} */
//console.log('ripple after promise', Date.now() - startTime);
//console.log('ripple tooSlow:', tooSlow);
/* if(tooSlow) {
span.remove();
return;
} */
window.requestAnimationFrame(() => {
span.classList.add('c-ripple__circle');
let rect = r.getBoundingClientRect();
let clickX = e.clientX - rect.left;
let clickY = e.clientY - rect.top;
let size: number, clickPos: number;
if(rect.width > rect.height) {
size = rect.width;
clickPos = clickX;
} else {
size = rect.height;
clickPos = clickY;
}
let offsetFromCenter = clickPos > (size / 2) ? size - clickPos : clickPos;
size = size - offsetFromCenter;
size *= 1.1;
// center of circle
let x = clickX - size / 2;
let y = clickY - size / 2;
//console.log('ripple click', offsetFromCenter, size, clickX, clickY);
span.style.width = span.style.height = size + 'px';
span.style.left = x + 'px';
span.style.top = y + 'px';
r.append(span);
//r.classList.add('active');
//handler();
});
//});
window.addEventListener('mouseup', () => {
//console.time('appImManager: pre render start');
handler();
}, {once: true});
});
}
let loadedURLs: {[url: string]: boolean} = {};
let set = (elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) => {
if(elem instanceof HTMLImageElement || elem instanceof HTMLSourceElement) elem.src = url;
else if(elem instanceof SVGImageElement) elem.setAttributeNS(null, 'href', url);
else elem.style.backgroundImage = 'url(' + url + ')';
};
export function renderImageFromUrl(elem: HTMLElement | HTMLImageElement | SVGImageElement | HTMLSourceElement, url: string) {
if(loadedURLs[url]) {
set(elem, url);
return true;
}
if(elem instanceof HTMLSourceElement) {
elem.src = url;
} else {
let loader = new Image();
loader.src = url;
loader.onload = () => {
set(elem, url);
loadedURLs[url] = true;
};
}
return false;
}
export function putPreloader(elem: Element, returnDiv = false) {
const html = `
<svg xmlns="http://www.w3.org/2000/svg" class="preloader-circular" viewBox="25 25 50 50">
<circle class="preloader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"/>
</svg>`;
if(returnDiv) {
let div = document.createElement('div');
div.classList.add('preloader');
div.innerHTML = html;
if(elem) {
elem.appendChild(div);
}
return div;
}
elem.innerHTML += html;
}
export function horizontalMenu(tabs: HTMLElement, content: HTMLDivElement, onClick?: (id: number, tabContent: HTMLDivElement) => void, onTransitionEnd?: () => void, transitionTime = 300) {
let hideTimeout: number = 0;
let prevTabContent: HTMLDivElement = null;
let prevId = -1;
let children = Array.from(content.children);
let tabsChildren = tabs ? Array.from(tabs.firstElementChild.children) : [];
let activeInSlide: Set<Element> = new Set();
let selectTab = async(id: number) => {
if(id == prevId) return false;
let p = prevTabContent;
/* children.forEach(child => {
if(child != p) {
child.classList.remove('active');
}
}); */
let tabContent = content.children[id] as HTMLDivElement;
tabContent.classList.add('active');
if(!activeInSlide.has(tabContent)) {
activeInSlide.add(tabContent);
}
//content.style.marginLeft = id > 0 ? (-id * 100) + '%' : '';
let toRight = prevId < id;
if(prevId != -1) {
//content.classList.remove('animated');
await new Promise((resolve) => window.requestAnimationFrame(() => {
content.style.cssText = `will-change: width, transform; width: ${activeInSlide.size * 100}%; transform: translateX(-${100 - 100 / activeInSlide.size}%);`;
content.classList.remove('animated');
if(toRight) {
content.classList.add('animated');
} else {
window.requestAnimationFrame(() => {
content.classList.add('animated');
content.style.transform = '';
});
}
resolve();
}));
/* content.style.cssText = `will-change: width, transform; width: ${activeInSlide.size * 100}%; transform: translateX(-${100 - 100 / activeInSlide.size}%);`;
content.classList.remove('animated');
if(toRight) {
content.classList.add('animated');
} else {
window.requestAnimationFrame(() => {
content.classList.add('animated');
content.style.transform = '';
});
} */
}
if(hideTimeout) clearTimeout(hideTimeout);
if(p/* && false */) {
//if(tabs) tabs.classList.add('disable-hover');
if(tabs) {
tabsChildren.forEach((c, idx) => {
if(idx != prevId && idx != id) {
(c as HTMLElement).dataset.ripple = '0';
}
});
}
hideTimeout = setTimeout(() => {
children.forEach(child => {
if(child != tabContent) {
child.classList.remove('active');
activeInSlide.delete(child);
}
});
if(tabs) {
tabsChildren.forEach(c => {
delete (c as HTMLElement).dataset.ripple;
});
}
content.classList.remove('animated');
content.style.cssText = '';
hideTimeout = 0;
if(onTransitionEnd) onTransitionEnd();
//if(tabs) tabs.classList.remove('disable-hover');
}, transitionTime);
}
prevId = id;
prevTabContent = tabContent;
};
if(tabs) {
let activeStripe = document.createElement('span');
activeStripe.classList.add('menu-horizontal__stripe');
tabs.append(activeStripe);
tabs.addEventListener('click', function(e) {
let target = e.target as HTMLLIElement;
if(target.tagName != 'LI') {
target = findUpTag(target, 'LI');
}
//console.log('tabs click:', target);
if(!target) return false;
let id = whichChild(target);
let tabContent = content.children[id] as HTMLDivElement;
if(activeInSlide.size >= 2 && !activeInSlide.has(tabContent)) {
return false;
}
if(onClick) onClick(id, tabContent);
if(target.classList.contains('active') || id == prevId) {
return false;
}
let prev = tabs.querySelector('li.active') as HTMLLIElement;
prev && prev.classList.remove('active');
let tabsRect = tabs.getBoundingClientRect();
let textRect = target.firstElementChild.getBoundingClientRect();
activeStripe.style.cssText = `width: ${textRect.width + (2 * 2)}px; transform: translateX(${textRect.left - tabsRect.left}px);`;
//activeStripe.style.transform = `scaleX(${textRect.width}) translateX(${(textRect.left - tabsRect.left) / textRect.width + 0.5}px)`;
console.log('tabs click:', tabsRect, textRect);
target.classList.add('active');
selectTab(id);
});
}
return selectTab;
}
export function formatPhoneNumber(str: string) {
str = str.replace(/\D/g, '');
let phoneCode = str.slice(0, 6);
////console.log('str', str, phoneCode);
let sortedCountries = Config.Countries.slice().sort((a, b) => b.phoneCode.length - a.phoneCode.length);
let country = sortedCountries.find((c) => {
return c.phoneCode.split(' and ').find((c) => phoneCode.indexOf(c.replace(/\D/g, '')) == 0);
});
let pattern = country ? country.pattern || country.phoneCode : '';
if(country) {
pattern.split('').forEach((symbol, idx) => {
if(symbol == ' ' && str[idx] != ' ' && str.length > idx) {
str = str.slice(0, idx) + ' ' + str.slice(idx);
}
});
if(country.pattern) {
str = str.slice(0, country.pattern.length);
}
}
return {formatted: str, country};
}
let onMouseMove = (e: MouseEvent) => {
let rect = openedMenu.getBoundingClientRect();
let {clientX, clientY} = e;
let diffX = clientX >= rect.right ? clientX - rect.right : rect.left - clientX;
let diffY = clientY >= rect.bottom ? clientY - rect.bottom : rect.top - clientY;
if(diffX >= 100 || diffY >= 100) {
openedMenu.classList.remove('active');
openedMenu.parentElement.classList.remove('menu-open');
//openedMenu.parentElement.click();
}
//console.log('mousemove', diffX, diffY);
};
let openedMenu: HTMLDivElement = null;
export function openBtnMenu(menuElement: HTMLDivElement) {
if(openedMenu) {
openedMenu.classList.remove('active');
openedMenu.parentElement.classList.remove('menu-open');
}
openedMenu = menuElement;
openedMenu.classList.add('active');
openedMenu.parentElement.classList.add('menu-open');
window.addEventListener('click', () => {
if(openedMenu) {
openedMenu.parentElement.classList.remove('menu-open');
openedMenu.classList.remove('active');
openedMenu = null;
}
window.removeEventListener('mousemove', onMouseMove);
}, {once: true});
window.addEventListener('mousemove', onMouseMove);
}