diff --git a/src/js/background.js b/src/js/background.js index d39312ef..597b82ac 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -58,28 +58,6 @@ var tgs = (function () { // eslint-disable-line no-unused-vars }); } - function getAllExpiredTabs(callback) { - var expiredTabs = []; - var checkTabExpiryPromises = []; - chrome.tabs.query({}, function (tabs) { - tabs.forEach(function (currentTab) { - if(gsUtils.isNormalTab(currentTab) && !gsUtils.isDiscardedTab(currentTab)) { - checkTabExpiryPromises.push(new Promise(function (resolve) { - gsMessages.sendRequestInfoToContentScript(currentTab.id, function (err, tabInfo) { - if (tabInfo && tabInfo.timerUp && (new Date(tabInfo.timerUp)) < new Date()) { - expiredTabs.push(currentTab); - } - resolve(); - }); - })); - } - }); - Promise.all(checkTabExpiryPromises).then(function () { - callback(expiredTabs); - }); - }); - } - // NOTE: Stationary here means has had focus for more than FOCUS_DELAY ms // So it may not necessarily have the tab.active flag set to true function isCurrentStationaryTab(tab) { @@ -1112,7 +1090,7 @@ var tgs = (function () { // eslint-disable-line no-unused-vars //restart timer on all normal tabs //NOTE: some tabs may have been prevented from suspending when computer was charging if (!_isCharging && gsStorage.getOption(gsStorage.IGNORE_WHEN_CHARGING)) { - gsMessages.sendResetToContentScripts([gsStorage.SUSPEND_TIME]); + gsMessages.sendResetTimerToAllContentScripts(); } }; }); @@ -1124,7 +1102,7 @@ var tgs = (function () { // eslint-disable-line no-unused-vars //restart timer on all normal tabs //NOTE: some tabs may have been prevented from suspending when internet was offline if (gsStorage.getOption(gsStorage.IGNORE_WHEN_OFFLINE)) { - gsMessages.sendResetToContentScripts([gsStorage.SUSPEND_TIME]); + gsMessages.sendResetTimerToAllContentScripts(); } setIconStatusForActiveTab(); }); @@ -1155,12 +1133,14 @@ var tgs = (function () { // eslint-disable-line no-unused-vars resuspendSuspendedTab: resuspendSuspendedTab, getActiveTabStatus: getActiveTabStatus, getDebugInfo: getDebugInfo, + calculateTabStatus: calculateTabStatus, isCharging: isCharging, isCurrentStationaryTab: isCurrentStationaryTab, isCurrentFocusedTab: isCurrentFocusedTab, initialiseUnsuspendedTab: initialiseUnsuspendedTab, initialiseSuspendedTab: initialiseSuspendedTab, + unsuspendTab: unsuspendTab, unsuspendHighlightedTab: unsuspendHighlightedTab, unwhitelistHighlightedTab: unwhitelistHighlightedTab, undoTemporarilyWhitelistHighlightedTab: undoTemporarilyWhitelistHighlightedTab, diff --git a/src/js/contentscript.js b/src/js/contentscript.js index 6f57d320..295e44c8 100644 --- a/src/js/contentscript.js +++ b/src/js/contentscript.js @@ -10,7 +10,9 @@ 'use strict'; var isInitialised = false, - inputState = false, + isFormListenerInitialised = false, + isReceivingFormInput = false, + isIgnoreForms = false, tempWhitelist = false, timerJob, suspendDateTime = false; @@ -24,25 +26,30 @@ return setTimeout(function () { //request suspension - if (!inputState && !tempWhitelist) { + if (!isReceivingFormInput && !tempWhitelist) { chrome.runtime.sendMessage({ action: 'suspendTab' }); } - suspendDateTime = false; }, timeToSuspend); } - function formInputListener(event) { - if (!inputState && !tempWhitelist) { - if (event.keyCode >= 48 && event.keyCode <= 90 && event.target.tagName) { - if (event.target.tagName.toUpperCase() === 'INPUT' || + function initFormInputListener() { + if (isFormListenerInitialised) { + return; + } + window.addEventListener('keydown', function (event) { + if (!isReceivingFormInput && !tempWhitelist) { + if (event.keyCode >= 48 && event.keyCode <= 90 && event.target.tagName) { + if (event.target.tagName.toUpperCase() === 'INPUT' || event.target.tagName.toUpperCase() === 'TEXTAREA' || event.target.tagName.toUpperCase() === 'FORM' || event.target.isContentEditable === true) { - inputState = true; - chrome.runtime.sendMessage(buildReportTabStatePayload()); + isReceivingFormInput = true; + chrome.runtime.sendMessage(buildReportTabStatePayload()); + } } } - } + }); + isFormListenerInitialised = true; } //listen for background events @@ -58,25 +65,15 @@ isInitialised = true; } - if (request.hasOwnProperty('ignoreForms')) { - window.removeEventListener('keydown', formInputListener); - if (request.ignoreForms) { - window.addEventListener('keydown', formInputListener); - } - inputState = inputState && request.ignoreForms; - } - if (request.hasOwnProperty('tempWhitelist')) { - if (inputState && !request.tempWhitelist) { - inputState = false; - } - tempWhitelist = request.tempWhitelist; - } if (request.hasOwnProperty('scrollPos')) { if (request.scrollPos !== '' && request.scrollPos !== '0') { document.body.scrollTop = request.scrollPos; document.documentElement.scrollTop = request.scrollPos; } } + if (request.hasOwnProperty('ignoredFormsSuspendTime') && isReceivingFormInput) { + request.suspendTime = request.ignoredFormsSuspendTime; + } if (request.hasOwnProperty('suspendTime')) { clearTimeout(timerJob); var suspendTime = Number(request.suspendTime); @@ -86,15 +83,27 @@ suspendDateTime = false; } } + if (request.hasOwnProperty('ignoreForms')) { + isIgnoreForms = request.ignoreForms; + if (isIgnoreForms) { + initFormInputListener(); + } + } + if (request.hasOwnProperty('tempWhitelist')) { + if (isReceivingFormInput && !request.tempWhitelist) { + isReceivingFormInput = false; + } + tempWhitelist = request.tempWhitelist; + } sendResponse(buildReportTabStatePayload()); return false; }); - function buildReportTabStatePayload(state) { + function buildReportTabStatePayload() { return { action: 'reportTabState', isInitialised: isInitialised, - status: state || (inputState ? 'formInput' : (tempWhitelist ? 'tempWhitelist' : 'normal')), + status: (isIgnoreForms && isReceivingFormInput) ? 'formInput' : (tempWhitelist ? 'tempWhitelist' : 'normal'), scrollPos: document.body.scrollTop || document.documentElement.scrollTop || 0, timerUp: suspendDateTime ? suspendDateTime + '' : false, }; diff --git a/src/js/gsMessages.js b/src/js/gsMessages.js index 550cdb68..753833d4 100644 --- a/src/js/gsMessages.js +++ b/src/js/gsMessages.js @@ -1,4 +1,4 @@ -/*global gsUtils, gsSession, gsStorage */ +/*global tgs, gsUtils, gsSession, gsStorage */ var gsMessages = { // eslint-disable-line no-unused-vars INFO: 'info', @@ -6,52 +6,27 @@ var gsMessages = { // eslint-disable-line no-unused-vars ERROR: 'error', sendInitTabToContentScript(tabId, ignoreForms, tempWhitelist, scrollPos, suspendTime, callback) { - var props = { + var payload = { action: 'initialiseContentScript', ignoreForms: ignoreForms, tempWhitelist: tempWhitelist, }; if (scrollPos) { - props.scrollPos = scrollPos; + payload.scrollPos = scrollPos; } if (suspendTime !== null && !isNaN(Number(suspendTime))) { - props.suspendTime = suspendTime; + payload.suspendTime = suspendTime; } - this.sendMessageToContentScript(tabId, props, this.ERROR, callback); + this.sendMessageToContentScript(tabId, payload, this.ERROR, callback); }, - sendResetToAllContentScripts: function (preferencesToUpdate) { + sendResetTimerToAllContentScripts: function () { var self = this; - var suspendTime; - var ignoreForms; - var activeTabSuspendTime; - if (preferencesToUpdate.indexOf(gsStorage.SUSPEND_TIME) > -1) { - suspendTime = gsStorage.getOption(gsStorage.SUSPEND_TIME); - } - if (preferencesToUpdate.indexOf(gsStorage.IGNORE_FORMS) > -1) { - ignoreForms = gsStorage.getOption(gsStorage.IGNORE_FORMS); - } - if (preferencesToUpdate.indexOf(gsStorage.IGNORE_ACTIVE_TABS) > -1) { - const ignoreActiveTabs = gsStorage.getOption(gsStorage.IGNORE_ACTIVE_TABS); - activeTabSuspendTime = ignoreActiveTabs ? '0' : gsStorage.getOption(gsStorage.SUSPEND_TIME); - } + var suspendTime = gsStorage.getOption(gsStorage.SUSPEND_TIME); + chrome.tabs.query({}, function (tabs) { tabs.forEach(function (currentTab) { - if (gsUtils.isSpecialTab(currentTab) || gsUtils.isSuspendedTab(currentTab) || gsUtils.isDiscardedTab(currentTab)) { - return true; - } - - let tabPayload = {}; - if (typeof ignoreForms !== 'undefined') { - tabPayload.ignoreForms = ignoreForms; - } - if (typeof suspendTime !== 'undefined') { - tabPayload.suspendTime = suspendTime; - } - if (typeof activeTabSuspendTime !== 'undefined' && gsUtils.isProtectedActiveTab(currentTab, true)) { - tabPayload.suspendTime = activeTabSuspendTime; - } - self.sendMessageToContentScript(currentTab.id, tabPayload, this.WARNING, function (err) { + self.sendMessageToContentScript(currentTab.id, { suspendTime: suspendTime }, this.WARNING, function (err) { if (err) { gsUtils.log(currentTab.id, 'Failed to resetContentScript. Tab is probably loading?', err); } @@ -60,6 +35,29 @@ var gsMessages = { // eslint-disable-line no-unused-vars }); }, + sendUpdateToContentScriptOfTab: function (tab, updateSuspendTime, updateIgnoreForms) { + var self = this; + var suspendTime = gsStorage.getOption(gsStorage.SUSPEND_TIME); + var ignoreForms = gsStorage.getOption(gsStorage.IGNORE_FORMS); + + if (gsUtils.isSpecialTab(tab) || gsUtils.isSuspendedTab(tab) || gsUtils.isDiscardedTab(tab)) { + return; + } + + let tabPayload = {}; + let tabSuspendTime = gsUtils.isProtectedActiveTab(tab) ? '0' : suspendTime; + if (updateSuspendTime) { + tabPayload.suspendTime = tabSuspendTime; + } + if (updateIgnoreForms) { + tabPayload.ignoreForms = ignoreForms; + if (!ignoreForms) { + tabPayload.ignoredFormsSuspendTime = tabSuspendTime; + } + } + self.sendMessageToContentScript(tab.id, tabPayload, this.WARNING); + }, + sendClearTimerToContentScript: function (tabId, callback) { this.sendMessageToContentScript(tabId, { suspendTime: '0', diff --git a/src/js/gsStorage.js b/src/js/gsStorage.js index 206ea160..fa515aa1 100755 --- a/src/js/gsStorage.js +++ b/src/js/gsStorage.js @@ -140,18 +140,22 @@ var gsStorage = { if (shouldSync) { var localSettings = self.getSettings(); var changedSettingKeys = []; + var oldValueBySettingKey = {}; + var newValueBySettingKey = {}; Object.keys(remoteSettings).forEach(function (key) { var remoteSetting = remoteSettings[key]; if (localSettings[key] !== remoteSetting.newValue) { gsUtils.log('gsStorage', 'Changed value from sync', key, remoteSetting.newValue); changedSettingKeys.push(key); + oldValueBySettingKey[key] = localSettings[key]; + newValueBySettingKey[key] = remoteSetting.newValue; localSettings[key] = remoteSetting.newValue; } }); if (changedSettingKeys.length > 0) { self.saveSettings(localSettings); - gsUtils.performPostSaveUpdates(changedSettingKeys); + gsUtils.performPostSaveUpdates(changedSettingKeys, oldValueBySettingKey, newValueBySettingKey); } } }); diff --git a/src/js/gsUtils.js b/src/js/gsUtils.js index 84bfe6bd..5629a9f5 100644 --- a/src/js/gsUtils.js +++ b/src/js/gsUtils.js @@ -95,8 +95,8 @@ var gsUtils = { // eslint-disable-line no-unused-vars return dontSuspendAudible && tab.audible; }, - isProtectedActiveTab: function (tab, ignorePref) { - var dontSuspendActiveTabs = ignorePref ? true : gsStorage.getOption(gsStorage.IGNORE_ACTIVE_TABS); + isProtectedActiveTab: function (tab) { + var dontSuspendActiveTabs = gsStorage.getOption(gsStorage.IGNORE_ACTIVE_TABS); return tgs.isCurrentFocusedTab(tab) || (dontSuspendActiveTabs && tab.active); }, @@ -117,8 +117,11 @@ var gsUtils = { // eslint-disable-line no-unused-vars }, checkWhiteList: function (url) { - var whitelist = gsStorage.getOption(gsStorage.WHITELIST), - whitelistItems = whitelist ? whitelist.split(/[\s\n]+/) : [], + return gsUtils.checkSpecificWhiteList(url, gsStorage.getOption(gsStorage.WHITELIST)); + }, + + checkSpecificWhiteList: function (url, whitelistString) { + var whitelistItems = whitelistString ? whitelistString.split(/[\s\n]+/) : [], whitelisted; whitelisted = whitelistItems.some(function (item) { @@ -128,8 +131,8 @@ var gsUtils = { // eslint-disable-line no-unused-vars }, removeFromWhitelist: function (url) { - var whitelist = gsStorage.getOption(gsStorage.WHITELIST), - whitelistItems = whitelist ? whitelist.split(/[\s\n]+/).sort() : '', + var oldWhitelistString = gsStorage.getOption(gsStorage.WHITELIST) || '', + whitelistItems = oldWhitelistString.split(/[\s\n]+/).sort(), i; for (i = whitelistItems.length - 1; i >= 0; i--) { @@ -140,6 +143,9 @@ var gsUtils = { // eslint-disable-line no-unused-vars var whitelistString = whitelistItems.join('\n'); gsStorage.setOption(gsStorage.WHITELIST, whitelistString); gsStorage.syncSettings({ [gsStorage.WHITELIST]: whitelistString }); + + var key = gsStorage.WHITELIST; + gsUtils.performPostSaveUpdates([key], { [key]: oldWhitelistString }, { [key]: whitelistString }); }, testForMatch: function (whitelistItem, word) { @@ -176,11 +182,14 @@ var gsUtils = { // eslint-disable-line no-unused-vars }, saveToWhitelist: function (newString) { - var whitelist = gsStorage.getOption(gsStorage.WHITELIST); - whitelist = whitelist ? whitelist + '\n' + newString : newString; - whitelist = this.cleanupWhitelist(whitelist); - gsStorage.setOption(gsStorage.WHITELIST, whitelist); - gsStorage.syncSettings({ [gsStorage.WHITELIST]: whitelist }); + var oldWhitelistString = gsStorage.getOption(gsStorage.WHITELIST) || ''; + var newWhitelistString = oldWhitelistString + '\n' + newString; + newWhitelistString = this.cleanupWhitelist(newWhitelistString); + gsStorage.setOption(gsStorage.WHITELIST, newWhitelistString); + gsStorage.syncSettings({ [gsStorage.WHITELIST]: newWhitelistString }); + + var key = gsStorage.WHITELIST; + gsUtils.performPostSaveUpdates([key], { [key]: oldWhitelistString }, { [key]: newWhitelistString }); }, cleanupWhitelist: function (whitelist) { @@ -193,6 +202,9 @@ var gsUtils = { // eslint-disable-line no-unused-vars if (j !== i) { whitelistItems.splice(i + 1, j - i); } + if (!whitelistItems[i] || whitelistItems[i] === '') { + whitelistItems.splice(i, 1); + } } if (whitelistItems.length) { return whitelistItems.join('\n'); @@ -338,48 +350,108 @@ var gsUtils = { // eslint-disable-line no-unused-vars }); }, - performPostSaveUpdates: function (changedSettingKeys) { + getAllExpiredTabs: function (callback) { + var expiredTabs = []; + var checkTabExpiryPromises = []; + chrome.tabs.query({}, function (tabs) { + tabs.forEach(function (currentTab) { + if(gsUtils.isNormalTab(currentTab) && !gsUtils.isDiscardedTab(currentTab)) { + checkTabExpiryPromises.push(new Promise(function (resolve) { + gsMessages.sendRequestInfoToContentScript(currentTab.id, function (err, tabInfo) { + if (tabInfo && tabInfo.timerUp && (new Date(tabInfo.timerUp)) < new Date()) { + expiredTabs.push(currentTab); + } + resolve(); + }); + })); + } + }); + Promise.all(checkTabExpiryPromises).then(function () { + callback(expiredTabs); + }); + }); + }, - //if interval, or form input preferences have changed then reset the content scripts - var contentScriptPreferencesToUpdate = []; - if (this.contains(changedSettingKeys, gsStorage.SUSPEND_TIME)) { - contentScriptPreferencesToUpdate.push(gsStorage.SUSPEND_TIME); - } - if (this.contains(changedSettingKeys, gsStorage.IGNORE_FORMS)) { - contentScriptPreferencesToUpdate.push(gsStorage.IGNORE_FORMS); - } - if (this.contains(changedSettingKeys, gsStorage.IGNORE_ACTIVE_TABS)) { - contentScriptPreferencesToUpdate.push(gsStorage.IGNORE_ACTIVE_TABS); - } - if (contentScriptPreferencesToUpdate.length > 0) { - gsMessages.sendResetToAllContentScripts(contentScriptPreferencesToUpdate); - } + performPostSaveUpdates: function (changedSettingKeys, oldValueBySettingKey, newValueBySettingKey) { + + chrome.tabs.query({}, function (tabs) { + tabs.forEach(function (tab) { - //if discarding strategy has changed then updated discarded and suspended tabs - if (this.contains(changedSettingKeys, gsStorage.SUSPEND_IN_PLACE_OF_DISCARD)) { - var suspendInPlaceOfDiscard = gsStorage.getOption(gsStorage.SUSPEND_IN_PLACE_OF_DISCARD); - chrome.tabs.query({}, function (tabs) { - var currentNormalTabs = tabs.filter(function (o) {return gsUtils.isNormalTab(o, true); }); - currentNormalTabs.forEach(function (normalTab) { - if (gsUtils.isDiscardedTab(normalTab) && suspendInPlaceOfDiscard) { - var suspendedUrl = gsUtils.generateSuspendedUrl(normalTab.url, normalTab.title, 0); - gsSuspendManager.forceTabSuspension(normalTab, suspendedUrl); + if (gsUtils.isSpecialTab(tab)) { + return; + } + + if (gsUtils.isSuspendedTab(tab)) { + //If toggling IGNORE_PINNED or IGNORE_ACTIVE_TABS to TRUE, then unsuspend any suspended pinned/active tabs + if ((changedSettingKeys.includes(gsStorage.IGNORE_PINNED) && gsUtils.isProtectedPinnedTab(tab)) || + (changedSettingKeys.includes(gsStorage.IGNORE_ACTIVE_TABS) && gsUtils.isProtectedActiveTab(tab))){ + tgs.unsuspendTab(tab); + return; } - }); - }); - } - //if theme or screenshot preferences have changed then refresh suspended tabs - var suspendedTabPreferencesToUpdate = {}; - if (this.contains(changedSettingKeys, gsStorage.THEME)) { - suspendedTabPreferencesToUpdate.theme = gsStorage.getOption(gsStorage.THEME); - } - if (this.contains(changedSettingKeys, gsStorage.SCREEN_CAPTURE)) { - suspendedTabPreferencesToUpdate.previewMode = gsStorage.getOption(gsStorage.SCREEN_CAPTURE); - } - if (Object.keys(suspendedTabPreferencesToUpdate).length > 0) { - gsMessages.sendRefreshToAllSuspendedTabs(suspendedTabPreferencesToUpdate); - } + //if theme, screenshot or whitelist preferences have changed then refresh suspended tabs + var payload = {}; + if (changedSettingKeys.includes(gsStorage.THEME)) { + payload.theme = gsStorage.getOption(gsStorage.THEME); + } + if (changedSettingKeys.includes(gsStorage.SCREEN_CAPTURE)) { + payload.previewMode = gsStorage.getOption(gsStorage.SCREEN_CAPTURE); + } + if (changedSettingKeys.includes(gsStorage.WHITELIST)) { + let suspendedUrl = gsUtils.getSuspendedUrl(tab.url); + let wasWhitelisted = gsUtils.checkSpecificWhiteList(suspendedUrl, oldValueBySettingKey[gsStorage.WHITELIST]); + let isWhitelisted = gsUtils.checkSpecificWhiteList(suspendedUrl, newValueBySettingKey[gsStorage.WHITELIST]); + if ((wasWhitelisted && !isWhitelisted) || (!wasWhitelisted && isWhitelisted)) { + payload.whitelisted = isWhitelisted; + } + } + if (Object.keys(payload).length > 0) { + gsMessages.sendUpdateSuspendedTab(tab.id, payload); + } + return; + } + + if (gsUtils.isDiscardedTab(tab)) { + + //if discarding strategy has changed then updated discarded and suspended tabs + if (changedSettingKeys.includes(gsStorage.SUSPEND_IN_PLACE_OF_DISCARD)) { + var suspendInPlaceOfDiscard = gsStorage.getOption(gsStorage.SUSPEND_IN_PLACE_OF_DISCARD); + if (suspendInPlaceOfDiscard) { + var suspendedUrl = gsUtils.generateSuspendedUrl(tab.url, tab.title, 0); + gsSuspendManager.forceTabSuspension(tab, suspendedUrl); + } + } + return; + } + + //update content scripts of normal tabs + let updateIgnoreForms = changedSettingKeys.includes(gsStorage.IGNORE_FORMS); + let updateSuspendTime = (changedSettingKeys.includes(gsStorage.SUSPEND_TIME) || + (changedSettingKeys.includes(gsStorage.IGNORE_ACTIVE_TABS) && tab.active) || + (changedSettingKeys.includes(gsStorage.IGNORE_PINNED) && !gsStorage.getOption(gsStorage.IGNORE_PINNED) && tab.pinned) || + (changedSettingKeys.includes(gsStorage.IGNORE_AUDIO) && !gsStorage.getOption(gsStorage.IGNORE_AUDIO) && tab.audible) || + (changedSettingKeys.includes(gsStorage.IGNORE_WHEN_OFFLINE) && !gsStorage.getOption(gsStorage.IGNORE_WHEN_OFFLINE) && !navigator.onLine) || + (changedSettingKeys.includes(gsStorage.IGNORE_WHEN_CHARGING) && !gsStorage.getOption(gsStorage.IGNORE_WHEN_CHARGING) && tgs.isCharging()) || + (changedSettingKeys.includes(gsStorage.WHITELIST) && (gsUtils.checkSpecificWhiteList(tab.url, oldValueBySettingKey[gsStorage.WHITELIST]) && !gsUtils.checkSpecificWhiteList(tab.url, newValueBySettingKey[gsStorage.WHITELIST])))); + + if (updateSuspendTime || updateIgnoreForms) { + gsMessages.sendUpdateToContentScriptOfTab(tab, updateSuspendTime, updateIgnoreForms); + } + + //if we aren't resetting the timer on this tab, then check to make sure it does not have an expired timer + //should always be caught by tests above, but we'll check all tabs anyway just in case + // if (!updateSuspendTime) { + // gsMessages.sendRequestInfoToContentScript(tab.id, function (err, tabInfo) { + // tgs.calculateTabStatus(tab, tabInfo, function (tabStatus) { + // if (tabStatus === 'normal' && tabInfo && tabInfo.timerUp && (new Date(tabInfo.timerUp)) < new Date()) { + // gsUtils.error(tab.id, 'Tab has an expired timer!', tabInfo); + // gsMessages.sendUpdateToContentScriptOfTab(tab, true, false); + // } + // }); + // }); + // } + }); + }); //if context menu has been disabled then remove from chrome if (this.contains(changedSettingKeys, gsStorage.ADD_CONTEXT)) { @@ -466,4 +538,17 @@ var gsUtils = { // eslint-disable-line no-unused-vars return currentDate + ' ' + monthNames[currentMonth] + ' ' + currentYear + ' ' + hoursString + ':' + minutesString + ampm; }, + + debounce: function (func, wait) { + var timeout; + return function () { + var context = this, args = arguments; + var later = function () { + timeout = null; + func.apply(context, args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }, }; diff --git a/src/js/options.js b/src/js/options.js index 368ff5c7..fc68d356 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -128,11 +128,11 @@ } } - var valueChanged = saveChange(element); - if (valueChanged) { + var [oldValue, newValue] = saveChange(element); + if (oldValue !== newValue) { gsStorage.syncSettings(); var prefKey = elementPrefMap[element.id]; - gsUtils.performPostSaveUpdates([prefKey]); + gsUtils.performPostSaveUpdates([prefKey], { [prefKey]: oldValue }, { [prefKey]: newValue }); } }; } @@ -151,7 +151,7 @@ //save option gsStorage.setOption(elementPrefMap[element.id], newValue); - return (oldValue !== newValue); + return [oldValue, newValue]; } gsUtils.documentReadyAndLocalisedAsPromsied(document).then(function () { @@ -166,7 +166,7 @@ for (i = 0; i < optionEls.length; i++) { element = optionEls[i]; if (element.tagName === 'TEXTAREA') { - element.addEventListener('input', handleChange(element), false); + element.addEventListener('input', gsUtils.debounce(handleChange(element), 200), false); } else { element.onchange = handleChange(element); }