diff --git a/edit/codemirror-default.js b/edit/codemirror-default.js index ca600532..a25efa73 100644 --- a/edit/codemirror-default.js +++ b/edit/codemirror-default.js @@ -1,4 +1,10 @@ -/* global CodeMirror prefs editor $ template */ +/* global + $ + CodeMirror + editor + prefs + t +*/ 'use strict'; @@ -183,7 +189,7 @@ // setTimeout(() => { // $('.CodeMirror-dialog', section).focus(); // }); - cm.openDialog(template.jumpToLine.cloneNode(true), str => { + cm.openDialog(t.template.jumpToLine.cloneNode(true), str => { const m = str.match(/^\s*(\d+)(?:\s*:\s*(\d+))?\s*$/); if (m) { cm.setCursor(m[1] - 1, m[2] ? m[2] - 1 : cur.ch); diff --git a/edit/edit.js b/edit/edit.js index 2e75d867..54c1f85f 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -26,7 +26,6 @@ setupLivePrefs SourceEditor t - tHTML tryCatch tryJSONparse */ @@ -449,7 +448,7 @@ function showHelp(title = '', body) { const contents = $('.contents', div); contents.textContent = ''; if (body) { - contents.appendChild(typeof body === 'string' ? tHTML(body) : body); + contents.appendChild(typeof body === 'string' ? t.HTML(body) : body); } $('.title', div).textContent = title; diff --git a/edit/global-search.js b/edit/global-search.js index 68cd2edc..ff18616f 100644 --- a/edit/global-search.js +++ b/edit/global-search.js @@ -1,5 +1,18 @@ -/* global CodeMirror focusAccessibility colorMimicry editor chromeLocal - onDOMready $ $$ $create t debounce tryRegExp stringAsRegExp template */ +/* global + $ + $$ + $create + chromeLocal + CodeMirror + colorMimicry + debounce + editor + focusAccessibility + onDOMready + stringAsRegExp + t + tryRegExp +*/ 'use strict'; onDOMready().then(() => { @@ -563,14 +576,14 @@ onDOMready().then(() => { state.originalFocus = document.activeElement; state.firstRun = true; - const dialog = state.dialog = template.searchReplaceDialog.cloneNode(true); + const dialog = state.dialog = t.template.searchReplaceDialog.cloneNode(true); Object.assign(dialog, DIALOG_PROPS.dialog); dialog.addEventListener('focusout', EVENTS.onfocusout); dialog.dataset.type = type; dialog.style.pointerEvents = 'auto'; const content = $('[data-type="content"]', dialog); - content.parentNode.replaceChild(template[type].cloneNode(true), content); + content.parentNode.replaceChild(t.template[type].cloneNode(true), content); createInput(0, 'input', state.find); createInput(1, 'input2', state.replace); @@ -633,7 +646,7 @@ onDOMready().then(() => { input.value = value; Object.assign(input, DIALOG_PROPS[name]); - input.parentElement.appendChild(template.clearSearch.cloneNode(true)); + input.parentElement.appendChild(t.template.clearSearch.cloneNode(true)); $('[data-action]', input.parentElement)._input = input; } diff --git a/edit/moz-section-widget.js b/edit/moz-section-widget.js index 3526874f..fcb6fce5 100644 --- a/edit/moz-section-widget.js +++ b/edit/moz-section-widget.js @@ -9,7 +9,6 @@ prefs regExpTester t - template tryCatch */ 'use strict'; @@ -55,7 +54,7 @@ function MozSectionWidget( $create('ul' + C_LIST), ]), listItem: - template.appliesTo.cloneNode(true), + t.template.appliesTo.cloneNode(true), appliesToEverything: $create('li.applies-to-everything', t('appliesToEverything')), }; diff --git a/edit/regexp-tester.js b/edit/regexp-tester.js index 5b7bf13e..82fab8ab 100644 --- a/edit/regexp-tester.js +++ b/edit/regexp-tester.js @@ -1,4 +1,12 @@ -/* global showHelp $ $create tryRegExp URLS t template openURL */ +/* global + $ + $create + openURL + showHelp + t + tryRegExp + URLS +*/ /* exported regExpTester */ 'use strict'; @@ -86,7 +94,7 @@ const regExpTester = (() => { full: {data: [], label: t('styleRegexpTestFull')}, partial: {data: [], label: [ t('styleRegexpTestPartial'), - template.regexpTestPartial.cloneNode(true), + t.template.regexpTestPartial.cloneNode(true), ]}, none: {data: [], label: t('styleRegexpTestNone')}, invalid: {data: [], label: t('styleRegexpTestInvalid')}, diff --git a/edit/sections-editor-section.js b/edit/sections-editor-section.js index 0bd7a35a..f094286c 100644 --- a/edit/sections-editor-section.js +++ b/edit/sections-editor-section.js @@ -9,7 +9,6 @@ prefs regExpTester t - template trimCommentLabel tryRegExp */ @@ -26,7 +25,7 @@ function createSection(originalSection, genId, si) { const {dirty} = editor; const sectionId = genId(); - const el = template.section.cloneNode(true); + const el = t.template.section.cloneNode(true); const elLabel = $('.code-label', el); const cm = cmFactory.create(wrapper => { // making it tall during initial load so IntersectionObserver sees only one adjacent CM @@ -265,8 +264,8 @@ function createSection(originalSection, genId, si) { function createApply({type = 'url', value, all = false}) { const applyId = genId(); const dirtyPrefix = `section.${sectionId}.apply.${applyId}`; - const el = all ? template.appliesToEverything.cloneNode(true) : - template.appliesTo.cloneNode(true); + const el = all ? t.template.appliesToEverything.cloneNode(true) : + t.template.appliesTo.cloneNode(true); const selectEl = !all && $('.applies-type', el); if (selectEl) { @@ -359,7 +358,7 @@ function createSection(originalSection, genId, si) { function createResizeGrip(cm) { const wrapper = cm.display.wrapper; wrapper.classList.add('resize-grip-enabled'); - const resizeGrip = template.resizeGrip.cloneNode(true); + const resizeGrip = t.template.resizeGrip.cloneNode(true); wrapper.appendChild(resizeGrip); let lastClickTime = 0; let initHeight; diff --git a/edit/show-keymap-help.js b/edit/show-keymap-help.js index 66cf08ea..b17971b7 100644 --- a/edit/show-keymap-help.js +++ b/edit/show-keymap-help.js @@ -1,5 +1,14 @@ -/* global CodeMirror showHelp onDOMready $ $$ $create template t - prefs stringAsRegExp */ +/* global + $ + $$ + $create + CodeMirror + onDOMready + prefs + showHelp + stringAsRegExp + t +*/ 'use strict'; onDOMready().then(() => { @@ -11,7 +20,7 @@ function showKeyMapHelp() { const keyMapSorted = Object.keys(keyMap) .map(key => ({key, cmd: keyMap[key]})) .sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1)); - const table = template.keymapHelp.cloneNode(true); + const table = t.template.keymapHelp.cloneNode(true); const tBody = table.tBodies[0]; const row = tBody.rows[0]; const cellA = row.children[0]; diff --git a/js/localization.js b/js/localization.js index 84cbc1e8..68656d55 100644 --- a/js/localization.js +++ b/js/localization.js @@ -1,97 +1,90 @@ -/* global tryCatch */ -/* exported tHTML formatDate */ 'use strict'; -const template = {}; -tDocLoader(); - - function t(key, params) { const s = chrome.i18n.getMessage(key, params); if (!s) throw `Missing string "${key}"`; return s; } +Object.assign(t, { + template: {}, + DOMParser: new DOMParser(), + ALLOWED_TAGS: 'a,b,code,i,sub,sup,wbr'.split(','), + RX_WORD_BREAK: new RegExp([ + '(', + /[\d\w\u007B-\uFFFF]{10}/, + '|', + /[\d\w\u007B-\uFFFF]{5,10}[!-/]/, + '|', + /((?!\s)\W){10}/, + ')', + /(?!\b|\s|$)/, + ].map(rx => rx.source || rx).join(''), 'g'), -function tHTML(html, tag) { - // body is a text node without HTML tags - if (typeof html === 'string' && !tag && /<\w+/.test(html) === false) { - return document.createTextNode(html); - } - if (typeof html === 'string') { - // spaces are removed; use   for an explicit space - html = html.replace(/>\s+<').trim(); - if (tag) { - html = `<${tag}>${html}`; - } - const body = t.DOMParser.parseFromString(html, 'text/html').body; - if (html.includes('i18n-')) { - tNodeList(body.getElementsByTagName('*')); - } - // the html string may contain more than one top-level node - if (!body.childNodes[1]) { - return body.firstChild; - } - const fragment = document.createDocumentFragment(); - while (body.firstChild) { - fragment.appendChild(body.firstChild); - } - return fragment; - } - return html; -} + HTML(html) { + return typeof html !== 'string' + ? html + : /<\w+/.test(html) // check for html tags + ? t.createHtml(html.replace(/>\n\s*<').trim()) + : document.createTextNode(html); + }, - -function tNodeList(nodes) { - const PREFIX = 'i18n-'; - - for (let n = nodes.length; --n >= 0;) { - const node = nodes[n]; - if (node.nodeType !== Node.ELEMENT_NODE) { - continue; - } - if (node.localName === 'template') { - createTemplate(node); - continue; - } - for (let a = node.attributes.length; --a >= 0;) { - const attr = node.attributes[a]; - const name = attr.nodeName; - if (!name.startsWith(PREFIX)) { + NodeList(nodes) { + const PREFIX = 'i18n-'; + for (let n = nodes.length; --n >= 0;) { + const node = nodes[n]; + if (node.nodeType !== Node.ELEMENT_NODE) { continue; } - const type = name.substr(PREFIX.length); - const value = t(attr.value); - let toInsert, before; - switch (type) { - case 'word-break': - // we already know that: hasWordBreak - break; - case 'text': - before = node.firstChild; - // fallthrough to text-append - case 'text-append': - toInsert = createText(value); - break; - case 'html': { - toInsert = createHtml(value); - break; + if (node.localName === 'template') { + t.createTemplate(node); + continue; + } + for (let a = node.attributes.length; --a >= 0;) { + const attr = node.attributes[a]; + const name = attr.nodeName; + if (!name.startsWith(PREFIX)) { + continue; } - default: - node.setAttribute(type, value); + const type = name.substr(PREFIX.length); + const value = t(attr.value); + let toInsert, before; + switch (type) { + case 'word-break': + // we already know that: hasWordBreak + break; + case 'text': + before = node.firstChild; + // fallthrough to text-append + case 'text-append': + toInsert = t.createText(value); + break; + case 'html': { + toInsert = t.createHtml(value); + break; + } + default: + node.setAttribute(type, value); + } + t.stopObserver(); + if (toInsert) { + node.insertBefore(toInsert, before || null); + } + node.removeAttribute(name); } - tDocLoader.pause(); - if (toInsert) { - node.insertBefore(toInsert, before || null); - } - node.removeAttribute(name); } - } + }, - function createTemplate(node) { + /** Adds soft hyphens every 10 characters to ensure the long words break before breaking the layout */ + breakWord(text) { + return text.length <= 10 ? text : + text.replace(t.RX_WORD_BREAK, '$&\u00AD'); + }, + + createTemplate(node) { const elements = node.content.querySelectorAll('*'); - tNodeList(elements); - template[node.dataset.id] = elements[0]; + t.NodeList(elements); + t.template[node.dataset.id] = elements[0]; // compress inter-tag whitespace to reduce number of DOM nodes by 25% const walker = document.createTreeWalker(elements[0], NodeFilter.SHOW_TEXT); const toRemove = []; @@ -101,104 +94,96 @@ function tNodeList(nodes) { toRemove.push(textNode); } } - tDocLoader.pause(); + t.stopObserver(); toRemove.forEach(el => el.remove()); - } + }, - function createText(str) { - return document.createTextNode(tWordBreak(str)); - } + createText(str) { + return document.createTextNode(t.breakWord(str)); + }, - function createHtml(value) { - // and are the only acceptable HTML elements, - // also allows `href` attribute with an http/https URL - const rx = /(<)(a|code)(\s[^>]*|)>(.*?)<\/\2>/i; + createHtml(str, trusted) { + const root = t.DOMParser.parseFromString(str, 'text/html').body; + if (!trusted) { + t.sanitizeHtml(root); + } else if (str.includes('i18n-')) { + t.NodeList(root.getElementsByTagName('*')); + } const bin = document.createDocumentFragment(); - for (let parts = value.split(rx), i = 0; i < parts.length; i++) { - const s = parts[i]; - if (s === '<') { - const tag = parts[++i].toLowerCase(); - const el = bin.appendChild(document.createElement(tag)); - const attrs = parts[++i]; - const href = tag === 'a' && /(?:^|\s)href\s*=\s*(["'])?(https?:\/\/\S*?)\1/i.exec(attrs); - if (href) el.href = href[2]; - el.appendChild(createText(parts[++i])); - } else { - bin.appendChild(createText(s)); - } + while (root.firstChild) { + bin.appendChild(root.firstChild); } return bin; - } -} + }, - -function tDocLoader() { - t.DOMParser = new DOMParser(); - t.RX_WORD_BREAK = new RegExp([ - '(', - /[\d\w\u007B-\uFFFF]{10}/, - '|', - /[\d\w\u007B-\uFFFF]{5,10}[!-/]/, - '|', - /((?!\s)\W){10}/, - ')', - /(?!\b|\s|$)/, - ].map(rx => rx.source || rx).join(''), 'g'); - - Object.assign(tDocLoader, { - observer: new MutationObserver(process), - start() { - if (!tDocLoader.observing) { - tDocLoader.observing = true; - tDocLoader.observer.observe(document, {subtree: true, childList: true}); + sanitizeHtml(root) { + const toRemove = []; + const walker = document.createTreeWalker(root); + for (let n; (n = walker.nextNode());) { + if (n.nodeType === Node.TEXT_NODE) { + n.nodeValue = t.breakWord(n.nodeValue); + } else if (t.ALLOWED_TAGS.includes(n.localName)) { + for (const attr of n.attributes) { + if (n.localName !== 'a' || attr.localName !== 'href' || !/^https?:/.test(n.href)) { + n.removeAttribute(attr.name); + } + } + } else { + toRemove.push(n); } - }, - stop() { - tDocLoader.pause(); - document.removeEventListener('DOMContentLoaded', onLoad); - }, - pause() { - if (tDocLoader.observing) { - tDocLoader.observing = false; - tDocLoader.observer.disconnect(); + } + for (const n of toRemove) { + const parent = n.parentNode; + if (parent) parent.removeChild(n); // not using .remove() as there may be a non-element + } + }, + + formatDate(date) { + if (!date) { + return ''; + } + try { + const newDate = new Date(Number(date) || date); + const string = newDate.toLocaleDateString([chrome.i18n.getUILanguage(), 'en'], { + day: '2-digit', + month: 'short', + year: newDate.getYear() === new Date().getYear() ? undefined : '2-digit', + }); + return string === 'Invalid Date' ? '' : string; + } catch (e) { + return ''; + } + }, +}); + +(() => { + const observer = new MutationObserver(process); + let observing = false; + Object.assign(t, { + stopObserver() { + if (observing) { + observing = false; + observer.disconnect(); } }, }); + document.addEventListener('DOMContentLoaded', () => { + process(observer.takeRecords()); + t.stopObserver(); + }, {once: true}); - tNodeList(document.getElementsByTagName('*')); - tDocLoader.start(); - document.addEventListener('DOMContentLoaded', onLoad); + t.NodeList(document.getElementsByTagName('*')); + start(); function process(mutations) { - for (const mutation of mutations) { - tNodeList(mutation.addedNodes); + mutations.forEach(m => t.NodeList(m.addedNodes)); + start(); + } + + function start() { + if (!observing) { + observing = true; + observer.observe(document, {subtree: true, childList: true}); } - tDocLoader.start(); } - - function onLoad() { - document.removeEventListener('DOMContentLoaded', onLoad); - process(tDocLoader.observer.takeRecords()); - tDocLoader.stop(); - } -} - - -function tWordBreak(text) { - // adds soft hyphens every 10 characters to ensure the long words break before breaking the layout - return text.length <= 10 ? text : - text.replace(t.RX_WORD_BREAK, '$&\u00AD'); -} - - -function formatDate(date) { - return !date ? '' : tryCatch(() => { - const newDate = new Date(Number(date) || date); - const string = newDate.toLocaleDateString([t.cache.browserUIlanguage, 'en'], { - day: '2-digit', - month: 'short', - year: newDate.getYear() === new Date().getYear() ? undefined : '2-digit', - }); - return string === 'Invalid Date' ? '' : string; - }) || ''; -} +})(); diff --git a/manage/config-dialog.js b/manage/config-dialog.js index 8d5d1751..75a408b0 100644 --- a/manage/config-dialog.js +++ b/manage/config-dialog.js @@ -1,5 +1,15 @@ -/* global messageBox deepCopy $create $createLink $ t tWordBreak - prefs setupLivePrefs debounce API */ +/* global + $ + $create + $createLink + API + debounce + deepCopy + messageBox + prefs + setupLivePrefs + t +*/ /* exported configDialog */ 'use strict'; @@ -305,7 +315,7 @@ function configDialog(style) { elements.push( $create(`label.config-${va.type}`, [ - $create('span.config-name', tWordBreak(va.label)), + $create('span.config-name', t.breakWord(va.label)), ...children, resetter, ])); diff --git a/manage/manage.js b/manage/manage.js index 813ad815..00ebc828 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -9,7 +9,6 @@ configDialog debounce filterAndAppend - formatDate getOwnTab getStyleWithNoCode handleUpdateInstalled @@ -25,8 +24,6 @@ showFiltersStats sorter t - template - tWordBreak VIVALDI */ 'use strict'; @@ -187,7 +184,7 @@ function showStyles(styles = [], matchUrlIds) { function createStyleElement({style, name: nameLC}) { // query the sub-elements just once, then reuse the references if ((createStyleElement.parts || {}).newUI !== newUI.enabled) { - const entry = template[`style${newUI.enabled ? 'Compact' : ''}`]; + const entry = t.template[`style${newUI.enabled ? 'Compact' : ''}`]; createStyleElement.parts = { newUI: newUI.enabled, entry, @@ -197,7 +194,7 @@ function createStyleElement({style, name: nameLC}) { editLink: $('.style-edit-link', entry) || {}, editHrefBase: 'edit.html?id=', homepage: $('.homepage', entry), - homepageIcon: template[`homepageIcon${newUI.enabled ? 'Small' : 'Big'}`], + homepageIcon: t.template[`homepageIcon${newUI.enabled ? 'Small' : 'Big'}`], appliesTo: $('.applies-to', entry), targets: $('.targets', entry), expander: $('.expander', entry), @@ -215,7 +212,7 @@ function createStyleElement({style, name: nameLC}) { const configurable = style.usercssData && style.usercssData.vars && Object.keys(style.usercssData.vars).length > 0; const name = style.customName || style.name; parts.checker.checked = style.enabled; - parts.nameLink.textContent = tWordBreak(name); + parts.nameLink.textContent = t.breakWord(name); parts.nameLink.href = parts.editLink.href = parts.editHrefBase + style.id; parts.homepage.href = parts.homepage.title = style.url || ''; if (!newUI.enabled) { @@ -243,10 +240,10 @@ function createStyleElement({style, name: nameLC}) { $('.homepage', entry).appendChild(parts.homepageIcon.cloneNode(true)); } if (style.updateUrl && newUI.enabled) { - $('.actions', entry).appendChild(template.updaterIcons.cloneNode(true)); + $('.actions', entry).appendChild(t.template.updaterIcons.cloneNode(true)); } if (configurable && newUI.enabled) { - $('.actions', entry).appendChild(template.configureIcon.cloneNode(true)); + $('.actions', entry).appendChild(t.template.configureIcon.cloneNode(true)); } createStyleTargetsElement({entry, style}); @@ -287,12 +284,12 @@ function createStyleTargetsElement({entry, expanded, style = entry.styleMeta}) { el = next; continue; } - const element = template.appliesToTarget.cloneNode(true); + const element = t.template.appliesToTarget.cloneNode(true); if (!newUI.enabled) { if (numTargets === maxTargets) { - container = container.appendChild(template.extraAppliesTo.cloneNode(true)); + container = container.appendChild(t.template.extraAppliesTo.cloneNode(true)); } else if (numTargets > 0) { - container.appendChild(template.appliesToSeparator.cloneNode(true)); + container.appendChild(t.template.appliesToSeparator.cloneNode(true)); } } element.dataset.type = type; @@ -311,7 +308,7 @@ function createStyleTargetsElement({entry, expanded, style = entry.styleMeta}) { if (entryTargets.firstElementChild) { entryTargets.textContent = ''; } - entryTargets.appendChild(template.appliesToEverything.cloneNode(true)); + entryTargets.appendChild(t.template.appliesToEverything.cloneNode(true)); } entry.classList.toggle('global', !numTargets); entry._allTargetsRendered = allTargetsRendered; @@ -525,7 +522,7 @@ Object.assign(handleEvent, { {prop: 'installDate', name: 'dateInstalled'}, {prop: 'updateDate', name: 'dateUpdated'}, ].map(({prop, name}) => - t(name) + ': ' + (formatDate(entry.styleMeta[prop]) || '—')).join('\n'); + t(name) + ': ' + (t.formatDate(entry.styleMeta[prop]) || '—')).join('\n'); }, }); diff --git a/msgbox/msgbox.js b/msgbox/msgbox.js index f9d2579b..21fc63c6 100644 --- a/msgbox/msgbox.js +++ b/msgbox/msgbox.js @@ -1,11 +1,18 @@ -/* global focusAccessibility moveFocus $ $create t tHTML animateElement */ +/* global + $ + $create + animateElement + focusAccessibility + moveFocus + t +*/ 'use strict'; /** * @param {Object} params * @param {String} params.title * @param {String|Node|Object|Array} params.contents - * a string gets parsed via tHTML, + * a string gets parsed via t.HTML, * a non-string is passed as is to $create() * @param {String} [params.className] * CSS class name of the message box element @@ -116,7 +123,7 @@ function messageBox({ $create('SVG:path', {d: 'M11.69,10l4.55,4.55-1.69,1.69L10,11.69,' + '5.45,16.23,3.77,14.55,8.31,10,3.77,5.45,5.45,3.77,10,8.31l4.55-4.55,1.69,1.69Z', }))), - $create(`#${id}-contents`, tHTML(contents)), + $create(`#${id}-contents`, t.HTML(contents)), $create(`#${id}-buttons`, buttons.map((content, buttonIndex) => content && $create('button', Object.assign({ diff --git a/popup/popup.js b/popup/popup.js index 899231ad..dbe355fe 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -1,7 +1,23 @@ -/* global configDialog hotkeys msg - getActiveTab CHROME FIREFOX URLS API onDOMready $ $$ prefs - setupLivePrefs template t $create animateElement - tryJSONparse CHROME_HAS_BORDER_BUG */ +/* global + $ + $$ + $create + animateElement + API + CHROME + CHROME_HAS_BORDER_BUG + configDialog + FIREFOX + getActiveTab + hotkeys + msg + onDOMready + prefs + setupLivePrefs + t + tryJSONparse + URLS +*/ 'use strict'; @@ -165,7 +181,7 @@ function initPopup(frames) { setTimeout(ping, 100, tab, --retryCountdown); return; } - const info = template.unreachableInfo; + const info = t.template.unreachableInfo; if (!FIREFOX) { // Chrome "Allow access to file URLs" in chrome://extensions message info.appendChild($create('p', t('unreachableFileHint'))); @@ -204,7 +220,7 @@ function createWriterElement(frame) { const targets = $create('span'); // For this URL - const urlLink = template.writeStyle.cloneNode(true); + const urlLink = t.template.writeStyle.cloneNode(true); const isAboutBlank = url === ABOUT_BLANK; Object.assign(urlLink, { href: 'edit.html?url-prefix=' + encodeURIComponent(url), @@ -233,7 +249,7 @@ function createWriterElement(frame) { if (domains.length > 1 && numParts === 1) { continue; } - const domainLink = template.writeStyle.cloneNode(true); + const domainLink = t.template.writeStyle.cloneNode(true); Object.assign(domainLink, { href: 'edit.html?domain=' + encodeURIComponent(domain), textContent: numParts > 2 ? domain.split('.')[0] : domain, @@ -322,7 +338,7 @@ function showStyles(frameResults) { if (entries.size) { resortEntries([...entries.values()]); } else { - installed.appendChild(template.noStyles); + installed.appendChild(t.template.noStyles); } window.dispatchEvent(new Event('showStyles:done')); } @@ -337,7 +353,7 @@ function resortEntries(entries) { function createStyleElement(style) { let entry = $.entry(style); if (!entry) { - entry = template.style.cloneNode(true); + entry = t.template.style.cloneNode(true); entry.setAttribute('style-id', style.id); Object.assign(entry, { id: ENTRY_ID_PREFIX_RAW + style.id, @@ -384,7 +400,7 @@ function createStyleElement(style) { $('.delete', entry).onclick = handleEvent.delete; - const indicator = template.regexpProblemIndicator.cloneNode(true); + const indicator = t.template.regexpProblemIndicator.cloneNode(true); indicator.appendChild(document.createTextNode('!')); indicator.onclick = handleEvent.indicator; $('.main-controls', entry).appendChild(indicator); @@ -587,7 +603,7 @@ Object.assign(handleEvent, { indicator(event) { const entry = handleEvent.getClickedStyleElement(event); - const info = template.regexpProblemExplanation.cloneNode(true); + const info = t.template.regexpProblemExplanation.cloneNode(true); $.remove('#' + info.id); $$('a', info).forEach(el => (el.onclick = handleEvent.openURLandHide)); $$('button', info).forEach(el => (el.onclick = handleEvent.closeExplanation)); @@ -684,7 +700,7 @@ function handleDelete(id) { const el = $.entry(id); if (el) { el.remove(); - if (!$('.entry')) installed.appendChild(template.noStyles); + if (!$('.entry')) installed.appendChild(t.template.noStyles); } } @@ -714,9 +730,9 @@ async function getStyleDataMerged(url, id) { function blockPopup(isBlocked = true) { document.body.classList.toggle('blocked', isBlocked); if (isBlocked) { - document.body.prepend(template.unavailableInfo); + document.body.prepend(t.template.unavailableInfo); } else { - template.unavailableInfo.remove(); - template.noStyles.remove(); + t.template.unavailableInfo.remove(); + t.template.noStyles.remove(); } } diff --git a/popup/search-results.js b/popup/search-results.js index 3036145d..a5dd4bde 100755 --- a/popup/search-results.js +++ b/popup/search-results.js @@ -1,5 +1,18 @@ -/* global URLS tabURL handleEvent $ $$ prefs template FIREFOX debounce - $create t API tWordBreak formatDate tryCatch download */ +/* global + $ + $$ + $create + API + debounce + download + FIREFOX + handleEvent + prefs + t + tabURL + tryCatch + URLS +*/ 'use strict'; window.addEventListener('showStyles:done', () => { @@ -103,7 +116,7 @@ window.addEventListener('showStyles:done', () => { const navOnClick = {prev, next}; for (const place of ['top', 'bottom']) { const nav = $(`.search-results-nav[data-type="${place}"]`); - nav.appendChild(template.searchNav.cloneNode(true)); + nav.appendChild(t.template.searchNav.cloneNode(true)); dom.nav[place] = nav; for (const child of $$('[data-type]', nav)) { const type = child.dataset.type; @@ -257,7 +270,7 @@ window.addEventListener('showStyles:done', () => { * @returns {Node} */ function createSearchResultNode(result) { - const entry = template.searchResult.cloneNode(true); + const entry = t.template.searchResult.cloneNode(true); const { i: id, n: name, @@ -276,7 +289,7 @@ window.addEventListener('showStyles:done', () => { href: URLS.usoArchive + `?category=${category}&style=${id}`, }); $('.search-result-title span', entry).textContent = - tWordBreak(name.length < 300 ? name : name.slice(0, 300) + '...'); + t.breakWord(name.length < 300 ? name : name.slice(0, 300) + '...'); // screenshot const auto = URLS.uso + `auto_style_screenshots/${id}${USO_AUTO_PIC_SUFFIX}`; Object.assign($('.search-result-screenshot', entry), { @@ -303,7 +316,7 @@ window.addEventListener('showStyles:done', () => { // time Object.assign($('[data-type="updated"] time', entry), { dateTime: updateTime * 1000, - textContent: formatDate(updateTime * 1000), + textContent: t.formatDate(updateTime * 1000), }); // totals $('[data-type="weekly"] dd', entry).textContent = formatNumber(weeklyInstalls);