diff options
Diffstat (limited to 'js/hosts-files.js')
-rw-r--r-- | js/hosts-files.js | 407 |
1 files changed, 209 insertions, 198 deletions
diff --git a/js/hosts-files.js b/js/hosts-files.js index 8c65648..ba57bde 100644 --- a/js/hosts-files.js +++ b/js/hosts-files.js @@ -21,25 +21,16 @@ uMatrix Home: https://github.com/gorhill/uMatrix */ -/* global uDom */ - 'use strict'; -/******************************************************************************/ - -(function() { - - /******************************************************************************/ - - var listDetails = {}, - lastUpdateTemplateString = vAPI.i18n('hostsFilesLastUpdate'), - hostsFilesSettingsHash, - reValidExternalList = /[a-z-]+:\/\/\S*\/\S+/; +(function () { + let listDetails = {}; + let lastUpdateTemplateString = vAPI.i18n('hostsFilesLastUpdate'); + let hostsFilesSettingsHash; + let reValidExternalList = /[a-z-]+:\/\/\S*\/\S+/; - /******************************************************************************/ - - vAPI.messaging.addListener(function onMessage(msg) { - switch ( msg.what ) { + vAPI.messaging.addListener(function (msg) { + switch (msg.what) { case 'assetUpdated': updateAssetStatus(msg); break; @@ -54,44 +45,51 @@ } }); - /******************************************************************************/ - - var renderNumber = function(value) { + let renderNumber = function (value) { return value.toLocaleString(); }; - /******************************************************************************/ - - var renderHostsFiles = function(soft) { - var listEntryTemplate = uDom('#templates .listEntry'), - listStatsTemplate = vAPI.i18n('hostsFilesPerFileStats'), - renderElapsedTimeToString = vAPI.i18n.renderElapsedTimeToString, - reExternalHostFile = /^https?:/; + let renderHostsFiles = function (soft) { + let listEntryTemplate = uDom('#templates .listEntry'); + let listStatsTemplate = vAPI.i18n('hostsFilesPerFileStats'); + let renderETTS = vAPI.i18n.renderElapsedTimeToString; + let reExternalHostFile = /^https?:/; // Assemble a pretty list name if possible - var listNameFromListKey = function(listKey) { - var list = listDetails.current[listKey] || listDetails.available[listKey]; - var listTitle = list ? list.title : ''; - if ( listTitle === '' ) { return listKey; } + let listNameFromListKey = function (listKey) { + let list = + listDetails.current[listKey] || listDetails.available[listKey]; + let listTitle = list ? list.title : ''; + + if (listTitle === '') { + return listKey; + } + return listTitle; }; - var liFromListEntry = function(listKey, li) { - var entry = listDetails.available[listKey], - elem; - if ( !li ) { + let liFromListEntry = function (listKey, li) { + let entry = listDetails.available[listKey]; + let elem; + + if (!li) { li = listEntryTemplate.clone().nodeAt(0); } - if ( li.getAttribute('data-listkey') !== listKey ) { + + if (li.getAttribute('data-listkey') !== listKey) { li.setAttribute('data-listkey', listKey); + elem = li.querySelector('input[type="checkbox"]'); - elem.checked = entry.off !== true; + elem.checked = (entry.off !== true); elem = li.querySelector('a:nth-of-type(1)'); - elem.setAttribute('href', 'asset-viewer.html?url=' + encodeURI(listKey)); + elem.setAttribute('href', + 'asset-viewer.html?url=' + encodeURI(listKey)); elem.setAttribute('type', 'text/html'); elem.textContent = listNameFromListKey(listKey); + li.classList.remove('toRemove'); - if ( entry.supportName ) { + + if (entry.supportName) { li.classList.add('support'); elem = li.querySelector('a.support'); elem.setAttribute('href', entry.supportURL); @@ -99,12 +97,14 @@ } else { li.classList.remove('support'); } - if ( entry.external ) { + + if (entry.external) { li.classList.add('external'); } else { li.classList.remove('external'); } - if ( entry.instructionURL ) { + + if (entry.instructionURL) { li.classList.add('mustread'); elem = li.querySelector('a.mustread'); elem.setAttribute('href', entry.instructionURL); @@ -112,40 +112,51 @@ li.classList.remove('mustread'); } } + // https://github.com/gorhill/uBlock/issues/1429 - if ( !soft ) { + if (!soft) { elem = li.querySelector('input[type="checkbox"]'); elem.checked = entry.off !== true; } + elem = li.querySelector('span.counts'); - var text = ''; - if ( !isNaN(+entry.entryUsedCount) && !isNaN(+entry.entryCount) ) { + + let text = ''; + if (!isNaN(+entry.entryUsedCount) && !isNaN(+entry.entryCount)) { text = listStatsTemplate - .replace('{{used}}', renderNumber(entry.off ? 0 : entry.entryUsedCount)) - .replace('{{total}}', renderNumber(entry.entryCount)); + .replace('{{used}}', + renderNumber(entry.off ? 0 : entry.entryUsedCount)) + .replace('{{total}}', + renderNumber(entry.entryCount)); } + elem.textContent = text; + // https://github.com/chrisaljoudi/uBlock/issues/104 - var asset = listDetails.cache[listKey] || {}; - var remoteURL = asset.remoteURL; - li.classList.toggle( - 'unsecure', - typeof remoteURL === 'string' && remoteURL.lastIndexOf('http:', 0) === 0 - ); + let asset = listDetails.cache[listKey] || {}; + let remoteURL = asset.remoteURL; + + li.classList.toggle('unsecure', + typeof remoteURL === 'string' + && remoteURL.lastIndexOf('http:', 0) === 0); li.classList.toggle('failed', asset.error !== undefined); li.classList.toggle('obsolete', asset.obsolete === true); - li.classList.toggle('cached', asset.cached === true && asset.writeTime > 0); - if ( asset.cached ) { - li.querySelector('.status.cache').setAttribute( - 'title', - lastUpdateTemplateString.replace('{{ago}}', renderElapsedTimeToString(asset.writeTime)) - ); + li.classList.toggle('cached', + asset.cached === true && asset.writeTime > 0); + + if (asset.cached) { + li.querySelector('.status.cache') + .setAttribute('title', + lastUpdateTemplateString + .replace('{{ago}}', + renderETTS(asset.writeTime))); } + li.classList.remove('discard'); return li; }; - var onListsReceived = function(details) { + let onListsReceived = function (details) { // Before all, set context vars listDetails = details; @@ -153,239 +164,239 @@ // DOM list entries. uDom('#lists .listEntry').addClass('discard'); - var availableLists = details.available, - listKeys = Object.keys(details.available); + let availableLists = details.available; + let listKeys = Object.keys(details.available); // Sort works this way: // - Send /^https?:/ items at the end (custom hosts file URL) - listKeys.sort(function(a, b) { - var ta = availableLists[a].title || a, - tb = availableLists[b].title || b; - if ( reExternalHostFile.test(ta) === reExternalHostFile.test(tb) ) { + listKeys.sort(function (a, b) { + let ta = availableLists[a].title || a; + let tb = availableLists[b].title || b; + + if (reExternalHostFile.test(ta) === reExternalHostFile.test(tb)) { return ta.localeCompare(tb); } + return reExternalHostFile.test(tb) ? -1 : 1; }); - var ulList = document.querySelector('#lists'); - for ( var i = 0; i < listKeys.length; i++ ) { - var liEntry = liFromListEntry(listKeys[i], ulList.children[i]); - if ( liEntry.parentElement === null ) { + let ulList = document.querySelector('#lists'); + + for (let i=0; i<listKeys.length; ++i) { + let liEntry = liFromListEntry(listKeys[i], ulList.children[i]); + if (liEntry.parentElement === null) { ulList.appendChild(liEntry); } } uDom('#lists .listEntry.discard').remove(); - uDom('#listsOfBlockedHostsPrompt').text( - vAPI.i18n('hostsFilesStats').replace( - '{{blockedHostnameCount}}', - renderNumber(details.blockedHostnameCount) - ) - ); - uDom('#autoUpdate').prop('checked', listDetails.autoUpdate === true); - - if ( !soft ) { + uDom('#listsOfBlockedHostsPrompt') + .text(vAPI.i18n('hostsFilesStats') + .replace('{{blockedHostnameCount}}', + renderNumber(details.blockedHostnameCount))); + uDom('#autoUpdate').prop('checked', + listDetails.autoUpdate === true); + + if (!soft) { hostsFilesSettingsHash = hashFromCurrentFromSettings(); } + renderWidgets(); }; - vAPI.messaging.send('hosts-files.js', { what: 'getLists' }, onListsReceived); + vAPI.messaging.send('hosts-files.js', { + what: 'getLists' + }, onListsReceived); }; - /******************************************************************************/ - - var renderWidgets = function() { - uDom('#buttonUpdate').toggleClass('disabled', document.querySelector('body:not(.updating) #lists .listEntry.obsolete > input[type="checkbox"]:checked') === null); - uDom('#buttonPurgeAll').toggleClass('disabled', document.querySelector('#lists .listEntry.cached') === null); - uDom('#buttonApply').toggleClass('disabled', hostsFilesSettingsHash === hashFromCurrentFromSettings()); + let renderWidgets = function () { + let sel1 = + 'body:not(.updating) #lists .listEntry.obsolete ' + + '> input[type="checkbox"]:checked'; + let sel2 = '#lists .listEntry.cached'; + + uDom('#buttonUpdate') + .toggleClass('disabled', document.querySelector(sel1) === null); + uDom('#buttonPurgeAll') + .toggleClass('disabled', document.querySelector(sel2) === null); + uDom('#buttonApply') + .toggleClass('disabled', + hostsFilesSettingsHash === + hashFromCurrentFromSettings()); }; - /******************************************************************************/ + let updateAssetStatus = function (details) { + let li = document + .querySelector('#lists .listEntry[data-listkey="'+details.key+'"]'); + if (li === null) { + return; + } - var updateAssetStatus = function(details) { - var li = document.querySelector('#lists .listEntry[data-listkey="' + details.key + '"]'); - if ( li === null ) { return; } li.classList.toggle('failed', !!details.failed); li.classList.toggle('obsolete', !details.cached); li.classList.toggle('cached', !!details.cached); - if ( details.cached ) { - li.querySelector('.status.cache').setAttribute( - 'title', - lastUpdateTemplateString.replace( - '{{ago}}', - vAPI.i18n.renderElapsedTimeToString(Date.now()) - ) - ); + + if (details.cached) { + let str = vAPI.i18n.renderElapsedTimeToString(Date.now()); + li.querySelector('.status.cache') + .setAttribute('title', + lastUpdateTemplateString.replace('{{ago}}', str)); } + renderWidgets(); }; - /******************************************************************************* - - Compute a hash from all the settings affecting how filter lists are loaded - in memory. - + /** + Compute a hash from all the settings affecting how filter lists are loaded + in memory. **/ - - var hashFromCurrentFromSettings = function() { - var hash = [], - listHash = [], - listEntries = document.querySelectorAll('#lists .listEntry[data-listkey]:not(.toRemove)'), - liEntry, - i = listEntries.length; - while ( i-- ) { - liEntry = listEntries[i]; - if ( liEntry.querySelector('input[type="checkbox"]:checked') !== null ) { - listHash.push(liEntry.getAttribute('data-listkey')); + let hashFromCurrentFromSettings = function () { + let hash = []; + let listHash = []; + let sel = '#lists .listEntry[data-listkey]:not(.toRemove)'; + let ext = 'externalHostsFiles'; + let listEntries = document.querySelectorAll(sel); + + for (let i=listEntries.length-1; i>=0; --i) { + let li = listEntries[i]; + if (li.querySelector('input[type="checkbox"]:checked') !== null) { + listHash.push(li.getAttribute('data-listkey')); } } - hash.push( - listHash.sort().join(), - reValidExternalList.test(document.getElementById('externalHostsFiles').value), - document.querySelector('#lists .listEntry.toRemove') !== null - ); + + hash.push(listHash.sort().join(), + reValidExternalList.test(document.getElementById(ext).value), + document.querySelector('#lists .listEntry.toRemove') !== null); + return hash.join(); }; - /******************************************************************************/ - - var onHostsFilesSettingsChanged = function() { + let onHostsFilesSettingsChanged = function () { renderWidgets(); }; - /******************************************************************************/ + let onRemoveExternalHostsFile = function (ev) { + let liEntry = uDom(this).ancestors('[data-listkey]'); + let listKey = liEntry.attr('data-listkey'); - var onRemoveExternalHostsFile = function(ev) { - var liEntry = uDom(this).ancestors('[data-listkey]'), - listKey = liEntry.attr('data-listkey'); - if ( listKey ) { + if (listKey) { liEntry.toggleClass('toRemove'); renderWidgets(); } + ev.preventDefault(); }; - /******************************************************************************/ + let onPurgeClicked = function () { + let button = uDom(this); + let liEntry = button.ancestors('[data-listkey]'); + let listKey = liEntry.attr('data-listkey'); - var onPurgeClicked = function() { - var button = uDom(this), - liEntry = button.ancestors('[data-listkey]'), - listKey = liEntry.attr('data-listkey'); - if ( !listKey ) { return; } + if (!listKey) { + return; + } + + vAPI.messaging.send('hosts-files.js', { + what: 'purgeCache', + assetKey: listKey + }); - vAPI.messaging.send('hosts-files.js', { what: 'purgeCache', assetKey: listKey }); liEntry.addClass('obsolete'); liEntry.removeClass('cached'); - if ( liEntry.descendants('input').first().prop('checked') ) { + if (liEntry.descendants('input').first().prop('checked')) { renderWidgets(); } }; - /******************************************************************************/ - - var selectHostsFiles = function(callback) { + let selectHostsFiles = function (callback) { // Hosts files to select - var toSelect = [], - liEntries = document.querySelectorAll('#lists .listEntry[data-listkey]:not(.toRemove)'), - i = liEntries.length, - liEntry; - while ( i-- ) { - liEntry = liEntries[i]; - if ( liEntry.querySelector('input[type="checkbox"]:checked') !== null ) { - toSelect.push(liEntry.getAttribute('data-listkey')); + let toSelect = []; + let sel = '#lists .listEntry[data-listkey]:not(.toRemove)'; + let sel2 = '#lists .listEntry.toRemove[data-listkey]'; + let liEntries = document.querySelectorAll(sel); + + for (let i=liEntries.length-1; i>=0; --i) { + let li = liEntries[i]; + if (li.querySelector('input[type="checkbox"]:checked') !== null) { + toSelect.push(li.getAttribute('data-listkey')); } } // External hosts files to remove - var toRemove = []; - liEntries = document.querySelectorAll('#lists .listEntry.toRemove[data-listkey]'); - i = liEntries.length; - while ( i-- ) { + let toRemove = []; + liEntries = document.querySelectorAll(sel2); + + for (let i=liEntries.length-1; i>=0; --i) { toRemove.push(liEntries[i].getAttribute('data-listkey')); } // External hosts files to import - var externalListsElem = document.getElementById('externalHostsFiles'), - toImport = externalListsElem.value.trim(); + let externalListsElem = document.getElementById('externalHostsFiles'); + let toImport = externalListsElem.value.trim(); + externalListsElem.value = ''; - vAPI.messaging.send( - 'hosts-files.js', - { - what: 'selectHostsFiles', - toSelect: toSelect, - toImport: toImport, - toRemove: toRemove - }, - callback - ); + vAPI.messaging.send('hosts-files.js', { + what: 'selectHostsFiles', + toSelect: toSelect, + toImport: toImport, + toRemove: toRemove + }, callback); hostsFilesSettingsHash = hashFromCurrentFromSettings(); }; - /******************************************************************************/ - - var buttonApplyHandler = function() { + let buttonApplyHandler = function () { uDom('#buttonApply').removeClass('enabled'); - selectHostsFiles(function() { - vAPI.messaging.send('hosts-files.js', { what: 'reloadHostsFiles' }); + selectHostsFiles(function () { + vAPI.messaging.send('hosts-files.js', { + what: 'reloadHostsFiles' + }); }); + renderWidgets(); }; - /******************************************************************************/ - - var buttonUpdateHandler = function() { + let buttonUpdateHandler = function () { uDom('#buttonUpdate').removeClass('enabled'); - selectHostsFiles(function() { + selectHostsFiles(function () { document.body.classList.add('updating'); - vAPI.messaging.send('hosts-files.js', { what: 'forceUpdateAssets' }); + vAPI.messaging.send('hosts-files.js', { + what: 'forceUpdateAssets' + }); renderWidgets(); }); renderWidgets(); }; - /******************************************************************************/ - - var buttonPurgeAllHandler = function() { + let buttonPurgeAllHandler = function () { uDom('#buttonPurgeAll').removeClass('enabled'); - vAPI.messaging.send( - 'hosts-files.js', - { what: 'purgeAllCaches' }, - function() { - renderHostsFiles(true); - } - ); + vAPI.messaging.send('hosts-files.js', { + what: 'purgeAllCaches' + }, function () { + renderHostsFiles(true); + }); }; - /******************************************************************************/ - - var autoUpdateCheckboxChanged = function() { - vAPI.messaging.send( - 'hosts-files.js', - { - what: 'userSettings', - name: 'autoUpdate', - value: this.checked - } - ); + let autoUpdateCheckboxChanged = function () { + vAPI.messaging.send('hosts-files.js', { + what: 'userSettings', + name: 'autoUpdate', + value: this.checked + }); }; - /******************************************************************************/ - uDom('#autoUpdate').on('change', autoUpdateCheckboxChanged); uDom('#buttonApply').on('click', buttonApplyHandler); uDom('#buttonUpdate').on('click', buttonUpdateHandler); uDom('#buttonPurgeAll').on('click', buttonPurgeAllHandler); - uDom('#lists').on('change', '.listEntry > input', onHostsFilesSettingsChanged); - uDom('#lists').on('click', '.listEntry > a.remove', onRemoveExternalHostsFile); + uDom('#lists').on('change', '.listEntry > input', + onHostsFilesSettingsChanged); + uDom('#lists').on('click', '.listEntry > a.remove', + onRemoveExternalHostsFile); uDom('#lists').on('click', 'span.cache', onPurgeClicked); uDom('#externalHostsFiles').on('input', onHostsFilesSettingsChanged); renderHostsFiles(); - - /******************************************************************************/ - })(); |