'use strict'; // ----------------- Internationalization ------------------ document.querySelectorAll('[data-i18n]').forEach(node => { let [text, attr] = node.dataset.i18n.split('|'); text = chrome.i18n.getMessage(text); attr ? node[attr] = text : node.appendChild(document.createTextNode(text)); }); // ----------------- /Internationalization ----------------- document.addEventListener('keyup', evt => { if (evt.keyCode === 27) { history.back(); // We either came from /proxy.html or /options.html } }); // ----------------- Spinner ------------------------------- const spinner = document.querySelector('.spinner'); function hideSpinner() { spinner.classList.remove('on'); setTimeout(() => { spinner.style.display = 'none'; }, 600); } function showSpinner() { spinner.style.display = 'flex'; spinner.classList.add('on'); } // ----------------- /spinner ------------------------------ // ----- global let proxy = {}; const header = document.querySelector('.header'); const tbody = document.querySelectorAll('tbody'); // there are 2 const template = document.querySelector('tr.template'); const docfrag = document.createDocumentFragment(); const defaultPattern = { title: '', active: true, pattern: '', type: 1, // PATTERN_TYPE_WILDCARD, protocols: 1 // PROTOCOL_ALL }; const protocolSet = { // converting to meaningful terms 1: 'All', 2: 'HTTP', 4: 'HTTPS' }; const patternTypeSet = { 1: 'wildcard', 2: 'Reg Exp' } // ----- check for Edit const id = localStorage.getItem('id'); const sync = localStorage.getItem('sync') === 'true'; const storageArea = !sync ? chrome.storage.local : chrome.storage.sync; if (id) { // This is an edit operation storageArea.get(id, result => { if (!Object.keys(result).length) { /* if (id === LASTRESORT) { // error prevention proxy = DEFAULT_PROXY_SETTING; processOptions(); return; }*/ console.error('Unable to edit saved proxy (could not get existing settings)') return; } proxy = result[id]; if (proxy.title) { header.textContent = chrome.i18n.getMessage('editPatternsFor', proxy.title); } processOptions(); hideSpinner(); }) } /* else { // Error, shouldn't ever get here hideSpinner(); document.querySelector('#error').classList.remove('hide'); document.querySelector('.main').classList.add('hide'); console.error("2: Unable to read saved proxy proxy (could not get existing settings)"); }*/ // --- processing all buttons document.querySelectorAll('button').forEach(item => item.addEventListener('click', process)); function process() { switch (this.dataset.i18n) { case 'back': // error case 'cancel': location.href = '/options.html'; break; case 'exportPatterns': exportPatterns(); break; case 'newWhite': addNew(tbody[0], 'whitePatterns'); break; case 'newBlack': addNew(tbody[1], 'blackPatterns'); break; case 'save': checkOptions(); break; case 'add': if (typeof(this.dataset.black) !== 'undefined') { proxy.blackPatterns.push(...blacklistSet); processOptions(); } else { proxy.whitePatterns.push(PATTERN_ALL_WHITE); processOptions(); } break; } } function processOptions() { // clearing the content tbody[0].textContent = ''; tbody[1].textContent = ''; proxy.whitePatterns.forEach((item, index) => docfrag.appendChild(makeRow(item, index, 'whitePatterns'))); docfrag.hasChildNodes() && tbody[0].appendChild(docfrag); proxy.blackPatterns.forEach((item, index) => docfrag.appendChild(makeRow(item, index, 'blackPatterns'))); docfrag.hasChildNodes() && tbody[1].appendChild(docfrag); } function makeRow(pat, index, bw) { const tr = template.cloneNode(true); tr.classList.remove('template'); tr.classList.add(pat.active ? 'success' : 'secondary'); tr.dataset.idx = index; tr.dataset.bw = bw; // black/white const td = tr.children; td[0].children[0].value = pat.title; td[1].children[0].value = pat.pattern; td[2].children[0].value = pat.type; td[3].children[0].value = pat.protocols; td[4].children[0].checked = pat.active; td[4].children[0].id = bw + index; td[4].children[1].setAttribute('for', td[4].children[0].id); pat.importedPattern && td[5].children[0].classList.remove('hide'); // add Listeners(); [...td[5].children].forEach(item => item.addEventListener('click', processEdit)); return tr; } function addNew(parent, bw) { const tr = makeRow(defaultPattern, parent.children.length, bw); parent.appendChild(tr); tr.children[1].children[0].focus(); } function processEdit() { const parent = this.parentNode.parentNode; const idx = parent.dataset.idx *1; const patternsArray = proxy[parent.dataset.bw]; // whitePatterns | blackPatterns switch (this.dataset.i18n) { case 'imported|title': alert(chrome.i18n.getMessage('importedPattern') + ' \n\n' + patternsArray[idx].importedPattern); break; case 'patternTester|title': const pat = patternsArray[idx]; if (pat) { localStorage.setItem('pattern', pat.pattern); localStorage.setItem('type', pat.type); localStorage.setItem('protocols', pat.protocols); } chrome.tabs.create({url: '/pattern-tester.html'}); break; case 'delete|title': parent.style.opacity = 0; setTimeout(() => { parent.remove(); }, 300); // remove row break; } } function checkOptions() { const pxy = { whitePatterns: [], blackPatterns: [] }; // use for loop to be able to return early on error for (const item of document.querySelectorAll('tr[data-idx]')) { const td = item.children; // --- trim text values [td[0].children[0], td[1].children[0]].forEach(item => item.value = item.value.trim()); // test pattern const regex = testPattern(td[1].children[0], td[2].children[0]); if (!regex) { return; } const bw = item.dataset.bw; pxy[bw].push({ title: td[0].children[0].value, pattern: td[1].children[0].value, type: td[2].children[0].value *1, protocols: td[3].children[0].value *1, active: td[4].children[0].checked }); } // all patterns passed proxy.whitePatterns = pxy.whitePatterns; proxy.blackPatterns = pxy.blackPatterns; storageArea.set({[id]: proxy}, () => location.href = '/options.html'); } function testPattern(pattern, type) { // --- reset pattern.classList.remove('invalid'); result.classList.add('hide'); result.classList.remove('alert'); // --- pattern check return checkPattern(pattern, type); } function exportPatterns() { const tmpObject = {whitePatterns: proxy.whitePatterns, blackPatterns: proxy.blackPatterns}; const blob = new Blob([JSON.stringify(tmpObject, null, 2)], {type : 'text/plain'}); const filename = 'foxyproxy' + (proxy.title ? '-' + proxy.title : '') + '-patterns' + '_' + new Date().toISOString().substring(0, 10) + '.json'; chrome.downloads.download({ url: URL.createObjectURL(blob), filename, saveAs: true, conflictAction: 'uniquify' }, () => console.log('Export/download finished')); // wait for it to complete before returning } document.getElementById('file').addEventListener('change', processFileSelect); function processFileSelect(e) { const file = e.target.files[0]; Utils.importFile(file, ['application/json'], 1024*1024*5, 'json', imported => { proxy.whitePatterns = imported.whitePatterns; proxy.blackPatterns = imported.blackPatterns; processOptions(); Utils.notify(chrome.i18n.getMessage('importBW', [proxy.whitePatterns.length, proxy.blackPatterns.length])); }); }