Replace timeOutAction() with debounce

Replace delegateRun()
Revert my throttle/debounce setTimeout() to Function.prototype[throttle/debounce]
This commit is contained in:
djmaze 2020-08-18 20:24:17 +02:00
parent f6a55898c7
commit 97a73c6639
28 changed files with 225 additions and 372 deletions

View file

@ -59,7 +59,7 @@ This fork uses downsized/simplified versions of scripts and has no support for I
The result is faster and smaller download code (good for mobile networks).
Things might work in Edge 16-18, Firefox 50-62 and Chrome 54-68 due to one polyfill for array.flat().
Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill for array.flat().
* Replaced jQuery with jQuery.slim
* Replaced ProgressJS with simple native dropin
@ -79,23 +79,23 @@ Things might work in Edge 16-18, Firefox 50-62 and Chrome 54-68 due to one polyf
|js/* |1.14.0 |native |
|----------- |--------: |--------: |
|admin.js |2.130.942 |1.089.940 |
|app.js |4.184.455 |2.774.461 |
|boot.js | 671.522 | 44.029 |
|libs.js | 647.614 | 316.107 |
|admin.js |2.130.942 |1.082.985 |
|app.js |4.184.455 |2.751.154 |
|boot.js | 671.522 | 43.995 |
|libs.js | 647.614 | 316.876 |
|polyfills.js | 325.834 | 0 |
|TOTAL |7.960.367 |4.224.537 |
|TOTAL |7.960.367 |4.195.010 |
|js/min/* |1.14.0 |native |gzip 1.14 |gzip |
|--------------- |--------: |--------: |--------: |--------: |
|admin.min.js | 252.147 | 148.234 | 73.657 | 42.376 |
|app.min.js | 511.202 | 371.731 |140.462 | 97.432 |
|boot.min.js | 66.007 | 5.589 | 22.567 | 2.332 |
|libs.min.js | 572.545 | 300.211 |176.720 | 92.699 |
|admin.min.js | 252.147 | 147.526 | 73.657 | 42.213 |
|app.min.js | 511.202 | 369.396 |140.462 | 97.130 |
|boot.min.js | 66.007 | 5.579 | 22.567 | 2.328 |
|libs.min.js | 572.545 | 300.520 |176.720 | 92.825 |
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 |
|TOTAL |1.434.353 | 825.765 |424.718 |234.839 |
|TOTAL |1.434.353 | 823.015 |424.718 |234.496 |
608.588 bytes (189.879 gzip) is not much, but it feels faster.
611.338 bytes (190.222 gzip) is not much, but it feels faster.
|css/* |1.14.0 |native |

View file

@ -31,25 +31,18 @@ class AbstractApp extends AbstractBoot {
this.isLocalAutocomplete = true;
this.lastErrorTime = 0;
var t;
addEventListener(
'resize',
()=>{
// throttle
if (!t) {
t = setTimeout(()=>{
const iH = $win.height(),
iW = $win.height();
(()=>{
const iH = $win.height(),
iW = $win.height();
if ($win.__sizes[0] !== iH || $win.__sizes[1] !== iW) {
$win.__sizes[0] = iH;
$win.__sizes[1] = iW;
dispatchEvent(new CustomEvent('resize.real'));
}
t = 0;
}, 50);
if ($win.__sizes[0] !== iH || $win.__sizes[1] !== iW) {
$win.__sizes[0] = iH;
$win.__sizes[1] = iW;
dispatchEvent(new CustomEvent('resize.real'));
}
}
}).throttle(50)
);
const $doc = document;
@ -64,12 +57,7 @@ class AbstractApp extends AbstractBoot {
}
});
var d;
const fn = ()=>{
// debounce
clearTimeout(d);
d = setTimeout(()=>dispatchEvent(new CustomEvent('rl.auto-logout-refresh')), 5000);
}
const fn = (()=>dispatchEvent(new CustomEvent('rl.auto-logout-refresh'))).debounce(5000);
$doc.addEventListener('mousemove', fn);
$doc.addEventListener('keypress', fn);

View file

@ -81,16 +81,14 @@ import { AbstractApp } from 'App/Abstract';
const doc = document;
if (!window.ResizeObserver) {
let rot;
window.ResizeObserver = class {
constructor(callback) {
callback = callback.debounce(250);
this.observer = new MutationObserver(mutations => {
let i = mutations.length;
while (i--) {
if ('style' == mutations[i].attributeName) {
// debounce
clearTimeout(rot);
rot = setTimeout(callback, 250);
callback();
break;
}
}
@ -113,15 +111,11 @@ class AppUser extends AbstractApp {
this.moveCache = {};
let qd, o = this;
this.quotaDebounce = ()=>{
// debounce
clearTimeout(qd);
qd = setTimeout(o.quota, 30000);
};
this.quotaDebounce = this.quota.debounce(30000);
this.moveOrDeleteResponseHelper = this.moveOrDeleteResponseHelper.bind(this);
this.messagesMoveTrigger = this.messagesMoveTrigger.debounce(500);
// wakeUp
const interval = 3600000; // 60m
var lastTime = (new Date()).getTime();
@ -262,30 +256,25 @@ class AppUser extends AbstractApp {
}
messagesMoveTrigger() {
// debounce
const o = this;
clearTimeout(o.mt);
o.mt = setTimeout(()=>{
const sTrashFolder = FolderStore.trashFolder(),
sSpamFolder = FolderStore.spamFolder();
const sTrashFolder = FolderStore.trashFolder(),
sSpamFolder = FolderStore.spamFolder();
Object.values(o.moveCache).forEach(item => {
const isSpam = sSpamFolder === item.To,
isTrash = sTrashFolder === item.To,
isHam = !isSpam && sSpamFolder === item.From && getFolderInboxName() === item.To;
Object.values(this.moveCache).forEach(item => {
const isSpam = sSpamFolder === item.To,
isTrash = sTrashFolder === item.To,
isHam = !isSpam && sSpamFolder === item.From && getFolderInboxName() === item.To;
Remote.messagesMove(
o.moveOrDeleteResponseHelper,
item.From,
item.To,
item.Uid,
isSpam ? 'SPAM' : isHam ? 'HAM' : '',
isSpam || isTrash
);
});
Remote.messagesMove(
this.moveOrDeleteResponseHelper,
item.From,
item.To,
item.Uid,
isSpam ? 'SPAM' : isHam ? 'HAM' : '',
isSpam || isTrash
);
});
o.moveCache = {};
}, 500);
this.moveCache = {};
}
messagesMoveHelper(fromFolderFullNameRaw, toFolderFullNameRaw, uidsForMove) {

View file

@ -145,7 +145,7 @@ class CookieDriver {
try {
const storageResult = Cookies.getJSON(CLIENT_SIDE_STORAGE_INDEX_NAME);
result = storageResult && undefined !== storageResult[key] ? storageResult[key] : null;
result = storageResult && null != storageResult[key] ? storageResult[key] : null;
} catch (e) {} // eslint-disable-line no-empty
return result;

View file

@ -47,7 +47,7 @@ class LocalStorageDriver {
const storageValue = this.s.getItem(CLIENT_SIDE_STORAGE_INDEX_NAME) || null,
storageResult = null === storageValue ? null : JSON.parse(storageValue);
return storageResult && undefined !== storageResult[key] ? storageResult[key] : null;
return storageResult && null != storageResult[key] ? storageResult[key] : null;
} catch (e) {} // eslint-disable-line no-empty
return null;

View file

@ -32,16 +32,7 @@ class HtmlEditor {
this.element = element;
this.$element = jQuery(element);
// throttle
var t, o = this;
this.resize = ()=>{
if (!t) {
t = setTimeout(()=>{
o.resizeEditor();
t = 0;
}, 100);
}
};
this.resize = this.resizeEditor.throttle(100);
this.init();
}

View file

@ -88,6 +88,6 @@ export function runSettingsViewModelHooks(admin) {
*/
export function settingsGet(pluginSection, name) {
let plugins = Settings.settingsGet('Plugins');
plugins = plugins && undefined !== plugins[pluginSection] ? plugins[pluginSection] : null;
return plugins ? (undefined === plugins[name] ? null : plugins[name]) : null;
plugins = plugins && null != plugins[pluginSection] ? plugins[pluginSection] : null;
return plugins ? (null == plugins[name] ? null : plugins[name]) : null;
}

