diff options
Diffstat (limited to 'data/extensions/uBlock0@raymondhill.net/js/whitelist.js')
-rw-r--r-- | data/extensions/uBlock0@raymondhill.net/js/whitelist.js | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/data/extensions/uBlock0@raymondhill.net/js/whitelist.js b/data/extensions/uBlock0@raymondhill.net/js/whitelist.js new file mode 100644 index 0000000..371d25f --- /dev/null +++ b/data/extensions/uBlock0@raymondhill.net/js/whitelist.js @@ -0,0 +1,258 @@ +/******************************************************************************* + + uBlock Origin - a comprehensive, efficient content blocker + Copyright (C) 2014-2018 Raymond Hill + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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://github.com/gorhill/uBlock +*/ + +/* global CodeMirror, uBlockDashboard */ + +import { dom, qs$ } from './dom.js'; +import { i18n$ } from './i18n.js'; + +/******************************************************************************/ + +const reComment = /^\s*#\s*/; + +function directiveFromLine(line) { + const match = reComment.exec(line); + return match === null + ? line.trim() + : line.slice(match.index + match[0].length).trim(); +} + +/******************************************************************************/ + +CodeMirror.defineMode("ubo-whitelist-directives", function() { + const reRegex = /^\/.+\/$/; + + return { + token: function token(stream) { + const line = stream.string.trim(); + stream.skipToEnd(); + if ( reBadHostname === undefined ) { + return null; + } + if ( reComment.test(line) ) { + return 'comment'; + } + if ( line.indexOf('/') === -1 ) { + if ( reBadHostname.test(line) ) { return 'error'; } + if ( whitelistDefaultSet.has(line.trim()) ) { + return 'keyword'; + } + return null; + } + if ( reRegex.test(line) ) { + try { + new RegExp(line.slice(1, -1)); + } catch { + return 'error'; + } + return null; + } + if ( reHostnameExtractor.test(line) === false ) { + return 'error'; + } + if ( whitelistDefaultSet.has(line.trim()) ) { + return 'keyword'; + } + return null; + } + }; +}); + +let reBadHostname; +let reHostnameExtractor; +let whitelistDefaultSet = new Set(); + +/******************************************************************************/ + +const messaging = vAPI.messaging; +const noopFunc = function(){}; + +let cachedWhitelist = ''; + +const cmEditor = new CodeMirror(qs$('#whitelist'), { + autofocus: true, + lineNumbers: true, + lineWrapping: true, + styleActiveLine: true, +}); + +uBlockDashboard.patchCodeMirrorEditor(cmEditor); + +/******************************************************************************/ + +function getEditorText() { + const text = cmEditor.getValue().trimEnd(); + return text === '' ? text : `${text}\n`; +} + +function setEditorText(text) { + cmEditor.setValue(`${text.trimEnd()}\n`); +} + +/******************************************************************************/ + +function whitelistChanged() { + const whitelistElem = qs$('#whitelist'); + const bad = qs$(whitelistElem, '.cm-error') !== null; + const changedWhitelist = getEditorText().trim(); + const changed = changedWhitelist !== cachedWhitelist; + qs$('#whitelistApply').disabled = !changed || bad; + qs$('#whitelistRevert').disabled = !changed; + CodeMirror.commands.save = changed && !bad ? applyChanges : noopFunc; +} + +cmEditor.on('changes', whitelistChanged); + +/******************************************************************************/ + +async function renderWhitelist() { + const details = await messaging.send('dashboard', { + what: 'getWhitelist', + }); + + const first = reBadHostname === undefined; + if ( first ) { + reBadHostname = new RegExp(details.reBadHostname); + reHostnameExtractor = new RegExp(details.reHostnameExtractor); + whitelistDefaultSet = new Set(details.whitelistDefault); + } + const toAdd = new Set(whitelistDefaultSet); + for ( const line of details.whitelist ) { + const directive = directiveFromLine(line); + if ( whitelistDefaultSet.has(directive) === false ) { continue; } + toAdd.delete(directive); + if ( toAdd.size === 0 ) { break; } + } + if ( toAdd.size !== 0 ) { + details.whitelist.push(...Array.from(toAdd).map(a => `# ${a}`)); + } + details.whitelist.sort((a, b) => { + const ad = directiveFromLine(a); + const bd = directiveFromLine(b); + const abuiltin = whitelistDefaultSet.has(ad); + if ( abuiltin !== whitelistDefaultSet.has(bd) ) { + return abuiltin ? -1 : 1; + } + return ad.localeCompare(bd); + }); + const whitelistStr = details.whitelist.join('\n').trim(); + cachedWhitelist = whitelistStr; + setEditorText(whitelistStr); + if ( first ) { + cmEditor.clearHistory(); + } +} + +/******************************************************************************/ + +function handleImportFilePicker() { + const file = this.files[0]; + if ( file === undefined || file.name === '' ) { return; } + if ( file.type.indexOf('text') !== 0 ) { return; } + const fr = new FileReader(); + fr.onload = ev => { + if ( ev.type !== 'load' ) { return; } + const content = uBlockDashboard.mergeNewLines( + getEditorText().trim(), + fr.result.trim() + ); + setEditorText(content); + }; + fr.readAsText(file); +} + +/******************************************************************************/ + +function startImportFilePicker() { + const input = qs$('#importFilePicker'); + // 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(); +} + +/******************************************************************************/ + +function exportWhitelistToFile() { + const val = getEditorText(); + if ( val === '' ) { return; } + const filename = + i18n$('whitelistExportFilename') + .replace('{{datetime}}', uBlockDashboard.dateNowToSensibleString()) + .replace(/ +/g, '_'); + vAPI.download({ + 'url': `data:text/plain;charset=utf-8,${encodeURIComponent(val + '\n')}`, + 'filename': filename + }); +} + +/******************************************************************************/ + +async function applyChanges() { + cachedWhitelist = getEditorText().trim(); + await messaging.send('dashboard', { + what: 'setWhitelist', + whitelist: cachedWhitelist, + }); + renderWhitelist(); +} + +function revertChanges() { + setEditorText(cachedWhitelist); +} + +/******************************************************************************/ + +function getCloudData() { + return getEditorText(); +} + +function setCloudData(data, append) { + if ( typeof data !== 'string' ) { return; } + if ( append ) { + data = uBlockDashboard.mergeNewLines(getEditorText().trim(), data); + } + setEditorText(data.trim()); +} + +self.cloud.onPush = getCloudData; +self.cloud.onPull = setCloudData; + +/******************************************************************************/ + +self.wikilink = 'https://github.com/gorhill/uBlock/wiki/Dashboard:-Trusted-sites'; + +self.hasUnsavedData = function() { + return getEditorText().trim() !== cachedWhitelist; +}; + +/******************************************************************************/ + +dom.on('#importWhitelistFromFile', 'click', startImportFilePicker); +dom.on('#importFilePicker', 'change', handleImportFilePicker); +dom.on('#exportWhitelistToFile', 'click', exportWhitelistToFile); +dom.on('#whitelistApply', 'click', ( ) => { applyChanges(); }); +dom.on('#whitelistRevert', 'click', revertChanges); + +renderWhitelist(); + +/******************************************************************************/ |