Browse Source

Fix Malaysia code

Fix shared media switching tab with scale
Refactor users & chats
Fix showing chatlist corner button with active search
master
Eduard Kuzmenko 4 years ago
parent
commit
92dea78bbd
  1. 5
      src/components/sidebarLeft/index.ts
  2. 2
      src/components/sidebarLeft/tabs/blockedUsers.ts
  3. 2
      src/components/sidebarLeft/tabs/settings.ts
  4. 4
      src/components/sidebarRight/tabs/sharedMedia.ts
  5. 10
      src/config/database.ts
  6. 2
      src/countries.ts
  7. 2
      src/helpers/object.ts
  8. 10
      src/helpers/schedulers.ts
  9. 70
      src/lib/appManagers/appChatsManager.ts
  10. 2
      src/lib/appManagers/appImManager.ts
  11. 9
      src/lib/appManagers/appMessagesManager.ts
  12. 15
      src/lib/appManagers/appProfileManager.ts
  13. 59
      src/lib/appManagers/appUsersManager.ts
  14. 95
      src/lib/idb.ts
  15. 32
      src/lib/storage.ts
  16. 2
      src/scripts/in/countries.dat
  17. 9
      src/scss/partials/_leftSidebar.scss
  18. 8
      src/scss/partials/_rightSidebar.scss

5
src/components/sidebarLeft/index.ts

@ -478,12 +478,13 @@ export class AppSidebarLeft extends SidebarSlider {
this.searchGroups.people.container.append(peopleContainer); this.searchGroups.people.container.append(peopleContainer);
let peopleScrollable = new ScrollableX(peopleContainer); let peopleScrollable = new ScrollableX(peopleContainer);
let first = true;
let hideNewBtnMenuTimeout: number; let hideNewBtnMenuTimeout: number;
//const transition = Transition.bind(null, searchContainer.parentElement, 150); //const transition = Transition.bind(null, searchContainer.parentElement, 150);
const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => { const transition = TransitionSlider(searchContainer.parentElement, 'zoom-fade', 150, (id) => {
if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout); if(hideNewBtnMenuTimeout) clearTimeout(hideNewBtnMenuTimeout);
if(id === 0) { if(id === 0 && !first) {
searchSuper.selectTab(0, false); searchSuper.selectTab(0, false);
this.inputSearch.onClearClick(); this.inputSearch.onClearClick();
hideNewBtnMenuTimeout = window.setTimeout(() => { hideNewBtnMenuTimeout = window.setTimeout(() => {
@ -491,6 +492,8 @@ export class AppSidebarLeft extends SidebarSlider {
this.newBtnMenu.classList.remove('is-hidden'); this.newBtnMenu.classList.remove('is-hidden');
}, 150); }, 150);
} }
first = false;
}); });
transition(0); transition(0);

2
src/components/sidebarLeft/tabs/blockedUsers.ts

@ -64,7 +64,7 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
if(user.pFlags.bot) { if(user.pFlags.bot) {
dom.lastMessageSpan.append('@' + user.username); dom.lastMessageSpan.append('@' + user.username);
} else { } else {
if(user.rPhone) dom.lastMessageSpan.innerHTML = user.rPhone; if(user.phone) dom.lastMessageSpan.innerHTML = appUsersManager.formatUserPhone(user.phone);
else dom.lastMessageSpan.append(user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId)); else dom.lastMessageSpan.append(user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId));
} }

2
src/components/sidebarLeft/tabs/settings.ts

@ -153,6 +153,6 @@ export default class AppSettingsTab extends SliderSuperTab {
this.avatarElem.setAttribute('peer', '' + user.id); this.avatarElem.setAttribute('peer', '' + user.id);
this.nameDiv.append(new PeerTitle({peerId: user.id}).element); this.nameDiv.append(new PeerTitle({peerId: user.id}).element);
this.phoneDiv.innerHTML = user.rPhone || ''; this.phoneDiv.innerHTML = user.phone ? appUsersManager.formatUserPhone(user.phone) : '';
} }
} }

4
src/components/sidebarRight/tabs/sharedMedia.ts