View file

@ -52,12 +52,7 @@ class Selector {
this.focusedItem = koFocusedItem || ko.observable(null);
this.selectedItem = koSelectedItem || ko.observable(null);
var d, o = this;
this.itemSelectedThrottle = (item)=>{
// debounce
clearTimeout(d);
d = setTimeout(()=>o.itemSelected(item), 300);
};
this.itemSelectedThrottle = (item=>this.itemSelected(item)).debounce(300);
this.listChecked.subscribe((items) => {
if (items.length) {

View file

@ -94,7 +94,7 @@ export function i18n(key, valueList, defaulValue) {
result = undefined === defaulValue ? key : defaulValue;
}
if (undefined !== valueList && null !== valueList) {
if (null != valueList) {
for (valueName in valueList) {
if (Object.prototype.hasOwnProperty.call(valueList, valueName)) {
result = result.replace('%' + valueName + '%', valueList[valueName]);

View file

@ -124,17 +124,6 @@ export function splitPlainText(text, len = 100) {
return prefix + result;
}
const timeOutAction = (() => {
const timeOuts = {};
return (action, fFunction, timeOut) => {
timeOuts[action] = undefined === timeOuts[action] ? 0 : timeOuts[action];
clearTimeout(timeOuts[action]);
timeOuts[action] = setTimeout(fFunction, timeOut);
};
})();
export { timeOutAction };
/**
* @param {any} m
* @returns {any}
@ -258,27 +247,6 @@ export function friendlySize(sizeInBytes) {
return sizeInBytes + 'B';
}
/**
* @param {?} object
* @param {string} methodName
* @param {Array=} params
* @param {number=} delay = 0
*/
export function delegateRun(object, methodName, params, delay = 0) {
if (object && object[methodName]) {
delay = pInt(delay);
params = isArray(params) ? params : [];
if (0 >= delay) {
object[methodName](...params);
} else {
setTimeout(() => {
object[methodName](...params);
}, delay);
}
}
}
/**
* @param {(Object|null|undefined)} context
* @param {Function} fExecute
@ -830,14 +798,9 @@ export function selectElement(element) {
sel.addRange(range);
}
var dv;
export const detectDropdownVisibility = ()=>{
// leading debounce
clearTimeout(dv);
dv = setTimeout(()=>
dropdownVisibility(!!GlobalsData.aBootstrapDropdowns.find(item => item.hasClass('open')))
, 50);
};
export const detectDropdownVisibility = (()=>
dropdownVisibility(!!GlobalsData.aBootstrapDropdowns.find(item => item.hasClass('open')))
).debounce(50);
/**
* @param {boolean=} delay = false
@ -881,11 +844,9 @@ export function getConfigurationFromScriptTag(configuration) {
export function delegateRunOnDestroy(objectOrObjects) {
if (objectOrObjects) {
if (isArray(objectOrObjects)) {
objectOrObjects.forEach(item => {
delegateRunOnDestroy(item);
});
} else if (objectOrObjects && objectOrObjects.onDestroy) {
objectOrObjects.onDestroy();
objectOrObjects.forEach(item => delegateRunOnDestroy(item));
} else {
objectOrObjects.onDestroy && objectOrObjects.onDestroy();
}
}
}
@ -1199,8 +1160,8 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
to,
cc,
bcc,
undefined === params.subject ? null : pString(decodeURIComponent(params.subject)),
undefined === params.body ? null : plainToHtml(pString(decodeURIComponent(params.body)))
null == params.subject ? null : pString(decodeURIComponent(params.subject)),
null == params.body ? null : plainToHtml(pString(decodeURIComponent(params.body)))
]);
return true;
@ -1212,7 +1173,7 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
var wr;
export const windowResize = timeout => {
clearTimeout(wr);
if (undefined === timeout || null === timeout) {
if (null == timeout) {
$win.trigger('resize');
} else {
wr = setTimeout(()=>$win.trigger('resize'), timeout);

View file

@ -1,6 +1,6 @@
import ko from 'ko';
import { delegateRun, inFocus } from 'Common/Utils';
import { inFocus } from 'Common/Utils';
import { KeyState, EventKeyCode } from 'Common/Enums';
import { keyScope } from 'Common/Globals';
@ -38,7 +38,7 @@ export class AbstractViewNext {
addEventListener('keydown', (event) => {
if (event && this.modalVisibility && this.modalVisibility()) {
if (!this.bDisabeCloseOnEsc && EventKeyCode.Esc === event.keyCode) {
delegateRun(this, 'cancelCommand');
this.cancelCommand && this.cancelCommand();
return false;
} else if (EventKeyCode.Backspace === event.keyCode && !inFocus()) {
return false;

View file

@ -3,7 +3,7 @@ import ko from 'ko';
import { runHook } from 'Common/Plugins';
import { $htmlCL, VIEW_MODELS, popupVisibilityNames } from 'Common/Globals';
import { pString, createCommandLegacy, delegateRun, isNonEmptyArray } from 'Common/Utils';
import { pString, createCommandLegacy, isNonEmptyArray } from 'Common/Utils';
let currentScreen = null,
defaultScreenName = '';
@ -90,7 +90,7 @@ export function routeOn() {
* @returns {?Object}
*/
export function screen(screenName) {
return screenName && undefined !== SCREENS[screenName] ? SCREENS[screenName] : null;
return screenName && null != SCREENS[screenName] ? SCREENS[screenName] : null;
}
/**
@ -181,10 +181,10 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm.onShowTrigger(!vm.onShowTrigger());
}
delegateRun(vm, 'onShowWithDelay', [], 500);
vm.onShowWithDelay && setTimeout(()=>vm.onShowWithDelay, 500);
} else {
delegateRun(vm, 'onHide');
delegateRun(vm, 'onHideWithDelay', [], 500);
vm.onHide && vm.onHide();
vm.onHideWithDelay && setTimeout(()=>vm.onHideWithDelay, 500);
if (vm.onHideTrigger) {
vm.onHideTrigger(!vm.onHideTrigger());
@ -213,7 +213,7 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm
);
delegateRun(vm, 'onBuild', [vmDom]);
vm.onBuild && vm.onBuild(vmDom);
if (vm && ViewType.Popup === position) {
vm.registerPopupKeyDown();
}
@ -238,11 +238,13 @@ export function showScreenPopup(ViewModelClassToShow, params = []) {
buildViewModel(ModalView);
if (ModalView.__vm && ModalView.__dom) {
delegateRun(ModalView.__vm, 'onBeforeShow', params || []);
params = params || [];
ModalView.__vm.onBeforeShow && ModalView.__vm.onBeforeShow(...params);
ModalView.__vm.modalVisibility(true);
delegateRun(ModalView.__vm, 'onShow', params || []);
ModalView.__vm.onShow && ModalView.__vm.onShow(...params);
vmRunHook('view-model-on-show', ModalView, params || []);
}
@ -259,7 +261,7 @@ export function warmUpScreenPopup(ViewModelClassToShow) {
buildViewModel(ModalView);
if (ModalView.__vm && ModalView.__dom) {
delegateRun(ModalView.__vm, 'onWarmUp');
ModalView.__vm.onWarmUp && ModalView.__vm.onWarmUp();
}
}
}
@ -309,14 +311,14 @@ export function screenOnRoute(screenName, subPart) {
});
}
delegateRun(vmScreen, 'onBuild');
vmScreen.onBuild && vmScreen.onBuild();
}
setTimeout(() => {
// hide screen
if (currentScreen && !isSameScreen) {
delegateRun(currentScreen, 'onHide');
delegateRun(currentScreen, 'onHideWithDelay', [], 500);
currentScreen.onHide && currentScreen.onHide();
currentScreen.onHideWithDelay && setTimeout(()=>currentScreen.onHideWithDelay(), 500);
if (currentScreen.onHideTrigger) {
currentScreen.onHideTrigger(!currentScreen.onHideTrigger());
@ -332,8 +334,8 @@ export function screenOnRoute(screenName, subPart) {
ViewModelClass.__dom.hide();
ViewModelClass.__vm.viewModelVisibility(false);
delegateRun(ViewModelClass.__vm, 'onHide');
delegateRun(ViewModelClass.__vm, 'onHideWithDelay', [], 500);
ViewModelClass.__vm.onHide && ViewModelClass.__vm.onHide();
ViewModelClass.__vm.onHideWithDelay && setTimeout(()=>ViewModelClass.__vm.onHideWithDelay(), 500);
if (ViewModelClass.__vm.onHideTrigger) {
ViewModelClass.__vm.onHideTrigger(!ViewModelClass.__vm.onHideTrigger());
@ -348,7 +350,7 @@ export function screenOnRoute(screenName, subPart) {
// show screen
if (currentScreen && !isSameScreen) {
delegateRun(currentScreen, 'onShow');
currentScreen.onShow && currentScreen.onShow();
if (currentScreen.onShowTrigger) {
currentScreen.onShowTrigger(!currentScreen.onShowTrigger());
}
@ -362,17 +364,18 @@ export function screenOnRoute(screenName, subPart) {
ViewModelClass.__dom &&
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
) {
delegateRun(ViewModelClass.__vm, 'onBeforeShow');
ViewModelClass.__vm.onBeforeShow && ViewModelClass.__vm.onBeforeShow();
ViewModelClass.__dom.show();
ViewModelClass.__vm.viewModelVisibility(true);
delegateRun(ViewModelClass.__vm, 'onShow');
ViewModelClass.__vm.onShow && ViewModelClass.__vm.onShow();
if (ViewModelClass.__vm.onShowTrigger) {
ViewModelClass.__vm.onShowTrigger(!ViewModelClass.__vm.onShowTrigger());
}
delegateRun(ViewModelClass.__vm, 'onShowWithDelay', [], 200);
ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200);
vmRunHook('view-model-on-show', ViewModelClass);
}
});
@ -415,7 +418,7 @@ export function startScreens(screensClasses) {
vmScreen.__start();
runHook('screen-pre-start', [vmScreen.screenName(), vmScreen]);
delegateRun(vmScreen, 'onStart');
vmScreen.onStart && vmScreen.onStart();
runHook('screen-post-start', [vmScreen.screenName(), vmScreen]);
}
});
@ -526,30 +529,23 @@ function commandDecorator(canExecute = true) {
* @returns {Function}
*/
function settingsMenuKeysHandler($items) {
// throttle
var t;
return (event, handler)=>{
if (!t) {
t = setTimeout(()=>{
const up = handler && 'up' === handler.shortcut;
return ((event, handler)=>{
const up = handler && 'up' === handler.shortcut;
if (event && $items.length) {
let index = $items.index($items.filter('.selected'));
if (up && 0 < index) {
index -= 1;
} else if (!up && index < $items.length - 1) {
index += 1;
}
if (event && $items.length) {
let index = $items.index($items.filter('.selected'));
if (up && 0 < index) {
index -= 1;
} else if (!up && index < $items.length - 1) {
index += 1;
}
const resultHash = $items.eq(index).attr('href');
if (resultHash) {
setHash(resultHash, false, true);
}
}
t = 0;
}, 200);
const resultHash = $items.eq(index).attr('href');
if (resultHash) {
setHash(resultHash, false, true);
}
}
};
}).throttle(200);
}
export {

View file

@ -37,7 +37,7 @@ class AbstractAjaxPromises extends AbstractBasicPromises {
ajaxRequest(action, isPost, timeOut, params, additionalGetString, fTrigger) {
additionalGetString = undefined === additionalGetString ? '' : pString(additionalGetString);
additionalGetString = pString(additionalGetString);
let init = {
mode: 'same-origin',
@ -65,7 +65,7 @@ class AbstractAjaxPromises extends AbstractBasicPromises {
}
};
buildFormData(formData, params);
init.body = (new URLSearchParams(formData)).toString();
init.body = new URLSearchParams(formData);
}
runHook('ajax-default-request', [action, params, additionalGetString]);

View file

@ -163,7 +163,7 @@ class AbstractAjaxRemote {
}
};
buildFormData(formData, params);
init.body = (new URLSearchParams(formData)).toString();
init.body = new URLSearchParams(formData);
}
if (window.AbortController) {

View file

@ -1,7 +1,7 @@
import ko from 'ko';
import { VIEW_MODELS } from 'Common/Globals';
import { delegateRun, windowResize, pString } from 'Common/Utils';
import { windowResize, pString } from 'Common/Utils';
import { settings } from 'Common/Links';
import { setHash } from 'Knoin/Knoin';
@ -94,7 +94,7 @@ class AbstractSettingsScreen extends AbstractScreen {
settingsScreen
);
delegateRun(settingsScreen, 'onBuild', [viewModelDom]);
settingsScreen.onBuild && settingsScreen.onBuild(viewModelDom);
} else {
console.log('Cannot find sub settings view model position: SettingsSubScreen');
}
@ -105,7 +105,7 @@ class AbstractSettingsScreen extends AbstractScreen {
setTimeout(() => {
// hide
if (o.oCurrentSubScreen) {
delegateRun(o.oCurrentSubScreen, 'onHide');
o.oCurrentSubScreen.onHide && o.oCurrentSubScreen.onHide();
o.oCurrentSubScreen.viewModelDom.hide();
}
// --
@ -114,10 +114,10 @@ class AbstractSettingsScreen extends AbstractScreen {
// show
if (o.oCurrentSubScreen) {
delegateRun(o.oCurrentSubScreen, 'onBeforeShow');
o.oCurrentSubScreen.onBeforeShow && o.oCurrentSubScreen.onBeforeShow();
o.oCurrentSubScreen.viewModelDom.show();
delegateRun(o.oCurrentSubScreen, 'onShow');
delegateRun(o.oCurrentSubScreen, 'onShowWithDelay', [], 200);
o.oCurrentSubScreen.onShow && o.oCurrentSubScreen.onShow();
o.oCurrentSubScreen.onShowWithDelay && setTimeout(() => o.oCurrentSubScreen.onShowWithDelay(), 200);
o.menu().forEach(item => {
item.selected(
@ -141,7 +141,7 @@ class AbstractSettingsScreen extends AbstractScreen {
onHide() {
if (this.oCurrentSubScreen && this.oCurrentSubScreen.viewModelDom) {
delegateRun(this.oCurrentSubScreen, 'onHide');
this.oCurrentSubScreen.onHide && this.oCurrentSubScreen.onHide();
this.oCurrentSubScreen.viewModelDom.hide();
}
}

View file

@ -4,7 +4,7 @@ import { MESSAGES_PER_PAGE_VALUES } from 'Common/Consts';
import { SaveSettingsStep, EditorDefaultType, Layout } from 'Common/Enums';
import { settingsSaveHelperSimpleFunction, convertLangName, timeOutAction } from 'Common/Utils';
import { settingsSaveHelperSimpleFunction, convertLangName } from 'Common/Utils';
import { i18n, trigger as translatorTrigger, reload as translatorReload } from 'Common/Translator';
@ -121,46 +121,28 @@ class GeneralUserSettings {
this.useCheckboxesInList.subscribe(Remote.saveSettingsHelper('UseCheckboxesInList', v=>v?'1':'0'));
this.enableDesktopNotification.subscribe((value) => {
timeOutAction(
'SaveDesktopNotifications',
() => {
Remote.saveSettings(null, {
'DesktopNotifications': value ? '1' : '0'
});
},
3000
);
});
this.enableDesktopNotification.subscribe((value =>
Remote.saveSettings(null, {
'DesktopNotifications': value ? 1 : 0
})
).debounce(3000));
this.enableSoundNotification.subscribe((value) => {
timeOutAction(
'SaveSoundNotification',
() => {
Remote.saveSettings(null, {
'SoundNotification': value ? '1' : '0'
});
},
3000
);
});
this.enableSoundNotification.subscribe((value =>
Remote.saveSettings(null, {
'SoundNotification': value ? 1 : 0
})
).debounce(3000));
this.replySameFolder.subscribe((value) => {
timeOutAction(
'SaveReplySameFolder',
() => {
Remote.saveSettings(null, {
'ReplySameFolder': value ? '1' : '0'
});
},
3000
);
});
this.replySameFolder.subscribe((value =>
Remote.saveSettings(null, {
'ReplySameFolder': value ? 1 : 0
})
).debounce(3000));
this.useThreads.subscribe((value) => {
MessageStore.messageList([]);
Remote.saveSettings(null, {
'UseThreads': value ? '1' : '0'
'UseThreads': value ? 1 : 0
});
});

View file

@ -9,7 +9,7 @@ APP_SETTINGS = null != APP_SETTINGS ? APP_SETTINGS : {};
* @returns {*}
*/
export function settingsGet(name) {
return undefined === SETTINGS[name] ? null : SETTINGS[name];
return null == SETTINGS[name] ? null : SETTINGS[name];
}
/**
@ -25,7 +25,7 @@ export function settingsSet(name, value) {
* @returns {*}
*/
export function appSettingsGet(name) {
return undefined === APP_SETTINGS[name] ? null : APP_SETTINGS[name];
return null == APP_SETTINGS[name] ? null : APP_SETTINGS[name];
}
/**

View file

@ -112,16 +112,7 @@ class MessageUserStore {
this.onMessageResponse = this.onMessageResponse.bind(this);
// throttle
var t, o = this;
this.purgeMessageBodyCacheThrottle = ()=>{
if (!t) {
t = setTimeout(()=>{
o.purgeMessageBodyCache();
t = 0;
}, 30000);
}
};
this.purgeMessageBodyCacheThrottle = this.purgeMessageBodyCache.throttle(30000);
}
computers() {
@ -203,20 +194,15 @@ class MessageUserStore {
this.messageListCompleteLoadingThrottleForAnimation(value);
});
var d;
this.messageList.subscribe(
(list)=>{
// debounce
clearTimeout(d);
d = setTimeout(()=>list.forEach(item => {
if (item && item.newForAnimation()) {
item.newForAnimation(false);
}
}), 500);
}
(list=> {
list.forEach(item =>
item && item.newForAnimation() && item.newForAnimation(false)
)
}).debounce(500)
);
this.message.subscribe((message) => {
this.message.subscribe(message => {
if (message) {
if (Layout.NoPreview === SettingsStore.layout()) {
AppStore.focusedState(Focused.MessageView);
@ -229,9 +215,7 @@ class MessageUserStore {
}
});
this.messageLoading.subscribe((value) => {
this.messageLoadingThrottle(value);
});
this.messageLoading.subscribe(value => this.messageLoadingThrottle(value));
this.messagesBodiesDom.subscribe((dom) => {
if (dom && !(dom instanceof $)) {
@ -239,7 +223,7 @@ class MessageUserStore {
}
});
this.messageListEndFolder.subscribe((folder) => {
this.messageListEndFolder.subscribe(folder => {
const message = this.message();
if (message && folder && folder !== message.folderFullNameRaw) {
this.message(null);
@ -745,7 +729,7 @@ class MessageUserStore {
iCount = pInt(data.Result.MessageResultCount),
iOffset = pInt(data.Result.Offset);
const folder = getFolderFromCacheList(null != data.Result.Folder ? data.Result.Folder : '');
const folder = getFolderFromCacheList(data.Result.Folder);
if (folder && !cached) {
folder.interval = Date.now() / 1000;

View file

@ -1,5 +1,4 @@
import ko from 'ko';
import { delegateRun } from 'Common/Utils';
import PgpStore from 'Stores/User/Pgp';
@ -83,7 +82,7 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
return false;
}
delegateRun(this, 'cancelCommand');
this.cancelCommand && this.cancelCommand();
return true;
}

View file

@ -12,7 +12,6 @@ import {
} from 'Common/Enums';
import {
delegateRun,
isNonEmptyArray,
clearBqSwitcher,
replySubjectAdd,
@ -85,7 +84,7 @@ class ComposePopupView extends AbstractViewNext {
this.sLastFocusedField = 'to';
this.resizerTrigger = this.resizerTrigger.bind(this);
this.resizerTrigger = this.resizerTrigger.debounce(50).bind(this);
this.allowContacts = !!AppStore.contactsIsAllowed();
this.allowFolders = !!Settings.capa(Capa.Folders);
@ -148,17 +147,9 @@ class ComposePopupView extends AbstractViewNext {
}
});
this.savedError.subscribe((value) => {
if (!value) {
this.savedErrorDesc('');
}
});
this.savedError.subscribe(value => !value && this.savedErrorDesc(''));
this.sendSuccessButSaveError.subscribe((value) => {
if (!value) {
this.savedErrorDesc('');
}
});
this.sendSuccessButSaveError.subscribe(value => !value && this.savedErrorDesc(''));
this.savedTime = ko.observable(0);
this.savedTimeText = ko.computed(() =>
@ -297,9 +288,6 @@ class ComposePopupView extends AbstractViewNext {
this.canBeSentOrSaved = ko.computed(() => !this.sending() && !this.saving());
this.sendMessageResponse = this.sendMessageResponse.bind(this);
this.saveMessageResponse = this.saveMessageResponse.bind(this);
setInterval(() => {
if (
this.modalVisibility() &&
@ -318,20 +306,10 @@ class ComposePopupView extends AbstractViewNext {
this.showBcc.subscribe(this.resizerTrigger);
this.showReplyTo.subscribe(this.resizerTrigger);
this.onMessageUploadAttachments = this.onMessageUploadAttachments.bind(this);
this.bDisabeCloseOnEsc = true;
this.sDefaultKeyScope = KeyState.Compose;
// debounce
var d, fn = this.tryToClosePopup.bind(this);
this.tryToClosePopup = ()=>{
clearTimeout(d);
d = setTimeout(fn, 200);
};
this.emailsSource = this.emailsSource.bind(this);
this.autosaveFunction = this.autosaveFunction.bind(this);
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
this.iTimer = 0;
}
@ -424,7 +402,7 @@ class ComposePopupView extends AbstractViewNext {
setFolderHash(sSentFolder, '');
Remote.sendMessage(
this.sendMessageResponse,
this.sendMessageResponse.bind(this),
this.getMessageRequestParams(sSentFolder)
);
}
@ -448,7 +426,7 @@ class ComposePopupView extends AbstractViewNext {
setFolderHash(FolderStore.draftFolder(), '');
Remote.saveMessage(
this.saveMessageResponse,
this.saveMessageResponse.bind(this),
this.getMessageRequestParams(FolderStore.draftFolder())
);
}
@ -517,7 +495,7 @@ class ComposePopupView extends AbstractViewNext {
autosaveStart() {
clearTimeout(this.iTimer);
this.iTimer = setTimeout(this.autosaveFunction, 60000);
this.iTimer = setTimeout(()=>this.autosaveFunction(), 60000);
}
autosaveStop() {
@ -525,9 +503,7 @@ class ComposePopupView extends AbstractViewNext {
}
emailsSource(oData, fResponse) {
getApp().getAutocomplete(oData.term, (aData) => {
fResponse(aData.map(oEmailItem => oEmailItem.toLine(false)));
});
getApp().getAutocomplete(oData.term, aData => fResponse(aData.map(oEmailItem => oEmailItem.toLine(false))));
}
openOpenPgpPopup() {
@ -615,9 +591,7 @@ class ComposePopupView extends AbstractViewNext {
if (StorageResultType.Success === statusResult && data && data.Result) {
result = true;
if (this.modalVisibility()) {
delegateRun(this, 'closeCommand');
}
this.modalVisibility() && this.closeCommand && this.closeCommand();
}
if (this.modalVisibility() && !result) {
@ -1096,7 +1070,7 @@ class ComposePopupView extends AbstractViewNext {
const downloads = this.getAttachmentsDownloadsForUpload();
if (isNonEmptyArray(downloads)) {
Remote.messageUploadAttachments(this.onMessageUploadAttachments, downloads);
Remote.messageUploadAttachments(()=>this.onMessageUploadAttachments(), downloads);
}
if (identity) {
@ -1147,13 +1121,13 @@ class ComposePopupView extends AbstractViewNext {
const PopupsAskViewModel = require('View/Popup/Ask');
if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) {
if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid())) {
delegateRun(this, 'closeCommand');
this.closeCommand && this.closeCommand();
} else {
showScreenPopup(PopupsAskViewModel, [
i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'),
() => {
if (this.modalVisibility()) {
delegateRun(this, 'closeCommand');
this.closeCommand && this.closeCommand();
}
}
]);
@ -1206,12 +1180,7 @@ class ComposePopupView extends AbstractViewNext {
return false;
});
var d, o = this;
addEventListener('resize.real', ()=>{
// debounce
clearTimeout(d);
d = setTimeout(o.resizerTrigger, 50);
});
addEventListener('resize.real', this.resizerTrigger);
setInterval(() => {
if (this.modalVisibility() && this.oEditor) {

View file

@ -2,7 +2,7 @@ import ko from 'ko';
import { FiltersAction, FilterConditionField, FilterConditionType } from 'Common/Enums';
import { bMobileDevice } from 'Common/Globals';
import { defautOptionsAfterRender, delegateRun } from 'Common/Utils';
import { defautOptionsAfterRender } from 'Common/Utils';
import { i18n, initOnStartOrLangChange } from 'Common/Translator';
import FilterStore from 'Stores/User/Filter';
@ -59,13 +59,9 @@ class FilterPopupView extends AbstractViewNext {
return false;
}
if (this.fTrueCallback) {
this.fTrueCallback(this.filter());
}
this.fTrueCallback && this.fTrueCallback(this.filter());
if (this.modalVisibility()) {
delegateRun(this, 'closeCommand');
}
this.modalVisibility() && this.closeCommand && this.closeCommand();
}
return true;

View file

@ -55,7 +55,6 @@ class FolderSystemPopupView extends AbstractViewNext {
this.trashFolder = FolderStore.trashFolder;
this.archiveFolder = FolderStore.archiveFolder;
var d;
const fSetSystemFolders = () => {
Settings.settingsSet('SentFolder', FolderStore.sentFolder());
Settings.settingsSet('DraftFolder', FolderStore.draftFolder());
@ -63,21 +62,17 @@ class FolderSystemPopupView extends AbstractViewNext {
Settings.settingsSet('TrashFolder', FolderStore.trashFolder());
Settings.settingsSet('ArchiveFolder', FolderStore.archiveFolder());
},
fSaveSystemFolders = ()=>{
// debounce
clearTimeout(d);
d = setTimeout(()=>{
fSetSystemFolders();
Remote.saveSystemFolders(()=>{}, {
SentFolder: FolderStore.sentFolder(),
DraftFolder: FolderStore.draftFolder(),
SpamFolder: FolderStore.spamFolder(),
TrashFolder: FolderStore.trashFolder(),
ArchiveFolder: FolderStore.archiveFolder(),
NullFolder: 'NullFolder'
});
}, 1000);
},
fSaveSystemFolders = (()=>{
fSetSystemFolders();
Remote.saveSystemFolders(()=>{}, {
SentFolder: FolderStore.sentFolder(),
DraftFolder: FolderStore.draftFolder(),
SpamFolder: FolderStore.spamFolder(),
TrashFolder: FolderStore.trashFolder(),
ArchiveFolder: FolderStore.archiveFolder(),
NullFolder: 'NullFolder'
});
}).debounce(1000),
fCallback = () => {
fSetSystemFolders();
fSaveSystemFolders();

View file

@ -14,39 +14,29 @@ class KeyboardShortcutsHelpPopupView extends AbstractViewNext {
}
onBuild(dom) {
var t;
key(
'tab, shift+tab, left, right',
KeyState.PopupKeyboardShortcutsHelp,
(event, handler)=>{
// throttle
if (!t) {
t = setTimeout(()=>{
t = 0;
if (event && handler) {
const $tabs = dom.find('.nav.nav-tabs > li'),
isNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut);
((event, handler)=>{
if (event && handler) {
const $tabs = dom.find('.nav.nav-tabs > li'),
isNext = handler && ('tab' === handler.shortcut || 'right' === handler.shortcut);
let index = $tabs.index($tabs.filter('.active'));
if (!isNext && 0 < index) {
index -= 1;
} else if (isNext && index < $tabs.length - 1) {
index += 1;
} else {
index = isNext ? 0 : $tabs.length - 1;
}
let index = $tabs.index($tabs.filter('.active'));
if (!isNext && 0 < index) {
index -= 1;
} else if (isNext && index < $tabs.length - 1) {
index += 1;
} else {
index = isNext ? 0 : $tabs.length - 1;
}
$tabs
.eq(index)
.find('a[data-toggle="tab"]')
.tab('show');
return false;
}
return true;
}, 100);
$tabs
.eq(index)
.find('a[data-toggle="tab"]')
.tab('show');
}
}
}).throttle(100)
);
}
}

View file

@ -1,6 +1,6 @@
import ko from 'ko';
import { delegateRun, pInt } from 'Common/Utils';
import { pInt } from 'Common/Utils';
import PgpStore from 'Stores/User/Pgp';
@ -69,7 +69,7 @@ class NewOpenPgpKeyPopupView extends AbstractViewNext {
openpgpKeyring.store();
getApp().reloadOpenPgpKeys();
delegateRun(this, 'cancelCommand');
this.cancelCommand && this.cancelCommand();
}
})
.catch((e) => {

View file

@ -1,7 +1,6 @@
import ko from 'ko';
import { KeyState, StorageResultType, Notification } from 'Common/Enums';
import { isNonEmptyArray, delegateRun } from 'Common/Utils';
import { getNotification, i18n } from 'Common/Translator';
import Remote from 'Remote/Admin/Ajax';
@ -41,12 +40,7 @@ class PluginPopupView extends AbstractViewNext {
this.bDisabeCloseOnEsc = true;
this.sDefaultKeyScope = KeyState.All;
var d, fn = this.tryToClosePopup.bind(this);
this.tryToClosePopup = ()=>{
// debounce
clearTimeout(d);
d = setTimeout(fn, 200);
};
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
}
@command((self) => self.hasConfiguration())
@ -89,7 +83,7 @@ class PluginPopupView extends AbstractViewNext {
this.readme(oPlugin.Readme);
const config = oPlugin.Config;
if (isNonEmptyArray(config)) {
if (Array.isArray(config) && config.length) {
this.configures(
config.map(item => ({
'value': ko.observable(item[0]),
@ -110,11 +104,7 @@ class PluginPopupView extends AbstractViewNext {
if (!isPopupVisible(PopupsAskViewModel)) {
showScreenPopup(PopupsAskViewModel, [
i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'),
() => {
if (this.modalVisibility()) {
delegateRun(this, 'cancelCommand');
}
}
() => this.modalVisibility() && this.cancelCommand && this.cancelCommand()
]);
}
}

View file

@ -539,20 +539,13 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.showFullInfo.subscribe(fCheckHeaderHeight);
this.message.subscribe(fCheckHeaderHeight);
var t;
addEventListener(
'resize',
()=>{
// throttle
if (!t) {
t = setTimeout(()=>{
setTimeout(fCheckHeaderHeight, 1);
setTimeout(fCheckHeaderHeight, 200);
setTimeout(fCheckHeaderHeight, 500);
t = 0;
}, 50);
}
}
(()=>{
setTimeout(fCheckHeaderHeight, 1);
setTimeout(fCheckHeaderHeight, 200);
setTimeout(fCheckHeaderHeight, 500);
}).throttle(50)
);
this.showFullInfo.subscribe((value) => {

34
dev/prototype-function.js vendored Normal file
View file

@ -0,0 +1,34 @@
/**
* Every time the function is executed,
* it will delay the execution with the given amount of milliseconds.
*/
if (!Function.prototype.debounce) {
Function.prototype.debounce = function(ms) {
let func = this, timer;
return function(...args) {
timer && clearTimeout(timer);
timer = setTimeout(()=>{
func.apply(this, args)
timer = 0;
}, ms);
};
};
}
/**
* No matter how many times the event is executed,
* the function will be executed only once, after the given amount of milliseconds.
*/
if (!Function.prototype.throttle) {
Function.prototype.throttle = function(ms) {
let func = this, timer;
return function(...args) {
if (!timer) {
timer = setTimeout(()=>{
func.apply(this, args)
timer = 0;
}, ms);
}
};
};
}

View file

@ -81,6 +81,7 @@ config.paths.js = {
'vendors/qr.js/qr.min.js', // fixed (license)
'vendors/bootstrap/js/bootstrap.min.js', // fixed
'dev/prototype-date.js',
'dev/prototype-function.js',
'node_modules/knockout/build/output/knockout-latest.js',
'node_modules/knockout-sortable/build/knockout-sortable.min.js ',
'node_modules/simplestatemanager/dist/ssm.min.js',