morethanwords 4 years ago
parent
commit
0c875ccbaf
  1. 27
      src/components/appNavigationController.ts
  2. 5
      src/components/chat/bubbles.ts
  3. 4
      src/components/chat/input.ts
  4. 2
      src/components/popups/datePicker.ts
  5. 35
      src/components/popups/index.ts
  6. 2
      src/components/popups/newMedia.ts
  7. 4
      src/helpers/userAgent.ts

27
src/components/appNavigationController.ts

@ -1,9 +1,12 @@
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
import { isSafari } from "../helpers/userAgent"; import { isSafari, isAppleMobile } from "../helpers/userAgent";
import { cancelEvent } from "../helpers/dom";
export type NavigationItem = { export type NavigationItem = {
type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | 'esg', type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | 'esg',
onPop: (canAnimate: boolean) => boolean | void onPop: (canAnimate: boolean) => boolean | void,
onEscape?: () => boolean,
noHistory?: boolean,
}; };
export class AppNavigationController { export class AppNavigationController {
@ -26,7 +29,7 @@ export class AppNavigationController {
return; return;
} }
const good = item.onPop(isSafari ? false : undefined); const good = item.onPop(isSafari && isAppleMobile ? false : undefined);
console.log('[NC]: popstate, navigation:', item, this.navigations); console.log('[NC]: popstate, navigation:', item, this.navigations);
if(good === false) { if(good === false) {
this.pushItem(item); this.pushItem(item);
@ -35,6 +38,15 @@ export class AppNavigationController {
//this.pushState(); // * prevent adding forward arrow //this.pushState(); // * prevent adding forward arrow
}); });
window.addEventListener('keydown', (e) => {
const item = this.navigations[this.navigations.length - 1];
if(!item) return;
if(e.key === 'Escape' && (item.onEscape ? item.onEscape() : true)) {
cancelEvent(e);
this.back();
}
}, {capture: true});
this.pushState(); // * push init state this.pushState(); // * push init state
} }
@ -45,7 +57,10 @@ export class AppNavigationController {
public pushItem(item: NavigationItem) { public pushItem(item: NavigationItem) {
this.navigations.push(item); this.navigations.push(item);
console.log('[NC]: pushstate', item, this.navigations); console.log('[NC]: pushstate', item, this.navigations);
this.pushState();
if(!item.noHistory) {
this.pushState();
}
} }
private pushState() { private pushState() {
@ -55,6 +70,10 @@ export class AppNavigationController {
public replaceState() { public replaceState() {
history.replaceState(this.id, ''); history.replaceState(this.id, '');
} }
public removeItem(item: NavigationItem) {
this.navigations.findAndSplice(i => i === item);
}
} }
const appNavigationController = new AppNavigationController(); const appNavigationController = new AppNavigationController();

5
src/components/chat/bubbles.ts

@ -1654,7 +1654,8 @@ export default class ChatBubbles {
public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) { public setBubblePosition(bubble: HTMLElement, message: any, reverse: boolean) {
const dateMessage = this.getDateContainerByMessage(message, reverse); const dateMessage = this.getDateContainerByMessage(message, reverse);
if(this.chat.type === 'scheduled' || this.chat.type === 'pinned') { if(this.chat.type === 'scheduled' || this.chat.type === 'pinned') {
let children = Array.from(dateMessage.container.children).slice(2) as HTMLElement[]; const offset = this.stickyIntersector ? 2 : 1;
let children = Array.from(dateMessage.container.children).slice(offset) as HTMLElement[];
let i = 0, foundMidOnSameTimestamp = 0; let i = 0, foundMidOnSameTimestamp = 0;
for(; i < children.length; ++i) { for(; i < children.length; ++i) {
const t = children[i]; const t = children[i];
@ -1671,7 +1672,7 @@ export default class ChatBubbles {
} }
// * 1 for date, 1 for date sentinel // * 1 for date, 1 for date sentinel
let index = this.stickyIntersector ? 2 + i : 1 + i; let index = offset + i;
/* if(bubble.parentElement) { // * if already mounted /* if(bubble.parentElement) { // * if already mounted
const currentIndex = whichChild(bubble); const currentIndex = whichChild(bubble);
if(index > currentIndex) { if(index > currentIndex) {

4
src/components/chat/input.ts

@ -556,7 +556,7 @@ export default class ChatInput {
} }
public saveDraft() { public saveDraft() {
if(!this.chat.peerId || this.editMsgId) return; if(!this.chat.peerId || this.editMsgId || this.chat.type === 'scheduled') return;
const entities: MessageEntity[] = []; const entities: MessageEntity[] = [];
const str = getRichValue(this.messageInputField.input, entities); const str = getRichValue(this.messageInputField.input, entities);
@ -604,7 +604,7 @@ export default class ChatInput {
} }
public setDraft(draft?: MyDraftMessage, fromUpdate = true) { public setDraft(draft?: MyDraftMessage, fromUpdate = true) {
if(!isInputEmpty(this.messageInput)) return false; if(!isInputEmpty(this.messageInput) || this.chat.type === 'scheduled') return false;
if(!draft) { if(!draft) {
draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId); draft = this.appDraftsManager.getDraft(this.chat.peerId, this.chat.threadId);

2
src/components/popups/datePicker.ts

@ -141,7 +141,7 @@ export default class PopupDatePicker extends PopupElement {
this.onPick(this.selectedDate.getTime() / 1000 | 0); this.onPick(this.selectedDate.getTime() / 1000 | 0);
} }
this.destroy(); this.hide();
}, {once: true}); }, {once: true});
this.body.append(this.timeDiv); this.body.append(this.timeDiv);

35
src/components/popups/index.ts

@ -2,6 +2,8 @@ import rootScope from "../../lib/rootScope";
import { blurActiveElement, cancelEvent, findUpClassName } from "../../helpers/dom"; import { blurActiveElement, cancelEvent, findUpClassName } from "../../helpers/dom";
import { ripple } from "../ripple"; import { ripple } from "../ripple";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
import appNavigationController, { NavigationItem } from "../appNavigationController";
import { isMobileSafari, isSafari } from "../../helpers/userAgent";
export type PopupOptions = Partial<{closable: true, overlayClosable: true, withConfirm: string, body: true}>; export type PopupOptions = Partial<{closable: true, overlayClosable: true, withConfirm: string, body: true}>;
export default class PopupElement { export default class PopupElement {
@ -17,6 +19,8 @@ export default class PopupElement {
protected onCloseAfterTimeout: () => void; protected onCloseAfterTimeout: () => void;
protected onEscape: () => boolean = () => true; protected onEscape: () => boolean = () => true;
protected navigationItem: NavigationItem;
constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) { constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) {
this.element.classList.add('popup'); this.element.classList.add('popup');
this.element.className = 'popup' + (className ? ' ' + className : ''); this.element.className = 'popup' + (className ? ' ' + className : '');
@ -33,7 +37,7 @@ export default class PopupElement {
//ripple(this.closeBtn); //ripple(this.closeBtn);
this.header.prepend(this.btnClose); this.header.prepend(this.btnClose);
this.btnClose.addEventListener('click', this.destroy, {once: true}); this.btnClose.addEventListener('click', this.hide, {once: true});
if(options.overlayClosable) { if(options.overlayClosable) {
const onOverlayClick = (e: MouseEvent) => { const onOverlayClick = (e: MouseEvent) => {
@ -46,8 +50,6 @@ export default class PopupElement {
} }
} }
window.addEventListener('keydown', this._onKeyDown, {capture: true});
if(options.withConfirm) { if(options.withConfirm) {
this.btnConfirm = document.createElement('button'); this.btnConfirm = document.createElement('button');
this.btnConfirm.classList.add('btn-primary'); this.btnConfirm.classList.add('btn-primary');
@ -98,14 +100,15 @@ export default class PopupElement {
this.element.append(this.container); this.element.append(this.container);
} }
private _onKeyDown = (e: KeyboardEvent) => {
if(e.key === 'Escape' && this.onEscape()) {
cancelEvent(e);
this.destroy();
}
};
public show() { public show() {
this.navigationItem = {
type: 'popup',
onPop: this.destroy,
onEscape: this.onEscape
};
appNavigationController.pushItem(this.navigationItem);
blurActiveElement(); // * hide mobile keyboard blurActiveElement(); // * hide mobile keyboard
document.body.append(this.element); document.body.append(this.element);
void this.element.offsetWidth; // reflow void this.element.offsetWidth; // reflow
@ -114,15 +117,21 @@ export default class PopupElement {
animationIntersector.checkAnimations(true); animationIntersector.checkAnimations(true);
} }
public destroy = () => { public hide = () => {
appNavigationController.back();
};
private destroy = () => {
this.onClose && this.onClose(); this.onClose && this.onClose();
this.element.classList.add('hiding'); this.element.classList.add('hiding');
this.element.classList.remove('active'); this.element.classList.remove('active');
window.removeEventListener('keydown', this._onKeyDown, {capture: true}); if(this.btnClose) this.btnClose.removeEventListener('click', this.hide);
if(this.btnClose) this.btnClose.removeEventListener('click', this.destroy);
rootScope.overlayIsActive = false; rootScope.overlayIsActive = false;
appNavigationController.removeItem(this.navigationItem);
this.navigationItem = undefined;
setTimeout(() => { setTimeout(() => {
this.element.remove(); this.element.remove();
this.onCloseAfterTimeout && this.onCloseAfterTimeout(); this.onCloseAfterTimeout && this.onCloseAfterTimeout();

2
src/components/popups/newMedia.ts

@ -142,7 +142,7 @@ export default class PopupNewMedia extends PopupElement {
return; return;
} }
this.destroy(); this.hide();
const willAttach = this.willAttach; const willAttach = this.willAttach;
willAttach.isMedia = willAttach.type === 'media' ? true : undefined; willAttach.isMedia = willAttach.type === 'media' ? true : undefined;

4
src/helpers/userAgent.ts

@ -18,4 +18,6 @@ export const isAppleMobile = (/iPad|iPhone|iPod/.test(navigator.platform) ||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) && (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
!ctx.MSStream; !ctx.MSStream;
export const isSafari = !!('safari' in ctx) || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))))/* || true */; export const isSafari = !!('safari' in ctx) || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))))/* || true */;
export const isMobileSafari = isSafari && isAppleMobile;

Loading…
Cancel
Save