@ -670,7 +670,7 @@ class PeerProfile {
let user = appUsersManager.getUser(peerId); let user = appUsersManager.getUser(peerId);
if(user.phone && peerId !== rootScope.myId) { if(user.phone && peerId !== rootScope.myId) {
setText(user.rPhone, this.phone); setText(appUsersManager.formatUserPhone(user.phone), this.phone);
} }
}/* else { }/* else {
//membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : ''; //membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';
@ -824,7 +824,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
const rect = this.searchSuper.nav.getBoundingClientRect(); const rect = this.searchSuper.nav.getBoundingClientRect();
if(!rect.width) return; if(!rect.width) return;
const top = rect.top; const top = rect.top - 1;
const isSharedMedia = top <= HEADER_HEIGHT; const isSharedMedia = top <= HEADER_HEIGHT;
animatedCloseIcon.classList.toggle('state-back', isSharedMedia); animatedCloseIcon.classList.toggle('state-back', isSharedMedia);
this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia); this.searchSuper.container.classList.toggle('is-full-viewport', isSharedMedia);

10
src/config/database.ts

@ -11,11 +11,19 @@ export type DatabaseStoreName = 'session' | 'stickerSets' | 'users' | 'chats' |
export type DatabaseStore = Omit<IDBStore, 'name'> & {name: DatabaseStoreName}; export type DatabaseStore = Omit<IDBStore, 'name'> & {name: DatabaseStoreName};
const Database = { const Database = {
name: 'tweb' + (Modes.test ? '_test' : ''), name: 'tweb' + (Modes.test ? '_test' : ''),
version: 5, version: 7,
stores: [{ stores: [{
name: 'session' name: 'session'
}, { }, {
name: 'stickerSets' name: 'stickerSets'
}, {
name: 'users'
}, {
name: 'chats'
}, {
name: 'dialogs'
}, {
name: 'messages'
}] as DatabaseStore[], }] as DatabaseStore[],
}; };

2
src/countries.ts

File diff suppressed because one or more lines are too long

2
src/helpers/object.ts

@ -72,7 +72,7 @@ export function safeReplaceObject(wasObject: any, newObject: any) {
} }
for(var key in wasObject) { for(var key in wasObject) {
if(!newObject.hasOwnProperty(key) && key.charAt(0) !== '$') { if(!newObject.hasOwnProperty(key)) {
delete wasObject[key]; delete wasObject[key];
} }
} }

10
src/helpers/schedulers.ts

@ -50,16 +50,16 @@ export function throttle<F extends AnyToVoidFunction>(
isPending = true; isPending = true;
args = _args; args = _args;
if (!interval) { if(!interval) {
if (shouldRunFirst) { if(shouldRunFirst) {
isPending = false; isPending = false;
// @ts-ignore // @ts-ignore
fn(...args); fn(...args);
} }
interval = window.setInterval(() => { interval = setInterval(() => {
if (!isPending) { if (!isPending) {
window.clearInterval(interval!); clearInterval(interval!);
interval = null; interval = null;
return; return;
} }
@ -67,7 +67,7 @@ export function throttle<F extends AnyToVoidFunction>(
isPending = false; isPending = false;
// @ts-ignore // @ts-ignore
fn(...args); fn(...args);
}, ms); }, ms) as any;
} }
}; };
} }

70
src/lib/appManagers/appChatsManager.ts

@ -18,6 +18,7 @@ import apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import rootScope from "../rootScope"; import rootScope from "../rootScope";
//import AppStorage from "../storage";
import apiUpdatesManager from "./apiUpdatesManager"; import apiUpdatesManager from "./apiUpdatesManager";
import appMessagesManager from "./appMessagesManager"; import appMessagesManager from "./appMessagesManager";
import appPeersManager from "./appPeersManager"; import appPeersManager from "./appPeersManager";
@ -32,14 +33,18 @@ export type ChatRights = keyof ChatBannedRights['pFlags'] | keyof ChatAdminRight
export type UserTyping = Partial<{userId: number, action: SendMessageAction, timeout: number}>; export type UserTyping = Partial<{userId: number, action: SendMessageAction, timeout: number}>;
export class AppChatsManager { export class AppChatsManager {
public chats: {[id: number]: Chat.channel | Chat.chat | any} = {}; /* private storage = new AppStorage<Record<number, Chat>>({
//public usernames: any = {}; storeName: 'chats'
//public channelAccess: any = {}; }); */
//public megagroups: {[id: number]: true} = {};
public megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {}; private chats: {[id: number]: Chat.channel | Chat.chat | any} = {};
//private usernames: any = {};
//private channelAccess: any = {};
//private megagroups: {[id: number]: true} = {};
public typingsInPeer: {[peerId: number]: UserTyping[]} = {}; private megagroupOnlines: {[id: number]: {timestamp: number, onlines: number}} = {};
private typingsInPeer: {[peerId: number]: UserTyping[]} = {};
constructor() { constructor() {
rootScope.addMultipleEventsListeners({ rootScope.addMultipleEventsListeners({
@ -57,9 +62,9 @@ export class AppChatsManager {
updateChatDefaultBannedRights: (update) => { updateChatDefaultBannedRights: (update) => {
const chatId = -appPeersManager.getPeerId(update.peer); const chatId = -appPeersManager.getPeerId(update.peer);
const chat: Chat = this.getChat(chatId); const chat: Chat.chat = this.chats[chatId];
if(chat._ !== 'chatEmpty') { if(chat) {
(chat as Chat.chat).default_banned_rights = update.default_banned_rights; chat.default_banned_rights = update.default_banned_rights;
rootScope.broadcast('chat_update', chatId); rootScope.broadcast('chat_update', chatId);
} }
}, },
@ -142,30 +147,39 @@ export class AppChatsManager {
} }
}; };
public saveApiChats(apiChats: any[]) { public getPeerTypings(peerId: number) {
apiChats.forEach(chat => this.saveApiChat(chat)); return this.typingsInPeer[peerId];
}
public saveApiChats(apiChats: any[], override?: boolean) {
apiChats.forEach(chat => this.saveApiChat(chat, override));
} }
public saveApiChat(chat: any) { public saveApiChat(chat: any, override?: boolean) {
/* if(chat._ !== 'chat' && chat._ !== 'channel') {
return;
} */
// * exclude from state // * exclude from state
// defineNotNumerableProperties(chat, ['rTitle', 'initials']); // defineNotNumerableProperties(chat, ['rTitle', 'initials']);
//chat.rTitle = chat.title || 'chat_title_deleted';
chat.rTitle = RichTextProcessor.wrapRichText(chat.title, {noLinks: true, noLinebreaks: true}) || 'chat_title_deleted';
const oldChat = this.chats[chat.id]; const oldChat = this.chats[chat.id];
chat.initials = RichTextProcessor.getAbbreviation(chat.title); /* if(oldChat && !override) {
return;
} */
if(chat.pFlags === undefined) { if(chat.pFlags === undefined) {
chat.pFlags = {}; chat.pFlags = {};
} }
if(chat.pFlags.min) { if(chat.pFlags.min && oldChat !== undefined) {
if(oldChat !== undefined) {
return; return;
} }
}
chat.initials = RichTextProcessor.getAbbreviation(chat.title);
//console.log('im the weatherman', chat.id);
if(chat._ === 'channel' && if(chat._ === 'channel' &&
chat.participants_count === undefined && chat.participants_count === undefined &&
@ -204,6 +218,10 @@ export class AppChatsManager {
if(changedTitle) { if(changedTitle) {
rootScope.broadcast('peer_title_edit', -chat.id); rootScope.broadcast('peer_title_edit', -chat.id);
} }
/* this.storage.set({
[chat.id]: chat
}); */
} }
public getChat(id: number) { public getChat(id: number) {
@ -335,10 +353,7 @@ export class AppChatsManager {
public isChannel(id: number) { public isChannel(id: number) {
if(id < 0) id = -id; if(id < 0) id = -id;
const chat = this.chats[id]; const chat = this.chats[id];
if(chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */) { return chat && (chat._ === 'channel' || chat._ === 'channelForbidden')/* || this.channelAccess[id] */;
return true;
}
return false;
} }
public isMegagroup(id: number) { public isMegagroup(id: number) {
@ -347,10 +362,7 @@ export class AppChatsManager {
} */ } */
const chat = this.chats[id]; const chat = this.chats[id];
if(chat && chat._ === 'channel' && chat.pFlags.megagroup) { return chat && chat._ === 'channel' && chat.pFlags.megagroup;
return true;
}
return false;
} }
public isBroadcast(id: number) { public isBroadcast(id: number) {
@ -430,7 +442,7 @@ export class AppChatsManager {
return i18n(key, [numberThousandSplitter(count)]); return i18n(key, [numberThousandSplitter(count)]);
} }
public wrapForFull(id: number, fullChat: any) { /* public wrapForFull(id: number, fullChat: any) {
const chatFull = copy(fullChat); const chatFull = copy(fullChat);
const chat = this.getChat(id); const chat = this.getChat(id);
@ -480,7 +492,7 @@ export class AppChatsManager {
} }
return participants; return participants;
} } */
public createChannel(title: string, about: string): Promise<number> { public createChannel(title: string, about: string): Promise<number> {
return apiManager.invokeApi('channels.createChannel', { return apiManager.invokeApi('channels.createChannel', {

2
src/lib/appManagers/appImManager.ts

@ -908,7 +908,7 @@ export class AppImManager {
public getPeerTyping(peerId: number, container?: HTMLElement) { public getPeerTyping(peerId: number, container?: HTMLElement) {
if(!appUsersManager.isBot(peerId)) { if(!appUsersManager.isBot(peerId)) {
const typings = appChatsManager.typingsInPeer[peerId]; const typings = appChatsManager.getPeerTypings(peerId);
if(!typings || !typings.length) { if(!typings || !typings.length) {
return; return;
} }

9
src/lib/appManagers/appMessagesManager.ts

@ -2331,7 +2331,8 @@ export class AppMessagesManager {
public saveMessages(messages: any[], options: Partial<{ public saveMessages(messages: any[], options: Partial<{
storage: MessagesStorage, storage: MessagesStorage,
isScheduled: true, isScheduled: true,
isOutgoing: true isOutgoing: true,
//isNew: boolean, // * new - from update
}> = {}) { }> = {}) {
//let groups: Set<string>; //let groups: Set<string>;
messages.forEach((message) => { messages.forEach((message) => {
@ -2503,6 +2504,12 @@ export class AppMessagesManager {
break; break;
case 'messageActionChatEditTitle': case 'messageActionChatEditTitle':
/* if(options.isNew) {
const chat = appChatsManager.getChat(-peerId);
chat.title = message.action.title;
appChatsManager.saveApiChat(chat, true);
} */
if(isBroadcast) { if(isBroadcast) {
message.action._ = 'messageActionChannelEditTitle'; message.action._ = 'messageActionChannelEditTitle';
} }

15
src/lib/appManagers/appProfileManager.ts

@ -154,21 +154,10 @@ export class AppProfileManager {
id: appUsersManager.getUserInput(id) id: appUsersManager.getUserInput(id)
}).then((userFull) => { }).then((userFull) => {
const user = userFull.user as User; const user = userFull.user as User;
/* if(override && isObject(override) && override.phone_number) {
user.phone = override.phone_number;
if(override.first_name || override.last_name) {
user.first_name = override.first_name;
user.last_name = override.last_name;
}
appUsersManager.saveApiUser(user);
} else { */
appUsersManager.saveApiUser(user, true); appUsersManager.saveApiUser(user, true);
//}
if(userFull.profile_photo) { if(userFull.profile_photo) {
userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId: id}); userFull.profile_photo = appPhotosManager.savePhoto(userFull.profile_photo, {type: 'profilePhoto', peerId: id});
/* appPhotosManager.savePhoto(userFull.profile_photo, {user_id: id}); */
} }
if(userFull.about !== undefined) { if(userFull.about !== undefined) {
@ -253,7 +242,7 @@ export class AppProfileManager {
return this.fullPromises[peerId] = apiManager.invokeApi('messages.getFullChat', { return this.fullPromises[peerId] = apiManager.invokeApi('messages.getFullChat', {
chat_id: id chat_id: id
}).then((result) => { }).then((result) => {
appChatsManager.saveApiChats(result.chats); appChatsManager.saveApiChats(result.chats, true);
appUsersManager.saveApiUsers(result.users); appUsersManager.saveApiUsers(result.users);
const fullChat = result.full_chat as ChatFull.chatFull; const fullChat = result.full_chat as ChatFull.chatFull;
if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) { if(fullChat && fullChat.chat_photo && fullChat.chat_photo.id) {
@ -362,7 +351,7 @@ export class AppProfileManager {
return this.fullPromises[peerId] = apiManager.invokeApi('channels.getFullChannel', { return this.fullPromises[peerId] = apiManager.invokeApi('channels.getFullChannel', {
channel: appChatsManager.getChannelInput(id) channel: appChatsManager.getChannelInput(id)
}).then((result) => { }).then((result) => {
appChatsManager.saveApiChats(result.chats); appChatsManager.saveApiChats(result.chats, true);
appUsersManager.saveApiUsers(result.users); appUsersManager.saveApiUsers(result.users);
const fullChannel = result.full_chat as ChatFull.channelFull; const fullChannel = result.full_chat as ChatFull.channelFull;
if(fullChannel && fullChannel.chat_photo.id) { if(fullChannel && fullChannel.chat_photo.id) {

59
src/lib/appManagers/appUsersManager.ts

@ -47,6 +47,8 @@ export class AppUsersManager {
private getTopPeersPromise: Promise<number[]>; private getTopPeersPromise: Promise<number[]>;
constructor() { constructor() {
//this.users = this.storage.getCache();
setInterval(this.updateUsersStatuses, 60000); setInterval(this.updateUsersStatuses, 60000);
rootScope.on('state_synchronized', this.updateUsersStatuses); rootScope.on('state_synchronized', this.updateUsersStatuses);
@ -67,7 +69,7 @@ export class AppUsersManager {
} }
} }
user.sortStatus = this.getUserStatusForSort(user.status); //user.sortStatus = this.getUserStatusForSort(user.status);
rootScope.broadcast('user_update', userId); rootScope.broadcast('user_update', userId);
} //////else console.warn('No user by id:', userId); } //////else console.warn('No user by id:', userId);
}, },
@ -99,7 +101,7 @@ export class AppUsersManager {
first_name: update.first_name, first_name: update.first_name,
last_name: update.last_name, last_name: update.last_name,
username: update.username username: update.username
})); }), true);
} }
} }
}); });
@ -271,42 +273,28 @@ export class AppUsersManager {
apiUsers.forEach((user) => this.saveApiUser(user)); apiUsers.forEach((user) => this.saveApiUser(user));
} }
public saveApiUser(_user: MTUser, noReplace?: boolean) { public saveApiUser(user: MTUser, override?: boolean) {
if(_user._ === 'userEmpty') return; if(user._ === 'userEmpty') return;
const user = _user; const userId = user.id;
if(noReplace && isObject(this.users[user.id]) && this.users[user.id].first_name) { const oldUser = this.users[userId];
if(oldUser && !override) {
return; return;
} }
const userId = user.id;
if(user.pFlags === undefined) { if(user.pFlags === undefined) {
user.pFlags = {}; user.pFlags = {};
} }
if(user.pFlags.min) { if(user.pFlags.min && oldUser !== undefined) {
if(this.users[userId] !== undefined) {
return; return;
} }
}
// * exclude from state // * exclude from state
// defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']); // defineNotNumerableProperties(user, ['initials', 'num', 'rFirstName', 'rFullName', 'rPhone', 'sortName', 'sortStatus']);
if(user.phone) {
user.rPhone = '+' + formatPhoneNumber(user.phone).formatted;
}
const fullName = user.first_name + ' ' + (user.last_name || ''); const fullName = user.first_name + ' ' + (user.last_name || '');
if(user.first_name) {
user.rFirstName = RichTextProcessor.wrapRichText(user.first_name, {noLinks: true, noLinebreaks: true});
user.rFullName = user.last_name ? RichTextProcessor.wrapRichText(fullName, {noLinks: true, noLinebreaks: true}) : user.rFirstName;
} else {
user.rFirstName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_first_name_deleted';
user.rFullName = RichTextProcessor.wrapRichText(user.last_name, {noLinks: true, noLinebreaks: true}) || user.rPhone || 'user_name_deleted';
}
if(user.username) { if(user.username) {
const searchUsername = searchIndexManager.cleanUsername(user.username); const searchUsername = searchIndexManager.cleanUsername(user.username);
this.usernames[searchUsername] = userId; this.usernames[searchUsername] = userId;
@ -318,22 +306,17 @@ export class AppUsersManager {
if(user.status) { if(user.status) {
if((user.status as UserStatus.userStatusOnline).expires) { if((user.status as UserStatus.userStatusOnline).expires) {
(user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset (user.status as UserStatus.userStatusOnline).expires -= serverTimeManager.serverTimeOffset;
} }
if((user.status as UserStatus.userStatusOffline).was_online) { if((user.status as UserStatus.userStatusOffline).was_online) {
(user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset (user.status as UserStatus.userStatusOffline).was_online -= serverTimeManager.serverTimeOffset;
} }
} }
if(user.pFlags.bot) { //user.sortStatus = user.pFlags.bot ? -1 : this.getUserStatusForSort(user.status);
user.sortStatus = -1;
} else {
user.sortStatus = this.getUserStatusForSort(user.status);
}
let changedTitle = false; let changedTitle = false;
const oldUser = this.users[userId];
if(oldUser === undefined) { if(oldUser === undefined) {
this.users[userId] = user; this.users[userId] = user;
} else { } else {
@ -347,11 +330,21 @@ export class AppUsersManager {
rootScope.broadcast('user_update', userId); rootScope.broadcast('user_update', userId);
} }
//console.log('we never give this up');
/* this.storage.set({
[userId]: user
}); */
if(changedTitle) { if(changedTitle) {
rootScope.broadcast('peer_title_edit', user.id); rootScope.broadcast('peer_title_edit', user.id);
} }
} }
public formatUserPhone(phone: string) {
return '+' + formatPhoneNumber(phone).formatted;
}
public getUserStatusForSort(status: User['status'] | number) { public getUserStatusForSort(status: User['status'] | number) {
if(typeof(status) === 'number') { if(typeof(status) === 'number') {
status = this.getUser(status).status; status = this.getUser(status).status;
@ -579,7 +572,7 @@ export class AppUsersManager {
expires: timestamp + onlineTimeFor expires: timestamp + onlineTimeFor
}; };
user.sortStatus = this.getUserStatusForSort(user.status); //user.sortStatus = this.getUserStatusForSort(user.status);
rootScope.broadcast('user_update', id); rootScope.broadcast('user_update', id);
} }
} }
@ -781,7 +774,7 @@ export class AppUsersManager {
}; };
user.status = status; user.status = status;
user.sortStatus = this.getUserStatusForSort(user.status); //user.sortStatus = this.getUserStatusForSort(user.status);
rootScope.broadcast('user_update', userId); rootScope.broadcast('user_update', userId);
} }
} }

95
src/lib/idb.ts

@ -225,7 +225,7 @@ export default class IDBStorage {
}); });
} }
public save(entryName: string, value: any) { public save(entryName: string | string[], value: any | any[]) {
return this.openDatabase().then((db) => { return this.openDatabase().then((db) => {
//this.log('save:', entryName, value); //this.log('save:', entryName, value);
@ -240,14 +240,25 @@ export default class IDBStorage {
} }
}; };
return new Promise<void>((resolve, reject) => {
try { try {
const transaction = db.transaction([this.storeName], 'readwrite'); const transaction = db.transaction([this.storeName], 'readwrite');
transaction.onerror = (e) => { transaction.onerror = (e) => {
handleError(transaction.error); handleError(transaction.error);
reject(transaction.error);
clearTimeout(timeout);
}; };
/* transaction.oncomplete = (e) => {
this.log('save: transaction complete:', entryName); transaction.oncomplete = (e) => {
}; */ //this.log('save: transaction complete:', entryName);
resolve();
clearTimeout(timeout);
};
const timeout = setTimeout(() => {
this.log.error('save: transaction not finished', entryName, transaction);
}, 10000);
/* transaction.addEventListener('abort', (e) => { /* transaction.addEventListener('abort', (e) => {
//handleError(); //handleError();
@ -255,29 +266,26 @@ export default class IDBStorage {
}); */ }); */
const objectStore = transaction.objectStore(this.storeName); const objectStore = transaction.objectStore(this.storeName);
var request = objectStore.put(value, entryName);
} catch(error) {
handleError(error);
return Promise.reject(error);
/* this.storageIsAvailable = false; if(!Array.isArray(entryName)) {
throw error; */ entryName = [].concat(entryName);
value = [].concat(value);
} }
return new Promise<void>((resolve, reject) => { for(let i = 0, length = entryName.length; i < length; ++i) {
const timeout = setTimeout(() => { const request = objectStore.put(value[i], entryName[i]);
this.log.error('save: request not finished', entryName, request);
}, 10000);
request.onsuccess = (event) => {
resolve();
clearTimeout(timeout);
};
request.onerror = (error) => { request.onerror = (error) => {
reject(error); reject(transaction.error);
clearTimeout(timeout); clearTimeout(timeout);
}; };
}
} catch(error) {
handleError(error);
reject(error);
/* this.storageIsAvailable = false;
throw error; */
}
}); });
}); });
} }
@ -401,6 +409,51 @@ export default class IDBStorage {
}); });
} }
public getAll<T>(): Promise<T[]> {
return this.openDatabase().then((db) => {
//this.log('getAll pre:', fileName);
try {
const transaction = db.transaction([this.storeName], 'readonly');
/* transaction.onabort = (e) => {
this.log.error('getAll transaction onabort?', e);
}; */
const objectStore = transaction.objectStore(this.storeName);
var request = objectStore.getAll();
//this.log.log('IDB getAll:', fileName, request);
} catch(err) {
this.log.error('getAll error:', err, request, request.error);
}
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
this.log.error('getAll request not finished!', request);
reject();
}, 3000);
request.onsuccess = function(event) {
const result = request.result;
if(result === undefined) {
reject('NO_ENTRY_FOUND');
} /* else if(typeof result === 'string' &&
result.substr(0, 5) === 'data:') {
resolve(dataUrlToBlob(result));
} */else {
resolve(result);
}
clearTimeout(timeout);
}
request.onerror = () => {
clearTimeout(timeout);
reject();
};
});
});
}
/* public getAllKeys(): Promise<Array<string>> { /* public getAllKeys(): Promise<Array<string>> {
console.time('getAllEntries'); console.time('getAllEntries');
return this.openDatabase().then((db) => { return this.openDatabase().then((db) => {

32
src/lib/storage.ts

@ -10,6 +10,7 @@
*/ */
import { DatabaseStore, DatabaseStoreName } from "../config/database"; import { DatabaseStore, DatabaseStoreName } from "../config/database";
import { throttle } from "../helpers/schedulers";
import IDBStorage, { IDBOptions } from "./idb"; import IDBStorage, { IDBOptions } from "./idb";
export default class AppStorage<Storage extends Record<string, any>/* Storage extends {[name: string]: any} *//* Storage extends Record<string, any> */> { export default class AppStorage<Storage extends Record<string, any>/* Storage extends {[name: string]: any} *//* Storage extends Record<string, any> */> {
@ -19,11 +20,29 @@ export default class AppStorage<Storage extends Record<string, any>/* Storage ex
//private cache: Partial<{[key: string]: Storage[typeof key]}> = {}; //private cache: Partial<{[key: string]: Storage[typeof key]}> = {};
private cache: Partial<Storage> = {}; private cache: Partial<Storage> = {};
private useStorage = true; private useStorage = true;
private updateKeys: Set<keyof Storage> = new Set();
private saveThrottled: () => void;
constructor(storageOptions: Omit<IDBOptions, 'storeName' | 'stores'> & {stores?: DatabaseStore[], storeName: DatabaseStoreName}) { constructor(storageOptions: Omit<IDBOptions, 'storeName' | 'stores'> & {stores?: DatabaseStore[], storeName: DatabaseStoreName}) {
this.storage = new IDBStorage(storageOptions); this.storage = new IDBStorage(storageOptions);
AppStorage.STORAGES.push(this); AppStorage.STORAGES.push(this);
this.saveThrottled = throttle(async() => {
const keys = Array.from(this.updateKeys.values()) as string[];
this.updateKeys.clear();
try {
//console.log('setItem: will set', key/* , value */);
//await this.cacheStorage.delete(key); // * try to prevent memory leak in Chrome leading to 'Unexpected internal error.'
//await this.storage.save(key, new Response(value, {headers: {'Content-Type': 'application/json'}}));
await this.storage.save(keys, keys.map(key => this.cache[key]));
//console.log('setItem: have set', key/* , value */);
} catch(e) {
//this.useCS = false;
console.error('[AS]: set error:', e, keys/* , value */);
}
}, 50, false);
} }
public getCache() { public getCache() {
@ -83,16 +102,8 @@ export default class AppStorage<Storage extends Record<string, any>/* Storage ex
console.log('LocalStorage set: stringify time by own stringify:', performance.now() - perf); */ console.log('LocalStorage set: stringify time by own stringify:', performance.now() - perf); */
if(this.useStorage && !onlyLocal) { if(this.useStorage && !onlyLocal) {
try { this.updateKeys.add(key);
//console.log('setItem: will set', key/* , value */); this.saveThrottled();
//await this.cacheStorage.delete(key); // * try to prevent memory leak in Chrome leading to 'Unexpected internal error.'
//await this.storage.save(key, new Response(value, {headers: {'Content-Type': 'application/json'}}));
await this.storage.save(key, value);
//console.log('setItem: have set', key/* , value */);
} catch(e) {
//this.useCS = false;
console.error('[AS]: set error:', e, key/* , value */);
}
} }
} }
} }
@ -126,6 +137,7 @@ export default class AppStorage<Storage extends Record<string, any>/* Storage ex
storage.useStorage = enabled; storage.useStorage = enabled;
if(!enabled) { if(!enabled) {
storage.updateKeys.clear();
return storage.clear(); return storage.clear();
} else { } else {
return storage.set(storage.cache); return storage.set(storage.cache);

2
src/scripts/in/countries.dat

@ -135,7 +135,7 @@
389;MK;Macedonia;;0;πŸ‡²πŸ‡° 389;MK;Macedonia;;0;πŸ‡²πŸ‡°
261;MG;Madagascar;261 XX XX XXX XX;12;πŸ‡²πŸ‡¬ 261;MG;Madagascar;261 XX XX XXX XX;12;πŸ‡²πŸ‡¬
265;MW;Malawi;;0;πŸ‡²πŸ‡Ό 265;MW;Malawi;;0;πŸ‡²πŸ‡Ό
60;MM;Malaysia;;0;πŸ‡²πŸ‡² 60;MY;Malaysia;;0;πŸ‡²πŸ‡Ύ
960;MV;Maldives;;0;πŸ‡²πŸ‡» 960;MV;Maldives;;0;πŸ‡²πŸ‡»
223;ML;Mali;223 XXXX XXXX;11;πŸ‡²πŸ‡± 223;ML;Mali;223 XXXX XXXX;11;πŸ‡²πŸ‡±
356;MT;Malta;356 XX XX XX XX;11;πŸ‡²πŸ‡Ή 356;MT;Malta;356 XX XX XX XX;11;πŸ‡²πŸ‡Ή

9
src/scss/partials/_leftSidebar.scss

@ -365,14 +365,17 @@
z-index: 1; z-index: 1;
} }
html:not(.no-touch) & { /* html:not(.no-touch) & {
transform: translateZ(0);
} */
&:not(.is-hidden) {
transform: translateZ(0); transform: translateZ(0);
} }
} }
html.no-touch &:hover .btn-corner:not(.is-hidden) { /* html.no-touch &:hover .btn-corner:not(.is-hidden) {
transform: translateZ(0); transform: translateZ(0);
} } */
} }
.connection-status { .connection-status {

8
src/scss/partials/_rightSidebar.scss

@ -150,17 +150,17 @@
} }
&.can-add-members { &.can-add-members {
@include respond-to(handhelds) { //@include respond-to(handhelds) {
.btn-corner:not(.is-hidden) { .btn-corner:not(.is-hidden) {
transform: translateZ(0); transform: translateZ(0);
} }
} //}
@include hover() { /* @include hover() {
.btn-corner:not(.is-hidden) { .btn-corner:not(.is-hidden) {
transform: translateZ(0); transform: translateZ(0);
} }
} } */
} }
.search-super { .search-super {

Loading…
Cancel
Save