Browse Source

Handle t.me/addstickers

master
Eduard Kuzmenko 3 years ago
parent
commit
ad4e70759d
  1. 8
      src/components/popups/stickers.ts
  2. 2
      src/lib/appManagers/apiUpdatesManager.ts
  3. 49
      src/lib/appManagers/appImManager.ts
  4. 56
      src/lib/appManagers/appStickersManager.ts
  5. 4
      src/lib/idb.ts
  6. 31
      src/lib/richtextprocessor.ts

8
src/components/popups/stickers.ts

@ -5,7 +5,7 @@
*/ */
import PopupElement from "."; import PopupElement from ".";
import appStickersManager from "../../lib/appManagers/appStickersManager"; import appStickersManager, { AppStickersManager } from "../../lib/appManagers/appStickersManager";
import { RichTextProcessor } from "../../lib/richtextprocessor"; import { RichTextProcessor } from "../../lib/richtextprocessor";
import Scrollable from "../scrollable"; import Scrollable from "../scrollable";
import { wrapSticker } from "../wrappers"; import { wrapSticker } from "../wrappers";
@ -29,11 +29,7 @@ export default class PopupStickers extends PopupElement {
private set: StickerSet.stickerSet; private set: StickerSet.stickerSet;
constructor(private stickerSetInput: { constructor(private stickerSetInput: Parameters<AppStickersManager['getStickerSet']>[0]) {
//_: 'inputStickerSetID',
id: string,
access_hash: string
}) {
super('popup-stickers', null, {closable: true, overlayClosable: true, body: true}); super('popup-stickers', null, {closable: true, overlayClosable: true, body: true});
this.h6 = document.createElement('h6'); this.h6 = document.createElement('h6');

2
src/lib/appManagers/apiUpdatesManager.ts

@ -248,7 +248,7 @@ export class ApiUpdatesManager {
const promise = apiManager.invokeApi('updates.getDifference', { const promise = apiManager.invokeApi('updates.getDifference', {
pts: updatesState.pts, pts: updatesState.pts,
pts_total_limit: first/* && false */ ? 50/* 1200 */ : undefined, pts_total_limit: first && false ? 50/* 1200 */ : undefined,
date: updatesState.date, date: updatesState.date,
qts: -1 qts: -1
}, { }, {

49
src/lib/appManagers/appImManager.ts

@ -59,6 +59,7 @@ import whichChild from '../../helpers/dom/whichChild';
import appEmojiManager from './appEmojiManager'; import appEmojiManager from './appEmojiManager';
import PopupElement from '../../components/popups'; import PopupElement from '../../components/popups';
import singleInstance from '../mtproto/singleInstance'; import singleInstance from '../mtproto/singleInstance';
import PopupStickers from '../../components/popups/stickers';
//console.log('appImManager included33!'); //console.log('appImManager included33!');
@ -223,9 +224,7 @@ export class AppImManager {
stateStorage.setToCache('chatPositions', c || {}); stateStorage.setToCache('chatPositions', c || {});
}); });
(window as any).showMaskedAlert = (element: HTMLAnchorElement, e: Event) => { this.addAnchorListener('showMaskedAlert', (params, element) => {
cancelEvent(null);
const href = element.href; const href = element.href;
const a = element.cloneNode(true) as HTMLAnchorElement; const a = element.cloneNode(true) as HTMLAnchorElement;
@ -244,19 +243,9 @@ export class AppImManager {
}, },
}] }]
}).show(); }).show();
}, false);
return false; this.addAnchorListener('execBotCommand', (params) => {
};
(window as any).execBotCommand = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
const params = this.parseUriParams(href);
if(!params) {
return;
}
const {command, bot} = params; const {command, bot} = params;
/* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId); /* const promise = bot ? this.openUsername(bot).then(() => this.chat.peerId) : Promise.resolve(this.chat.peerId);
@ -267,23 +256,35 @@ export class AppImManager {
appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : '')); appMessagesManager.sendText(this.chat.peerId, '/' + command + (bot ? '@' + bot : ''));
//console.log(command, bot); //console.log(command, bot);
});
return false; this.addAnchorListener('searchByHashtag', (params) => {
};
(window as any).searchByHashtag = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
const params = this.parseUriParams(href);
if(!params) { if(!params) {
return; return;
} }
const {hashtag} = params; const {hashtag} = params;
this.chat.initSearch('#' + hashtag + ' '); this.chat.initSearch('#' + hashtag + ' ');
});
return false; this.addAnchorListener('addstickers', (params) => {
new PopupStickers({id: params[1]}).show();
}, true);
}
private addAnchorListener(name: 'showMaskedAlert' | 'execBotCommand' | 'searchByHashtag' | 'addstickers',
callback: (params: any, element: HTMLAnchorElement) => boolean | void, parseParams = true) {
(window as any)[name] = (element: HTMLAnchorElement, e: Event) => {
cancelEvent(null);
const href = element.href;
let params: any;
if(parseParams) {
params = !element.href.includes('#') ? new URL(element.href).pathname.split('/').slice(1) : this.parseUriParams(href);
}
const res = callback(params, element);
return res === undefined ? res : false;
}; };
} }

56
src/lib/appManagers/appStickersManager.ts

@ -16,6 +16,11 @@ import DATABASE_STATE from '../../config/databases/state';
const CACHE_TIME = 3600e3; const CACHE_TIME = 3600e3;
export type MyStickerSetInput = {
id: string,
access_hash?: string
};
export class AppStickersManager { export class AppStickersManager {
private storage = new AppStorage<Record<string, MessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets'); private storage = new AppStorage<Record<string, MessagesStickerSet>, typeof DATABASE_STATE>(DATABASE_STATE, 'stickerSets');
@ -23,7 +28,7 @@ export class AppStickersManager {
private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {}; private getStickersByEmoticonsPromises: {[emoticon: string]: Promise<Document[]>} = {};
constructor() { constructor() {
this.getStickerSet({id: 'emoji', access_hash: ''}); this.getStickerSet({id: 'emoji'}, {saveById: true});
rootScope.addMultipleEventsListeners({ rootScope.addMultipleEventsListeners({
updateNewStickerSet: (update) => { updateNewStickerSet: (update) => {
@ -42,24 +47,23 @@ export class AppStickersManager {
}); });
} }
public async getStickerSet(set: { public async getStickerSet(set: MyStickerSetInput, params: Partial<{
id: string,
access_hash: string
}, params: Partial<{
overwrite: boolean, overwrite: boolean,
useCache: boolean useCache: boolean,
saveById: boolean
}> = {}): Promise<MessagesStickerSet> { }> = {}): Promise<MessagesStickerSet> {
if(this.getStickerSetPromises[set.id]) { const id = set.id;
return this.getStickerSetPromises[set.id]; if(this.getStickerSetPromises[id]) {
return this.getStickerSetPromises[id];
} }
return this.getStickerSetPromises[set.id] = new Promise(async(resolve) => { return this.getStickerSetPromises[id] = new Promise(async(resolve) => {
if(!params.overwrite) { if(!params.overwrite) {
const cachedSet = await this.storage.get(set.id); const cachedSet = await this.storage.get(id);
if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) { if(cachedSet && cachedSet.documents?.length && ((Date.now() - cachedSet.refreshTime) < CACHE_TIME || params.useCache)) {
this.saveStickers(cachedSet.documents); this.saveStickers(cachedSet.documents);
resolve(cachedSet); resolve(cachedSet);
delete this.getStickerSetPromises[set.id]; delete this.getStickerSetPromises[id];
return; return;
} }
} }
@ -69,14 +73,15 @@ export class AppStickersManager {
stickerset: this.getStickerSetInput(set) stickerset: this.getStickerSetInput(set)
}); });
this.saveStickerSet(stickerSet, set.id); const saveById = params.saveById ? id : stickerSet.set.id;
this.saveStickerSet(stickerSet, saveById);
resolve(stickerSet); resolve(stickerSet);
} catch(err) { } catch(err) {
resolve(null); resolve(null);
} }
delete this.getStickerSetPromises[set.id]; delete this.getStickerSetPromises[id];
}); });
} }
@ -158,14 +163,23 @@ export class AppStickersManager {
//return promise; //return promise;
} */ } */
public getStickerSetInput(set: {id: string, access_hash: string}): InputStickerSet { public getStickerSetInput(set: MyStickerSetInput): InputStickerSet {
return set.id === 'emoji' ? { if(set.id === 'emoji') {
_: 'inputStickerSetAnimatedEmoji' return {
} : { _: 'inputStickerSetAnimatedEmoji'
_: 'inputStickerSetID', };
id: set.id, } else if(!set.access_hash) {
access_hash: set.access_hash return {
}; _: 'inputStickerSetShortName',
short_name: set.id
};
} else {
return {
_: 'inputStickerSetID',
id: set.id,
access_hash: set.access_hash
};
}
} }
public async getFeaturedStickers() { public async getFeaturedStickers() {

4
src/lib/idb.ts

@ -354,6 +354,10 @@ export default class IDBStorage<T extends Database<any>> {
return this.openDatabase().then((db) => { return this.openDatabase().then((db) => {
return new Promise<T>((resolve, reject) => { return new Promise<T>((resolve, reject) => {
/* if(mode === 'readwrite') {
return;
} */
const transaction = db.transaction([storeName], mode); const transaction = db.transaction([storeName], mode);
transaction.onerror = (e) => { transaction.onerror = (e) => {

31
src/lib/richtextprocessor.ts

@ -573,12 +573,15 @@ namespace RichTextProcessor {
const entityText = text.substr(entity.offset, entity.length); const entityText = text.substr(entity.offset, entity.length);
// let inner: string; // let inner: string;
let url: string; let url: string = (entity as MessageEntity.messageEntityTextUrl).url || entityText;
let masked = false; let masked = false;
if(entity._ === 'messageEntityTextUrl') { let onclick: string;
url = (entity as MessageEntity.messageEntityTextUrl).url;
url = wrapUrl(url, true); const wrapped = wrapUrl(url, true);
url = wrapped.url;
onclick = wrapped.onclick;
if(entity._ === 'messageEntityTextUrl') {
const nextEntity = entities[i + 1]; const nextEntity = entities[i + 1];
if(nextEntity?._ === 'messageEntityUrl' && if(nextEntity?._ === 'messageEntityUrl' &&
nextEntity.length === entity.length && nextEntity.length === entity.length &&
@ -590,11 +593,13 @@ namespace RichTextProcessor {
masked = true; masked = true;
} }
} else { } else {
url = wrapUrl(entityText, false);
//inner = encodeEntities(replaceUrlEncodings(entityText)); //inner = encodeEntities(replaceUrlEncodings(entityText));
} }
const currentContext = url[0] === '#'; const currentContext = url[0] === '#';
if(!onclick && masked && !currentContext) {
onclick = 'showMaskedAlert';
}
const href = (currentContext || typeof electronHelpers === 'undefined') const href = (currentContext || typeof electronHelpers === 'undefined')
? encodeEntities(url) ? encodeEntities(url)
@ -603,7 +608,7 @@ namespace RichTextProcessor {
const target = (currentContext || typeof electronHelpers !== 'undefined') const target = (currentContext || typeof electronHelpers !== 'undefined')
? '' : ' target="_blank" rel="noopener noreferrer"'; ? '' : ' target="_blank" rel="noopener noreferrer"';
insertPart(entity, `<a class="anchor-url" href="${href}"${target}${masked && !currentContext ? 'onclick="showMaskedAlert(this)"' : ''}>`, '</a>'); insertPart(entity, `<a class="anchor-url" href="${href}"${target}${onclick ? `onclick="${onclick}(this)"` : ''}>`, '</a>');
} }
break; break;
@ -789,13 +794,14 @@ namespace RichTextProcessor {
return wrapRichText(text, {entities}); return wrapRichText(text, {entities});
} }
export function wrapUrl(url: string, unsafe?: number | boolean): string { export function wrapUrl(url: string, unsafe?: number | boolean): {url: string, onclick: string} {
if(!matchUrlProtocol(url)) { if(!matchUrlProtocol(url)) {
url = 'https://' + url; url = 'https://' + url;
} }
let tgMeMatch; let tgMeMatch;
let telescoPeMatch; let telescoPeMatch;
let onclick: string;
/* if(unsafe === 2) { /* if(unsafe === 2) {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url); url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) { } else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
@ -803,12 +809,19 @@ namespace RichTextProcessor {
const path = fullPath.split('/'); const path = fullPath.split('/');
switch(path[0]) { switch(path[0]) {
case 'joinchat': case 'joinchat':
case 'addstickers':
onclick = path[0];
break;
/* case 'joinchat':
onclick = 'joinchat';
url = 'tg://join?invite=' + path[1]; url = 'tg://join?invite=' + path[1];
break; break;
case 'addstickers': case 'addstickers':
onclick = 'addstickers';
url = 'tg://addstickers?set=' + path[1]; url = 'tg://addstickers?set=' + path[1];
break; break; */
default: default:
if(path[1] && path[1].match(/^\d+$/)) { // https://t.me/.+/[0-9]+ (channel w/ username) if(path[1] && path[1].match(/^\d+$/)) { // https://t.me/.+/[0-9]+ (channel w/ username)
@ -846,7 +859,7 @@ namespace RichTextProcessor {
url = 'tg://unsafe_url?url=' + encodeURIComponent(url); url = 'tg://unsafe_url?url=' + encodeURIComponent(url);
} */ } */
return url; return {url, onclick};
} }
export function matchUrlProtocol(text: string) { export function matchUrlProtocol(text: string) {

Loading…
Cancel
Save