diff options
author | Alessio Vanni <vannilla@firemail.cc> | 2020-10-04 18:33:13 +0200 |
---|---|---|
committer | Jesús <heckyel@hyperbola.info> | 2022-04-06 09:43:45 +0800 |
commit | 9147038defa859e42b999573b1279f90c5822c2f (patch) | |
tree | d803a6f5e9eb5c362d9e752c69597e02d8998872 | |
parent | adf5b9165c0712d1bcb834e03582d22837facce9 (diff) | |
download | ematrix-9147038defa859e42b999573b1279f90c5822c2f.tar.lz ematrix-9147038defa859e42b999573b1279f90c5822c2f.tar.xz ematrix-9147038defa859e42b999573b1279f90c5822c2f.zip |
Style changes
Signed-off-by: Jesús <heckyel@hyperbola.info>
-rw-r--r-- | js/about.js | 167 | ||||
-rw-r--r-- | js/i18n.js | 7 | ||||
-rw-r--r-- | js/pagestats.js | 186 | ||||
-rw-r--r-- | js/storage.js | 471 | ||||
-rw-r--r-- | js/udom.js | 905 |
5 files changed, 820 insertions, 916 deletions
diff --git a/js/about.js b/js/about.js index 17ff741..a35b45c 100644 --- a/js/about.js +++ b/js/about.js @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -25,123 +25,116 @@ 'use strict'; -/******************************************************************************/ +uDom.onLoad(function () { -uDom.onLoad(function() { - - /******************************************************************************/ - - var backupUserDataToFile = function() { - var userDataReady = function(userData) { + let backupUserDataToFile = function () { + let userDataReady = function (userData) { vAPI.download({ - 'url': 'data:text/plain,' + encodeURIComponent(JSON.stringify(userData, null, 2)), - 'filename': uDom('[data-i18n="aboutBackupFilename"]').text() + 'url': 'data:text/plain,' + + encodeURIComponent(JSON.stringify(userData, null, 2)), + 'filename': uDom('[data-i18n="aboutBackupFilename"]').text() }); - }; + }; - vAPI.messaging.send('about.js', { what: 'getAllUserData' }, userDataReady); + vAPI.messaging.send('about.js', { + what: 'getAllUserData' + }, userDataReady); }; - /******************************************************************************/ + let restoreUserDataFromFile = function () { + let validateBackup = function (s) { + let userData = null; - function restoreUserDataFromFile() { - var validateBackup = function(s) { - var userData = null; try { - userData = JSON.parse(s); + userData = JSON.parse(s); } catch (e) { - userData = null; - } - if ( userData === null ) { - return null; + userData = null; } - if ( - typeof userData !== 'object' || - typeof userData.version !== 'string' || - typeof userData.when !== 'number' || - typeof userData.settings !== 'object' || - typeof userData.rules !== 'string' || - typeof userData.hostsFiles !== 'object' - ) { - return null; + + if (userData === null + || typeof userData !== 'object' + || typeof userData.version !== 'string' + || typeof userData.when !== 'number' + || typeof userData.settings !== 'object' + || typeof userData.rules !== 'string' + || typeof userData.hostsFiles !== 'object') { + return null; } + return userData; - }; + }; - var fileReaderOnLoadHandler = function() { - var userData = validateBackup(this.result); - if ( !userData ) { - window.alert(uDom('[data-i18n="aboutRestoreError"]').text()); - return; + let fileReaderOnLoadHandler = function () { + let userData = validateBackup(this.result); + if (!userData) { + window.alert(uDom('[data-i18n="aboutRestoreError"]').text()); + return; } - var time = new Date(userData.when); - var msg = uDom('[data-i18n="aboutRestoreConfirm"]').text() - .replace('{{time}}', time.toLocaleString()); - var proceed = window.confirm(msg); - if ( proceed ) { - vAPI.messaging.send( - 'about.js', - { what: 'restoreAllUserData', userData: userData } - ); + let time = new Date(userData.when); + let msg = + uDom('[data-i18n="aboutRestoreConfirm"]') + .text() + .replace('{{time}}', time.toLocaleString()); + let proceed = window.confirm(msg); + if (proceed) { + vAPI.messaging.send('about.js', { + what: 'restoreAllUserData', + userData: userData + }); } - }; + }; - var file = this.files[0]; - if ( file === undefined || file.name === '' ) { + let file = this.files[0]; + if (file === undefined || file.name === '') { return; - } - if ( file.type.indexOf('text') !== 0 ) { + } + if (file.type.indexOf('text') !== 0) { return; - } - var fr = new FileReader(); - fr.onload = fileReaderOnLoadHandler; - fr.readAsText(file); + } + let fr = new FileReader(); + fr.onload = fileReaderOnLoadHandler; + fr.readAsText(file); } - /******************************************************************************/ - - var startRestoreFilePicker = function() { - var input = document.getElementById('restoreFilePicker'); - // Reset to empty string, this will ensure an change event is properly - // triggered if the user pick a file, even if it is the same as the last - // one picked. - input.value = ''; - input.click(); + let startRestoreFilePicker = function () { + let input = document.getElementById('restoreFilePicker'); + // Reset to empty string, this will ensure a change event is + // properly triggered if the user pick a file, even if it is + // the same as the last one picked. + input.value = ''; + input.click(); }; - /******************************************************************************/ - - var resetUserData = function() { - var proceed = window.confirm(uDom('[data-i18n="aboutResetConfirm"]').text()); - if ( proceed ) { - vAPI.messaging.send('about.js', { what: 'resetAllUserData' }); - } + let resetUserData = function () { + let proceed = + window.confirm(uDom('[data-i18n="aboutResetConfirm"]').text()); + if (proceed) { + vAPI.messaging.send('about.js', { + what: 'resetAllUserData' + }); + } }; - /******************************************************************************/ - - (function() { - var renderStats = function(details) { - document.getElementById('aboutVersion').textContent = details.version; - var template = uDom('[data-i18n="aboutStorageUsed"]').text(); - var storageUsed = '?'; - if ( typeof details.storageUsed === 'number' ) { - storageUsed = details.storageUsed.toLocaleString(); + (function () { + let renderStats = function (details) { + document.getElementById('aboutVersion') + .textContent = details.version; + let template = uDom('[data-i18n="aboutStorageUsed"]').text(); + let storageUsed = '?'; + if (typeof details.storageUsed === 'number') { + storageUsed = details.storageUsed.toLocaleString(); } document.getElementById('aboutStorageUsed').textContent = - template.replace('{{storageUsed}}', storageUsed); - }; - vAPI.messaging.send('about.js', { what: 'getSomeStats' }, renderStats); + template.replace('{{storageUsed}}', storageUsed); + }; + vAPI.messaging.send('about.js', { + what: 'getSomeStats' + }, renderStats); })(); - /******************************************************************************/ - uDom('#backupUserDataButton').on('click', backupUserDataToFile); uDom('#restoreUserDataButton').on('click', startRestoreFilePicker); uDom('#restoreFilePicker').on('change', restoreUserDataFromFile); uDom('#resetUserDataButton').on('click', resetUserData); - - /******************************************************************************/ - }); @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -76,6 +76,9 @@ // Firefox extension validator warns if using a variable as // argument for document.createElement(). // ηMatrix: is it important for us? + // ηMatrix (4.4.3 onwards): let's just use the variable and + // hope for the best, no need to have a redundant switch. + /* switch (text) { case 'b': return document.createElement('b'); @@ -96,6 +99,8 @@ default: break; } + */ + return document.createElement(text); }; let safeTextToTextNode = function (text) { diff --git a/js/pagestats.js b/js/pagestats.js index 2851df6..b4c65c1 100644 --- a/js/pagestats.js +++ b/js/pagestats.js @@ -17,25 +17,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ 'use strict'; -/******************************************************************************/ - ηMatrix.pageStoreFactory = (function() { Cu.import('chrome://ematrix/content/lib/UriTools.jsm'); - /******************************************************************************/ - - var ηm = ηMatrix; + let ηm = ηMatrix; - /******************************************************************************/ - - var BlockedCollapsibles = function() { + let BlockedCollapsibles = function () { this.boundPruneAsyncCallback = this.pruneAsyncCallback.bind(this); this.blocked = new Map(); this.hash = 0; @@ -43,16 +37,18 @@ }; BlockedCollapsibles.prototype = { - shelfLife: 10 * 1000, - add: function(type, url, isSpecific) { - if ( this.blocked.size === 0 ) { this.pruneAsync(); } - var now = Date.now() / 1000 | 0; - // The following "trick" is to encode the specifity into the lsb of the - // time stamp so as to avoid to have to allocate a memory structure to - // store both time stamp and specificity. - if ( isSpecific ) { + add: function (type, url, isSpecific) { + if (this.blocked.size === 0) { + this.pruneAsync(); + } + let now = Date.now() / 1000 | 0; + // The following "trick" is to encode the specifity into + // the lsb of the time stamp so as to avoid to have to + // allocate a memory structure to store both time stamp + // and specificity. + if (isSpecific) { now |= 0x00000001; } else { now &= 0xFFFFFFFE; @@ -60,45 +56,39 @@ this.blocked.set(type + ' ' + url, now); this.hash = now; }, - - reset: function() { + reset: function () { this.blocked.clear(); this.hash = 0; - if ( this.timer !== null ) { + if (this.timer !== null) { clearTimeout(this.timer); this.timer = null; } }, - - pruneAsync: function() { - if ( this.timer === null ) { - this.timer = vAPI.setTimeout( - this.boundPruneAsyncCallback, - this.shelfLife * 2 - ); + pruneAsync: function () { + if (this.timer === null) { + this.timer = vAPI.setTimeout(this.boundPruneAsyncCallback, + this.shelfLife * 2); } }, - - pruneAsyncCallback: function() { + pruneAsyncCallback: function () { this.timer = null; - var obsolete = Date.now() - this.shelfLife; - for ( var entry of this.blocked ) { - if ( entry[1] <= obsolete ) { + let obsolete = Date.now() - this.shelfLife; + for (let entry of this.blocked) { + if (entry[1] <= obsolete) { this.blocked.delete(entry[0]); } } - if ( this.blocked.size !== 0 ) { this.pruneAsync(); } + if (this.blocked.size !== 0) { + this.pruneAsync(); + } } }; - /******************************************************************************/ - // Ref: Given a URL, returns a (somewhat) unique 32-bit value // Based on: FNV32a // http://www.isthe.com/chongo/tech/comp/fnv/index.html#FNV-reference-source // The rest is custom, suited for uMatrix. - - var PageStore = function(tabContext) { + let PageStore = function (tabContext) { this.hostnameTypeCells = new Map(); this.domains = new Set(); this.blockedCollapsibles = new BlockedCollapsibles(); @@ -108,11 +98,10 @@ }; PageStore.prototype = { - collapsibleTypes: new Set([ 'image' ]), pageStoreJunkyard: [], - init: function(tabContext) { + init: function (tabContext) { this.tabId = tabContext.tabId; this.rawUrl = tabContext.rawURL; this.pageUrl = tabContext.normalURL; @@ -136,8 +125,7 @@ this.mtxCountModifiedTime = 0; return this; }, - - dispose: function() { + dispose: function () { this.rawUrl = ''; this.pageUrl = ''; this.pageHostname = ''; @@ -147,68 +135,70 @@ this.domains.clear(); this.allHostnamesString = ' '; this.blockedCollapsibles.reset(); - if ( this.incinerationTimer !== null ) { + if (this.incinerationTimer !== null) { clearTimeout(this.incinerationTimer); this.incinerationTimer = null; } - if ( this.pageStoreJunkyard.length < 8 ) { + if (this.pageStoreJunkyard.length < 8) { this.pageStoreJunkyard.push(this); } }, - - cacheBlockedCollapsible: function(type, url, specificity) { - if ( this.collapsibleTypes.has(type) ) { - this.blockedCollapsibles.add( - type, - url, - specificity !== 0 && specificity < 5 - ); + cacheBlockedCollapsible: function (type, url, specificity) { + if (this.collapsibleTypes.has(type)) { + this.blockedCollapsibles.add(type, + url, + specificity !== 0 + && specificity < 5); } }, + lookupBlockedCollapsibles: function (request, response) { + let tabContext = ηm.tabContextManager.lookup(this.tabId); + if (tabContext === null) { + return; + } - lookupBlockedCollapsibles: function(request, response) { - var tabContext = ηm.tabContextManager.lookup(this.tabId); - if ( tabContext === null ) { return; } - - var collapseBlacklisted = ηm.userSettings.collapseBlacklisted, - collapseBlocked = ηm.userSettings.collapseBlocked, - entry; + let collapseBlacklisted = ηm.userSettings.collapseBlacklisted; + let collapseBlocked = ηm.userSettings.collapseBlocked; + let blockedResources = response.blockedResources; - var blockedResources = response.blockedResources; + if (Array.isArray(request.toFilter) && request.toFilter.length !== 0) { + let roothn = tabContext.rootHostname; + let hnFromURI = UriTools.hostnameFromURI; + let tMatrix = ηm.tMatrix; - if ( - Array.isArray(request.toFilter) && - request.toFilter.length !== 0 - ) { - var roothn = tabContext.rootHostname, - hnFromURI = UriTools.hostnameFromURI, - tMatrix = ηm.tMatrix; - for ( entry of request.toFilter ) { - if ( tMatrix.mustBlock(roothn, hnFromURI(entry.url), entry.type) === false ) { + for (let entry of request.toFilter) { + if (tMatrix.mustBlock(roothn, + hnFromURI(entry.url), + entry.type) === false) { continue; } + blockedResources.push([ entry.type + ' ' + entry.url, - collapseBlocked || - collapseBlacklisted && tMatrix.specificityRegister !== 0 && - tMatrix.specificityRegister < 5 + collapseBlocked + || collapseBlacklisted + && tMatrix.specificityRegister !== 0 + && tMatrix.specificityRegister < 5 ]); } } - if ( this.blockedCollapsibles.hash === response.hash ) { return; } + if (this.blockedCollapsibles.hash === response.hash) { + return; + } response.hash = this.blockedCollapsibles.hash; - for ( entry of this.blockedCollapsibles.blocked ) { + for (let entry of this.blockedCollapsibles.blocked) { blockedResources.push([ entry[0], - collapseBlocked || collapseBlacklisted && (entry[1] & 1) !== 0 + collapseBlocked + || collapseBlacklisted + && (entry[1] & 1) !== 0 ]); } }, - - recordRequest: function(type, url, block) { - if ( block !== false ) { + recordRequest: function (type, url, block) { + if (block !== false) { this.perLoadBlockedRequestCount++; } else { this.perLoadAllowedRequestCount++; @@ -218,16 +208,20 @@ // - remember which hostname/type were seen // - count the number of distinct URLs for any given // hostname-type pair - var hostname = UriTools.hostnameFromURI(url), - key = hostname + ' ' + type, - uids = this.hostnameTypeCells.get(key); - if ( uids === undefined ) { + let hostname = UriTools.hostnameFromURI(url); + let key = hostname + ' ' + type; + let uids = this.hostnameTypeCells.get(key); + + if (uids === undefined) { this.hostnameTypeCells.set(key, (uids = new Set())); - } else if ( uids.size > 99 ) { + } else if (uids.size > 99) { + return; + } + + let uid = this.uidFromURL(url); + if (uids.has(uid)) { return; } - var uid = this.uidFromURL(url); - if ( uids.has(uid) ) { return; } uids.add(uid); // Count blocked/allowed requests @@ -241,17 +235,16 @@ // this.distinctRequestCount++; this.mtxCountModifiedTime = Date.now(); - if ( this.domains.has(hostname) === false ) { + if (this.domains.has(hostname) === false) { this.domains.add(hostname); this.allHostnamesString += hostname + ' '; this.mtxContentModifiedTime = Date.now(); } }, - - uidFromURL: function(uri) { - var hint = 0x811c9dc5, - i = uri.length; - while ( i-- ) { + uidFromURL: function (uri) { + var hint = 0x811c9dc5; + let i = uri.length; + while (i--) { hint ^= uri.charCodeAt(i) | 0; hint += (hint<<1) + (hint<<4) + (hint<<7) + (hint<<8) + (hint<<24) | 0; hint >>>= 0; @@ -260,18 +253,11 @@ } }; - /******************************************************************************/ - - return function pageStoreFactory(tabContext) { - var entry = PageStore.prototype.pageStoreJunkyard.pop(); - if ( entry ) { + return function (tabContext) { + let entry = PageStore.prototype.pageStoreJunkyard.pop(); + if (entry) { return entry.init(tabContext); } return new PageStore(tabContext); }; - - /******************************************************************************/ - })(); - -/******************************************************************************/ diff --git a/js/storage.js b/js/storage.js index c4447c4..f5afca8 100644 --- a/js/storage.js +++ b/js/storage.js @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uMatrix */ @@ -28,60 +28,52 @@ Components.utils.import('chrome://ematrix/content/lib/PublicSuffixList.jsm'); Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); -/******************************************************************************/ - -ηMatrix.getBytesInUse = function() { - var ηm = this; - var getBytesInUseHandler = function(bytesInUse) { +ηMatrix.getBytesInUse = function () { + let ηm = this; + let getBytesInUseHandler = function (bytesInUse) { ηm.storageUsed = bytesInUse; }; + // Not all WebExtension implementations support getBytesInUse(). - if ( typeof vAPI.storage.getBytesInUse === 'function' ) { + // ηMatrix: not really our business, but does it impact us? + if (typeof vAPI.storage.getBytesInUse === 'function') { vAPI.storage.getBytesInUse(null, getBytesInUseHandler); } else { ηm.storageUsed = undefined; } }; -/******************************************************************************/ - -ηMatrix.saveUserSettings = function() { - this.XAL.keyvalSetMany( - this.userSettings, - this.getBytesInUse.bind(this) - ); +ηMatrix.saveUserSettings = function () { + this.XAL.keyvalSetMany(this.userSettings, + this.getBytesInUse.bind(this)); }; -ηMatrix.loadUserSettings = function(callback) { - var ηm = this; +ηMatrix.loadUserSettings = function (callback) { + let ηm = this; - if ( typeof callback !== 'function' ) { + if (typeof callback !== 'function') { callback = this.noopFunc; } - var settingsLoaded = function(store) { + var settingsLoaded = function (store) { // console.log('storage.js > loaded user settings'); - ηm.userSettings = store; - callback(ηm.userSettings); }; vAPI.storage.get(this.userSettings, settingsLoaded); }; -/******************************************************************************/ - -ηMatrix.loadRawSettings = function() { - var ηm = this; +ηMatrix.loadRawSettings = function () { + let ηm = this; + let onLoaded = function (bin) { + if (!bin || bin.rawSettings instanceof Object === false) { + return; + } - var onLoaded = function(bin) { - if ( !bin || bin.rawSettings instanceof Object === false ) { return; } - for ( var key of Object.keys(bin.rawSettings) ) { - if ( - ηm.rawSettings.hasOwnProperty(key) === false || - typeof bin.rawSettings[key] !== typeof ηm.rawSettings[key] - ) { + for (let key of Object.keys(bin.rawSettings)) { + if (ηm.rawSettings.hasOwnProperty(key) === false + || typeof bin.rawSettings[key] !== typeof ηm.rawSettings[key]) { continue; } ηm.rawSettings[key] = bin.rawSettings[key]; @@ -92,131 +84,135 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); vAPI.storage.get('rawSettings', onLoaded); }; -ηMatrix.saveRawSettings = function(rawSettings, callback) { - var keys = Object.keys(rawSettings); - if ( keys.length === 0 ) { - if ( typeof callback === 'function' ) { +ηMatrix.saveRawSettings = function (rawSettings, callback) { + let keys = Object.keys(rawSettings); + if (keys.length === 0) { + if (typeof callback === 'function') { callback(); } return; } - for ( var key of keys ) { - if ( - this.rawSettingsDefault.hasOwnProperty(key) && - typeof rawSettings[key] === typeof this.rawSettingsDefault[key] - ) { + + for (let key of keys) { + if (this.rawSettingsDefault.hasOwnProperty(key) + && typeof rawSettings[key] === typeof this.rawSettingsDefault[key]) { this.rawSettings[key] = rawSettings[key]; } } - vAPI.storage.set({ rawSettings: this.rawSettings }, callback); + vAPI.storage.set({ + rawSettings: this.rawSettings + }, callback); this.rawSettingsWriteTime = Date.now(); }; -ηMatrix.rawSettingsFromString = function(raw) { - var result = {}, - lineIter = new Tools.LineIterator(raw), - line, matches, name, value; - while ( lineIter.eot() === false ) { - line = lineIter.next().trim(); - matches = /^(\S+)(\s+(.+))?$/.exec(line); - if ( matches === null ) { continue; } - name = matches[1]; - if ( this.rawSettingsDefault.hasOwnProperty(name) === false ) { +ηMatrix.rawSettingsFromString = function (raw) { + let result = {}; + let lineIter = new Tools.LineIterator(raw); + + while (lineIter.eot() === false) { + let line = lineIter.next().trim(); + let matches = /^(\S+)(\s+(.+))?$/.exec(line); + + if (matches === null) { + continue; + } + + let name = matches[1]; + if (this.rawSettingsDefault.hasOwnProperty(name) === false) { continue; } - value = (matches[2] || '').trim(); - switch ( typeof this.rawSettingsDefault[name] ) { + + let value = (matches[2] || '').trim(); + + switch (typeof this.rawSettingsDefault[name]) { case 'boolean': - if ( value === 'true' ) { + if (value === 'true') { value = true; - } else if ( value === 'false' ) { + } else if (value === 'false') { value = false; } else { value = this.rawSettingsDefault[name]; } break; case 'string': - if ( value === '' ) { + if (value === '') { value = this.rawSettingsDefault[name]; } break; case 'number': value = parseInt(value, 10); - if ( isNaN(value) ) { + if (isNaN(value)) { value = this.rawSettingsDefault[name]; } break; default: break; } - if ( this.rawSettings[name] !== value ) { + if (this.rawSettings[name] !== value) { result[name] = value; } } this.saveRawSettings(result); }; -ηMatrix.stringFromRawSettings = function() { - var out = []; - for ( var key of Object.keys(this.rawSettings).sort() ) { +ηMatrix.stringFromRawSettings = function () { + let out = []; + for (let key of Object.keys(this.rawSettings).sort()) { out.push(key + ' ' + this.rawSettings[key]); } return out.join('\n'); }; -/******************************************************************************/ - // save white/blacklist -ηMatrix.saveMatrix = function() { +ηMatrix.saveMatrix = function () { ηMatrix.XAL.keyvalSetOne('userMatrix', this.pMatrix.toString()); }; -/******************************************************************************/ - -ηMatrix.loadMatrix = function(callback) { - if ( typeof callback !== 'function' ) { +ηMatrix.loadMatrix = function (callback) { + if (typeof callback !== 'function') { callback = this.noopFunc; } - var ηm = this; - var onLoaded = function(bin) { - if ( bin.hasOwnProperty('userMatrix') ) { + + let ηm = this; + let onLoaded = function (bin) { + if (bin.hasOwnProperty('userMatrix')) { ηm.pMatrix.fromString(bin.userMatrix); ηm.tMatrix.assign(ηm.pMatrix); callback(); } }; + this.XAL.keyvalGetOne('userMatrix', onLoaded); }; -/******************************************************************************/ - -ηMatrix.listKeysFromCustomHostsFiles = function(raw) { - var out = new Set(), - reIgnore = /^[!#]/, - reValid = /^[a-z-]+:\/\/\S+/, - lineIter = new Tools.LineIterator(raw), - location; - while ( lineIter.eot() === false ) { - location = lineIter.next().trim(); - if ( reIgnore.test(location) || !reValid.test(location) ) { continue; } +ηMatrix.listKeysFromCustomHostsFiles = function (raw) { + let out = new Set(); + let reIgnore = /^[!#]/; + let reValid = /^[a-z-]+:\/\/\S+/; + let lineIter = new Tools.LineIterator(raw); + + while (lineIter.eot() === false) { + let location = lineIter.next().trim(); + if (reIgnore.test(location) || !reValid.test(location)) { + continue; + } out.add(location); } return Tools.setToArray(out); }; -/******************************************************************************/ - -ηMatrix.getAvailableHostsFiles = function(callback) { - var ηm = this, - availableHostsFiles = {}; +ηMatrix.getAvailableHostsFiles = function (callback) { + let ηm = this; + let availableHostsFiles = {}; // Custom filter lists. - var importedListKeys = this.listKeysFromCustomHostsFiles(ηm.userSettings.externalHostsFiles), - i = importedListKeys.length, - listKey, entry; - while ( i-- ) { - listKey = importedListKeys[i]; - entry = { + let importedListKeys = + this.listKeysFromCustomHostsFiles(ηm.userSettings.externalHostsFiles); + let i = importedListKeys.length; + + while (i--) { + let listKey = importedListKeys[i]; + let entry = { content: 'filters', contentURL: listKey, external: true, @@ -228,31 +224,41 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // selected lists - var onSelectedHostsFilesLoaded = function(bin) { + let onSelectedHostsFilesLoaded = function (bin) { // Now get user's selection of lists - for ( var assetKey in bin.liveHostsFiles ) { - var availableEntry = availableHostsFiles[assetKey]; - if ( availableEntry === undefined ) { continue; } - var liveEntry = bin.liveHostsFiles[assetKey]; + for (let assetKey in bin.liveHostsFiles) { + let availableEntry = availableHostsFiles[assetKey]; + if (availableEntry === undefined) { + continue; + } + + let liveEntry = bin.liveHostsFiles[assetKey]; availableEntry.off = liveEntry.off || false; - if ( liveEntry.entryCount !== undefined ) { + if (liveEntry.entryCount !== undefined) { availableEntry.entryCount = liveEntry.entryCount; } - if ( liveEntry.entryUsedCount !== undefined ) { + if (liveEntry.entryUsedCount !== undefined) { availableEntry.entryUsedCount = liveEntry.entryUsedCount; } + // This may happen if the list name was pulled from the list content - if ( availableEntry.title === '' && liveEntry.title !== undefined ) { + if (availableEntry.title === '' && liveEntry.title !== undefined) { availableEntry.title = liveEntry.title; } } // Remove unreferenced imported filter lists. - var dict = new Set(importedListKeys); - for ( assetKey in availableHostsFiles ) { - var entry = availableHostsFiles[assetKey]; - if ( entry.submitter !== 'user' ) { continue; } - if ( dict.has(assetKey) ) { continue; } + let dict = new Set(importedListKeys); + for (let assetKey in availableHostsFiles) { + let entry = availableHostsFiles[assetKey]; + if (entry.submitter !== 'user') { + continue; + } + + if (dict.has(assetKey)) { + continue; + } + delete availableHostsFiles[assetKey]; ηm.assets.unregisterAssetSource(assetKey); ηm.assets.remove(assetKey); @@ -262,60 +268,67 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); }; // built-in lists - var onBuiltinHostsFilesLoaded = function(entries) { - for ( var assetKey in entries ) { - if ( entries.hasOwnProperty(assetKey) === false ) { continue; } - entry = entries[assetKey]; - if ( entry.content !== 'filters' ) { continue; } + let onBuiltinHostsFilesLoaded = function (entries) { + for (let assetKey in entries) { + if (entries.hasOwnProperty(assetKey) === false) { + continue; + } + + let entry = entries[assetKey]; + if (entry.content !== 'filters') { + continue; + } availableHostsFiles[assetKey] = Object.assign({}, entry); } // Now get user's selection of lists - vAPI.storage.get( - { 'liveHostsFiles': availableHostsFiles }, - onSelectedHostsFilesLoaded - ); + vAPI.storage.get({ + 'liveHostsFiles': availableHostsFiles + }, onSelectedHostsFilesLoaded); }; this.assets.metadata(onBuiltinHostsFilesLoaded); }; -/******************************************************************************/ +ηMatrix.loadHostsFiles = function (callback) { + let ηm = ηMatrix; + let hostsFileLoadCount; -ηMatrix.loadHostsFiles = function(callback) { - var ηm = ηMatrix; - var hostsFileLoadCount; - - if ( typeof callback !== 'function' ) { + if (typeof callback !== 'function') { callback = this.noopFunc; } - var loadHostsFilesEnd = function() { + let loadHostsFilesEnd = function () { ηm.ubiquitousBlacklist.freeze(); - vAPI.storage.set({ 'liveHostsFiles': ηm.liveHostsFiles }); - vAPI.messaging.broadcast({ what: 'loadHostsFilesCompleted' }); + vAPI.storage.set({ + 'liveHostsFiles': ηm.liveHostsFiles + }); + vAPI.messaging.broadcast({ + what: 'loadHostsFilesCompleted' + }); ηm.getBytesInUse(); callback(); }; - var mergeHostsFile = function(details) { + let mergeHostsFile = function (details) { ηm.mergeHostsFile(details); hostsFileLoadCount -= 1; - if ( hostsFileLoadCount === 0 ) { + if (hostsFileLoadCount === 0) { loadHostsFilesEnd(); } }; - var loadHostsFilesStart = function(hostsFiles) { + let loadHostsFilesStart = function (hostsFiles) { ηm.liveHostsFiles = hostsFiles; ηm.ubiquitousBlacklist.reset(); - var locations = Object.keys(hostsFiles); + + let locations = Object.keys(hostsFiles); hostsFileLoadCount = locations.length; // Load all hosts file which are not disabled. - var location; - while ( (location = locations.pop()) ) { - if ( hostsFiles[location].off ) { + let location; + while ((location = locations.pop())) { + if (hostsFiles[location].off) { hostsFileLoadCount -= 1; continue; } @@ -323,7 +336,7 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // https://github.com/gorhill/uMatrix/issues/2 - if ( hostsFileLoadCount === 0 ) { + if (hostsFileLoadCount === 0) { loadHostsFilesEnd(); return; } @@ -332,11 +345,9 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); this.getAvailableHostsFiles(loadHostsFilesStart); }; -/******************************************************************************/ - -ηMatrix.mergeHostsFile = function(details) { - var usedCount = this.ubiquitousBlacklist.count; - var duplicateCount = this.ubiquitousBlacklist.duplicateCount; +ηMatrix.mergeHostsFile = function (details) { + let usedCount = this.ubiquitousBlacklist.count; + let duplicateCount = this.ubiquitousBlacklist.duplicateCount; this.mergeHostsFileContent(details.content); @@ -348,22 +359,20 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); hostsFilesMeta.entryUsedCount = usedCount; }; -/******************************************************************************/ - -ηMatrix.mergeHostsFileContent = function(rawText) { - var rawEnd = rawText.length; - var ubiquitousBlacklist = this.ubiquitousBlacklist; - var reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g; - var reAsciiSegment = /^[\x21-\x7e]+$/; - var matches; - var lineBeg = 0, lineEnd; - var line; +ηMatrix.mergeHostsFileContent = function (rawText) { + let rawEnd = rawText.length; + let ubiquitousBlacklist = this.ubiquitousBlacklist; + let reLocalhost = /(^|\s)(localhost\.localdomain|localhost|local|broadcasthost|0\.0\.0\.0|127\.0\.0\.1|::1|fe80::1%lo0)(?=\s|$)/g; + let reAsciiSegment = /^[\x21-\x7e]+$/; + let matches; + let lineBeg = 0, lineEnd; + let line; - while ( lineBeg < rawEnd ) { + while (lineBeg < rawEnd) { lineEnd = rawText.indexOf('\n', lineBeg); - if ( lineEnd < 0 ) { + if (lineEnd < 0) { lineEnd = rawText.indexOf('\r', lineBeg); - if ( lineEnd < 0 ) { + if (lineEnd < 0) { lineEnd = rawEnd; } } @@ -385,19 +394,19 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); // The filter is whatever sequence of printable ascii character without // whitespaces matches = reAsciiSegment.exec(line); - if ( !matches || matches.length === 0 ) { + if (!matches || matches.length === 0) { continue; } // Bypass anomalies // For example, when a filter contains whitespace characters, or // whatever else outside the range of printable ascii characters. - if ( matches[0] !== line ) { + if (matches[0] !== line) { continue; } line = matches[0]; - if ( line === '' ) { + if (line === '') { continue; } @@ -405,22 +414,18 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } }; -/******************************************************************************/ - // `switches` contains the filter lists for which the switch must be revisited. - -ηMatrix.selectHostsFiles = function(details, callback) { - var ηm = this, - externalHostsFiles = this.userSettings.externalHostsFiles, - i, n, assetKey; +ηMatrix.selectHostsFiles = function (details, callback) { + let ηm = this; + let externalHostsFiles = this.userSettings.externalHostsFiles; // Hosts file to select - if ( Array.isArray(details.toSelect) ) { - for ( assetKey in this.liveHostsFiles ) { - if ( this.liveHostsFiles.hasOwnProperty(assetKey) === false ) { + if (Array.isArray(details.toSelect)) { + for (let assetKey in this.liveHostsFiles) { + if (this.liveHostsFiles.hasOwnProperty(assetKey) === false) { continue; } - if ( details.toSelect.indexOf(assetKey) !== -1 ) { + if (details.toSelect.indexOf(assetKey) !== -1) { this.liveHostsFiles[assetKey].off = false; } else if ( details.merge !== true ) { this.liveHostsFiles[assetKey].off = true; @@ -429,18 +434,17 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // Imported hosts files to remove - if ( Array.isArray(details.toRemove) ) { - var removeURLFromHaystack = function(haystack, needle) { - return haystack.replace( - new RegExp( - '(^|\\n)' + - needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + - '(\\n|$)', 'g'), - '\n' - ).trim(); + if (Array.isArray(details.toRemove)) { + let removeURLFromHaystack = function (haystack, needle) { + return haystack + .replace(new RegExp('(^|\\n)' + + needle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + + '(\\n|$)', 'g'), + '\n').trim(); }; - for ( i = 0, n = details.toRemove.length; i < n; i++ ) { - assetKey = details.toRemove[i]; + + for (let i=0, n=details.toRemove.length; i<n; ++i) { + let assetKey = details.toRemove[i]; delete this.liveHostsFiles[assetKey]; externalHostsFiles = removeURLFromHaystack(externalHostsFiles, assetKey); this.assets.remove(assetKey); @@ -448,88 +452,105 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // Hosts file to import - if ( typeof details.toImport === 'string' ) { + if (typeof details.toImport === 'string') { // https://github.com/gorhill/uBlock/issues/1181 // Try mapping the URL of an imported filter list to the assetKey of an // existing stock list. - var assetKeyFromURL = function(url) { - var needle = url.replace(/^https?:/, ''); - var assets = ηm.liveHostsFiles, asset; - for ( var assetKey in assets ) { - asset = assets[assetKey]; - if ( asset.content !== 'filters' ) { continue; } - if ( typeof asset.contentURL === 'string' ) { - if ( asset.contentURL.endsWith(needle) ) { return assetKey; } + let assetKeyFromURL = function (url) { + let needle = url.replace(/^https?:/, ''); + let assets = ηm.liveHostsFiles; + + for (let assetKey in assets) { + let asset = assets[assetKey]; + if (asset.content !== 'filters') { + continue; + } + if (typeof asset.contentURL === 'string') { + if (asset.contentURL.endsWith(needle)) { + return assetKey; + } continue; } - if ( Array.isArray(asset.contentURL) === false ) { continue; } - for ( i = 0, n = asset.contentURL.length; i < n; i++ ) { - if ( asset.contentURL[i].endsWith(needle) ) { + if (Array.isArray(asset.contentURL) === false) { + continue; + } + for (let i=0, n=asset.contentURL.length; i<n; ++i) { + if (asset.contentURL[i].endsWith(needle)) { return assetKey; } } } + return url; }; - var importedSet = new Set(this.listKeysFromCustomHostsFiles(externalHostsFiles)), - toImportSet = new Set(this.listKeysFromCustomHostsFiles(details.toImport)), - iter = toImportSet.values(); + + let importedSet = new Set(this.listKeysFromCustomHostsFiles(externalHostsFiles)); + let toImportSet = new Set(this.listKeysFromCustomHostsFiles(details.toImport)); + let iter = toImportSet.values(); + for (;;) { - var entry = iter.next(); - if ( entry.done ) { break; } - if ( importedSet.has(entry.value) ) { continue; } - assetKey = assetKeyFromURL(entry.value); - if ( assetKey === entry.value ) { + let entry = iter.next(); + if (entry.done) { + break; + } + + if (importedSet.has(entry.value)) { + continue; + } + + let assetKey = assetKeyFromURL(entry.value); + if (assetKey === entry.value) { importedSet.add(entry.value); } + this.liveHostsFiles[assetKey] = { content: 'filters', contentURL: [ assetKey ], title: assetKey }; } + externalHostsFiles = Tools.setToArray(importedSet).sort().join('\n'); } - if ( externalHostsFiles !== this.userSettings.externalHostsFiles ) { + if (externalHostsFiles !== this.userSettings.externalHostsFiles) { this.userSettings.externalHostsFiles = externalHostsFiles; - vAPI.storage.set({ externalHostsFiles: externalHostsFiles }); + vAPI.storage.set({ + externalHostsFiles: externalHostsFiles + }); } - vAPI.storage.set({ 'liveHostsFiles': this.liveHostsFiles }); - if ( typeof callback === 'function' ) { + vAPI.storage.set({ + 'liveHostsFiles': this.liveHostsFiles + }); + + if (typeof callback === 'function') { callback(); } }; -/******************************************************************************/ - // `switches` contains the preset blacklists for which the switch must be // revisited. - -ηMatrix.reloadHostsFiles = function() { +ηMatrix.reloadHostsFiles = function () { this.loadHostsFiles(); }; -/******************************************************************************/ - -ηMatrix.loadPublicSuffixList = function(callback) { - if ( typeof callback !== 'function' ) { +ηMatrix.loadPublicSuffixList = function (callback) { + if (typeof callback !== 'function') { callback = this.noopFunc; } - var applyPublicSuffixList = function(details) { - if ( !details.error ) { + let applyPublicSuffixList = function (details) { + if (!details.error) { publicSuffixList.parse(details.content, Punycode.toASCII); } + callback(); }; this.assets.get(this.pslAssetKey, applyPublicSuffixList); }; -/******************************************************************************/ - ηMatrix.scheduleAssetUpdater = (function () { let timer; let next = 0; @@ -563,21 +584,17 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); }; })(); -/******************************************************************************/ - -ηMatrix.assetObserver = function(topic, details) { +ηMatrix.assetObserver = function (topic, details) { // Do not update filter list if not in use. - if ( topic === 'before-asset-updated' ) { - if ( - this.liveHostsFiles.hasOwnProperty(details.assetKey) === false || - this.liveHostsFiles[details.assetKey].off === true - ) { + if (topic === 'before-asset-updated') { + if (this.liveHostsFiles.hasOwnProperty(details.assetKey) === false || + this.liveHostsFiles[details.assetKey].off === true) { return false; } return true; } - if ( topic === 'after-asset-updated' ) { + if (topic === 'after-asset-updated') { vAPI.messaging.broadcast({ what: 'assetUpdated', key: details.assetKey, @@ -587,7 +604,7 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // Update failed. - if ( topic === 'asset-update-failed' ) { + if (topic === 'asset-update-failed') { vAPI.messaging.broadcast({ what: 'assetUpdated', key: details.assetKey, @@ -597,11 +614,11 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); } // Reload all filter lists if needed. - if ( topic === 'after-assets-updated' ) { - if ( details.assetKeys.length !== 0 ) { + if (topic === 'after-assets-updated') { + if (details.assetKeys.length !== 0) { this.loadHostsFiles(); } - if ( this.userSettings.autoUpdate ) { + if (this.userSettings.autoUpdate) { this.scheduleAssetUpdater(25200000); } else { this.scheduleAssetUpdater(0); @@ -615,9 +632,9 @@ Components.utils.import('chrome://ematrix/content/lib/Tools.jsm'); // New asset source became available, if it's a filter list, should we // auto-select it? - if ( topic === 'builtin-asset-source-added' ) { - if ( details.entry.content === 'filters' ) { - if ( details.entry.off !== true ) { + if (topic === 'builtin-asset-source-added') { + if (details.entry.content === 'filters') { + if (details.entry.off !== true) { this.saveSelectedFilterLists([ details.assetKey ], true); } } @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see {http://www.gnu.org/licenses/}. - Home: https://libregit.spks.xyz/heckyel/ematrix + Home: https://gitlab.com/vannilla/ematrix uMatrix Home: https://github.com/gorhill/uBlock */ @@ -33,698 +33,601 @@ // Opera rules, I am not allowed to use a cut-down version of jQuery. So // the code here does *only* what I need, and nothing more, and with a lot // of assumption on passed parameters, etc. I grow it on a per-need-basis only. +// ηMatrix: well, we are not bound by these rules, but not being +// reliant on jQuery is not a bad thing. -var uDom = (function() { +var uDom = (function () { - /******************************************************************************/ - - var DOMList = function() { - this.nodes = []; + let DOMList = function () { + this.nodes = []; }; - /******************************************************************************/ - - Object.defineProperty( - DOMList.prototype, - 'length', - { - get: function() { - return this.nodes.length; - } - } - ); - - /******************************************************************************/ + Object.defineProperty(DOMList.prototype, 'length', { + get: function() { + return this.nodes.length; + } + }); - var DOMListFactory = function(selector, context) { - var r = new DOMList(); - if ( typeof selector === 'string' ) { + let DOMListFactory = function (selector, context) { + let r = new DOMList(); + if (typeof selector === 'string') { selector = selector.trim(); - if ( selector !== '' ) { - return addSelectorToList(r, selector, context); + if (selector !== '') { + return addSelectorToList(r, selector, context); } - } - if ( selector instanceof Node ) { + } + if (selector instanceof Node) { return addNodeToList(r, selector); - } - if ( selector instanceof NodeList ) { + } + if (selector instanceof NodeList) { return addNodeListToList(r, selector); - } - if ( selector instanceof DOMList ) { + } + if (selector instanceof DOMList) { return addListToList(r, selector); - } - return r; + } + return r; }; - /******************************************************************************/ - - DOMListFactory.onLoad = function(callback) { - window.addEventListener('load', callback); + DOMListFactory.onLoad = function (callback) { + window.addEventListener('load', callback); }; - /******************************************************************************/ - - DOMListFactory.nodeFromId = function(id) { - return document.getElementById(id); + DOMListFactory.nodeFromId = function (id) { + return document.getElementById(id); }; - DOMListFactory.nodeFromSelector = function(selector) { - return document.querySelector(selector); + DOMListFactory.nodeFromSelector = function (selector) { + return document.querySelector(selector); }; - /******************************************************************************/ - - var addNodeToList = function(list, node) { - if ( node ) { + let addNodeToList = function (list, node) { + if (node) { list.nodes.push(node); - } - return list; + } + return list; }; - /******************************************************************************/ - - var addNodeListToList = function(list, nodelist) { - if ( nodelist ) { - var n = nodelist.length; - for ( var i = 0; i < n; i++ ) { - list.nodes.push(nodelist[i]); + let addNodeListToList = function (list, nodelist) { + if (nodelist) { + let n = nodelist.length; + for (let i=0; i<n; ++i) { + list.nodes.push(nodelist[i]); } - } - return list; + } + return list; }; - /******************************************************************************/ - - var addListToList = function(list, other) { - list.nodes = list.nodes.concat(other.nodes); - return list; + let addListToList = function (list, other) { + list.nodes = list.nodes.concat(other.nodes); + return list; }; - /******************************************************************************/ - - var addSelectorToList = function(list, selector, context) { - var p = context || document; - var r = p.querySelectorAll(selector); - var n = r.length; - for ( var i = 0; i < n; i++ ) { + let addSelectorToList = function (list, selector, context) { + let p = context || document; + let r = p.querySelectorAll(selector); + let n = r.length; + for (let i=0; i<n; ++i) { list.nodes.push(r[i]); - } - return list; + } + return list; }; - /******************************************************************************/ - - var nodeInNodeList = function(node, nodeList) { - var i = nodeList.length; - while ( i-- ) { - if ( nodeList[i] === node ) { - return true; + let nodeInNodeList = function (node, nodeList) { + let i = nodeList.length; + while (i--) { + if (nodeList[i] === node) { + return true; } - } - return false; + } + return false; }; - /******************************************************************************/ - - var doesMatchSelector = function(node, selector) { - if ( !node ) { + let doesMatchSelector = function (node, selector) { + if (!node) { return false; - } - if ( node.nodeType !== 1 ) { + } + if (node.nodeType !== 1) { return false; - } - if ( selector === undefined ) { + } + if (selector === undefined) { return true; - } - var parentNode = node.parentNode; - if ( !parentNode || !parentNode.setAttribute ) { + } + + let parentNode = node.parentNode; + if (!parentNode || !parentNode.setAttribute) { return false; - } - var doesMatch = false; - parentNode.setAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO', ''); - var grandpaNode = parentNode.parentNode || document; - var nl = grandpaNode.querySelectorAll('[uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO] > ' + selector); - var i = nl.length; - while ( doesMatch === false && i-- ) { - doesMatch = nl[i] === node; - } - parentNode.removeAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO'); - return doesMatch; - }; + } - /******************************************************************************/ + let doesMatch = false; + parentNode.setAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO', ''); - DOMList.prototype.nodeAt = function(i) { - return this.nodes[i] || null; + let grandpaNode = parentNode.parentNode || document; + let nl = grandpaNode + .querySelectorAll('[uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO] > ' + + selector); + let i = nl.length; + while (doesMatch === false && i--) { + doesMatch = nl[i] === node; + } + parentNode.removeAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO'); + return doesMatch; }; - DOMList.prototype.at = function(i) { - return addNodeToList(new DOMList(), this.nodes[i]); + DOMList.prototype.nodeAt = function (i) { + return this.nodes[i] || null; }; - /******************************************************************************/ - - DOMList.prototype.toArray = function() { - return this.nodes.slice(); + DOMList.prototype.at = function (i) { + return addNodeToList(new DOMList(), this.nodes[i]); }; - /******************************************************************************/ - - DOMList.prototype.pop = function() { - return addNodeToList(new DOMList(), this.nodes.pop()); + DOMList.prototype.toArray = function () { + return this.nodes.slice(); }; - /******************************************************************************/ + DOMList.prototype.pop = function () { + return addNodeToList(new DOMList(), this.nodes.pop()); + }; - DOMList.prototype.forEach = function(fn) { - var n = this.nodes.length; - for ( var i = 0; i < n; i++ ) { + DOMList.prototype.forEach = function (fn) { + let n = this.nodes.length; + for (let i=0; i<n; ++i) { fn(this.at(i), i); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.subset = function(i, l) { - var r = new DOMList(); - var n = l !== undefined ? l : this.nodes.length; - var j = Math.min(i + n, this.nodes.length); - if ( i < j ) { + DOMList.prototype.subset = function (i, l) { + let r = new DOMList(); + let n = (l !== undefined) ? l : this.nodes.length; + let j = Math.min(i + n, this.nodes.length); + if (i < j) { r.nodes = this.nodes.slice(i, j); - } - return r; + } + return r; }; - /******************************************************************************/ - - DOMList.prototype.first = function() { - return this.subset(0, 1); + DOMList.prototype.first = function () { + return this.subset(0, 1); }; - /******************************************************************************/ - - DOMList.prototype.next = function(selector) { - var r = new DOMList(); - var n = this.nodes.length; - var node; - for ( var i = 0; i < n; i++ ) { - node = this.nodes[i]; - while ( node.nextSibling !== null ) { - node = node.nextSibling; - if ( node.nodeType !== 1 ) { + DOMList.prototype.next = function (selector) { + let r = new DOMList(); + let n = this.nodes.length; + for (let i=0; i<n; ++i) { + let node = this.nodes[i]; + while (node.nextSibling !== null) { + node = node.nextSibling; + if (node.nodeType !== 1) { continue; - } - if ( doesMatchSelector(node, selector) === false ) { + } + if (doesMatchSelector(node, selector) === false) { continue; - } - addNodeToList(r, node); - break; + } + addNodeToList(r, node); + break; } - } - return r; + } + return r; }; - /******************************************************************************/ - - DOMList.prototype.parent = function() { - var r = new DOMList(); - if ( this.nodes.length ) { + DOMList.prototype.parent = function () { + var r = new DOMList(); + if (this.nodes.length) { addNodeToList(r, this.nodes[0].parentNode); - } - return r; + } + return r; }; - /******************************************************************************/ + DOMList.prototype.filter = function (filter) { + let r = new DOMList(); + let filterFunc; - DOMList.prototype.filter = function(filter) { - var r = new DOMList(); - var filterFunc; - if ( typeof filter === 'string' ) { - filterFunc = function() { - return doesMatchSelector(this, filter); + if (typeof filter === 'string') { + filterFunc = function () { + return doesMatchSelector(this, filter); }; - } else if ( typeof filter === 'function' ) { + } else if (typeof filter === 'function') { filterFunc = filter; - } else { - filterFunc = function(){ - return true; + } else { + filterFunc = function (){ + return true; }; - } - var n = this.nodes.length; - var node; - for ( var i = 0; i < n; i++ ) { - node = this.nodes[i]; - if ( filterFunc.apply(node) ) { - addNodeToList(r, node); + } + + let n = this.nodes.length; + for (let i=0; i<n; ++i) { + let node = this.nodes[i]; + if (filterFunc.apply(node)) { + addNodeToList(r, node); } - } - return r; + } + return r; }; - /******************************************************************************/ - // TODO: Avoid possible duplicates - - DOMList.prototype.ancestors = function(selector) { - var r = new DOMList(); - var n = this.nodes.length; - var node; - for ( var i = 0; i < n; i++ ) { - node = this.nodes[i].parentNode; - while ( node ) { - if ( doesMatchSelector(node, selector) ) { + DOMList.prototype.ancestors = function (selector) { + let r = new DOMList(); + let n = this.nodes.length; + for (let i=0; i<n; ++i) { + let node = this.nodes[i].parentNode; + while (node) { + if (doesMatchSelector(node, selector)) { addNodeToList(r, node); - } - node = node.parentNode; + } + node = node.parentNode; } - } - return r; + } + return r; }; - /******************************************************************************/ - - DOMList.prototype.descendants = function(selector) { - var r = new DOMList(); - var n = this.nodes.length; - var nl; - for ( var i = 0; i < n; i++ ) { - nl = this.nodes[i].querySelectorAll(selector); + DOMList.prototype.descendants = function (selector) { + let r = new DOMList(); + let n = this.nodes.length; + for (let i=0; i<n; ++i) { + let nl = this.nodes[i].querySelectorAll(selector); addNodeListToList(r, nl); - } - return r; - }; - - /******************************************************************************/ - - DOMList.prototype.contents = function() { - var r = new DOMList(); - var cnodes, cn, ci; - var n = this.nodes.length; - for ( var i = 0; i < n; i++ ) { - cnodes = this.nodes[i].childNodes; - cn = cnodes.length; - for ( ci = 0; ci < cn; ci++ ) { - addNodeToList(r, cnodes.item(ci)); + } + return r; + }; + + DOMList.prototype.contents = function () { + let r = new DOMList(); + let n = this.nodes.length; + for (let i=0; i<n; ++i) { + let cnodes = this.nodes[i].childNodes; + let cn = cnodes.length; + for (let ci=0; ci<cn; ++ci) { + addNodeToList(r, cnodes.item(ci)); } - } - return r; + } + return r; }; - /******************************************************************************/ - DOMList.prototype.remove = function() { - var cn, p; - var i = this.nodes.length; - while ( i-- ) { - cn = this.nodes[i]; - if ( (p = cn.parentNode) ) { - p.removeChild(cn); + let i = this.nodes.length; + while (i--) { + let cn = this.nodes[i]; + if ((p = cn.parentNode)) { + p.removeChild(cn); } - } - return this; + } + return this; }; DOMList.prototype.detach = DOMList.prototype.remove; - /******************************************************************************/ - - DOMList.prototype.empty = function() { - var node; - var i = this.nodes.length; - while ( i-- ) { - node = this.nodes[i]; - while ( node.firstChild ) { - node.removeChild(node.firstChild); + DOMList.prototype.empty = function () { + let i = this.nodes.length; + while (i--) { + let node = this.nodes[i]; + while (node.firstChild) { + node.removeChild(node.firstChild); } - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.append = function(selector, context) { - var p = this.nodes[0]; - if ( p ) { - var c = DOMListFactory(selector, context); - var n = c.nodes.length; - for ( var i = 0; i < n; i++ ) { - p.appendChild(c.nodes[i]); + DOMList.prototype.append = function (selector, context) { + let p = this.nodes[0]; + if (p) { + let c = DOMListFactory(selector, context); + let n = c.nodes.length; + for (let i=0; i<n; ++i) { + p.appendChild(c.nodes[i]); } - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.prepend = function(selector, context) { - var p = this.nodes[0]; - if ( p ) { - var c = DOMListFactory(selector, context); - var i = c.nodes.length; - while ( i-- ) { - p.insertBefore(c.nodes[i], p.firstChild); + DOMList.prototype.prepend = function (selector, context) { + let p = this.nodes[0]; + if (p) { + let c = DOMListFactory(selector, context); + let i = c.nodes.length; + while (i--) { + p.insertBefore(c.nodes[i], p.firstChild); } - } - return this; + } + return this; }; - /******************************************************************************/ + DOMList.prototype.appendTo = function (selector, context) { + let p = (selector instanceof DOMListFactory) + ? selector + : DOMListFactory(selector, context); - DOMList.prototype.appendTo = function(selector, context) { - var p = selector instanceof DOMListFactory ? selector : DOMListFactory(selector, context); - var n = p.length; - for ( var i = 0; i < n; i++ ) { + let n = p.length; + for (let i=0; i<n; ++i) { p.nodes[0].appendChild(this.nodes[i]); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.insertAfter = function(selector, context) { - if ( this.nodes.length === 0 ) { + DOMList.prototype.insertAfter = function (selector, context) { + if (this.nodes.length === 0) { return this; - } - var p = this.nodes[0].parentNode; - if ( !p ) { + } + let p = this.nodes[0].parentNode; + if (!p) { return this; - } - var c = DOMListFactory(selector, context); - var n = c.nodes.length; - for ( var i = 0; i < n; i++ ) { + } + let c = DOMListFactory(selector, context); + let n = c.nodes.length; + for (let i=0; i<n; ++i) { p.appendChild(c.nodes[i]); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.insertBefore = function(selector, context) { - if ( this.nodes.length === 0 ) { + DOMList.prototype.insertBefore = function (selector, context) { + if (this.nodes.length === 0) { return this; - } - var referenceNodes = DOMListFactory(selector, context); - if ( referenceNodes.nodes.length === 0 ) { + } + let referenceNodes = DOMListFactory(selector, context); + if (referenceNodes.nodes.length === 0) { return this; - } - var referenceNode = referenceNodes.nodes[0]; - var parentNode = referenceNode.parentNode; - if ( !parentNode ) { + } + let referenceNode = referenceNodes.nodes[0]; + let parentNode = referenceNode.parentNode; + if (!parentNode) { return this; - } - var n = this.nodes.length; - for ( var i = 0; i < n; i++ ) { + } + let n = this.nodes.length; + for (let i=0; i<n; ++i) { parentNode.insertBefore(this.nodes[i], referenceNode); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.clone = function(notDeep) { - var r = new DOMList(); - var n = this.nodes.length; - for ( var i = 0; i < n; i++ ) { + DOMList.prototype.clone = function (notDeep) { + let r = new DOMList(); + let n = this.nodes.length; + for (let i=0; i<n; ++i) { addNodeToList(r, this.nodes[i].cloneNode(!notDeep)); - } - return r; + } + return r; }; - /******************************************************************************/ - - DOMList.prototype.nthOfType = function() { - if ( this.nodes.length === 0 ) { + DOMList.prototype.nthOfType = function () { + if (this.nodes.length === 0) { return 0; - } - var node = this.nodes[0]; - var tagName = node.tagName; - var i = 1; - while ( node.previousElementSibling !== null ) { + } + let node = this.nodes[0]; + let tagName = node.tagName; + let i = 1; + while (node.previousElementSibling !== null) { node = node.previousElementSibling; - if ( typeof node.tagName !== 'string' ) { - continue; + if (typeof node.tagName !== 'string') { + continue; } - if ( node.tagName !== tagName ) { - continue; + if (node.tagName !== tagName) { + continue; } i++; - } - return i; + } + return i; }; - /******************************************************************************/ - - DOMList.prototype.attr = function(attr, value) { - var i = this.nodes.length; - if ( value === undefined && typeof attr !== 'object' ) { + DOMList.prototype.attr = function (attr, value) { + let i = this.nodes.length; + if (value === undefined && typeof attr !== 'object') { return i ? this.nodes[0].getAttribute(attr) : undefined; - } - if ( typeof attr === 'object' ) { - var attrNames = Object.keys(attr); - var node, j, attrName; - while ( i-- ) { - node = this.nodes[i]; - j = attrNames.length; - while ( j-- ) { - attrName = attrNames[j]; - node.setAttribute(attrName, attr[attrName]); - } + } + if (typeof attr === 'object') { + let attrNames = Object.keys(attr); + while (i--) { + let node = this.nodes[i]; + let j = attrNames.length; + while (j--) { + node.setAttribute(attrNames[j], attr[attrName]); + } } - } else { - while ( i-- ) { - this.nodes[i].setAttribute(attr, value); + } else { + while (i--) { + this.nodes[i].setAttribute(attr, value); } - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.prop = function(prop, value) { - var i = this.nodes.length; - if ( value === undefined ) { + DOMList.prototype.prop = function (prop, value) { + let i = this.nodes.length; + if (value === undefined) { return i !== 0 ? this.nodes[0][prop] : undefined; - } - while ( i-- ) { + } + while (i--) { this.nodes[i][prop] = value; - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.css = function(prop, value) { - var i = this.nodes.length; - if ( value === undefined ) { + DOMList.prototype.css = function (prop, value) { + let i = this.nodes.length; + if (value === undefined) { return i ? this.nodes[0].style[prop] : undefined; - } - if ( value !== '' ) { - while ( i-- ) { - this.nodes[i].style.setProperty(prop, value); + } + if (value !== '') { + while (i--) { + this.nodes[i].style.setProperty(prop, value); } return this; - } - while ( i-- ) { + } + while (i--) { this.nodes[i].style.removeProperty(prop); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.val = function(value) { - return this.prop('value', value); + DOMList.prototype.val = function (value) { + return this.prop('value', value); }; - /******************************************************************************/ - - DOMList.prototype.html = function(html) { - var i = this.nodes.length; - if ( html === undefined ) { + DOMList.prototype.html = function (html) { + let i = this.nodes.length; + if (html === undefined) { return i ? this.nodes[0].innerHTML : ''; - } - while ( i-- ) { + } + while (i--) { vAPI.insertHTML(this.nodes[i], html); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.text = function(text) { - var i = this.nodes.length; - if ( text === undefined ) { + DOMList.prototype.text = function (text) { + let i = this.nodes.length; + if (text === undefined) { return i ? this.nodes[0].textContent : ''; - } - while ( i-- ) { + } + while (i--) { this.nodes[i].textContent = text; - } - return this; + } + return this; }; - /******************************************************************************/ - - var toggleClass = function(node, className, targetState) { - var tokenList = node.classList; - if ( tokenList instanceof DOMTokenList === false ) { + let toggleClass = function (node, className, targetState) { + let tokenList = node.classList; + if (tokenList instanceof DOMTokenList === false) { return; - } - var currentState = tokenList.contains(className); - var newState = targetState; - if ( newState === undefined ) { + } + let currentState = tokenList.contains(className); + let newState = targetState; + if (newState === undefined) { newState = !currentState; - } - if ( newState === currentState ) { + } + if (newState === currentState) { return; - } - tokenList.toggle(className, newState); + } + tokenList.toggle(className, newState); }; - /******************************************************************************/ - - DOMList.prototype.hasClass = function(className) { - if ( !this.nodes.length ) { + DOMList.prototype.hasClass = function (className) { + if (!this.nodes.length) { return false; - } - var tokenList = this.nodes[0].classList; - return tokenList instanceof DOMTokenList && - tokenList.contains(className); + } + let tokenList = this.nodes[0].classList; + return tokenList instanceof DOMTokenList + && tokenList.contains(className); }; + DOMList.prototype.hasClassName = DOMList.prototype.hasClass; - DOMList.prototype.addClass = function(className) { - return this.toggleClass(className, true); + DOMList.prototype.addClass = function (className) { + return this.toggleClass(className, true); }; - DOMList.prototype.removeClass = function(className) { - if ( className !== undefined ) { + DOMList.prototype.removeClass = function (className) { + if (className !== undefined) { return this.toggleClass(className, false); - } - var i = this.nodes.length; - while ( i-- ) { + } + let i = this.nodes.length; + while (i--) { this.nodes[i].className = ''; - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.toggleClass = function(className, targetState) { - if ( className.indexOf(' ') !== -1 ) { + DOMList.prototype.toggleClass = function (className, targetState) { + if (className.indexOf(' ') !== -1) { return this.toggleClasses(className, targetState); - } - var i = this.nodes.length; - while ( i-- ) { + } + let i = this.nodes.length; + while (i--) { toggleClass(this.nodes[i], className, targetState); - } - return this; - }; - - /******************************************************************************/ - - DOMList.prototype.toggleClasses = function(classNames, targetState) { - var tokens = classNames.split(/\s+/); - var i = this.nodes.length; - var node, j; - while ( i-- ) { - node = this.nodes[i]; - j = tokens.length; - while ( j-- ) { - toggleClass(node, tokens[j], targetState); + } + return this; + }; + + DOMList.prototype.toggleClasses = function (classNames, targetState) { + let tokens = classNames.split(/\s+/); + let i = this.nodes.length; + while (i--) { + let node = this.nodes[i]; + let j = tokens.length; + while (j--) { + toggleClass(node, tokens[j], targetState); } - } - return this; + } + return this; }; - /******************************************************************************/ + let listenerEntries = []; - var listenerEntries = []; - - var ListenerEntry = function(target, type, capture, callback) { - this.target = target; - this.type = type; - this.capture = capture; - this.callback = callback; - target.addEventListener(type, callback, capture); + let ListenerEntry = function (target, type, capture, callback) { + this.target = target; + this.type = type; + this.capture = capture; + this.callback = callback; + target.addEventListener(type, callback, capture); }; - ListenerEntry.prototype.dispose = function() { - this.target.removeEventListener(this.type, this.callback, this.capture); - this.target = null; - this.callback = null; + ListenerEntry.prototype.dispose = function () { + this.target.removeEventListener(this.type, this.callback, this.capture); + this.target = null; + this.callback = null; }; - /******************************************************************************/ - - var makeEventHandler = function(selector, callback) { - return function(event) { - var dispatcher = event.currentTarget; - if ( !dispatcher || typeof dispatcher.querySelectorAll !== 'function' ) { - return; + let makeEventHandler = function (selector, callback) { + return function (event) { + let dispatcher = event.currentTarget; + if (!dispatcher + || typeof dispatcher.querySelectorAll !== 'function') { + return; } - var receiver = event.target; - if ( nodeInNodeList(receiver, dispatcher.querySelectorAll(selector)) ) { - callback.call(receiver, event); + let receiver = event.target; + if (nodeInNodeList(receiver, dispatcher.querySelectorAll(selector))) { + callback.call(receiver, event); } - }; + }; }; - DOMList.prototype.on = function(etype, selector, callback) { - if ( typeof selector === 'function' ) { + DOMList.prototype.on = function (etype, selector, callback) { + if (typeof selector === 'function') { callback = selector; selector = undefined; - } else { + } else { callback = makeEventHandler(selector, callback); - } + } - var i = this.nodes.length; - while ( i-- ) { - listenerEntries.push(new ListenerEntry(this.nodes[i], etype, selector !== undefined, callback)); - } - return this; + let i = this.nodes.length; + while (i--) { + listenerEntries.push(new ListenerEntry(this.nodes[i], + etype, + selector !== undefined, + callback)); + } + return this; }; - /******************************************************************************/ - // TODO: Won't work for delegated handlers. Need to figure // what needs to be done. - - DOMList.prototype.off = function(evtype, callback) { - var i = this.nodes.length; - while ( i-- ) { + DOMList.prototype.off = function (evtype, callback) { + let i = this.nodes.length; + while (i--) { this.nodes[i].removeEventListener(evtype, callback); - } - return this; + } + return this; }; - /******************************************************************************/ - - DOMList.prototype.trigger = function(etype) { - var ev = new CustomEvent(etype); - var i = this.nodes.length; - while ( i-- ) { + DOMList.prototype.trigger = function (etype) { + let ev = new CustomEvent(etype); + let i = this.nodes.length; + while (i--) { this.nodes[i].dispatchEvent(ev); - } - return this; + } + return this; }; - /******************************************************************************/ - // Cleanup - - var onBeforeUnload = function() { - var entry; - while ( (entry = listenerEntries.pop()) ) { + let onBeforeUnload = function () { + let entry; + while ((entry = listenerEntries.pop())) { entry.dispose(); - } - window.removeEventListener('beforeunload', onBeforeUnload); + } + window.removeEventListener('beforeunload', onBeforeUnload); }; window.addEventListener('beforeunload', onBeforeUnload); - /******************************************************************************/ - return DOMListFactory; - })(); |