From 0440073853d7530ae605d56f3ba1e4a27c3200d5 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 23 May 2017 22:28:45 +0300 Subject: [PATCH 01/94] restore style code in popup::onMessage --- popup.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/popup.js b/popup.js index 9ac807be..fde184bf 100644 --- a/popup.js +++ b/popup.js @@ -22,7 +22,9 @@ function onRuntimeMessage(msg) { switch (msg.method) { case 'styleAdded': case 'styleUpdated': - handleUpdate(msg.style); + // notifyAllTabs sets msg.style's code to null so we have to get the actual style + // because we analyze its code in detectSloppyRegexps + handleUpdate(BG.cachedStyles.byId.get(msg.style.id)); break; case 'styleDeleted': handleDelete(msg.id); From 26f84c5852638fb52daf4a4a898d62de4a3157b6 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 23 May 2017 22:31:40 +0300 Subject: [PATCH 02/94] play safe in *Safe() as BG gets defined only in .then --- messaging.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/messaging.js b/messaging.js index 063f4a2a..c11e1f4c 100644 --- a/messaging.js +++ b/messaging.js @@ -272,13 +272,13 @@ function sessionStorageHash(name) { } -function onBackgroundReady(...dataPassthru) { - return BG ? Promise.resolve(...dataPassthru) : new Promise(ping); +function onBackgroundReady() { + return BG ? Promise.resolve() : new Promise(ping); function ping(resolve) { chrome.runtime.sendMessage({method: 'healthCheck'}, health => { if (health !== undefined) { BG = chrome.extension.getBackgroundPage(); - resolve(...dataPassthru); + resolve(); } else { ping(resolve); } @@ -289,13 +289,14 @@ function onBackgroundReady(...dataPassthru) { // in case Chrome haven't yet loaded the bg page and displays our page like edit/manage function getStylesSafe(options) { - return onBackgroundReady(options).then(BG.getStyles); + return onBackgroundReady() + .then(() => BG.getStyles(options)); } function saveStyleSafe(style) { - return onBackgroundReady(BG.deepCopy(style)) - .then(BG.saveStyle) + return onBackgroundReady() + .then(() => BG.saveStyle(BG.deepCopy(style))) .then(savedStyle => { if (style.notify === false) { handleUpdate(savedStyle, style); @@ -306,8 +307,8 @@ function saveStyleSafe(style) { function deleteStyleSafe({id, notify = true} = {}) { - return onBackgroundReady({id, notify}) - .then(BG.deleteStyle) + return onBackgroundReady() + .then(() => BG.deleteStyle({id, notify})) .then(() => { if (!notify) { handleDelete(id); From ddc5cc0ccfcad34efa899b545c43667c2459d3d4 Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 26 May 2017 20:48:26 +0300 Subject: [PATCH 03/94] beautify: option for indenting conditional blocks --- _locales/en/messages.json | 4 +++ beautify/beautify-css-mod.js | 56 +++++++++++++++++++++--------------- edit.js | 16 +++++++---- prefs.js | 2 +- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index b4ed254c..c3108037 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -498,6 +498,10 @@ "message": "Beautify", "description": "Label for the CSS-beautifier button on the edit style page" }, + "styleBeautifyIndentConditional": { + "message": "Indent @media, @supports", + "description": "CSS-beautifier option" + }, "styleCancelEditLabel": { "message": "Back to manage", "description": "Label for cancel button for style editing" diff --git a/beautify/beautify-css-mod.js b/beautify/beautify-css-mod.js index e7524144..c2e90f72 100644 --- a/beautify/beautify-css-mod.js +++ b/beautify/beautify-css-mod.js @@ -100,27 +100,26 @@ var newlinesFromLastWSEat = 0; var indentSize = options.indent_size ? parseInt(options.indent_size, 10) : 4; var indentCharacter = options.indent_char || ' '; - var preserve_newlines = (options.preserve_newlines === undefined) ? false : options.preserve_newlines; - var selectorSeparatorNewline = (options.selector_separator_newline === undefined) ? true : options.selector_separator_newline; - var end_with_newline = (options.end_with_newline === undefined) ? false : options.end_with_newline; - var newline_between_rules = (options.newline_between_rules === undefined) ? true : options.newline_between_rules; - var space_around_combinator = (options.space_around_combinator === undefined) ? false : options.space_around_combinator; - space_around_combinator = space_around_combinator || ((options.space_around_selector_separator === undefined) ? false : options.space_around_selector_separator); var eol = options.eol ? options.eol : 'auto'; + var { + preserve_newlines = false, + selector_separator_newline = true, + end_with_newline = false, + newline_between_rules = true, + space_around_combinator = true, + indent_conditional = true, + newline_between_properties = true, + newline_before_open_brace = false, + newline_after_open_brace = true, + newline_before_close_brace = true, + } = options; - /* STYLUS: hack start */ - const defaultOption = (opt, defaultValue) => opt === undefined ? defaultValue : opt; - var newline_between_properties = defaultOption(options.newline_between_properties, true); - var newline_before_open_brace = defaultOption(options.newline_before_open_brace, false); - var newline_after_open_brace = defaultOption(options.newline_after_open_brace, true); - var newline_before_close_brace = defaultOption(options.newline_before_close_brace, true); var translatePos = (options.translate_positions || [])[0]; var translatePosIndex = 0; var translatePosLine = translatePos && translatePos.line; var translatePosCol = translatePos && translatePos.ch; var inputPosLine = 0, inputPosCol = 0; var outputPosLine = 0, outputPosCol = 0; - /* STYLUS: hack end */ if (options.indent_with_tabs) { indentCharacter = '\t'; @@ -304,9 +303,11 @@ newline_before_open_brace ? print.newLine() : print.singleSpace(); output.push(ch); outputPosCol++; - indent(); + if (!enteringConditionalGroup || indent_conditional) { + indent(); + } if (!eatWhitespace(true)) { - newline_after_open_brace ? print.newLine() : print.singleSpace(); + newline_after_open_brace || enteringConditionalGroup ? print.newLine() : print.singleSpace(); } }; print["}"] = function(newline) { @@ -315,7 +316,7 @@ } output.push('}'); outputPosCol++; - if (!eatWhitespace(true)) { + if (!eatWhitespace(true) && peek(true) != '}') { print.newLine(); } }; @@ -386,6 +387,7 @@ var insideRule = false; var insidePropertyValue = false; var enteringConditionalGroup = false; + var insideConditionalGroup = false; var top_ch = ''; var last_top_ch = ''; @@ -438,13 +440,16 @@ print.singleSpace(); } - variableOrRule = variableOrRule.replace(/\s$/, ''); + variableOrRule = '@' + variableOrRule.replace(/\s$/, ''); // might be a nesting at-rule if (variableOrRule in css_beautify.NESTED_AT_RULE) { nestedLevel += 1; if (variableOrRule in css_beautify.CONDITIONAL_GROUP_RULE) { enteringConditionalGroup = true; + if (!indent_conditional) { + nestedLevel--; + } } } } @@ -467,6 +472,7 @@ // when entering conditional groups, only rulesets are allowed if (enteringConditionalGroup) { enteringConditionalGroup = false; + insideConditionalGroup = true; insideRule = (indentLevel > nestedLevel); } else { // otherwise, declarations are also allowed @@ -478,10 +484,14 @@ print["}"](true); insideRule = false; insidePropertyValue = false; - if (nestedLevel) { + if (nestedLevel && (indent_conditional || !insideConditionalGroup)) { nestedLevel--; } - if (newlinesFromLastWSEat < 2 && newline_between_rules && indentLevel === 0) { + insideConditionalGroup = false; + if (newlinesFromLastWSEat < 2 + && newline_between_rules + //&& indentLevel === 0 + && peek(true) != '}') { print.newLine(true); } } else if (ch === ":") { @@ -553,7 +563,7 @@ } else if (ch === ',') { output.push(ch); outputPosCol++; - if (!eatWhitespace(true) && selectorSeparatorNewline && !insidePropertyValue && parenLevel < 1) { + if (!eatWhitespace(true) && selector_separator_newline && !insidePropertyValue && parenLevel < 1) { print.newLine(); } else { print.singleSpace(); @@ -624,12 +634,12 @@ // also in CONDITIONAL_GROUP_RULE below "@media": true, "@supports": true, - "@document": true + "@-moz-document": true }; css_beautify.CONDITIONAL_GROUP_RULE = { "@media": true, "@supports": true, - "@document": true + "@-moz-document": true }; /*global define */ @@ -652,4 +662,4 @@ global.css_beautify = css_beautify; } -}()); \ No newline at end of file +}()); diff --git a/edit.js b/edit.js index dbbedf18..702c8046 100644 --- a/edit.js +++ b/edit.js @@ -1054,6 +1054,9 @@ function beautify(event) { optionHtml("border: none;", "newline_between_properties", true) + optionHtml("display: block;", "newline_before_close_brace", true) + optionHtml("}", "newline_between_rules") + + `' + "" + "
"); @@ -1096,13 +1099,14 @@ function beautify(event) { }, 0); }); - document.querySelector(".beautify-options").addEventListener("change", function(event) { - var value = event.target.selectedIndex > 0; - options[event.target.dataset.option] = value; - prefs.set("editor.beautify", options); - event.target.parentNode.setAttribute("newline", value.toString()); + document.querySelector('.beautify-options').onchange = ({target}) => { + const value = target.type == 'checkbox' ? target.checked : target.selectedIndex > 0; + prefs.set('editor.beautify', Object.assign(options, {[target.dataset.option]: value})); + if (target.parentNode.hasAttribute('newline')) { + target.parentNode.setAttribute('newline', value.toString()); + } doBeautify(); - }); + }; function optionHtml(label, optionName, indent) { var value = options[optionName]; diff --git a/prefs.js b/prefs.js index c632d1e9..00b74663 100644 --- a/prefs.js +++ b/prefs.js @@ -37,7 +37,7 @@ var prefs = new function Prefs() { newline_before_close_brace: true, newline_between_rules: false, end_with_newline: false, - space_around_selector_separator: true, + indent_conditional: true, }, 'editor.lintDelay': 500, // lint gutter marker update delay, ms 'editor.lintReportDelay': 4500, // lint report update delay, ms From 8bbab9e0e16c4ca6cfb6dbcee3bfde50d161822f Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 27 May 2017 11:38:13 +0300 Subject: [PATCH 04/94] beautify: don't add extra \n after comments --- beautify/beautify-css-mod.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/beautify/beautify-css-mod.js b/beautify/beautify-css-mod.js index c2e90f72..b5baa1fd 100644 --- a/beautify/beautify-css-mod.js +++ b/beautify/beautify-css-mod.js @@ -401,17 +401,12 @@ if (!ch) { break; } else if (ch === '/' && peek() === '*') { /* css comment */ - var header = indentLevel === 0; - - if (isAfterNewline || header) { + if (isAfterNewline) { print.newLine(); } print.text(eatComment()); print.newLine(); - if (header) { - print.newLine(true); - } } else if (ch === '/' && peek() === '/') { // single line comment if (!isAfterNewline && last_top_ch !== '{') { print.trim(); From 1098f2666c5aaff17bbe890dbde69af602f67a5a Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 26 May 2017 22:03:14 +0300 Subject: [PATCH 05/94] beautifier: reworded "Undo in all sections" label --- _locales/ar/messages.json | 4 ---- _locales/el/messages.json | 4 ---- _locales/en/messages.json | 2 +- _locales/fi/messages.json | 4 ---- _locales/fr/messages.json | 4 ---- _locales/it/messages.json | 4 ---- _locales/ja/messages.json | 4 ---- _locales/pt_BR/messages.json | 4 ---- _locales/sv/messages.json | 4 ---- _locales/sv_SE/messages.json | 4 ---- _locales/te/messages.json | 4 ---- _locales/tr/messages.json | 4 ---- _locales/zh/messages.json | 4 ---- 13 files changed, 1 insertion(+), 49 deletions(-) diff --git a/_locales/ar/messages.json b/_locales/ar/messages.json index 50c8f547..f6ec193f 100644 --- a/_locales/ar/messages.json +++ b/_locales/ar/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "اكتمل التحديث.", "description": "Text that displays when an update completed" diff --git a/_locales/el/messages.json b/_locales/el/messages.json index ac685072..450b7526 100644 --- a/_locales/el/messages.json +++ b/_locales/el/messages.json @@ -302,10 +302,6 @@ "message": "Απενεργοποιηση ολων των στυλ", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Η ενημέρωση ολοκληρώθηκε.", "description": "Text that displays when an update completed" diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c3108037..973eabf5 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -577,7 +577,7 @@ "description": "Button label" }, "undoGlobal": { - "message": "Undo (global)", + "message": "Undo in all sections", "description": "CSS-beautify global Undo button label" }, "unreachableContentScript": { diff --git a/_locales/fi/messages.json b/_locales/fi/messages.json index 9d7e0ea8..8a4ce03a 100644 --- a/_locales/fi/messages.json +++ b/_locales/fi/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Päivitys suoritettu.", "description": "Text that displays when an update completed" diff --git a/_locales/fr/messages.json b/_locales/fr/messages.json index b399a0d5..66621f9b 100644 --- a/_locales/fr/messages.json +++ b/_locales/fr/messages.json @@ -302,10 +302,6 @@ "message": "Désactiver tous les styles", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Mise à jour terminée.", "description": "Text that displays when an update completed" diff --git a/_locales/it/messages.json b/_locales/it/messages.json index 3a485c49..3093b539 100644 --- a/_locales/it/messages.json +++ b/_locales/it/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Aggiornamento completato.", "description": "Text that displays when an update completed" diff --git a/_locales/ja/messages.json b/_locales/ja/messages.json index db2a6210..e46b5c52 100644 --- a/_locales/ja/messages.json +++ b/_locales/ja/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "更新が完了しました", "description": "Text that displays when an update completed" diff --git a/_locales/pt_BR/messages.json b/_locales/pt_BR/messages.json index 729f3dd4..2caebfdc 100644 --- a/_locales/pt_BR/messages.json +++ b/_locales/pt_BR/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Atualização concluída.", "description": "Text that displays when an update completed" diff --git a/_locales/sv/messages.json b/_locales/sv/messages.json index 5b015421..4677bf41 100644 --- a/_locales/sv/messages.json +++ b/_locales/sv/messages.json @@ -302,10 +302,6 @@ "message": "Stäng av alla stilar", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Uppdatering slutförd.", "description": "Text that displays when an update completed" diff --git a/_locales/sv_SE/messages.json b/_locales/sv_SE/messages.json index 1016654e..f726569e 100644 --- a/_locales/sv_SE/messages.json +++ b/_locales/sv_SE/messages.json @@ -302,10 +302,6 @@ "message": "Stäng av alla stilar", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Uppdatering slutförd.", "description": "Text that displays when an update completed" diff --git a/_locales/te/messages.json b/_locales/te/messages.json index ed0550f2..7b532ef5 100644 --- a/_locales/te/messages.json +++ b/_locales/te/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Update completed.", "description": "Text that displays when an update completed" diff --git a/_locales/tr/messages.json b/_locales/tr/messages.json index efbc2fd3..a0f19961 100644 --- a/_locales/tr/messages.json +++ b/_locales/tr/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "Güncelleme tamamlandı.", "description": "Text that displays when an update completed" diff --git a/_locales/zh/messages.json b/_locales/zh/messages.json index a28bf22c..49712720 100644 --- a/_locales/zh/messages.json +++ b/_locales/zh/messages.json @@ -298,10 +298,6 @@ "message": "Turn all styles off", "description": "Label for the checkbox that turns all enabled styles off." }, - "undoGlobal": { - "message": "Undo (global)", - "description": "CSS-beautify global Undo button label" - }, "updateCompleted": { "message": "更新完成.", "description": "Text that displays when an update completed" From 14e8dedded92c3c7222bfda9d6d8f2c16ebd78ef Mon Sep 17 00:00:00 2001 From: Jeremy Schomery Date: Tue, 30 May 2017 16:21:41 +0430 Subject: [PATCH 06/94] version 1.0.9 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 9612f5c4..de82f459 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "Stylus", - "version": "1.0.8", + "version": "1.0.9", "minimum_chrome_version": "49", "description": "__MSG_description__", "homepage_url": "http://add0n.com/stylus.html", From cec649e0eef78350d2cfb9fe0dab753b06b0ba11 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 3 Jun 2017 16:52:58 +0300 Subject: [PATCH 07/94] openURL should not open own pages in incognito tabs We're using the default "spanning mode" which doesn't support it --- messaging.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/messaging.js b/messaging.js index c11e1f4c..5e4766c3 100644 --- a/messaging.js +++ b/messaging.js @@ -142,7 +142,8 @@ function openURL({url, currentWindow = true}) { } } getActiveTab().then(tab => { - if (tab && tab.url == 'chrome://newtab/') { + if (tab && tab.url == 'chrome://newtab/' + && (!url.startsWith(URLS.ownOrigin) || !tab.incognito)) { chrome.tabs.update({url}, resolve); } else { chrome.tabs.create(tab && !FIREFOX ? {url, openerTabId: tab.id} : {url}, resolve); From be9cfe072d1e3b1743d118eddc8eb52a9f3d6a47 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 3 Jun 2017 16:57:52 +0300 Subject: [PATCH 08/94] openURL should not redirect incognito NTP to chrome URLs --- messaging.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/messaging.js b/messaging.js index 5e4766c3..72a0fa0a 100644 --- a/messaging.js +++ b/messaging.js @@ -143,7 +143,8 @@ function openURL({url, currentWindow = true}) { } getActiveTab().then(tab => { if (tab && tab.url == 'chrome://newtab/' - && (!url.startsWith(URLS.ownOrigin) || !tab.incognito)) { + // prevent redirecting incognito NTP to a chrome URL as it crashes Chrome + && (!url.startsWith('chrome') || !tab.incognito)) { chrome.tabs.update({url}, resolve); } else { chrome.tabs.create(tab && !FIREFOX ? {url, openerTabId: tab.id} : {url}, resolve); From 2b1d8742367fe0f25c516c08e6d5deaf8ca0be5a Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 4 Jun 2017 10:39:27 +0300 Subject: [PATCH 09/94] Update style settings on USO without page reload --- install.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/install.js b/install.js index 560546e7..d84aca21 100644 --- a/install.js +++ b/install.js @@ -122,18 +122,32 @@ function saveStyleCode(message, name, addProps) { if (!confirm(chrome.i18n.getMessage(message, [name]))) { return; } - + enableUpdateButton(false); getResource(getStyleURL()).then(code => { chrome.runtime.sendMessage( Object.assign(JSON.parse(code), addProps, { method: 'saveStyle', reason: 'update', }), - () => sendEvent('styleInstalledChrome') + style => { + if (style.updateUrl.includes('?')) { + enableUpdateButton(true); + } else { + sendEvent('styleInstalledChrome'); + } + } ); resolve(); }); }); + + function enableUpdateButton(state) { + const button = document.getElementById('update_style_button'); + if (button) { + button.style.cssText = state ? '' : + 'pointer-events: none !important; opacity: .25 !important;'; + } + } } From 5a67d926da06f8658102130676884d368ec4d32a Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 4 Jun 2017 12:22:51 +0300 Subject: [PATCH 10/94] manage: fix toggling a style when filtering by search Previously a style entry would disappear when toggled on manage page with search filter applied because filterContainer() altered the original "container" parameter. --- manage.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/manage.js b/manage.js index d1f3149e..c5485367 100644 --- a/manage.js +++ b/manage.js @@ -764,8 +764,7 @@ function filterAndAppend({entry, container}) { if (!filtersSelector.hide || !entry.matches(filtersSelector.hide)) { entry.classList.add('hidden'); } - } - if ($('#search').value.trim()) { + } else if ($('#search').value.trim()) { searchStyles({immediately: true, container}); } reapplyFilter(container); @@ -774,14 +773,20 @@ function filterAndAppend({entry, container}) { function reapplyFilter(container = installed) { // A: show - let toUnhide = filtersSelector.hide ? filterContainer({hide: false}) : container; + let toHide = []; + let toUnhide = []; + if (filtersSelector.hide) { + filterContainer({hide: false}); + } else { + toUnhide = container; + } // showStyles() is building the page and no filters are active if (toUnhide instanceof DocumentFragment) { installed.appendChild(toUnhide); return; } else if (toUnhide.length && $('#search').value.trim()) { searchStyles({immediately: true, container: toUnhide}); - toUnhide = filterContainer({hide: false}); + filterContainer({hide: false}); } // filtering needed or a single-element job from handleUpdate() const entries = installed.children; @@ -798,7 +803,9 @@ function reapplyFilter(container = installed) { } } // B: hide - const toHide = filtersSelector.hide ? filterContainer({hide: true}) : []; + if (filtersSelector.hide) { + filterContainer({hide: true}); + } if (!toHide.length) { return; } @@ -831,16 +838,16 @@ function reapplyFilter(container = installed) { if (container.filter) { if (hide) { // already filtered in previous invocation - return container; + return; } - const toHide = [], toUnhide = []; for (const el of container) { (el.matches(selector) ? toUnhide : toHide).push(el); } - container = toHide; - return toUnhide; + return; + } else if (hide) { + toHide = $$(selector, container); } else { - return $$(selector, container); + toUnhide = $$(selector, container); } } From cd84a33a538281b327c9f9fe6c1e7de73f536ffa Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 4 Jun 2017 18:26:53 +0300 Subject: [PATCH 11/94] fixup: "Install style" should not persist on click --- install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.js b/install.js index d84aca21..a4311be4 100644 --- a/install.js +++ b/install.js @@ -130,7 +130,7 @@ function saveStyleCode(message, name, addProps) { reason: 'update', }), style => { - if (style.updateUrl.includes('?')) { + if (message == 'styleUpdate' && style.updateUrl.includes('?')) { enableUpdateButton(true); } else { sendEvent('styleInstalledChrome'); From 7a4f499e0d4d36c1acc13c757b64e4c0b2737788 Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 4 Jun 2017 15:55:31 +0300 Subject: [PATCH 12/94] patch buggy USO site to use actual style settings --- install.js | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/install.js b/install.js index a4311be4..12a433c1 100644 --- a/install.js +++ b/install.js @@ -19,6 +19,78 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { } }); +// TODO: remove the following statement when USO is fixed +document.documentElement.appendChild(document.createElement('script')).text = '(' + + function() { + let settings; + document.addEventListener('stylusFixBuggyUSOsettings', function _({detail}) { + document.removeEventListener('stylusFixBuggyUSOsettings', _); + settings = /\?/.test(detail) && new URLSearchParams(new URL(detail).search); + }); + const originalResponseJson = Response.prototype.json; + Response.prototype.json = function(...args) { + return originalResponseJson.call(this, ...args).then(json => { + Response.prototype.json = originalResponseJson; + if (!settings || typeof ((json || {}).style_settings || {}).every != 'function') { + return json; + } + const images = new Map(); + for (const jsonSetting of json.style_settings) { + let value = settings.get('ik-' + jsonSetting.install_key); + if (!value + || !jsonSetting.style_setting_options + || !jsonSetting.style_setting_options[0]) { + continue; + } + if (value.startsWith('ik-')) { + value = value.replace(/^ik-/, ''); + const defaultItem = jsonSetting.style_setting_options.find(item => item.default); + if (!defaultItem || defaultItem.install_key != value) { + if (defaultItem) { + defaultItem.default = false; + } + jsonSetting.style_setting_options.some(item => { + if (item.install_key == value) { + item.default = true; + return true; + } + }); + } + } else if (jsonSetting.setting_type == 'image') { + jsonSetting.style_setting_options.some(item => { + if (item.default) { + item.default = false; + return true; + } + }); + images.set(jsonSetting.install_key, value); + } else { + const item = jsonSetting.style_setting_options[0]; + if (item.value !== value && item.install_key == 'placeholder') { + item.value = value; + } + } + } + if (images.size) { + new MutationObserver((_, observer) => { + if (!document.getElementById('style-settings')) { + return; + } + observer.disconnect(); + for (const [name, url] of images.entries()) { + const elRadio = document.querySelector(`input[name="ik-${name}"][value="user-url"]`); + const elUrl = elRadio && document.getElementById(elRadio.id.replace('url-choice', 'user-url')); + if (elUrl) { + elUrl.value = url; + } + } + }).observe(document, {childList: true, subtree: true}); + } + return json; + }); + }; + } + ')()'; + new MutationObserver((mutations, observer) => { if (document.body) { observer.disconnect(); @@ -46,6 +118,10 @@ function getStyleURL () { } function checkUpdatability([installedStyle]) { + // TODO: remove the following statement when USO is fixed + document.dispatchEvent(new CustomEvent('stylusFixBuggyUSOsettings', { + detail: installedStyle && installedStyle.updateUrl, + })); if (!installedStyle) { sendEvent('styleCanBeInstalledChrome'); return; From 19754a5a900c9564c47d574ba9957f629e76ed5b Mon Sep 17 00:00:00 2001 From: Jeremy Schomery Date: Mon, 5 Jun 2017 15:45:07 +0430 Subject: [PATCH 13/94] updating es locale --- _locales/es/messages.json | 92 +++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/_locales/es/messages.json b/_locales/es/messages.json index 0bf45dd6..364fec03 100644 --- a/_locales/es/messages.json +++ b/_locales/es/messages.json @@ -40,11 +40,11 @@ "description": "Label for the text box controlling tab size option for the style editor." }, "enableStyleLabel": { - "message": "Habilitar", + "message": "Activar", "description": "Label for the button to enable a style" }, "styleMissingName": { - "message": "Introduzca un nombre.", + "message": "Introduzca un nombre", "description": "Error displayed when user saves without providing a name" }, "genericHistoryLabel": { @@ -52,7 +52,7 @@ "description": "Used in various places to show a history log of something" }, "shortcutsNote": { - "message": "Define atajos de teclado", + "message": "Defina atajos de teclado", "description": "" }, "appliesDomainOption": { @@ -68,7 +68,7 @@ "description": "Tooltip in the popup for styles that were not applied at all" }, "styleRegexpInvalidExplanation": { - "message": "Algunas reglas 'regexp()' que no se pudieron compilar en absoluto.", + "message": "Algunas reglas «regexp()» que no se pudieron compilar en absoluto.", "description": "" }, "importAppendLabel": { @@ -92,7 +92,7 @@ "description": "Prompt in the dialog displayed after clicking 'Import from Mozilla format' button" }, "dragDropMessage": { - "message": "Suelte su fichero de copia de seguridad en cualquier lugar de esta página para importar.", + "message": "Suelte su fichero de copia de seguridad en cualquier lugar de esta página para importarlo.", "description": "Drag'n'drop message" }, "helpAlt": { @@ -116,7 +116,7 @@ "description": "'Yes' button in a confirm dialog" }, "findStylesForSite": { - "message": "Buscar más estilos para este sitio", + "message": "Encontrar más estilos para este sitio.", "description": "Text for a link that gets a list of styles for the current site" }, "manageHeading": { @@ -132,7 +132,7 @@ "description": "Tooltip in the popup for styles that were applied only partially" }, "styleEnabledLabel": { - "message": "Habilitado", + "message": "Activado", "description": "Label for the enabled state of styles" }, "styleToMozillaFormatHelp": { @@ -168,7 +168,7 @@ "description": "'Stop' button in a confirm dialog" }, "writeStyleForURL": { - "message": "Esta URL", + "message": "este URL", "description": "Text for link in toolbar pop-up to write a new style for the current URL" }, "optionsSubheading": { @@ -184,7 +184,7 @@ "description": "Option to make the style apply to the entered string as a regular expression" }, "optionsAdvancedExposeIframesNote": { - "message": "Habilita la escritura de CSS específico-para-iframe como 'html[stylus-iframe] h1 { display:none }'", + "message": "Activa la escritura de CSS específico-para-iframe como «html[stylus-iframe] h1 { display:none }»", "description": "" }, "importReportLegendUpdatedCode": { @@ -192,7 +192,7 @@ "description": "Text after the number of styles with updated code (meta info is unchanged) in the report shown after importing styles" }, "styleInstall": { - "message": "¿Instalar \"$stylename$\" en Stylus?", + "message": "¿Quiere instalar «$stylename$» en Stylus?", "description": "Confirmation when installing a style", "placeholders": { "stylename": { @@ -201,7 +201,7 @@ } }, "optionsBadgeDisabled": { - "message": "Color de fondo cuando está deshabilitado", + "message": "Color de fondo cuando está desactivado", "description": "" }, "optionsCheck": { @@ -229,15 +229,15 @@ "description": "Label for the button to apply all detected updates" }, "unreachableFileHint": { - "message": "Stylus puede acceder a URLs file:// sólo si habilita la casilla correspondiente para la extensión Stylus en la página chrome://extensions.", + "message": "Stylus puede acceder a URL file:// solo si activa la casilla correspondiente para la extensión Stylus en la página chrome://extensions.", "description": "Note in the toolbar popup for file:// URLs" }, "disableStyleLabel": { - "message": "Deshabilitar", + "message": "Desactivar", "description": "Label for the button to disable a style" }, "prefShowBadge": { - "message": "Número de estilos activos para el sitio actual", + "message": "Número de estilos activos en el sitio actual", "description": "Label for the checkbox controlling toolbar badge text." }, "manageFavicons": { @@ -269,7 +269,7 @@ "description": "Go to shortcut configuration" }, "updateCheckFailServerUnreachable": { - "message": "Error de actualización - No se pudo alcanzar el servidor.", + "message": "Error de actualización: no se pudo contactar con el servidor.", "description": "Text that displays when an update check failed because the update server is unreachable" }, "manageFilters": { @@ -281,7 +281,7 @@ "description": "Label for the button to apply all detected updates" }, "optionsReset": { - "message": "Reinicializar las opciones a sus valores predeterminados.", + "message": "Restablecer las opciones a sus valores predeterminados.", "description": "" }, "optionsCustomizeUpdate": { @@ -289,7 +289,7 @@ "description": "" }, "deleteStyleConfirm": { - "message": "¿Está seguro de que quiere eliminar este estilo?", + "message": "¿Confirma que quiere eliminar este estilo?", "description": "Confirmation before deleting a style" }, "optionsCustomizePopup": { @@ -297,7 +297,7 @@ "description": "" }, "styleBadRegexp": { - "message": "La expresión regular (regexp) introducida no es válida", + "message": "La expresión regular proporcionada no es válida.", "description": "Validation message for a bad regexp in a style" }, "optionsHeading": { @@ -318,7 +318,7 @@ "description": "Label for the style maanger opener in the browser action context menu." }, "styleUpdate": { - "message": "¿Está seguro de que quiere actualizar '$stylename$'?", + "message": "¿Confirma que quiere actualizar «$stylename$»?", "description": "Confirmation when updating a style", "placeholders": { "stylename": { @@ -348,7 +348,7 @@ "description": "Text that displays when an update check completed and no update is available" }, "appliesUrlPrefixOption": { - "message": "URLs que empiezan por", + "message": "URLs que empiezan con", "description": "Option to make the style apply to the entered string as a URL prefix" }, "cm_matchHighlightToken": { @@ -356,7 +356,7 @@ "description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of of the word/token under cursor even if nothing is selected" }, "searchRegexp": { - "message": "Use la sintaxis /re/ para búsquedas con regexp", + "message": "Use la sintaxis /re/ para búsquedas con expresiones regulares", "description": "Label after the search input field in the editor shown on Ctrl-F" }, "updateCheckManualUpdateHint": { @@ -372,7 +372,7 @@ "description": "Label for the button to import and overwrite current style" }, "popupStylesFirst": { - "message": "Estilos antes de los comandos", + "message": "Estilos antes que las órdenes", "description": "Label for the checkbox controlling section order in the popup." }, "sectionHelp": { @@ -432,7 +432,7 @@ "description": "Link to open the manage page." }, "updateCheckFailBadResponseCode": { - "message": "Error de actualización - El servidor ha respondido con el código $code$.", + "message": "Error de actualización: el servidor ha respondido con el código $code$.", "description": "Text that displays when an update check failed because the response code indicates an error", "placeholders": { "code": { @@ -468,6 +468,10 @@ "message": "Este estilo utiliza expresiones regulares (regexps) parcialmente coincidentes violando así la especificación @document de CSS4 que requiere una coincidencia completa de URL. Las secciones CSS afectadas no se aplicaron a la página. Probablemente este estilo fue creado con Stylish-para-Chrome, que evalúa de modo incorrecto las reglas 'regexp()' desde la primera versión (un fallo conocido).", "description": "" }, + "styleBeautifyIndentConditional": { + "message": "Sangrar @media, @supports", + "description": "CSS-beautifier option" + }, "unreachableContentScript": { "message": "No se pudo comunicar con la página. Pruebe a recargar la pestaña.", "description": "Note in the toolbar popup usually on file:// URLs after [re]loading Stylus" @@ -477,15 +481,15 @@ "description": "Label for the button to remove a section" }, "disableAllStyles": { - "message": "Deshabilitar todos los estlos", + "message": "Desactivar todos los estilos", "description": "Label for the checkbox that turns all enabled styles off." }, "updateCheckSkippedMaybeLocallyEdited": { - "message": "Este estilo podría haber sido editado localmente.", + "message": "Este estilo podría haberse editado localmente.", "description": "Text that displays when an update check skipped updating the style to avoid losing possible local modifications" }, "undoGlobal": { - "message": "Deshacer (global)", + "message": "Deshacer en todas las secciones", "description": "CSS-beautify global Undo button label" }, "updateCompleted": { @@ -513,7 +517,7 @@ "description": "Text that displays when an update check skipped updating the style to avoid losing local modifications" }, "optionsResetButton": { - "message": "Opciones de reinicialización", + "message": "Restablecer opciones", "description": "" }, "sectionCode": { @@ -521,7 +525,7 @@ "description": "Label for the code for a section" }, "optionsAdvancedContextDelete": { - "message": "Añadir 'Borrar' al menú contextual del editor", + "message": "Añadir 'Eliminar' al menú contextual del editor", "description": "" }, "importReportLegendUpdatedBoth": { @@ -533,11 +537,11 @@ "description": "Label for the checkbox controlling smart indentation option for the style editor." }, "styleRegexpTestButton": { - "message": "Test de regexp", + "message": "Prueba de regexp", "description": "RegExp test button label in the editor shown when applies-to list has a regexp value" }, "appliesHelp": { - "message": "Utilice los controles 'Se aplica a' para limitar las URLs a las que se aplica el código de esta sección.", + "message": "Utilice los controles 'Se aplica a' para limitar a qué URLs se aplica el código de esta sección.", "description": "Help text for 'applies to' section" }, "editStyleHeading": { @@ -545,9 +549,13 @@ "description": "Title of the page for editing styles" }, "editDeleteText": { - "message": "Borrar", + "message": "Eliminar", "description": "Label for the context menu item in the editor to delete selected text" }, + "stylusUnavailableForURLdetails": { + "message": "Como medida de precaución, el navegador prohíbe que las extensiones afecten a sus páginas internas (como chrome://version o about:addons) además de las páginas internas de otras extensiones. Cada navegador además restringe el acceso a su propia galería de extensiones (como Chrome Web Store o AMO).", + "description": "Sub-note in the toolbar pop-up when on a URL Stylus can't affect" + }, "cm_matchHighlightSelection": { "message": "Sólo selección", "description": "Style editor's 'highglight' drop-down list option: highlight the occurrences of currently selected text" @@ -601,7 +609,7 @@ "description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short" }, "styleRegexpTestInvalid": { - "message": "Regexp no válidas omitidas", + "message": "Expresiones regulares no válidas omitidas", "description": "RegExp test report: label for the invalid expressions" }, "replaceAll": { @@ -661,7 +669,7 @@ "description": "Label for the drop-down list controlling the keymap for the style editor." }, "manageNewUI": { - "message": "Nuevo diseño de interfaz de administración", + "message": "Nuevo diseño de interfaz de gestión", "description": "Label for the checkbox that toggles the new UI on manage page" }, "importReportUndoneTitle": { @@ -669,7 +677,7 @@ "description": "Title of the message box shown after undoing the import of styles" }, "genericDisabledLabel": { - "message": "Deshabilitado", + "message": "Desactivado", "description": "Used in various lists/options to indicate that something is disabled" }, "cm_indentWithTabs": { @@ -693,11 +701,11 @@ "description": "" }, "addStyleLabel": { - "message": "Escribir nuevo estilo", + "message": "Escribir un nuevo estilo", "description": "Label for the button to go to the add style page" }, "optionsUpdateIntervalNote": { - "message": "Para deshabilitar las búsquedas automáticas de actualizaciones, establezca el intervalo a 0", + "message": "Para desactivar las búsquedas automáticas de actualizaciones, establezca el intervalo a 0", "description": "" }, "backupButtons": { @@ -705,7 +713,7 @@ "description": "Heading for backup" }, "manageOnlyEnabled": { - "message": "Sólo estilos habilitados", + "message": "Sólo estilos activos", "description": "Checkbox to show only enabled styles" }, "editStyleLabel": { @@ -713,11 +721,11 @@ "description": "Label for the button to go to the edit style page" }, "cm_theme": { - "message": "Tema", + "message": "Temas", "description": "Label for the style editor's CSS theme." }, "backupMessage": { - "message": "Seleccione un fichero o arrastre y suéltelo en esta página.", + "message": "Seleccione un fichero o arrástrelo y suéltelo en esta página.", "description": "Message for backup" }, "importReportUndone": { @@ -725,11 +733,11 @@ "description": "Text after the number of styles reverted in the message box shown after undoing the import of styles" }, "helpKeyMapCommand": { - "message": "Escriba un nombre de comando", + "message": "Nombre del comando", "description": "Placeholder text of inputbox in keymap help popup on the edit style page. Must be very short" }, "description": { - "message": "Modifique el estilo de la Web con Stylus, un administrador de estilos de usuario. Stylus le permite instalar fácilmente temas y coberturas para muchos sitios populares.", + "message": "Rediseñe la web con Stylus, un administrador de estilos de usuario. Stylus le permite instalar fácilmente temas y coberturas para muchos sitios populares.", "description": "Extension description" } -} +} \ No newline at end of file From ac5e9b965a11937a9a12c7cb8a8a900d143a6a71 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 6 Jun 2017 04:40:08 +0300 Subject: [PATCH 14/94] saveStyle's codeIsUpdated can be true or false, not undefined --- storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage.js b/storage.js index 3ffb020f..c56fc4f8 100644 --- a/storage.js +++ b/storage.js @@ -260,7 +260,7 @@ function saveStyle(style) { if (reason == 'update-digest' && oldStyle.originalDigest == style.originalDigest) { return style; } - codeIsUpdated = !existed || style.sections && !styleSectionsEqual(style, oldStyle); + codeIsUpdated = !existed || 'sections' in style && !styleSectionsEqual(style, oldStyle); style = Object.assign({}, oldStyle, style); return write(style, store); }); From 6df239213252872f7909d7bcdf0e756fd741f777 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 6 Jun 2017 10:33:45 +0300 Subject: [PATCH 15/94] FF bug workaround for tabs.query with moz-extension:// --- messaging.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/messaging.js b/messaging.js index 72a0fa0a..5cf66013 100644 --- a/messaging.js +++ b/messaging.js @@ -133,8 +133,10 @@ function openURL({url, currentWindow = true}) { return new Promise(resolve => { // [some] chromium forks don't handle their fake branded protocols url = url.replace(/^(opera|vivaldi)/, 'chrome'); + // FF doesn't handle moz-extension:// URLs (bug) // API doesn't handle the hash-fragment part - chrome.tabs.query({url: url.replace(/#.*/, ''), currentWindow}, tabs => { + const urlQuery = url.startsWith('moz-extension') ? undefined : url.replace(/#.*/, ''); + chrome.tabs.query({url: urlQuery, currentWindow}, tabs => { for (const tab of tabs) { if (tab.url == url) { activateTab(tab).then(resolve); From 4559162d457cef014325c34ab27ef3e62c4c5a16 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 6 Jun 2017 10:56:49 +0300 Subject: [PATCH 16/94] Alt-Enter in the editor to toggle&save the style --- _locales/en/messages.json | 4 ++++ edit.html | 5 ++++- edit.js | 15 ++++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 973eabf5..a5b7c4fe 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -514,6 +514,10 @@ "message": "Enabled", "description": "Label for the enabled state of styles" }, + "styleEnabledToggleHint": { + "message": "Press Alt-Enter to toggle enabled/disabled state and save the style", + "description": "Help text for the '[x] enable' checkbox in the editor" + }, "styleInstall": { "message": "Install '$stylename$' into Stylus?", "description": "Confirmation when installing a style", diff --git a/edit.html b/edit.html index 5d8df5a9..a263cc66 100644 --- a/edit.html +++ b/edit.html @@ -672,7 +672,10 @@
- + + +
diff --git a/edit.js b/edit.js index 702c8046..354f2c08 100644 --- a/edit.js +++ b/edit.js @@ -53,7 +53,8 @@ getCodeMirrorThemes(); var hotkeyRerouter = { commands: { save: true, jumpToLine: true, nextEditor: true, prevEditor: true, - find: true, findNext: true, findPrev: true, replace: true, replaceAll: true + find: true, findNext: true, findPrev: true, replace: true, replaceAll: true, + toggleStyle: true, }, setState: function(enable) { setTimeout(function() { @@ -166,6 +167,7 @@ function initCodeMirror() { theme: "default", keyMap: prefs.get("editor.keyMap"), extraKeys: { // independent of current keyMap + "Alt-Enter": "toggleStyle", "Alt-PageDown": "nextEditor", "Alt-PageUp": "prevEditor" } @@ -179,6 +181,7 @@ function initCodeMirror() { CM.commands.blockComment = function(cm) { cm.blockComment(cm.getCursor("from"), cm.getCursor("to"), {fullLines: false}); }; + CM.commands.toggleStyle = toggleStyle; // "basic" keymap only has basic keys by design, so we skip it @@ -849,6 +852,11 @@ function jumpToLine(cm) { }, {value: cur.line+1}); } +function toggleStyle() { + $('#enabled').checked = !$('#enabled').checked; + save(); +} + function refocusMinidialog(cm) { var section = cm.getSection(); if (!section.querySelector(".CodeMirror-dialog")) { @@ -1211,6 +1219,7 @@ function initHooks() { node.addEventListener("change", onChange); node.addEventListener("input", onChange); }); + document.getElementById("toggle-style-help").addEventListener("click", showToggleStyleHelp); document.getElementById("to-mozilla").addEventListener("click", showMozillaFormat, false); document.getElementById("to-mozilla-help").addEventListener("click", showToMozillaHelp, false); document.getElementById("from-mozilla").addEventListener("click", fromMozillaFormat); @@ -1581,6 +1590,10 @@ function showToMozillaHelp() { showHelp(t("styleMozillaFormatHeading"), t("styleToMozillaFormatHelp")); } +function showToggleStyleHelp() { + showHelp(t("helpAlt"), t("styleEnabledToggleHint")); +} + function showKeyMapHelp() { var keyMap = mergeKeyMaps({}, prefs.get("editor.keyMap"), CodeMirror.defaults.extraKeys); var keyMapSorted = Object.keys(keyMap) From d36489216c0bb326b88e315fd61daa2c17c6c100 Mon Sep 17 00:00:00 2001 From: tophf Date: Tue, 6 Jun 2017 16:44:16 +0300 Subject: [PATCH 17/94] Don't save maximized editor window size&pos This fixes the bug with reloading the editor tab in a maximized state: previously the window was losing its state. Assuming a detached editor window normally is expected to have a smaller size and custom position, the user may occasionally maximize it for convenience, in which case we don't save its size and position. Even if this assumption is wrong, it's easy to manually resize the window to fill the entire screen so that the size/position are remembered. --- edit.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/edit.js b/edit.js index 354f2c08..9bf5c618 100644 --- a/edit.js +++ b/edit.js @@ -423,7 +423,9 @@ document.addEventListener("wheel", function(event) { chrome.tabs.query({currentWindow: true}, function(tabs) { var windowId = tabs[0].windowId; if (prefs.get("openEditInWindow")) { - if (sessionStorage.saveSizeOnClose && 'left' in prefs.get('windowPosition', {})) { + if (sessionStorage.saveSizeOnClose + && 'left' in prefs.get('windowPosition', {}) + && !isWindowMaximized()) { // window was reopened via Ctrl-Shift-T etc. chrome.windows.update(windowId, prefs.get('windowPosition')); } @@ -458,8 +460,15 @@ function goBackToManage(event) { } } +function isWindowMaximized() { + return window.screenLeft == 0 + && window.screenTop == 0 + && window.outerWidth == screen.availWidth + && window.outerHeight == screen.availHeight; +} + window.onbeforeunload = function() { - if (saveSizeOnClose) { + if (saveSizeOnClose && !isWindowMaximized()) { prefs.set("windowPosition", { left: screenLeft, top: screenTop, From 972968b109c6f92917aadbc99b58101c9662c745 Mon Sep 17 00:00:00 2001 From: tophf Date: Fri, 9 Jun 2017 01:46:25 +0300 Subject: [PATCH 18/94] FF popup has 2 buttons so each should be 50% --- popup.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/popup.css b/popup.css index 9124fa3e..dec24989 100644 --- a/popup.css +++ b/popup.css @@ -348,6 +348,10 @@ body.blocked .actions > .left-gutter { text-overflow: ellipsis; } +.firefox #popup-options button { + width: 50%; +} + /* confirm */ #confirm, From 0817a03b61aa675e2ca809cf7481450ecbb7bb9a Mon Sep 17 00:00:00 2001 From: Jeremy Schomery Date: Sat, 10 Jun 2017 11:29:17 +0430 Subject: [PATCH 19/94] renaming the repository name from stylish-chrome to stylus --- README.md | 4 ++-- backup/fileSaveLoad.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d811f077..f5e0f4ff 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,9 @@ See the [help docs](http://userstyles.org/help/stylish_chrome) or [ask in userst ## Contributing -The source is hosted on [GitHub](https://github.com/schomery/stylish-chrome) and pull requests are welcome. +The source is hosted on [GitHub](https://github.com/schomery/stylus) and pull requests are welcome. -You can help us translate the extension on [Transifex](https://www.transifex.com/github-7/Stylus). When `messages.json` file is ready to be merged, please open a new bug report in [stylish-chrome/issues](https://github.com/schomery/stylish-chrome/issues). +You can help us translate the extension on [Transifex](https://www.transifex.com/github-7/Stylus). When `messages.json` file is ready to be merged, please open a new bug report in [stylus/issues](https://github.com/schomery/stylus/issues). ## License diff --git a/backup/fileSaveLoad.js b/backup/fileSaveLoad.js index 9ebd7f62..ab57ca70 100644 --- a/backup/fileSaveLoad.js +++ b/backup/fileSaveLoad.js @@ -297,7 +297,7 @@ $('#file-all-styles').onclick = () => { const text = JSON.stringify(styles, null, '\t'); const url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(text); return url; - // for long URLs; https://github.com/schomery/stylish-chrome/issues/13#issuecomment-284582600 + // for long URLs; https://github.com/schomery/stylus/issues/13#issuecomment-284582600 }).then(fetch) .then(res => res.blob()) .then(blob => { From 2e86c95842dd39c61a6beff028f14ed717124854 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 10 Jun 2017 12:41:44 +0300 Subject: [PATCH 20/94] csslint: fire startdocument on { --- csslint/csslint-worker.js | 3 ++- edit.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/csslint/csslint-worker.js b/csslint/csslint-worker.js index 75b5df44..46a72d4b 100644 --- a/csslint/csslint-worker.js +++ b/csslint/csslint-worker.js @@ -1675,7 +1675,6 @@ Parser.prototype = function() { } tokenStream.mustMatch(Tokens.LBRACE); - this._readWhitespace(); this.fire({ type: "startdocument", @@ -1685,6 +1684,8 @@ Parser.prototype = function() { col: token.startCol }); + this._readWhitespace(); // Stylus hack + var ok = true; while (ok) { switch (tokenStream.peek()) { diff --git a/edit.js b/edit.js index 9bf5c618..2f9ede93 100644 --- a/edit.js +++ b/edit.js @@ -1576,7 +1576,7 @@ function fromMozillaFormat() { } function backtrackTo(parser, tokenType, startEnd) { var tokens = parser._tokenStream._lt; - for (var i = tokens.length - 2; i >= 0; --i) { + for (var i = parser._tokenStream._ltIndex - 1; i >= 0; --i) { if (tokens[i].type == tokenType) { return {line: tokens[i][startEnd+"Line"], col: tokens[i][startEnd+"Col"]}; } From 2687d1e1671eadb858259cdc81b04d7b50ec3e9a Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 10 Jun 2017 14:08:03 +0300 Subject: [PATCH 21/94] FF bug workaround: retranslate CSS content --- dom.js | 12 ++++++++++++ manage.js | 11 ++++++++++- popup.js | 15 +++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/dom.js b/dom.js index 30d21779..b1443562 100644 --- a/dom.js +++ b/dom.js @@ -123,3 +123,15 @@ function $element(opt) { } return element; } + + +function retranslateCSS(selectorToMessageMap) { + // TODO: remove when this bug is fixed in FF + // Note: selectors must be spec-normalized e.g. ::before, not :before + for (const rule of document.styleSheets[0].cssRules) { + const msg = selectorToMessageMap[rule.selectorText]; + if (msg) { + rule.style.content = '"' + msg.replace(/__MSG_(\w+)__/g, (_, id) => t(id)) + '"'; + } + } +} diff --git a/manage.js b/manage.js index c5485367..61829014 100644 --- a/manage.js +++ b/manage.js @@ -1,4 +1,4 @@ -/* global messageBox, getStyleWithNoCode */ +/* global messageBox, getStyleWithNoCode, retranslateCSS */ 'use strict'; let installed; @@ -31,6 +31,15 @@ Promise.all([ showStyles(styles); }); +if (FIREFOX) { + // TODO: remove when this bug is fixed in FF + retranslateCSS({ + '.disabled h2::after': + '__MSG_genericDisabledLabel__', + '#update-all-no-updates[data-skipped-edited="true"]::after': + ' __MSG_updateAllCheckSucceededSomeEdited__', + }); +} chrome.runtime.onMessage.addListener(onRuntimeMessage); diff --git a/popup.js b/popup.js index fde184bf..1e951533 100644 --- a/popup.js +++ b/popup.js @@ -1,3 +1,4 @@ +/* global retranslateCSS */ 'use strict'; let installed; @@ -16,6 +17,20 @@ getActiveTabRealURL().then(url => { }); }); +if (FIREFOX) { + // TODO: remove when this bug is fixed in FF + retranslateCSS({ + '.blocked::before': + '__MSG_stylusUnavailableForURL__', + '.blocked #installed::before': + '__MSG_stylusUnavailableForURLdetails__', + '.unreachable::before': + '__MSG_unreachableContentScript__', + '.unreachable #installed::before': + '__MSG_unreachableFileHint__', + }); +} + chrome.runtime.onMessage.addListener(onRuntimeMessage); function onRuntimeMessage(msg) { From 22a20865350aa75955eeb74772d2a0e04a3ff2d9 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 10 Jun 2017 21:33:37 +0300 Subject: [PATCH 22/94] FF: suppress pingCS() errors in browser console --- background.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/background.js b/background.js index 0d80d7ce..eed9a9aa 100644 --- a/background.js +++ b/background.js @@ -190,7 +190,12 @@ contextMenus = Object.assign({ cs.matches.some(match => { if ((match == ALL_URLS || url.match(match)) && (!url.startsWith('chrome') || url == NTP)) { - chrome.tabs.sendMessage(id, PING, pong => !pong && injectCS(cs, id)); + chrome.tabs.sendMessage(id, PING, pong => { + if (!pong) { + injectCS(cs, id); + } + ignoreChromeError(); + }); return true; } }); From 218c6adfa025b2b3f328c759872d1d1de4ee24bc Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 11 Jun 2017 15:01:48 +0300 Subject: [PATCH 23/94] patch buggy USO site pagination links in category mode --- install.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/install.js b/install.js index 12a433c1..faba121c 100644 --- a/install.js +++ b/install.js @@ -91,9 +91,29 @@ document.documentElement.appendChild(document.createElement('script')).text = '( }; } + ')()'; +// TODO: remove the following statement when USO pagination is fixed +if (location.search.includes('category=')) { + document.addEventListener('DOMContentLoaded', function _() { + document.removeEventListener('DOMContentLoaded', _); + new MutationObserver((_, observer) => { + if (!document.getElementById('pagination')) { + return; + } + observer.disconnect(); + const category = '&' + location.search.match(/category=[^&]+/)[0]; + const links = document.querySelectorAll('#pagination a[href*="page="]:not([href*="category="])'); + for (let i = 0; i < links.length; i++) { + links[i].href += category; + } + }).observe(document, {childList: true, subtree: true}); + }); +} + new MutationObserver((mutations, observer) => { if (document.body) { observer.disconnect(); + // TODO: remove the following statement when USO pagination title is fixed + document.title = document.title.replace(/^\d+&category=/, ''); chrome.runtime.sendMessage({ method: 'getStyles', url: getMeta('stylish-id-url') || location.href From 90275ae47aa835458fed675c3b2b53502d707786 Mon Sep 17 00:00:00 2001 From: tophf Date: Wed, 14 Jun 2017 00:20:35 +0300 Subject: [PATCH 24/94] Help buggy USO support Linux Chromium --- install.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install.js b/install.js index faba121c..b4738c2b 100644 --- a/install.js +++ b/install.js @@ -1,5 +1,6 @@ 'use strict'; +const CHROMIUM = /Chromium/.test(navigator.userAgent); // non-Windows Chromium const FIREFOX = /Firefox/.test(navigator.userAgent); const VIVALDI = /Vivaldi/.test(navigator.userAgent); const OPERA = /OPR/.test(navigator.userAgent); @@ -127,8 +128,8 @@ new MutationObserver((mutations, observer) => { */ function getStyleURL () { const url = getMeta('stylish-code-chrome'); - - if (FIREFOX || OPERA || VIVALDI) { + // TODO: remove when USO is fixed + if (FIREFOX || OPERA || VIVALDI || CHROMIUM) { /* get custom settings from the update url */ return Object.assign(new URL(url), { search: (new URL(getMeta('stylish-update-url'))).search From c5a340e44e03f0f44ba85d0374105f85bae74c8e Mon Sep 17 00:00:00 2001 From: Jeremy Schomery Date: Wed, 14 Jun 2017 09:30:19 +0430 Subject: [PATCH 25/94] version 1.1.0 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index de82f459..7e6f1741 100644 --- a/manifest.json +++ b/manifest.json @@ -1,6 +1,6 @@ { "name": "Stylus", - "version": "1.0.9", + "version": "1.1.0", "minimum_chrome_version": "49", "description": "__MSG_description__", "homepage_url": "http://add0n.com/stylus.html", From b4e00cd892e09dff9e38802c00fdd0c6b0c0568e Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 17 Jun 2017 08:49:12 +0300 Subject: [PATCH 26/94] Lazify notifyAllTabs() and injectCS() * notifyAllTabs: the active tab gets notified immediately, the rest lazily * notifyAllTabs + injectCS: don't notify lazy-loaded tabs in FF --- background.js | 10 +++++++--- messaging.js | 30 +++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/background.js b/background.js index eed9a9aa..976d4a82 100644 --- a/background.js +++ b/background.js @@ -202,9 +202,13 @@ contextMenus = Object.assign({ }; chrome.tabs.query({}, tabs => - tabs.forEach(tab => - contentScripts.forEach(cs => - pingCS(cs, tab)))); + tabs.forEach(tab => { + // skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF + if (!FIREFOX || tab.width) { + contentScripts.forEach(cs => + setTimeout(pingCS, 0, cs, tab)); + } + })); } diff --git a/messaging.js b/messaging.js index 5cf66013..93e053c0 100644 --- a/messaging.js +++ b/messaging.js @@ -62,18 +62,30 @@ function notifyAllTabs(msg) { const affectsPopup = affectsAll || msg.affects.popup; const affectsSelf = affectsPopup || msg.prefs; if (affectsTabs || affectsIcon) { + const notifyTab = tab => { + // own pages will be notified via runtime.sendMessage later + if ((affectsTabs || URLS.optionsUI.includes(tab.url)) + && !(affectsSelf && tab.url.startsWith(URLS.ownOrigin)) + // skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF + && (!FIREFOX || tab.width)) { + chrome.tabs.sendMessage(tab.id, msg); + } + if (affectsIcon && BG) { + BG.updateIcon(tab); + } + }; // list all tabs including chrome-extension:// which can be ours chrome.tabs.query(affectsOwnOriginOnly ? {url: URLS.ownOrigin + '*'} : {}, tabs => { - for (const tab of tabs) { - // own pages will be notified via runtime.sendMessage later - if ((affectsTabs || URLS.optionsUI.includes(tab.url)) - && !(affectsSelf && tab.url.startsWith(URLS.ownOrigin))) { - chrome.tabs.sendMessage(tab.id, msg); + getActiveTab().then(activeTab => { + const activeTabId = activeTab && activeTab.id; + for (const tab of tabs) { + if (tab.id === activeTabId) { + notifyTab(tab); + } else { + setTimeout(notifyTab, 0, tab); + } } - if (affectsIcon && BG) { - BG.updateIcon(tab); - } - } + }); }); } // notify self: the message no longer is sent to the origin in new Chrome From fba85b36cc046f429e2a8f710fcf72fe2a654fac Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 17 Jun 2017 13:00:10 +0300 Subject: [PATCH 27/94] promisify chrome.tabs.query as queryTabs() --- .eslintrc | 1 + background.js | 2 +- backup/fileSaveLoad.js | 2 +- edit.js | 4 ++-- messaging.js | 35 +++++++++++++++++++++-------------- 5 files changed, 26 insertions(+), 18 deletions(-) diff --git a/.eslintrc b/.eslintrc index 24b34542..b52a054d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -16,6 +16,7 @@ globals: URLS: false BG: false notifyAllTabs: false + queryTabs: false getTab: false getActiveTab: false getActiveTabRealURL: false diff --git a/background.js b/background.js index 976d4a82..ea7db689 100644 --- a/background.js +++ b/background.js @@ -201,7 +201,7 @@ contextMenus = Object.assign({ }); }; - chrome.tabs.query({}, tabs => + queryTabs().then(tabs => tabs.forEach(tab => { // skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF if (!FIREFOX || tab.width) { diff --git a/backup/fileSaveLoad.js b/backup/fileSaveLoad.js index ab57ca70..d0c946a2 100644 --- a/backup/fileSaveLoad.js +++ b/backup/fileSaveLoad.js @@ -270,7 +270,7 @@ function importFromString(jsonString) { function refreshAllTabs() { return getActiveTab().then(activeTab => new Promise(resolve => { // list all tabs including chrome-extension:// which can be ours - chrome.tabs.query({}, tabs => { + queryTabs().then(tabs => { const lastTab = tabs[tabs.length - 1]; for (const tab of tabs) { getStylesSafe({matchUrl: tab.url, enabled: true, asHash: true}).then(styles => { diff --git a/edit.js b/edit.js index 2f9ede93..119b22cd 100644 --- a/edit.js +++ b/edit.js @@ -420,7 +420,7 @@ document.addEventListener("wheel", function(event) { } }); -chrome.tabs.query({currentWindow: true}, function(tabs) { +queryTabs({currentWindow: true}).then(tabs => { var windowId = tabs[0].windowId; if (prefs.get("openEditInWindow")) { if (sessionStorage.saveSizeOnClose @@ -1720,7 +1720,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) { chrome.tabs.onUpdated.removeListener(_); } }); - chrome.tabs.query({}, tabs => { + queryTabs().then(tabs => { const supported = tabs.map(tab => tab.url) .filter(url => URLS.supported.test(url)); const unique = [...new Set(supported).values()]; diff --git a/messaging.js b/messaging.js index 93e053c0..e0be522a 100644 --- a/messaging.js +++ b/messaging.js @@ -75,17 +75,18 @@ function notifyAllTabs(msg) { } }; // list all tabs including chrome-extension:// which can be ours - chrome.tabs.query(affectsOwnOriginOnly ? {url: URLS.ownOrigin + '*'} : {}, tabs => { - getActiveTab().then(activeTab => { - const activeTabId = activeTab && activeTab.id; - for (const tab of tabs) { - if (tab.id === activeTabId) { - notifyTab(tab); - } else { - setTimeout(notifyTab, 0, tab); - } + Promise.all([ + queryTabs(affectsOwnOriginOnly ? {url: URLS.ownOrigin + '*'} : {}), + getActiveTab(), + ]).then(([tabs, activeTab]) => { + const activeTabId = activeTab && activeTab.id; + for (const tab of tabs) { + if (tab.id === activeTabId) { + notifyTab(tab); + } else { + setTimeout(notifyTab, 0, tab); } - }); + } }); } // notify self: the message no longer is sent to the origin in new Chrome @@ -103,6 +104,13 @@ function notifyAllTabs(msg) { } +function queryTabs(options = {}) { + return new Promise(resolve => + chrome.tabs.query(options, tabs => + resolve(tabs))); +} + + function getTab(id) { return new Promise(resolve => chrome.tabs.get(id, tab => @@ -111,9 +119,8 @@ function getTab(id) { function getActiveTab() { - return new Promise(resolve => - chrome.tabs.query({currentWindow: true, active: true}, tabs => - resolve(tabs[0]))); + return queryTabs({currentWindow: true, active: true}) + .then(tabs => tabs[0]); } @@ -148,7 +155,7 @@ function openURL({url, currentWindow = true}) { // FF doesn't handle moz-extension:// URLs (bug) // API doesn't handle the hash-fragment part const urlQuery = url.startsWith('moz-extension') ? undefined : url.replace(/#.*/, ''); - chrome.tabs.query({url: urlQuery, currentWindow}, tabs => { + queryTabs({url: urlQuery, currentWindow}).then(tabs => { for (const tab of tabs) { if (tab.url == url) { activateTab(tab).then(resolve); From 050109428c1f7c200b93474d3097597b036ebfb4 Mon Sep 17 00:00:00 2001 From: tophf Date: Sat, 17 Jun 2017 14:55:34 +0300 Subject: [PATCH 28/94] USO bug workaround: generalize getStyleURL() --- install.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/install.js b/install.js index b4738c2b..f62af69f 100644 --- a/install.js +++ b/install.js @@ -129,10 +129,11 @@ new MutationObserver((mutations, observer) => { function getStyleURL () { const url = getMeta('stylish-code-chrome'); // TODO: remove when USO is fixed - if (FIREFOX || OPERA || VIVALDI || CHROMIUM) { + const directUrl = getMeta('stylish-update-url'); + if (directUrl.includes('?') && !url.includes('?')) { /* get custom settings from the update url */ return Object.assign(new URL(url), { - search: (new URL(getMeta('stylish-update-url'))).search + search: (new URL(directUrl)).search }).href; } return url; From c4f871b4ed94e6746823eedfe24e7943f1096f78 Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 18 Jun 2017 12:27:00 +0300 Subject: [PATCH 29/94] editor: use MouseEvent.pageY in resizeGrip --- edit.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/edit.js b/edit.js index 119b22cd..ad3e763b 100644 --- a/edit.js +++ b/edit.js @@ -360,9 +360,13 @@ function setupCodeMirror(textarea, index) { var cm = e.target.parentNode.CodeMirror; var minHeight = cm.defaultTextHeight() + cm.display.lineDiv.offsetParent.offsetTop /* .CodeMirror-lines padding */ - + cm.display.wrapper.offsetHeight - cm.display.wrapper.scrollHeight /* borders */; + + cm.display.wrapper.offsetHeight - cm.display.wrapper.clientHeight /* borders */; function resize(e) { - cm.setSize(null, Math.max(minHeight, cm.display.wrapper.scrollHeight + e.movementY)); + const cmPageY = cm.display.wrapper.getBoundingClientRect().top + window.scrollY; + const height = Math.max(minHeight, e.pageY - cmPageY); + if (height != cm.display.wrapper.clientHeight) { + cm.setSize(null, height); + } } document.addEventListener("mousemove", resize); document.addEventListener("mouseup", function resizeStop() { From 3128c7f06333815024f852a5994987ce39000d4b Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 18 Jun 2017 12:28:39 +0300 Subject: [PATCH 30/94] editor: keep 's-resize' cursor over code box --- edit.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/edit.js b/edit.js index ad3e763b..060218f6 100644 --- a/edit.js +++ b/edit.js @@ -361,6 +361,8 @@ function setupCodeMirror(textarea, index) { var minHeight = cm.defaultTextHeight() + cm.display.lineDiv.offsetParent.offsetTop /* .CodeMirror-lines padding */ + cm.display.wrapper.offsetHeight - cm.display.wrapper.clientHeight /* borders */; + cm.display.wrapper.style.pointerEvents = 'none'; + document.body.style.cursor = 's-resize'; function resize(e) { const cmPageY = cm.display.wrapper.getBoundingClientRect().top + window.scrollY; const height = Math.max(minHeight, e.pageY - cmPageY); @@ -372,6 +374,8 @@ function setupCodeMirror(textarea, index) { document.addEventListener("mouseup", function resizeStop() { document.removeEventListener("mouseup", resizeStop); document.removeEventListener("mousemove", resize); + cm.display.wrapper.style.pointerEvents = ''; + document.body.style.cursor = ''; }); }); // resizeGrip has enough space when scrollbars.horiz is visible From 8e4b2fbbb0c645396d5387a15b9bac7a2ff6cc3b Mon Sep 17 00:00:00 2001 From: tophf Date: Sun, 18 Jun 2017 15:46:53 +0300 Subject: [PATCH 31/94] manage: hardcode edit link; fixes #29 broken in 7084dd12 --- manage.html | 6 +++--- manage.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/manage.html b/manage.html index eb405e0a..d23e8985 100644 --- a/manage.html +++ b/manage.html @@ -17,7 +17,7 @@ - - - - - - + + + + + + @@ -216,7 +216,7 @@
- + diff --git a/manifest.json b/manifest.json index 4f2ccca1..97b600e4 100644 --- a/manifest.json +++ b/manifest.json @@ -19,7 +19,13 @@ "" ], "background": { - "scripts": ["messaging.js", "storage.js", "prefs.js", "background.js", "update.js"] + "scripts": [ + "background/messaging.js", + "background/storage.js", + "js/prefs.js", + "background/background.js", + "background/update.js" + ] }, "commands": { "openManage": { @@ -35,13 +41,13 @@ "run_at": "document_start", "all_frames": true, "match_about_blank": true, - "js": ["apply.js"] + "js": ["content/apply.js"] }, { "matches": ["http://userstyles.org/*", "https://userstyles.org/*"], "run_at": "document_start", "all_frames": false, - "js": ["install.js"] + "js": ["content/install.js"] } ], "browser_action": { @@ -56,7 +62,7 @@ }, "default_locale": "en", "options_ui": { - "page": "options/index.html", + "page": "index.html", "chrome_style": true } } diff --git a/options/index.js b/options/index.js index decc038d..68e6b955 100644 --- a/options/index.js +++ b/options/index.js @@ -15,7 +15,7 @@ document.onclick = e => { switch (target.dataset.cmd) { case 'open-manage': - openURL({url: '/manage.html'}); + openURL({url: 'manage.html'}); break; case 'check-updates': diff --git a/popup.html b/popup.html index 7684eb05..fe5c967f 100644 --- a/popup.html +++ b/popup.html @@ -2,7 +2,7 @@ - + +* Make any changes within a branch of this repository (not the `master` branch). +* Submit a pull request and include a reference to the initial issue with the discussion. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..a44bd728 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,28 @@ + + +* **Browser**: +* **Operating System**: +* **Screenshot**: + +* **HTML of the section where the issue occurs**: + + + +````html + +```` diff --git a/README.md b/README.md index f5e0f4ff..cc1c379b 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,15 @@ See the [help docs](http://userstyles.org/help/stylish_chrome) or [ask in userst ## Contributing -The source is hosted on [GitHub](https://github.com/schomery/stylus) and pull requests are welcome. +The source is hosted on [GitHub](https://github.com/openstyles/stylus) and pull requests are welcome. -You can help us translate the extension on [Transifex](https://www.transifex.com/github-7/Stylus). When `messages.json` file is ready to be merged, please open a new bug report in [stylus/issues](https://github.com/schomery/stylus/issues). +You can help us translate the extension on [Transifex](https://www.transifex.com/github-7/Stylus). When `messages.json` file is ready to be merged, please open a new bug report in [stylus/issues](https://github.com/openstyles/stylus/issues). + +See our [contributing](./.github/CONTRIBUTING.md) page for more details. ## License -For copyright status of the "codemirror" directory, see codemirror/LICENSE. Everything else is: +For copyright status of the "codemirror" directory, see [codemirror/LICENSE](https://github.com/openstyles/stylus/blob/master/src/vendor/codemirror/LICENSE). Everything else is: Copyright (C) 2005-2014 Jason Barnabe From f49747e1bd12c087de883709a1208b80419019af Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Thu, 13 Jul 2017 19:50:24 -0500 Subject: [PATCH 78/94] Adjust pull_locales paths --- tools/pull_locales.rb | 2 +- tools/pull_locales_postprocess.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/pull_locales.rb b/tools/pull_locales.rb index 967cee9b..23ff1225 100644 --- a/tools/pull_locales.rb +++ b/tools/pull_locales.rb @@ -22,7 +22,7 @@ project = transifex.project(project_slug) project.languages.each do |language| code = language.language_code puts "Getting locale #{code}" - dir_name = "_locales/#{code}" + dir_name = "../_locales/#{code}" Dir.mkdir(dir_name) if !Dir.exist?(dir_name) has_content = false project.resources.each do |resource| diff --git a/tools/pull_locales_postprocess.py b/tools/pull_locales_postprocess.py index d9d0b43a..a4cdb6c2 100644 --- a/tools/pull_locales_postprocess.py +++ b/tools/pull_locales_postprocess.py @@ -2,19 +2,19 @@ import io, os, json, re from collections import OrderedDict -with io.open('/_locales/en/messages.json', 'r', encoding='utf-8') as f: +with io.open('../_locales/en/messages.json', 'r', encoding='utf-8') as f: items = json.load(f).items() english = [(k, v['message']) for k, v in items if 'message' in v] english_placeholders = [(k, v['placeholders']) for k,v in items if 'placeholders' in v] -for locale_name in os.listdir('_locales'): +for locale_name in os.listdir('../_locales'): if locale_name == 'en': continue if not re.match(r'^\w{2}(_\w{2,3})?$', locale_name): print('Skipped %s: not a locale dir' % locale_name) continue - loc_path = '/_locales/' + locale_name + '/messages.json' + loc_path = '../_locales/' + locale_name + '/messages.json' with io.open(loc_path, 'r+', encoding='utf-8') as f: loc = json.load(f, object_pairs_hook=OrderedDict) From ac91e25eb42cae49198a735adadd7c2b4de31df3 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Thu, 13 Jul 2017 19:52:40 -0500 Subject: [PATCH 79/94] Move messaging.js file & references --- edit.html | 2 +- index.html | 2 +- {background => js}/messaging.js | 0 manage.html | 2 +- manifest.json | 2 +- popup.html | 2 +- 6 files changed, 5 insertions(+), 5 deletions(-) rename {background => js}/messaging.js (100%) diff --git a/edit.html b/edit.html index fbb1ed9c..5df54d54 100644 --- a/edit.html +++ b/edit.html @@ -3,7 +3,7 @@ - + diff --git a/index.html b/index.html index ea19ac4f..c673ac44 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ Stylus - + diff --git a/background/messaging.js b/js/messaging.js similarity index 100% rename from background/messaging.js rename to js/messaging.js diff --git a/manage.html b/manage.html index 855db9eb..b3bb0545 100644 --- a/manage.html +++ b/manage.html @@ -122,7 +122,7 @@ - + diff --git a/manifest.json b/manifest.json index 97b600e4..2070b4ba 100644 --- a/manifest.json +++ b/manifest.json @@ -20,7 +20,7 @@ ], "background": { "scripts": [ - "background/messaging.js", + "js/messaging.js", "background/storage.js", "js/prefs.js", "background/background.js", diff --git a/popup.html b/popup.html index fe5c967f..933df669 100644 --- a/popup.html +++ b/popup.html @@ -56,7 +56,7 @@ - + From 370a0a2c35e85aae73b877f40585472ac6a9ac56 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:21:07 -0500 Subject: [PATCH 80/94] Remove duplicated code in fileSaveLoad.js --- manage/fileSaveLoad.js | 396 ----------------------------------------- 1 file changed, 396 deletions(-) diff --git a/manage/fileSaveLoad.js b/manage/fileSaveLoad.js index 125ed9e0..9d37fc1b 100644 --- a/manage/fileSaveLoad.js +++ b/manage/fileSaveLoad.js @@ -352,402 +352,6 @@ $('#file-all-styles').onclick = () => { }; -$('#unfile-all-styles').onclick = () => { - importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT}); -}; - -Object.assign(document.body, { - ondragover(event) { - const hasFiles = event.dataTransfer.types.includes('Files'); - event.dataTransfer.dropEffect = hasFiles || event.target.type == 'search' ? 'copy' : 'none'; - this.classList.toggle('dropzone', hasFiles); - if (hasFiles) { - event.preventDefault(); - clearTimeout(this.fadeoutTimer); - this.classList.remove('fadeout'); - } - }, - ondragend(event) { - animateElement(this, {className: 'fadeout', removeExtraClasses: ['dropzone']}).then(() => { - this.style.animationDuration = ''; - }); - }, - ondragleave(event) { - try { - // in Firefox event.target could be XUL browser and hence there is no permission to access it - if (event.target === this) { - this.ondragend(); - } - } catch (e) { - this.ondragend(); - } - }, - ondrop(event) { - this.ondragend(); - if (event.dataTransfer.files.length) { - event.preventDefault(); - if ($('#onlyUpdates input').checked) { - $('#onlyUpdates input').click(); - } - importFromFile({file: event.dataTransfer.files[0]}); - } - }, -}); -======= -/* global messageBox, handleUpdate, applyOnMessage */ -'use strict'; - -const STYLISH_DUMP_FILE_EXT = '.txt'; -const STYLUS_BACKUP_FILE_EXT = '.json'; - - -function importFromFile({fileTypeFilter, file} = {}) { - return new Promise(resolve => { - const fileInput = document.createElement('input'); - if (file) { - readFile(); - return; - } - fileInput.style.display = 'none'; - fileInput.type = 'file'; - fileInput.accept = fileTypeFilter || STYLISH_DUMP_FILE_EXT; - fileInput.acceptCharset = 'utf-8'; - - document.body.appendChild(fileInput); - fileInput.initialValue = fileInput.value; - fileInput.onchange = readFile; - fileInput.click(); - - function readFile() { - if (file || fileInput.value !== fileInput.initialValue) { - file = file || fileInput.files[0]; - if (file.size > 100e6) { - console.warn("100MB backup? I don't believe you."); - importFromString('').then(resolve); - return; - } - document.body.style.cursor = 'wait'; - const fReader = new FileReader(); - fReader.onloadend = event => { - fileInput.remove(); - importFromString(event.target.result).then(numStyles => { - document.body.style.cursor = ''; - resolve(numStyles); - }); - }; - fReader.readAsText(file, 'utf-8'); - } - } - }); -} - - -function importFromString(jsonString) { - if (!BG) { - onBackgroundReady().then(() => importFromString(jsonString)); - return; - } - // create objects in background context - const json = BG.tryJSONparse(jsonString) || []; - if (typeof json.slice != 'function') { - json.length = 0; - } - const oldStyles = json.length && BG.deepCopy(BG.cachedStyles.list || []); - const oldStylesByName = json.length && new Map( - oldStyles.map(style => [style.name.trim(), style])); - - const stats = { - added: {names: [], ids: [], legend: 'importReportLegendAdded'}, - unchanged: {names: [], ids: [], legend: 'importReportLegendIdentical'}, - metaAndCode: {names: [], ids: [], legend: 'importReportLegendUpdatedBoth'}, - metaOnly: {names: [], ids: [], legend: 'importReportLegendUpdatedMeta'}, - codeOnly: {names: [], ids: [], legend: 'importReportLegendUpdatedCode'}, - invalid: {names: [], legend: 'importReportLegendInvalid'}, - }; - - let index = 0; - let lastRenderTime = performance.now(); - const renderQueue = []; - const RENDER_NAP_TIME_MAX = 1000; // ms - const RENDER_QUEUE_MAX = 50; // number of styles - const SAVE_OPTIONS = {reason: 'import', notify: false}; - - return new Promise(proceed); - - function proceed(resolve) { - while (index < json.length) { - const item = json[index++]; - const info = analyze(item); - if (info) { - // using saveStyle directly since json was parsed in background page context - return BG.saveStyle(Object.assign(item, SAVE_OPTIONS)) - .then(style => account({style, info, resolve})); - } - } - renderQueue.forEach(style => handleUpdate(style, {reason: 'import'})); - renderQueue.length = 0; - done(resolve); - } - - function analyze(item) { - if (!item || !item.name || !item.name.trim() || typeof item != 'object' - || (item.sections && typeof item.sections.slice != 'function')) { - stats.invalid.names.push(`#${index}: ${limitString(item && item.name || '')}`); - return; - } - item.name = item.name.trim(); - const byId = BG.cachedStyles.byId.get(item.id); - const byName = oldStylesByName.get(item.name); - oldStylesByName.delete(item.name); - let oldStyle; - if (byId) { - if (sameStyle(byId, item)) { - oldStyle = byId; - } else { - item.id = null; - } - } - if (!oldStyle && byName) { - item.id = byName.id; - oldStyle = byName; - } - const oldStyleKeys = oldStyle && Object.keys(oldStyle); - const metaEqual = oldStyleKeys && - oldStyleKeys.length == Object.keys(item).length && - oldStyleKeys.every(k => k == 'sections' || oldStyle[k] === item[k]); - const codeEqual = oldStyle && BG.styleSectionsEqual(oldStyle, item); - if (metaEqual && codeEqual) { - stats.unchanged.names.push(oldStyle.name); - stats.unchanged.ids.push(oldStyle.id); - return; - } - return {oldStyle, metaEqual, codeEqual}; - } - - function sameStyle(oldStyle, newStyle) { - return oldStyle.name.trim() === newStyle.name.trim() || - ['updateUrl', 'originalMd5', 'originalDigest'] - .some(field => oldStyle[field] && oldStyle[field] == newStyle[field]); - } - - function account({style, info, resolve}) { - renderQueue.push(style); - if (performance.now() - lastRenderTime > RENDER_NAP_TIME_MAX - || renderQueue.length > RENDER_QUEUE_MAX) { - renderQueue.forEach(style => handleUpdate(style, {reason: 'import'})); - setTimeout(scrollElementIntoView, 0, $('#style-' + renderQueue.pop().id)); - renderQueue.length = 0; - lastRenderTime = performance.now(); - } - setTimeout(proceed, 0, resolve); - const {oldStyle, metaEqual, codeEqual} = info; - if (!oldStyle) { - stats.added.names.push(style.name); - stats.added.ids.push(style.id); - return; - } - if (!metaEqual && !codeEqual) { - stats.metaAndCode.names.push(reportNameChange(oldStyle, style)); - stats.metaAndCode.ids.push(style.id); - return; - } - if (!codeEqual) { - stats.codeOnly.names.push(style.name); - stats.codeOnly.ids.push(style.id); - return; - } - stats.metaOnly.names.push(reportNameChange(oldStyle, style)); - stats.metaOnly.ids.push(style.id); - } - - function done(resolve) { - const numChanged = stats.metaAndCode.names.length + - stats.metaOnly.names.length + - stats.codeOnly.names.length + - stats.added.names.length; - Promise.resolve(numChanged && refreshAllTabs()).then(() => { - const report = Object.keys(stats) - .filter(kind => stats[kind].names.length) - .map(kind => { - const {ids, names, legend} = stats[kind]; - const listItemsWithId = (name, i) => - $element({dataset: {id: ids[i]}, textContent: name}); - const listItems = name => - $element({textContent: name}); - const block = - $element({tag: 'details', dataset: {id: kind}, appendChild: [ - $element({tag: 'summary', appendChild: - $element({tag: 'b', textContent: names.length + ' ' + t(legend)}) - }), - $element({tag: 'small', appendChild: - names.map(ids ? listItemsWithId : listItems) - }), - ]}); - return block; - }); - scrollTo(0, 0); - messageBox({ - title: t('importReportTitle'), - contents: report.length ? report : t('importReportUnchanged'), - buttons: [t('confirmOK'), numChanged && t('undo')], - onshow: bindClick, - }).then(({button, enter, esc}) => { - if (button == 1) { - undo(); - } - }); - resolve(numChanged); - }); - } - - function undo() { - const oldStylesById = new Map(oldStyles.map(style => [style.id, style])); - const newIds = [ - ...stats.metaAndCode.ids, - ...stats.metaOnly.ids, - ...stats.codeOnly.ids, - ...stats.added.ids, - ]; - let resolve; - index = 0; - return new Promise(resolve_ => { - resolve = resolve_; - undoNextId(); - }).then(refreshAllTabs) - .then(() => messageBox({ - title: t('importReportUndoneTitle'), - contents: newIds.length + ' ' + t('importReportUndone'), - buttons: [t('confirmOK')], - })); - function undoNextId() { - if (index == newIds.length) { - resolve(); - return; - } - const id = newIds[index++]; - deleteStyleSafe({id, notify: false}).then(id => { - const oldStyle = oldStylesById.get(id); - if (oldStyle) { - saveStyleSafe(Object.assign(oldStyle, SAVE_OPTIONS)) - .then(undoNextId); - } else { - undoNextId(); - } - }); - } - } - - function bindClick(box) { - const highlightElement = event => { - const styleElement = $('#style-' + event.target.dataset.id); - if (styleElement) { - scrollElementIntoView(styleElement); - animateElement(styleElement); - } - }; - for (const block of $$('details')) { - if (block.dataset.id != 'invalid') { - block.style.cursor = 'pointer'; - block.onclick = highlightElement; - } - } - } - - function limitString(s, limit = 100) { - return s.length <= limit ? s : s.substr(0, limit) + '...'; - } - - function reportNameChange(oldStyle, newStyle) { - return newStyle.name != oldStyle.name - ? oldStyle.name + ' —> ' + newStyle.name - : oldStyle.name; - } - - function refreshAllTabs() { - return Promise.all([ - getActiveTab(), - getOwnTab(), - ]).then(([activeTab, ownTab]) => new Promise(resolve => { - // list all tabs including chrome-extension:// which can be ours - queryTabs().then(tabs => { - const lastTab = tabs[tabs.length - 1]; - for (const tab of tabs) { - // skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF - if (FIREFOX && !tab.width) { - if (tab == lastTab) { - resolve(); - } - continue; - } - getStylesSafe({matchUrl: tab.url, enabled: true, asHash: true}).then(styles => { - const message = {method: 'styleReplaceAll', styles}; - if (tab.id == ownTab.id) { - applyOnMessage(message); - } else { - invokeOrPostpone(tab.id == activeTab.id, - chrome.tabs.sendMessage, tab.id, message, ignoreChromeError); - } - setTimeout(BG.updateIcon, 0, tab, styles); - if (tab == lastTab) { - resolve(); - } - }); - } - }); - })); - } -} - - -$('#file-all-styles').onclick = () => { - getStylesSafe().then(styles => { - const text = JSON.stringify(styles, null, '\t'); - const url = 'data:text/plain;charset=utf-8,' + encodeURIComponent(text); - return url; - // for long URLs; https://github.com/schomery/stylus/issues/13#issuecomment-284582600 - }).then(fetch) - .then(res => res.blob()) - .then(blob => { - const objectURL = URL.createObjectURL(blob); - let link = $element({ - tag:'a', - href: objectURL, - type: 'application/json', - download: generateFileName(), - }); - // TODO: remove the fallback when FF multi-process bug is fixed - if (!FIREFOX) { - link.dispatchEvent(new MouseEvent('click')); - setTimeout(() => URL.revokeObjectURL(objectURL)); - } else { - const iframe = document.body.appendChild($element({ - tag: 'iframe', - style: 'width: 0; height: 0; position: fixed; opacity: 0;'.replace(/;/g, '!important;'), - })); - doTimeout().then(() => { - link = iframe.contentDocument.importNode(link, true); - iframe.contentDocument.body.appendChild(link); - }) - .then(doTimeout) - .then(() => link.dispatchEvent(new MouseEvent('click'))) - .then(doTimeout(1000)) - .then(() => { - URL.revokeObjectURL(objectURL); - iframe.remove(); - }); - } - }); - - function generateFileName() { - const today = new Date(); - const dd = ('0' + today.getDate()).substr(-2); - const mm = ('0' + (today.getMonth() + 1)).substr(-2); - const yyyy = today.getFullYear(); - return `stylus-${mm}-${dd}-${yyyy}${STYLUS_BACKUP_FILE_EXT}`; - } -}; - - $('#unfile-all-styles').onclick = () => { importFromFile({fileTypeFilter: STYLUS_BACKUP_FILE_EXT}); }; From 4cbd48b9f959fe2c81cb47e641c92fa247388551 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:25:33 -0500 Subject: [PATCH 81/94] Rename options.html & fix path --- js/messaging.js | 2 +- manifest.json | 2 +- index.html => options.html | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename index.html => options.html (100%) diff --git a/js/messaging.js b/js/messaging.js index ac529c92..a1e1c4b0 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -11,7 +11,7 @@ const URLS = { ownOrigin: chrome.runtime.getURL(''), optionsUI: [ - chrome.runtime.getURL('options/index.html'), + chrome.runtime.getURL('options.html'), 'chrome://extensions/?options=' + chrome.runtime.id, ], diff --git a/manifest.json b/manifest.json index 2070b4ba..958f5a5e 100644 --- a/manifest.json +++ b/manifest.json @@ -62,7 +62,7 @@ }, "default_locale": "en", "options_ui": { - "page": "index.html", + "page": "options.html", "chrome_style": true } } diff --git a/index.html b/options.html similarity index 100% rename from index.html rename to options.html From 61327bfaf1f7826bacd0912d3e782ced29844fa4 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:33:59 -0500 Subject: [PATCH 82/94] Restore case declarations in edit.js --- edit/edit.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index ed9dd8d6..7e1d4856 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -295,13 +295,13 @@ function acmeEventListener(event) { return; } let value = el.type == 'checkbox' ? el.checked : el.value; - let url; - const themeLink = document.getElementById('cm-theme'); switch (option) { case 'tabSize': CodeMirror.setOption('indentUnit', Number(value)); break; + /* eslint-disable no-case-declarations */ case 'theme': + const themeLink = document.getElementById('cm-theme'); // use non-localized 'default' internally if (!value || value == 'default' || value == t('defaultTheme')) { value = 'default'; @@ -312,7 +312,7 @@ function acmeEventListener(event) { el.selectedIndex = 0; break; } - url = chrome.runtime.getURL('vendor/codemirror/theme/' + value + '.css'); + const url = chrome.runtime.getURL('vendor/codemirror/theme/' + value + '.css'); if (themeLink.href == url) { // preloaded in initCodeMirror() break; } @@ -327,6 +327,7 @@ function acmeEventListener(event) { }, 100); })(); return; + /* eslint-enable no-case-declarations */ case 'autocompleteOnTyping': editors.forEach(cm => { const onOff = el.checked ? 'on' : 'off'; From 1a630033bd5b7b00e8a9a4cb5f4d50abf20b40f6 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:46:10 -0500 Subject: [PATCH 83/94] Use a single declaration per line --- background/storage.js | 6 ++++-- edit/edit.js | 11 +++++++---- vendor-overwrites/beautify/beautify-css-mod.js | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/background/storage.js b/background/storage.js index 0791d6b3..00b4f392 100644 --- a/background/storage.js +++ b/background/storage.js @@ -189,7 +189,8 @@ function filterStylesInternal({ const needSections = asHash || matchUrl !== null; - for (let i = 0, style; (style = styles[i]); i++) { + let style; + for (let i = 0; (style = styles[i]); i++) { if ((enabled === null || style.enabled == enabled) && (url === null || style.url == url) && (id === null || style.id == id)) { @@ -230,7 +231,8 @@ function saveStyle(style) { if (!style.name) { delete style.name; } - let existed, codeIsUpdated; + let existed; + let codeIsUpdated; if (reason == 'update' || reason == 'update-digest') { return calcStyleDigest(style).then(digest => { style.originalDigest = digest; diff --git a/edit/edit.js b/edit/edit.js index 7e1d4856..6997f63c 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -602,8 +602,8 @@ function addSection(event, section) { } function removeAppliesTo(event) { - const appliesTo = event.target.parentNode, - appliesToList = appliesTo.parentNode; + const appliesTo = event.target.parentNode; + const appliesToList = appliesTo.parentNode; removeAreaAndSetDirty(appliesTo); if (!appliesToList.hasChildNodes()) { addAppliesTo(appliesToList); @@ -744,7 +744,8 @@ function setupGlobalSearch() { && searchAppliesTo(activeCM)) { return; } - for (let i = 0, cm = activeCM; i < editors.length; i++) { + let cm = activeCM; + for (let i = 0; i < editors.length; i++) { state = updateState(cm); if (!cm.hasFocus()) { pos = reverse ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(0, 0); @@ -799,7 +800,9 @@ function setupGlobalSearch() { } function replace(activeCM, all) { - let queue, query, replacement; + let queue; + let query; + let replacement; activeCM = focusClosestCM(activeCM); customizeOpenDialog(activeCM, template[all ? 'replaceAll' : 'replace'], function(txt) { query = txt; diff --git a/vendor-overwrites/beautify/beautify-css-mod.js b/vendor-overwrites/beautify/beautify-css-mod.js index b5baa1fd..a03fd7d8 100644 --- a/vendor-overwrites/beautify/beautify-css-mod.js +++ b/vendor-overwrites/beautify/beautify-css-mod.js @@ -364,7 +364,8 @@ } } outputPosCol = 0; - let i = output.length, token; + let i = output.length; + let token; while (--i >= 0 && (token = output[i]) != '\n') { outputPosCol += token.length; } From a3e149a30ed1fa6ba06571bcd57ff4ebe6904eb0 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:57:28 -0500 Subject: [PATCH 84/94] Fix & rename scoped state variable --- edit/edit.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index 6997f63c..9c4ac192 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -1014,7 +1014,8 @@ function updateLintReport(cm, delay) { setTimeout(cm => { cm.performLint(); update(cm); }, delay, cm); return; } - const state = cm.state.lint; + // eslint-disable-next-line no-var + var state = cm.state.lint; if (!state) { return; } @@ -1028,13 +1029,12 @@ function updateLintReport(cm, delay) { const scope = cm ? [cm] : editors; let changed = false; let fixedOldIssues = false; - let state; scope.forEach(function(cm) { - state = cm.state.lint || {}; - const oldMarkers = state.markedLast || {}; + const scopedState = cm.state.lint || {}; + const oldMarkers = scopedState.markedLast || {}; const newMarkers = {}; - const html = !state.marked || state.marked.length == 0 ? '' : '' + - state.marked.map(function(mark) { + const html = !scopedState.marked || scopedState.marked.length == 0 ? '' : '' + + scopedState.marked.map(function(mark) { const info = mark.__annotation; const isActiveLine = info.from.line == cm.getCursor().line; const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch); @@ -1054,10 +1054,10 @@ function updateLintReport(cm, delay) { '' + (info.from.ch + 1) + '' + '' + message + ''; }).join('') + ''; - state.markedLast = newMarkers; - fixedOldIssues |= state.reportDisplayed && Object.keys(oldMarkers).length > 0; - if (state.html != html) { - state.html = html; + scopedState.markedLast = newMarkers; + fixedOldIssues |= scopedState.reportDisplayed && Object.keys(oldMarkers).length > 0; + if (scopedState.html != html) { + scopedState.html = html; changed = true; } }); From 01e63d5b1a89a18613259073558a930d6ab74841 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 03:59:13 -0500 Subject: [PATCH 85/94] Remove escaped single quote --- edit/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/edit/edit.js b/edit/edit.js index 9c4ac192..c607ad85 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -1073,7 +1073,7 @@ function updateLintReport(cm, delay) { } } function escapeHtml(html) { - const chars = {'&': '&', '<': '<', '>': '>', '"': '"', '\'': ''', '/': '/'}; + const chars = {'&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/'}; return html.replace(/[&<>"'/]/g, function(char) { return chars[char]; }); } } From 81484bbc37f71decf20aa060d1e8de9752779f19 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 04:02:04 -0500 Subject: [PATCH 86/94] Fix for-loop index declarations --- edit/edit.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index c607ad85..2415642b 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -547,8 +547,7 @@ function addSection(event, section) { if (section) { codeElement.value = section.code; - let i; - for (i in propertyToCss) { + for (const i in propertyToCss) { if (section[i]) { section[i].forEach(function(url) { addAppliesTo(appliesTo, propertyToCss[i], url); @@ -1234,8 +1233,7 @@ function init() { // This is an add tE('heading', 'addStyleTitle'); const section = {code: ''}; - let i; - for (i in CssToProperty) { + for (const i in CssToProperty) { if (params[i]) { section[CssToProperty[i]] = [params[i]]; } @@ -1518,8 +1516,7 @@ function showMozillaFormat() { function toMozillaFormat() { return getSectionsHashes().map(function(section) { let cssMds = []; - let i; - for (i in propertyToCss) { + for (const i in propertyToCss) { if (section[i]) { cssMds = cssMds.concat(section[i].map(function(v) { return propertyToCss[i] + '("' + v.replace(/\\/g, '\\\\') + '")'; From 11d8687af7bc6c3c54cca762a0d8540e074b2e86 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Fri, 14 Jul 2017 04:42:55 -0500 Subject: [PATCH 87/94] Wrap case statement to fix eslint issue --- edit/edit.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index 2415642b..53053f95 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -299,8 +299,7 @@ function acmeEventListener(event) { case 'tabSize': CodeMirror.setOption('indentUnit', Number(value)); break; - /* eslint-disable no-case-declarations */ - case 'theme': + case 'theme': { const themeLink = document.getElementById('cm-theme'); // use non-localized 'default' internally if (!value || value == 'default' || value == t('defaultTheme')) { @@ -327,7 +326,7 @@ function acmeEventListener(event) { }, 100); })(); return; - /* eslint-enable no-case-declarations */ + } case 'autocompleteOnTyping': editors.forEach(cm => { const onOff = el.checked ? 'on' : 'off'; From a1bec922ef0b372b6e249a43a4fee55e967b21ed Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 08:55:16 -0500 Subject: [PATCH 88/94] Update eslint rules --- .eslintrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.eslintrc b/.eslintrc index c1fb1656..04989f20 100644 --- a/.eslintrc +++ b/.eslintrc @@ -132,7 +132,7 @@ rules: no-duplicate-imports: [2] no-else-return: [0] no-empty-character-class: [2] - no-empty-function: [0] + no-empty-function: [1] no-empty-pattern: [2] no-empty: [2, {allowEmptyCatch: true}] no-eq-null: [2] @@ -166,7 +166,7 @@ rules: no-mixed-operators: [0] no-mixed-requires: [2, true] no-mixed-spaces-and-tabs: [2] - no-multi-spaces: [0] + no-multi-spaces: [2, {ignoreEOLComments: true}] no-multi-str: [2] no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] no-native-reassign: [2] @@ -249,7 +249,7 @@ rules: sort-imports: [0] sort-keys: [0] space-before-blocks: [2, always] - space-before-function-paren: [1, never] + space-before-function-paren: [2, {anonymous: always, asyncArrow: always, named: never}] space-in-parens: [2, never] space-infix-ops: [2] space-unary-ops: [2] From 1940318f0fc21b67fb06209a84104b61e8d13ff4 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 11:49:31 -0500 Subject: [PATCH 89/94] Fix eslint issues & use arrow functions --- content/install.js | 4 +- edit/edit.js | 213 ++++++++++++++++++++++----------------------- manage/manage.js | 2 +- options/index.js | 2 +- popup/popup.js | 2 +- 5 files changed, 110 insertions(+), 113 deletions(-) diff --git a/content/install.js b/content/install.js index f8bba479..89600266 100644 --- a/content/install.js +++ b/content/install.js @@ -22,14 +22,14 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { // TODO: remove the following statement when USO is fixed document.documentElement.appendChild(document.createElement('script')).text = '(' + - function() { + function () { let settings; document.addEventListener('stylusFixBuggyUSOsettings', function _({detail}) { document.removeEventListener('stylusFixBuggyUSOsettings', _); settings = /\?/.test(detail) && new URLSearchParams(new URL(detail).search); }); const originalResponseJson = Response.prototype.json; - Response.prototype.json = function(...args) { + Response.prototype.json = function (...args) { return originalResponseJson.call(this, ...args).then(json => { Response.prototype.json = originalResponseJson; if (!settings || typeof ((json || {}).style_settings || {}).every != 'function') { diff --git a/edit/edit.js b/edit/edit.js index 53053f95..6eb0406b 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -16,7 +16,7 @@ const CssToProperty = {'url': 'urls', 'url-prefix': 'urlPrefixes', 'domain': 'do onBackgroundReady(); // make querySelectorAll enumeration code readable -['forEach', 'some', 'indexOf', 'map'].forEach(function(method) { +['forEach', 'some', 'indexOf', 'map'].forEach(method => { NodeList.prototype[method] = Array.prototype[method]; }); @@ -24,7 +24,7 @@ onBackgroundReady(); Element.prototype.matches = Element.prototype.matches || Element.prototype.webkitMatchesSelector; // Chrome pre-41 polyfill -Element.prototype.closest = Element.prototype.closest || function(selector) { +Element.prototype.closest = Element.prototype.closest || function (selector) { let e; // eslint-disable-next-line no-empty for (e = this; e && !e.matches(selector); e = e.parentElement) {} @@ -32,14 +32,14 @@ Element.prototype.closest = Element.prototype.closest || function(selector) { }; // eslint-disable-next-line no-extend-native -Array.prototype.rotate = function(amount) { // negative amount == rotate left +Array.prototype.rotate = function (amount) { // negative amount == rotate left const r = this.slice(-amount, this.length); Array.prototype.push.apply(r, this.slice(0, this.length - r.length)); return r; }; // eslint-disable-next-line no-extend-native -Object.defineProperty(Array.prototype, 'last', {get: function() { return this[this.length - 1]; }}); +Object.defineProperty(Array.prototype, 'last', {get: function () { return this[this.length - 1]; }}); // preload the theme so that CodeMirror can calculate its metrics in DOMContentLoaded->setupLivePrefs() new MutationObserver((mutations, observer) => { @@ -60,12 +60,12 @@ const hotkeyRerouter = { find: true, findNext: true, findPrev: true, replace: true, replaceAll: true, toggleStyle: true, }, - setState: function(enable) { - setTimeout(function() { + setState: enable => { + setTimeout(() => { document[(enable ? 'add' : 'remove') + 'EventListener']('keydown', hotkeyRerouter.eventHandler); }, 0); }, - eventHandler: function(event) { + eventHandler: event => { const keyName = CodeMirror.keyName(event); if ( CodeMirror.lookupKey(keyName, CodeMirror.getOption('keyMap'), handleCommand) == 'handled' || @@ -139,7 +139,7 @@ function setCleanGlobal() { } function setCleanSection(section) { - section.querySelectorAll('.style-contributor').forEach(function(node) { setCleanItem(node, true); }); + section.querySelectorAll('.style-contributor').forEach(node => { setCleanItem(node, true); }); // #header section has no codemirror const cm = section.CodeMirror; @@ -182,10 +182,10 @@ function initCodeMirror() { // additional commands CM.commands.jumpToLine = jumpToLine; - CM.commands.nextEditor = function(cm) { nextPrevEditor(cm, 1); }; - CM.commands.prevEditor = function(cm) { nextPrevEditor(cm, -1); }; + CM.commands.nextEditor = cm => { nextPrevEditor(cm, 1); }; + CM.commands.prevEditor = cm => { nextPrevEditor(cm, -1); }; CM.commands.save = save; - CM.commands.blockComment = function(cm) { + CM.commands.blockComment = cm => { cm.blockComment(cm.getCursor('from'), cm.getCursor('to'), {fullLines: false}); }; CM.commands.toggleStyle = toggleStyle; @@ -193,7 +193,7 @@ function initCodeMirror() { // 'basic' keymap only has basic keys by design, so we skip it const extraKeysCommands = {}; - Object.keys(CM.defaults.extraKeys).forEach(function(key) { + Object.keys(CM.defaults.extraKeys).forEach(key => { extraKeysCommands[CM.defaults.extraKeys[key]] = true; }); if (!extraKeysCommands.jumpToLine) { @@ -222,18 +222,18 @@ function initCodeMirror() { } // try to remap non-interceptable Ctrl-(Shift-)N/T/W hotkeys - ['N', 'T', 'W'].forEach(function(char) { + ['N', 'T', 'W'].forEach(char => { [{from: 'Ctrl-', to: ['Alt-', 'Ctrl-Alt-']}, {from: 'Shift-Ctrl-', to: ['Ctrl-Alt-', 'Shift-Ctrl-Alt-']} // Note: modifier order in CM is S-C-A - ].forEach(function(remap) { + ].forEach(remap => { const oldKey = remap.from + char; - Object.keys(CM.keyMap).forEach(function(keyMapName) { + Object.keys(CM.keyMap).forEach(keyMapName => { const keyMap = CM.keyMap[keyMapName]; const command = keyMap[oldKey]; if (!command) { return; } - remap.to.some(function(newMod) { + remap.to.some(newMod => { const newKey = newMod + char; if (!(newKey in keyMap)) { delete keyMap[oldKey]; @@ -247,23 +247,21 @@ function initCodeMirror() { } // user option values - CM.getOption = function(o) { - return CodeMirror.defaults[o]; - }; - CM.setOption = function(o, v) { + CM.getOption = o => CodeMirror.defaults[o]; + CM.setOption = (o, v) => { CodeMirror.defaults[o] = v; - editors.forEach(function(editor) { + editors.forEach(editor => { editor.setOption(o, v); }); }; - CM.prototype.getSection = function() { + CM.prototype.getSection = function () { return this.display.wrapper.parentNode; }; // initialize global editor controls function optionsHtmlFromArray(options) { - return options.map(function(opt) { return ''; }).join(''); + return options.map(opt => '').join(''); } const themeControl = document.getElementById('editor.theme'); const themeList = localStorage.codeMirrorThemes; @@ -318,8 +316,8 @@ function acmeEventListener(event) { // avoid flicker: wait for the second stylesheet to load, then apply the theme document.head.insertAdjacentHTML('beforeend', ''); - (function() { - setTimeout(function() { + (() => { + setTimeout(() => { CodeMirror.setOption(option, value); themeLink.remove(); document.getElementById('cm-theme2').id = 'cm-theme'; @@ -426,13 +424,13 @@ function getSections() { // remind Chrome to repaint a previously invisible editor box by toggling any element's transform // this bug is present in some versions of Chrome (v37-40 or something) -document.addEventListener('scroll', function() { +document.addEventListener('scroll', () => { const style = document.getElementById('name').style; style.webkitTransform = style.webkitTransform ? '' : 'scale(1)'; }); // Shift-Ctrl-Wheel scrolls entire page even when mouse is over a code editor -document.addEventListener('wheel', function(event) { +document.addEventListener('wheel', event => { if (event.shiftKey && event.ctrlKey && !event.altKey && !event.metaKey) { // Chrome scrolls horizontally when Shift is pressed but on some PCs this might be different window.scrollBy(0, event.deltaX || event.deltaY); @@ -450,7 +448,7 @@ queryTabs({currentWindow: true}).then(tabs => { chrome.windows.update(windowId, prefs.get('windowPosition')); } if (tabs.length == 1 && window.history.length == 1) { - chrome.windows.getAll(function(windows) { + chrome.windows.getAll(windows => { if (windows.length > 1) { sessionStorageHash('saveSizeOnClose').set(windowId, true); saveSizeOnClose = true; @@ -460,7 +458,7 @@ queryTabs({currentWindow: true}).then(tabs => { saveSizeOnClose = sessionStorageHash('saveSizeOnClose').value[windowId]; } } - chrome.tabs.onRemoved.addListener(function(tabId, info) { + chrome.tabs.onRemoved.addListener((tabId, info) => { sessionStorageHash('manageStylesHistory').unset(tabId); if (info.windowId == windowId && info.isWindowClosing) { sessionStorageHash('saveSizeOnClose').unset(windowId); @@ -489,7 +487,7 @@ function isWindowMaximized() { && window.outerHeight == screen.availHeight; } -window.onbeforeunload = function() { +window.onbeforeunload = () => { if (saveSizeOnClose && !isWindowMaximized()) { prefs.set('windowPosition', { left: screenLeft, @@ -527,7 +525,7 @@ function addAppliesTo(list, name, value) { } else { e = template.appliesToEverything.cloneNode(true); } - e.querySelector('.add-applies-to').addEventListener('click', function() { + e.querySelector('.add-applies-to').addEventListener('click', function () { addAppliesTo(this.parentNode.parentNode); }, false); list.appendChild(e); @@ -548,7 +546,7 @@ function addSection(event, section) { codeElement.value = section.code; for (const i in propertyToCss) { if (section[i]) { - section[i].forEach(function(url) { + section[i].forEach(url => { addAppliesTo(appliesTo, propertyToCss[i], url); appliesToAdded = true; }); @@ -621,7 +619,7 @@ function removeAreaAndSetDirty(area) { if (!contributors.length) { setCleanItem(area, false); } - contributors.some(function(node) { + contributors.some(node => { if (node.savedValue) { // it's a saved section, so make it dirty and stop the enumeration setCleanItem(area, false); @@ -688,11 +686,11 @@ function setupGlobalSearch() { // temporarily overrides the original openDialog with the provided template's innerHTML function customizeOpenDialog(cm, template, callback) { - cm.openDialog = function(tmpl, cb, opt) { + cm.openDialog = (tmpl, cb, opt) => { // invoke 'callback' and bind 'this' to the original callback originalOpenDialog.call(cm, template.innerHTML, callback.bind(cb), opt); }; - setTimeout(function() { cm.openDialog = originalOpenDialog; }, 0); + setTimeout(() => { cm.openDialog = originalOpenDialog; }, 0); refocusMinidialog(cm); } @@ -707,13 +705,13 @@ function setupGlobalSearch() { function find(activeCM) { activeCM = focusClosestCM(activeCM); - customizeOpenDialog(activeCM, template.find, function(query) { + customizeOpenDialog(activeCM, template.find, function (query) { this(query); curState = activeCM.state.search; if (editors.length == 1 || !curState.query) { return; } - editors.forEach(function(cm) { + editors.forEach(cm => { if (cm != activeCM) { cm.execCommand('clearSearch'); updateState(cm, curState); @@ -776,14 +774,14 @@ function setupGlobalSearch() { inputs = inputs.reverse(); } inputs.splice(0, inputs.indexOf(document.activeElement) + 1); - return inputs.some(function(input) { + return inputs.some(input => { const match = rxQuery.exec(input.value); if (match) { input.focus(); const end = match.index + match[0].length; // scroll selected part into view in long inputs, // works only outside of current event handlers chain, hence timeout=0 - setTimeout(function() { + setTimeout(() => { input.setSelectionRange(end, end); input.setSelectionRange(match.index, end); }, 0); @@ -802,9 +800,9 @@ function setupGlobalSearch() { let query; let replacement; activeCM = focusClosestCM(activeCM); - customizeOpenDialog(activeCM, template[all ? 'replaceAll' : 'replace'], function(txt) { + customizeOpenDialog(activeCM, template[all ? 'replaceAll' : 'replace'], txt => { query = txt; - customizeOpenDialog(activeCM, template.replaceWith, function(txt) { + customizeOpenDialog(activeCM, template.replaceWith, txt => { replacement = txt; queue = editors.rotate(-editors.indexOf(activeCM)); if (all) { @@ -826,8 +824,8 @@ function setupGlobalSearch() { return; } // hide the first two dialogs (replace, replaceWith) - cm.openDialog = function(tmpl, callback, opt) { - cm.openDialog = function(tmpl, callback, opt) { + cm.openDialog = (tmpl, callback, opt) => { + cm.openDialog = (tmpl, callback, opt) => { cm.openDialog = originalOpenDialog; if (all) { callback(replacement); @@ -848,25 +846,23 @@ function setupGlobalSearch() { let wrapAround = false; const origPos = cm.getCursor(); cm.openConfirm = function overrideConfirm(tmpl, callbacks, opt) { - const ovrCallbacks = callbacks.map(function(callback) { - return function() { - makeSectionVisible(cm); - cm.openConfirm = overrideConfirm; - setTimeout(function() { cm.openConfirm = originalOpenConfirm; }, 0); + const ovrCallbacks = callbacks.map(callback => () => { + makeSectionVisible(cm); + cm.openConfirm = overrideConfirm; + setTimeout(() => { cm.openConfirm = originalOpenConfirm; }, 0); - const pos = cm.getCursor(); - callback(); - const cmp = CodeMirror.cmpPos(cm.getCursor(), pos); - wrapAround |= cmp <= 0; + const pos = cm.getCursor(); + callback(); + const cmp = CodeMirror.cmpPos(cm.getCursor(), pos); + wrapAround |= cmp <= 0; - const dlg = cm.getWrapperElement().querySelector('.CodeMirror-dialog'); - if (!dlg || cmp == 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) { - if (dlg) { - dlg.remove(); - } - doReplace(); + const dlg = cm.getWrapperElement().querySelector('.CodeMirror-dialog'); + if (!dlg || cmp == 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) { + if (dlg) { + dlg.remove(); } - }; + doReplace(); + } }); originalOpenConfirm.call(cm, template.replaceConfirm.innerHTML, ovrCallbacks, opt); }; @@ -887,7 +883,7 @@ function setupGlobalSearch() { function jumpToLine(cm) { const cur = cm.getCursor(); refocusMinidialog(cm); - cm.openDialog(template.jumpToLine.innerHTML, function(str) { + cm.openDialog(template.jumpToLine.innerHTML, 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); @@ -959,7 +955,7 @@ function refocusMinidialog(cm) { // close the currently opened minidialog cm.focus(); // make sure to focus the input in newly opened minidialog - setTimeout(function() { + setTimeout(() => { section.querySelector('.CodeMirror-dialog').focus(); }, 0); } @@ -980,8 +976,8 @@ function getEditorInSight(nearbyElement) { } if (!cm || offscreenDistance(cm) > 0) { const sorted = editors - .map(function(cm, index) { return {cm: cm, distance: offscreenDistance(cm), index: index}; }) - .sort(function(a, b) { return a.distance - b.distance || a.index - b.index; }); + .map((cm, index) => ({cm: cm, distance: offscreenDistance(cm), index: index})) + .sort((a, b) => a.distance - b.distance || a.index - b.index); cm = sorted[0].cm; if (sorted[0].distance > 0) { makeSectionVisible(cm); @@ -1027,12 +1023,12 @@ function updateLintReport(cm, delay) { const scope = cm ? [cm] : editors; let changed = false; let fixedOldIssues = false; - scope.forEach(function(cm) { + scope.forEach(cm => { const scopedState = cm.state.lint || {}; const oldMarkers = scopedState.markedLast || {}; const newMarkers = {}; const html = !scopedState.marked || scopedState.marked.length == 0 ? '' : '' + - scopedState.marked.map(function(mark) { + scopedState.marked.map(mark => { const info = mark.__annotation; const isActiveLine = info.from.line == cm.getCursor().line; const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch); @@ -1064,7 +1060,7 @@ function updateLintReport(cm, delay) { if (!state || !state.postponeNewIssues || fixedOldIssues) { renderLintReport(true); } else { - state.renderTimeout = setTimeout(function() { + state.renderTimeout = setTimeout(() => { renderLintReport(true); }, CodeMirror.defaults.lintReportDelay); } @@ -1072,7 +1068,7 @@ function updateLintReport(cm, delay) { } function escapeHtml(html) { const chars = {'&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '/': '/'}; - return html.replace(/[&<>"'/]/g, function(char) { return chars[char]; }); + return html.replace(/[&<>"'/]/g, char => chars[char]); } } @@ -1082,7 +1078,7 @@ function renderLintReport(someBlockChanged) { const label = t('sectionCode'); const newContent = content.cloneNode(false); let issueCount = 0; - editors.forEach(function(cm, index) { + editors.forEach((cm, index) => { if (cm.state.lint && cm.state.lint.html) { const newBlock = newContent.appendChild(document.createElement('table')); const html = '' + label + ' ' + (index + 1) + '' + cm.state.lint.html; @@ -1165,9 +1161,9 @@ function beautify(event) { const undoButton = document.querySelector('#help-popup button[role="undo"]'); undoButton.textContent = t(scope.length == 1 ? 'undo' : 'undoGlobal'); - undoButton.addEventListener('click', function() { + undoButton.addEventListener('click', () => { let undoable = false; - scope.forEach(function(cm) { + scope.forEach(cm => { if (cm.beautifyChange && cm.beautifyChange[cm.changeGeneration()]) { delete cm.beautifyChange[cm.changeGeneration()]; cm.undo(); @@ -1178,8 +1174,8 @@ function beautify(event) { undoButton.disabled = !undoable; }); - scope.forEach(function(cm) { - setTimeout(function() { + scope.forEach(cm => { + setTimeout(() => { const pos = options.translate_positions = [].concat.apply([], cm.doc.sel.ranges.map(r => [Object.assign({}, r.anchor), Object.assign({}, r.head)])); @@ -1283,7 +1279,7 @@ function initWithStyle({style, codeIsUpdated}) { } // if this was done in response to an update, we need to clear existing sections - getSections().forEach(function(div) { div.remove(); }); + getSections().forEach(div => { div.remove(); }); const queue = style.sections.length ? style.sections.slice() : [{code: ''}]; const queueStart = new Date().getTime(); // after 100ms the sections will be added asynchronously @@ -1310,7 +1306,7 @@ function initWithStyle({style, codeIsUpdated}) { } function initHooks() { - document.querySelectorAll('#header .style-contributor').forEach(function(node) { + document.querySelectorAll('#header .style-contributor').forEach(node => { node.addEventListener('change', onChange); node.addEventListener('input', onChange); }); @@ -1378,7 +1374,7 @@ function maximizeCodeHeight(sectionDiv, isLast) { } stats.totalHeight += stats.firstSectionTop; if (stats.totalHeight <= window.innerHeight) { - editors.forEach(function(cm, index) { + editors.forEach((cm, index) => { cm.setSize(null, stats.deltas[index] + stats.cmActualHeight); }); return; @@ -1390,10 +1386,10 @@ function maximizeCodeHeight(sectionDiv, isLast) { if (available <= 0) { return; } - const totalDelta = stats.deltas.reduce(function(sum, d) { return sum + d; }, 0); + const totalDelta = stats.deltas.reduce((sum, d) => sum + d, 0); const q = available / totalDelta; const baseHeight = stats.cmActualHeight - stats.sectionMarginTop; - stats.deltas.forEach(function(delta, index) { + stats.deltas.forEach((delta, index) => { editors[index].setSize(null, baseHeight + Math.floor(q * delta)); }); } @@ -1413,8 +1409,8 @@ function validate() { return t('styleMissingName'); } // validate the regexps - if (document.querySelectorAll('.applies-to-list').some(function(list) { - return list.childNodes.some(function(li) { + if (document.querySelectorAll('.applies-to-list').some(list => { + list.childNodes.some(li => { if (li.className == template.appliesToEverything.className) { return false; } @@ -1466,7 +1462,7 @@ function save() { function getSectionsHashes() { const sections = []; - getSections().forEach(function(div) { + getSections().forEach(div => { const meta = getMeta(div); const code = div.CodeMirror.getValue(); if (/^\s*$/.test(code) && Object.keys(meta).length == 0) { @@ -1480,7 +1476,7 @@ function getSectionsHashes() { function getMeta(e) { const meta = {urls: [], urlPrefixes: [], domains: [], regexps: []}; - e.querySelector('.applies-to-list').childNodes.forEach(function(li) { + e.querySelector('.applies-to-list').childNodes.forEach(li => { if (li.className == template.appliesToEverything.className) { return; } @@ -1513,13 +1509,13 @@ function showMozillaFormat() { } function toMozillaFormat() { - return getSectionsHashes().map(function(section) { + return getSectionsHashes().map(section => { let cssMds = []; for (const i in propertyToCss) { if (section[i]) { - cssMds = cssMds.concat(section[i].map(function(v) { - return propertyToCss[i] + '("' + v.replace(/\\/g, '\\\\') + '")'; - })); + cssMds = cssMds.concat(section[i].map(v => + propertyToCss[i] + '("' + v.replace(/\\/g, '\\\\') + '")' + )); } } return cssMds.length ? '@-moz-document ' + cssMds.join(', ') + ' {\n' + section.code + '\n}' : section.code; @@ -1540,9 +1536,9 @@ function fromMozillaFormat() { popup.querySelector('[name="import-append"]').addEventListener('click', doImport); popup.querySelector('[name="import-replace"]').addEventListener('click', doImport); - popup.codebox.on('change', function() { + popup.codebox.on('change', () => { clearTimeout(popup.mozillaTimeout); - popup.mozillaTimeout = setTimeout(function() { + popup.mozillaTimeout = setTimeout(() => { popup.classList.toggle('ready', trimNewLines(popup.codebox.getValue())); }, 100); }); @@ -1558,7 +1554,7 @@ function fromMozillaFormat() { // let oldSectionCount = editors.length; let firstAddedCM; - parser.addListener('startdocument', function(e) { + parser.addListener('startdocument', function (e) { let outerText = getRange(sectionStack.last.start, (--e.col, e)); const gapComment = outerText.match(/(\/\*[\s\S]*?\*\/)[\s\n]*$/); const section = {code: '', start: backtrackTo(this, parserlib.css.Tokens.LBRACE, 'end')}; @@ -1572,7 +1568,7 @@ function fromMozillaFormat() { doAddSection(sectionStack.last); sectionStack.last.code = ''; } - e.functions.forEach(function(f) { + e.functions.forEach(f => { const m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/); const aType = CssToProperty[m[1]]; const aValue = aType != 'regexps' ? m[3] : m[3].replace(/\\\\/g, '\\'); @@ -1581,7 +1577,7 @@ function fromMozillaFormat() { sectionStack.push(section); }); - parser.addListener('enddocument', function() { + parser.addListener('enddocument', function () { const end = backtrackTo(this, parserlib.css.Tokens.RBRACE, 'start'); const section = sectionStack.pop(); section.code += getRange(section.start, end); @@ -1589,14 +1585,14 @@ function fromMozillaFormat() { doAddSection(section); }); - parser.addListener('endstylesheet', function() { + parser.addListener('endstylesheet', () => { // add nonclosed outer sections (either broken or the last global one) const endOfText = {line: lines.length, col: lines.last.length + 1}; sectionStack.last.code += getRange(sectionStack.last.start, endOfText); sectionStack.forEach(doAddSection); delete maximizeCodeHeight.stats; - editors.forEach(function(cm) { + editors.forEach(cm => { maximizeCodeHeight(cm.getSection(), cm == editors.last); }); @@ -1608,7 +1604,7 @@ function fromMozillaFormat() { } }); - parser.addListener('error', function(e) { + parser.addListener('error', e => { errors += e.line + ':' + e.col + ' ' + e.message.replace(/ at line \d.+$/, '') + '
'; }); @@ -1655,7 +1651,7 @@ function fromMozillaFormat() { return false; } if (replaceOldStyle) { - editors.slice(0).reverse().forEach(function(cm) { + editors.slice(0).reverse().forEach(cm => { removeSection({target: cm.getSection().firstElementChild}); }); } else if (!editors.last.getValue()) { @@ -1699,16 +1695,16 @@ function showToggleStyleHelp() { function showKeyMapHelp() { const keyMap = mergeKeyMaps({}, prefs.get('editor.keyMap'), CodeMirror.defaults.extraKeys); const keyMapSorted = Object.keys(keyMap) - .map(function(key) { return {key: key, cmd: keyMap[key]}; }) + .map(key => ({key: key, cmd: keyMap[key]})) .concat([{key: 'Shift-Ctrl-Wheel', cmd: 'scrollWindow'}]) - .sort(function(a, b) { return a.cmd < b.cmd || (a.cmd == b.cmd && a.key < b.key) ? -1 : 1; }); + .sort((a, b) => (a.cmd < b.cmd || (a.cmd == b.cmd && a.key < b.key) ? -1 : 1)); showHelp(t('cm_keyMap') + ': ' + prefs.get('editor.keyMap'), '' + '' + '' + - '' + keyMapSorted.map(function(value) { - return ''; - }).join('') + + '' + keyMapSorted.map(value => + '' + ).join('') + '' + '
' + value.key + '' + value.cmd + '
' + value.key + '' + value.cmd + '
'); @@ -1734,12 +1730,13 @@ function showKeyMapHelp() { this.value = normalizedKey.replace('-dummy', ''); filterTable(event); } + function filterTable(event) { const input = event.target; const query = stringAsRegExp(input.value, 'gi'); const col = input.parentNode.cellIndex; inputs[1 - col].value = ''; - table.tBodies[0].childNodes.forEach(function(row) { + table.tBodies[0].childNodes.forEach(row => { let cell = row.children[col]; cell.innerHTML = cell.textContent.replace(query, '$&'); row.style.display = query.test(cell.textContent) ? '' : 'none'; @@ -1753,7 +1750,7 @@ function showKeyMapHelp() { if (typeof keyMap == 'string') { keyMap = CodeMirror.keyMap[keyMap]; } - Object.keys(keyMap).forEach(function(key) { + Object.keys(keyMap).forEach(key => { let cmd = keyMap[key]; // filter out '...', 'attach', etc. (hotkeys start with an uppercase letter) if (!merged[key] && !key.match(/^[a-z]/) && cmd != '...') { @@ -1777,9 +1774,9 @@ function showKeyMapHelp() { function showLintHelp() { showHelp(t('issues'), t('issuesHelp') + '
    ' + - CSSLint.getRules().map(function(rule) { - return '
  • ' + rule.name + '
    ' + rule.desc + '
  • '; - }).join('') + '
' + CSSLint.getRules().map(rule => + '
  • ' + rule.name + '
    ' + rule.desc + '
  • ' + ).join('') + '' ); } @@ -1932,8 +1929,8 @@ function showCodeMirrorPopup(title, html, options) { keyMap: prefs.get('editor.keyMap') }, options)); popup.codebox.focus(); - popup.codebox.on('focus', function() { hotkeyRerouter.setState(false); }); - popup.codebox.on('blur', function() { hotkeyRerouter.setState(true); }); + popup.codebox.on('focus', () => { hotkeyRerouter.setState(false); }); + popup.codebox.on('blur', () => { hotkeyRerouter.setState(true); }); return popup; } @@ -1943,7 +1940,7 @@ function getParams() { if (urlParts.length == 1) { return params; } - urlParts[1].split('&').forEach(function(keyValue) { + urlParts[1].split('&').forEach(keyValue => { const splitKeyValue = keyValue.split('=', 2); params[decodeURIComponent(splitKeyValue[0])] = decodeURIComponent(splitKeyValue[1]); }); @@ -1969,7 +1966,7 @@ function onRuntimeMessage(request) { break; case 'styleDeleted': if (styleId && styleId == request.id) { - window.onbeforeunload = function() {}; + window.onbeforeunload = () => {}; window.close(); break; } diff --git a/manage/manage.js b/manage/manage.js index 434e7b49..e8fcb481 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -903,7 +903,7 @@ function reapplyFilter(container = installed) { // 3. move the shortest group; repeat 2-3 if (hidden.len < visible.len && (fullPass || hidden.len % 2)) { // 3a. move hidden under the horizon - for (let j = 0; j < (fullPass ? hidden.len : 1); j++) { + for (let j = 0; j < (fullPass ? hidden.len : 1); j++) { const entry = entries[hidden.start]; installed.insertBefore(entry, horizon); horizon = entry; diff --git a/options/index.js b/options/index.js index 68e6b955..6404eefb 100644 --- a/options/index.js +++ b/options/index.js @@ -65,7 +65,7 @@ function checkUpdates() { function setupRadioButtons() { const sets = {}; - const onChange = function() { + const onChange = function () { const newValue = sets[this.name].indexOf(this); if (newValue >= 0 && prefs.get(this.name) != newValue) { prefs.set(this.name, newValue); diff --git a/popup/popup.js b/popup/popup.js index f82b978f..42dd69e3 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -79,7 +79,7 @@ function initPopup(url) { } // action buttons - $('#disableAll').onchange = function() { + $('#disableAll').onchange = function () { installed.classList.toggle('disabled', this.checked); }; setupLivePrefs(); From 24dd0cb562378f5c43c779e0168efd35a5d3479b Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 12:01:39 -0500 Subject: [PATCH 90/94] More cleanup --- edit/edit.js | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index 6eb0406b..f8e63006 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -441,9 +441,11 @@ document.addEventListener('wheel', event => { queryTabs({currentWindow: true}).then(tabs => { const windowId = tabs[0].windowId; if (prefs.get('openEditInWindow')) { - if (sessionStorage.saveSizeOnClose - && 'left' in prefs.get('windowPosition', {}) - && !isWindowMaximized()) { + if ( + sessionStorage.saveSizeOnClose && + 'left' in prefs.get('windowPosition', {}) && + !isWindowMaximized() + ) { // window was reopened via Ctrl-Shift-T etc. chrome.windows.update(windowId, prefs.get('windowPosition')); } @@ -481,10 +483,10 @@ function goBackToManage(event) { } function isWindowMaximized() { - return window.screenLeft == 0 - && window.screenTop == 0 - && window.outerWidth == screen.availWidth - && window.outerHeight == screen.availHeight; + return window.screenLeft == 0 && + window.screenTop == 0 && + window.outerWidth == screen.availWidth && + window.outerHeight == screen.availHeight; } window.onbeforeunload = () => { @@ -570,8 +572,10 @@ function addSection(event, section) { item.querySelector('.applies-value').value.trim()); div.classList.toggle('has-regexp', show); appliesTo.oninput = appliesTo.oninput || show && (event => { - if (event.target.matches('.applies-value') - && event.target.parentElement.querySelector('.applies-type').value == 'regexp') { + if ( + event.target.matches('.applies-value') && + event.target.parentElement.querySelector('.applies-type').value == 'regexp' + ) { showRegExpTester(null, div); } }); @@ -736,8 +740,11 @@ function setupGlobalSearch() { const rxQuery = typeof state.query == 'object' ? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? 'i' : ''); - if (document.activeElement && document.activeElement.name == 'applies-value' - && searchAppliesTo(activeCM)) { + if ( + document.activeElement && + document.activeElement.name == 'applies-value' && + searchAppliesTo(activeCM) + ) { return; } let cm = activeCM; From 417e3b5de3424d8b6b2e53c1168ee945938beef5 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 13:02:00 -0500 Subject: [PATCH 91/94] Add eqeqeq definition to eslint --- .eslintrc | 2 +- background/background.js | 22 +++---- background/storage.js | 54 +++++++-------- background/update.js | 10 +-- content/apply.js | 18 ++--- content/install.js | 30 ++++----- edit/edit.js | 138 +++++++++++++++++++-------------------- js/dom.js | 8 +-- js/localization.js | 12 ++-- js/messaging.js | 24 +++---- js/prefs.js | 30 ++++----- manage/fileSaveLoad.js | 30 ++++----- manage/manage.js | 76 ++++++++++----------- msgbox/msgbox.js | 6 +- options/index.js | 2 +- popup/popup.js | 16 ++--- 16 files changed, 240 insertions(+), 238 deletions(-) diff --git a/.eslintrc b/.eslintrc index 04989f20..2e335468 100644 --- a/.eslintrc +++ b/.eslintrc @@ -82,7 +82,7 @@ rules: dot-location: [2, property] dot-notation: [0] eol-last: [2] - eqeqeq: [0] + eqeqeq: [1, always] func-call-spacing: [2, never] func-name-matching: [0] func-names: [0] diff --git a/background/background.js b/background/background.js index fc5a7f30..3b4f1aa7 100644 --- a/background/background.js +++ b/background/background.js @@ -33,7 +33,7 @@ chrome.tabs.onAttached.addListener((tabId, data) => { if (tab.url.startsWith(URLS.ownOrigin + 'edit.html')) { chrome.windows.get(tab.windowId, {populate: true}, win => { // If there's only one tab in this window, it's been dragged to new window - prefs.set('openEditInWindow', win.tabs.length == 1); + prefs.set('openEditInWindow', win.tabs.length === 1); }); } }); @@ -59,13 +59,13 @@ updateIcon({id: undefined}, {}); const manifest = chrome.runtime.getManifest(); // Open FAQs page once after installation to guide new users. // Do not display it in development mode. - if (reason == 'install' && manifest.update_url) { + if (reason === 'install' && manifest.update_url) { setTimeout(openURL, 100, { url: 'http://add0n.com/stylus.html' }); } // reset L10N cache on update - if (reason == 'update') { + if (reason === 'update') { localStorage.L10N = JSON.stringify({ browserUIlanguage: chrome.i18n.getUILanguage(), }); @@ -138,7 +138,7 @@ contextMenus = Object.assign({ const item = Object.assign({id}, contextMenus[id]); const prefValue = prefs.readOnlyValues[id]; item.title = chrome.i18n.getMessage(item.title); - if (!item.type && typeof prefValue == 'boolean') { + if (!item.type && typeof prefValue === 'boolean') { item.type = 'checkbox'; item.checked = prefValue; } @@ -151,7 +151,7 @@ contextMenus = Object.assign({ }; createContextMenus(); prefs.subscribe((id, checked) => { - if (id == 'editor.contextDelete') { + if (id === 'editor.contextDelete') { if (checked) { createContextMenus([id]); } else { @@ -160,7 +160,7 @@ contextMenus = Object.assign({ } else { chrome.contextMenus.update(id, {checked}, ignoreChromeError); } - }, Object.keys(contextMenus).filter(key => typeof prefs.readOnlyValues[key] == 'boolean')); + }, Object.keys(contextMenus).filter(key => typeof prefs.readOnlyValues[key] === 'boolean')); } // ************************************************************************* @@ -176,7 +176,7 @@ contextMenus = Object.assign({ .replace(/\*/g, '.*?'), flags); for (const cs of contentScripts) { cs.matches = cs.matches.map(m => ( - m == ALL_URLS ? m : wildcardAsRegExp(m) + m === ALL_URLS ? m : wildcardAsRegExp(m) )); } @@ -191,8 +191,8 @@ contextMenus = Object.assign({ const pingCS = (cs, {id, url}) => { cs.matches.some(match => { - if ((match == ALL_URLS || url.match(match)) - && (!url.startsWith('chrome') || url == NTP)) { + if ((match === ALL_URLS || url.match(match)) + && (!url.startsWith('chrome') || url === NTP)) { chrome.tabs.sendMessage(id, PING, pong => { if (!pong) { injectCS(cs, id); @@ -229,7 +229,7 @@ function webNavigationListener(method, {url, tabId, frameId}) { }); } // main page frame id is 0 - if (frameId == 0) { + if (frameId === 0) { updateIcon({id: tabId, url}, styles); } }); @@ -258,7 +258,7 @@ function updateIcon(tab, styles) { } } const disableAll = 'disableAll' in styles ? styles.disableAll : prefs.get('disableAll'); - const postfix = disableAll ? 'x' : numStyles == 0 ? 'w' : ''; + const postfix = disableAll ? 'x' : numStyles === 0 ? 'w' : ''; const color = prefs.get(disableAll ? 'badgeDisabled' : 'badgeNormal'); const text = prefs.get('show-badge') && numStyles ? String(numStyles) : ''; const iconset = ['', 'light/'][prefs.get('iconset')] || ''; diff --git a/background/storage.js b/background/storage.js index 00b4f392..7531f0fb 100644 --- a/background/storage.js +++ b/background/storage.js @@ -63,7 +63,7 @@ function dbExec(method, data) { reject(event); }, onupgradeneeded(event) { - if (event.oldVersion == 0) { + if (event.oldVersion === 0) { event.target.result.createObjectStore('styles', { keyPath: 'id', autoIncrement: true, @@ -111,15 +111,17 @@ function filterStyles({ asHash = null, strictRegexp = true, // used by the popup to detect bad regexps } = {}) { - enabled = enabled === null || typeof enabled == 'boolean' ? enabled : - typeof enabled == 'string' ? enabled == 'true' : null; + enabled = enabled === null || typeof enabled === 'boolean' ? enabled : + typeof enabled === 'string' ? enabled === 'true' : null; id = id === null ? null : Number(id); - if (enabled === null - && url === null - && id === null - && matchUrl === null - && asHash != true) { + if ( + enabled === null && + url === null && + id === null && + matchUrl === null && + asHash !== true + ) { return cachedStyles.list; } const blankHash = asHash && { @@ -191,9 +193,9 @@ function filterStylesInternal({ let style; for (let i = 0; (style = styles[i]); i++) { - if ((enabled === null || style.enabled == enabled) - && (url === null || style.url == url) - && (id === null || style.id == id)) { + if ((enabled === null || style.enabled === enabled) + && (url === null || style.url === url) + && (id === null || style.id === id)) { const sections = needSections && getApplicableSections({style, matchUrl, strictRegexp, stopOnFirst: !asHash}); if (asHash) { @@ -233,16 +235,16 @@ function saveStyle(style) { } let existed; let codeIsUpdated; - if (reason == 'update' || reason == 'update-digest') { + if (reason === 'update' || reason === 'update-digest') { return calcStyleDigest(style).then(digest => { style.originalDigest = digest; return decide(); }); } - if (reason == 'import') { + if (reason === 'import') { style.originalDigest = style.originalDigest || style.styleDigest; // TODO: remove in the future delete style.styleDigest; // TODO: remove in the future - if (typeof style.originalDigest != 'string' || style.originalDigest.length != 40) { + if (typeof style.originalDigest !== 'string' || style.originalDigest.length !== 40) { delete style.originalDigest; } } @@ -255,7 +257,7 @@ function saveStyle(style) { return dbExec('get', id).then((event, store) => { const oldStyle = event.target.result; existed = Boolean(oldStyle); - if (reason == 'update-digest' && oldStyle.originalDigest == style.originalDigest) { + if (reason === 'update-digest' && oldStyle.originalDigest === style.originalDigest) { return style; } codeIsUpdated = !existed || 'sections' in style && !styleSectionsEqual(style, oldStyle); @@ -289,7 +291,7 @@ function saveStyle(style) { } function done(event) { - if (reason == 'update-digest') { + if (reason === 'update-digest') { return style; } style.id = style.id || event.target.result; @@ -367,14 +369,14 @@ function getApplicableSections({style, matchUrl, strictRegexp = true, stopOnFirs function arraySomeMatches(array, matchUrl, strictRegexp) { for (const regexp of array) { for (let pass = 1; pass <= (strictRegexp ? 1 : 2); pass++) { - const cacheKey = pass == 1 ? regexp : SLOPPY_REGEXP_PREFIX + regexp; + const cacheKey = pass === 1 ? regexp : SLOPPY_REGEXP_PREFIX + regexp; let rx = cachedStyles.regexps.get(cacheKey); - if (rx == false) { + if (rx === false) { // invalid regexp break; } if (!rx) { - const anchored = pass == 1 ? '^(?:' + regexp + ')$' : '^' + regexp + '$'; + const anchored = pass === 1 ? '^(?:' + regexp + ')$' : '^' + regexp + '$'; rx = tryRegExp(anchored); cachedStyles.regexps.set(cacheKey, rx || false); if (!rx) { @@ -415,7 +417,7 @@ function styleSectionsEqual({sections: a}, {sections: b}) { if (!a || !b) { return undefined; } - if (a.length != b.length) { + if (a.length !== b.length) { return false; } const checkedInB = []; @@ -432,16 +434,16 @@ function styleSectionsEqual({sections: a}, {sections: b}) { return false; } } - return equalOrEmpty(secA.code, secB.code, 'substr', (a, b) => a == b); + return equalOrEmpty(secA.code, secB.code, 'substr', (a, b) => a === b); } function equalOrEmpty(a, b, telltale, comparator) { - const typeA = a && typeof a[telltale] == 'function'; - const typeB = b && typeof b[telltale] == 'function'; + const typeA = a && typeof a[telltale] === 'function'; + const typeB = b && typeof b[telltale] === 'function'; return ( (a === null || a === undefined || (typeA && !a.length)) && (b === null || b === undefined || (typeB && !b.length)) - ) || typeA && typeB && a.length == b.length && comparator(a, b); + ) || typeA && typeB && a.length === b.length && comparator(a, b); } function arrayMirrors(array1, array2) { @@ -525,12 +527,12 @@ function cleanupCachedFilters({force = false} = {}) { function getDomains(url) { - if (url.indexOf('file:') == 0) { + if (url.indexOf('file:') === 0) { return []; } let d = /.*?:\/*([^/:]+)/.exec(url)[1]; const domains = [d]; - while (d.indexOf('.') != -1) { + while (d.indexOf('.') !== -1) { d = d.substring(d.indexOf('.') + 1); domains.push(d); } diff --git a/background/update.js b/background/update.js index a536098c..04f368f5 100644 --- a/background/update.js +++ b/background/update.js @@ -68,17 +68,17 @@ var updater = { }); function maybeFetchMd5(digest) { - if (!ignoreDigest && style.originalDigest && style.originalDigest != digest) { + if (!ignoreDigest && style.originalDigest && style.originalDigest !== digest) { return Promise.reject(updater.EDITED); } return download(style.md5Url); } function maybeFetchCode(md5) { - if (!md5 || md5.length != 32) { + if (!md5 || md5.length !== 32) { return Promise.reject(updater.ERROR_MD5); } - if (md5 == style.originalMd5 && style.originalDigest && !ignoreDigest) { + if (md5 === style.originalMd5 && style.originalDigest && !ignoreDigest) { return Promise.reject(updater.SAME_MD5); } return download(style.updateUrl); @@ -109,8 +109,8 @@ var updater = { return json && json.sections && json.sections.length - && typeof json.sections.every == 'function' - && typeof json.sections[0].code == 'string'; + && typeof json.sections.every === 'function' + && typeof json.sections[0].code === 'string'; } }, diff --git a/content/apply.js b/content/apply.js index 6e310f05..0cb626e0 100644 --- a/content/apply.js +++ b/content/apply.js @@ -28,7 +28,7 @@ function requestStyles(options, callback = applyStyles) { // dynamic about: and javascript: iframes don't have an URL yet // so we'll try the parent frame which is guaranteed to have a real URL try { - if (window != parent) { + if (window !== parent) { matchUrl = parent.location.href; } } catch (e) {} @@ -49,7 +49,7 @@ function requestStyles(options, callback = applyStyles) { function applyOnMessage(request, sender, sendResponse) { - if (request.styles == 'DIY') { + if (request.styles === 'DIY') { // Do-It-Yourself tells our built-in pages to fetch the styles directly // which is faster because IPC messaging JSON-ifies everything internally requestStyles({}, styles => { @@ -114,7 +114,7 @@ function doDisableAll(disable = disableAll) { disableAll = disable; Array.prototype.forEach.call(document.styleSheets, stylesheet => { if (stylesheet.ownerNode.matches(`STYLE.stylus[id^="${ID_PREFIX}"]`) - && stylesheet.disabled != disable) { + && stylesheet.disabled !== disable) { stylesheet.disabled = disable; } }); @@ -122,14 +122,14 @@ function doDisableAll(disable = disableAll) { function doExposeIframes(state = exposeIframes) { - if (state === exposeIframes || window == parent) { + if (state === exposeIframes || window === parent) { return; } exposeIframes = state; const attr = document.documentElement.getAttribute('stylus-iframe'); - if (state && attr != '') { + if (state && attr !== '') { document.documentElement.setAttribute('stylus-iframe', ''); - } else if (!state && attr == '') { + } else if (!state && attr === '') { document.documentElement.removeAttribute('stylus-iframe'); } } @@ -193,7 +193,7 @@ function applyStyles(styles) { } if (document.head && document.head.firstChild - && document.head.firstChild.id == 'xml-viewer-style') { + && document.head.firstChild.id === 'xml-viewer-style') { // when site response is application/xml Chrome displays our style elements // under document.documentElement as plain text so we need to move them into HEAD // which is already autogenerated at this moment @@ -293,7 +293,7 @@ function initDocRewriteObserver() { for (let m = mutations.length; --m >= 0;) { const added = mutations[m].addedNodes; for (let n = added.length; --n >= 0;) { - if (added[n].localName == 'html') { + if (added[n].localName === 'html') { reinjectStyles(); return; } @@ -303,7 +303,7 @@ function initDocRewriteObserver() { docRewriteObserver.observe(document, {childList: true}); // detect dynamic iframes rewritten after creation by the embedder i.e. externally setTimeout(() => { - if (document.documentElement != ROOT) { + if (document.documentElement !== ROOT) { reinjectStyles(); } }); diff --git a/content/install.js b/content/install.js index 89600266..0445af7f 100644 --- a/content/install.js +++ b/content/install.js @@ -15,7 +15,7 @@ document.addEventListener('stylishInstallOpera', onInstallClicked); chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { // orphaned content script check - if (msg.method == 'ping') { + if (msg.method === 'ping') { sendResponse(true); } }); @@ -32,7 +32,7 @@ document.documentElement.appendChild(document.createElement('script')).text = '( Response.prototype.json = function (...args) { return originalResponseJson.call(this, ...args).then(json => { Response.prototype.json = originalResponseJson; - if (!settings || typeof ((json || {}).style_settings || {}).every != 'function') { + if (!settings || typeof ((json || {}).style_settings || {}).every !== 'function') { return json; } const images = new Map(); @@ -46,18 +46,18 @@ document.documentElement.appendChild(document.createElement('script')).text = '( if (value.startsWith('ik-')) { value = value.replace(/^ik-/, ''); const defaultItem = jsonSetting.style_setting_options.find(item => item.default); - if (!defaultItem || defaultItem.install_key != value) { + if (!defaultItem || defaultItem.install_key !== value) { if (defaultItem) { defaultItem.default = false; } jsonSetting.style_setting_options.some(item => { - if (item.install_key == value) { + if (item.install_key === value) { item.default = true; return true; } }); } - } else if (jsonSetting.setting_type == 'image') { + } else if (jsonSetting.setting_type === 'image') { jsonSetting.style_setting_options.some(item => { if (item.default) { item.default = false; @@ -67,7 +67,7 @@ document.documentElement.appendChild(document.createElement('script')).text = '( images.set(jsonSetting.install_key, value); } else { const item = jsonSetting.style_setting_options[0]; - if (item.value !== value && item.install_key == 'placeholder') { + if (item.value !== value && item.install_key === 'placeholder') { item.value = value; } } @@ -151,7 +151,7 @@ function checkUpdatability([installedStyle]) { const md5Url = getMeta('stylish-md5-url'); if (md5Url && installedStyle.md5Url && installedStyle.originalMd5) { getResource(md5Url).then(md5 => { - reportUpdatable(md5 != installedStyle.originalMd5); + reportUpdatable(md5 !== installedStyle.originalMd5); }); } else { getResource(getStyleURL()).then(code => { @@ -180,7 +180,7 @@ function sendEvent(type, detail = null) { type = type.replace('Chrome', 'Opera'); } detail = {detail}; - if (typeof cloneInto != 'undefined') { + if (typeof cloneInto !== 'undefined') { // Firefox requires explicit cloning, however USO can't process our messages anyway // because USO tries to use a global "event" variable deprecated in Firefox detail = cloneInto(detail, document); // eslint-disable-line no-undef @@ -227,7 +227,7 @@ function saveStyleCode(message, name, addProps) { reason: 'update', }), style => { - if (message == 'styleUpdate' && style.updateUrl.includes('?')) { + if (message === 'styleUpdate' && style.updateUrl.includes('?')) { enableUpdateButton(true); } else { sendEvent('styleInstalledChrome'); @@ -269,7 +269,7 @@ function styleSectionsEqual({sections: a}, {sections: b}) { if (!a || !b) { return undefined; } - if (a.length != b.length) { + if (a.length !== b.length) { return false; } const checkedInB = []; @@ -286,16 +286,16 @@ function styleSectionsEqual({sections: a}, {sections: b}) { return false; } } - return equalOrEmpty(secA.code, secB.code, 'substr', (a, b) => a == b); + return equalOrEmpty(secA.code, secB.code, 'substr', (a, b) => a === b); } function equalOrEmpty(a, b, telltale, comparator) { - const typeA = a && typeof a[telltale] == 'function'; - const typeB = b && typeof b[telltale] == 'function'; + const typeA = a && typeof a[telltale] === 'function'; + const typeB = b && typeof b[telltale] === 'function'; return ( (a === null || a === undefined || (typeA && !a.length)) && (b === null || b === undefined || (typeB && !b.length)) - ) || typeA && typeB && a.length == b.length && comparator(a, b); + ) || typeA && typeB && a.length === b.length && comparator(a, b); } function arrayMirrors(array1, array2) { @@ -315,7 +315,7 @@ function styleSectionsEqual({sections: a}, {sections: b}) { function onDOMready() { - if (document.readyState != 'loading') { + if (document.readyState !== 'loading') { return Promise.resolve(); } return new Promise(resolve => { diff --git a/edit/edit.js b/edit/edit.js index f8e63006..8afb891e 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -45,7 +45,7 @@ Object.defineProperty(Array.prototype, 'last', {get: function () { return this[t new MutationObserver((mutations, observer) => { const themeElement = document.getElementById('cm-theme'); if (themeElement) { - themeElement.href = prefs.get('editor.theme') == 'default' ? '' + themeElement.href = prefs.get('editor.theme') === 'default' ? '' : 'vendor/codemirror/theme/' + prefs.get('editor.theme') + '.css'; observer.disconnect(); } @@ -68,8 +68,8 @@ const hotkeyRerouter = { eventHandler: event => { const keyName = CodeMirror.keyName(event); if ( - CodeMirror.lookupKey(keyName, CodeMirror.getOption('keyMap'), handleCommand) == 'handled' || - CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand) == 'handled' + CodeMirror.lookupKey(keyName, CodeMirror.getOption('keyMap'), handleCommand) === 'handled' || + CodeMirror.lookupKey(keyName, CodeMirror.defaults.extraKeys, handleCommand) === 'handled' ) { event.preventDefault(); event.stopPropagation(); @@ -90,7 +90,7 @@ function onChange(event) { setCleanItem(node, node.savedValue === currentValue); } else { // the manually added section's applies-to is dirty only when the value is non-empty - setCleanItem(node, node.localName != 'input' || !node.value.trim()); + setCleanItem(node, node.localName !== 'input' || !node.value.trim()); delete node.savedValue; // only valid when actually saved } updateTitle(); @@ -122,7 +122,7 @@ function setCleanItem(node, isClean) { } function isCleanGlobal() { - const clean = Object.keys(dirty).length == 0; + const clean = Object.keys(dirty).length === 0; setDirtyClass(document.body, !clean); // let saveBtn = document.getElementById('save-button') // if (clean){ @@ -270,7 +270,7 @@ function initCodeMirror() { } else { // Chrome is starting up and shows our edit.html, but the background page isn't loaded yet const theme = prefs.get('editor.theme'); - themeControl.innerHTML = optionsHtmlFromArray([theme == 'default' ? t('defaultTheme') : theme]); + themeControl.innerHTML = optionsHtmlFromArray([theme === 'default' ? t('defaultTheme') : theme]); getCodeMirrorThemes().then(() => { const themes = (localStorage.codeMirrorThemes || '').split(/\s+/); themeControl.innerHTML = optionsHtmlFromArray(themes); @@ -292,7 +292,7 @@ function acmeEventListener(event) { console.error('acmeEventListener: no "cm_option" %O', el); return; } - let value = el.type == 'checkbox' ? el.checked : el.value; + let value = el.type === 'checkbox' ? el.checked : el.value; switch (option) { case 'tabSize': CodeMirror.setOption('indentUnit', Number(value)); @@ -300,9 +300,9 @@ function acmeEventListener(event) { case 'theme': { const themeLink = document.getElementById('cm-theme'); // use non-localized 'default' internally - if (!value || value == 'default' || value == t('defaultTheme')) { + if (!value || value === 'default' || value === t('defaultTheme')) { value = 'default'; - if (prefs.get(el.id) != value) { + if (prefs.get(el.id) !== value) { prefs.set(el.id, value); } themeLink.href = ''; @@ -310,7 +310,7 @@ function acmeEventListener(event) { break; } const url = chrome.runtime.getURL('vendor/codemirror/theme/' + value + '.css'); - if (themeLink.href == url) { // preloaded in initCodeMirror() + if (themeLink.href === url) { // preloaded in initCodeMirror() break; } // avoid flicker: wait for the second stylesheet to load, then apply the theme @@ -337,7 +337,7 @@ function acmeEventListener(event) { case 'token': case 'selection': document.body.dataset[option] = value; - value = {showToken: value == 'token' && /[#.\-\w]/, annotateScrollbar: true}; + value = {showToken: value === 'token' && /[#.\-\w]/, annotateScrollbar: true}; break; default: value = null; @@ -372,7 +372,7 @@ function setupCodeMirror(textarea, index) { let lastClickTime = 0; const resizeGrip = wrapper.appendChild(template.resizeGrip.cloneNode(true)); resizeGrip.onmousedown = event => { - if (event.button != 0) { + if (event.button !== 0) { return; } event.preventDefault(); @@ -390,7 +390,7 @@ function setupCodeMirror(textarea, index) { function resize(e) { const cmPageY = wrapper.getBoundingClientRect().top + window.scrollY; const height = Math.max(minHeight, e.pageY - cmPageY); - if (height != wrapper.clientHeight) { + if (height !== wrapper.clientHeight) { cm.setSize(null, height); } } @@ -449,7 +449,7 @@ queryTabs({currentWindow: true}).then(tabs => { // window was reopened via Ctrl-Shift-T etc. chrome.windows.update(windowId, prefs.get('windowPosition')); } - if (tabs.length == 1 && window.history.length == 1) { + if (tabs.length === 1 && window.history.length === 1) { chrome.windows.getAll(windows => { if (windows.length > 1) { sessionStorageHash('saveSizeOnClose').set(windowId, true); @@ -462,14 +462,14 @@ queryTabs({currentWindow: true}).then(tabs => { } chrome.tabs.onRemoved.addListener((tabId, info) => { sessionStorageHash('manageStylesHistory').unset(tabId); - if (info.windowId == windowId && info.isWindowClosing) { + if (info.windowId === windowId && info.isWindowClosing) { sessionStorageHash('saveSizeOnClose').unset(windowId); } }); }); getActiveTab().then(tab => { - useHistoryBack = sessionStorageHash('manageStylesHistory').value[tab.id] == location.href; + useHistoryBack = sessionStorageHash('manageStylesHistory').value[tab.id] === location.href; }); function goBackToManage(event) { @@ -483,10 +483,10 @@ function goBackToManage(event) { } function isWindowMaximized() { - return window.screenLeft == 0 && - window.screenTop == 0 && - window.outerWidth == screen.availWidth && - window.outerHeight == screen.availHeight; + return window.screenLeft === 0 && + window.screenTop === 0 && + window.outerWidth === screen.availWidth && + window.outerHeight === screen.availHeight; } window.onbeforeunload = () => { @@ -568,13 +568,13 @@ function addSection(event, section) { function toggleTestRegExpVisibility() { const show = [...appliesTo.children].some(item => !item.matches('.applies-to-everything') && - item.querySelector('.applies-type').value == 'regexp' && + item.querySelector('.applies-type').value === 'regexp' && item.querySelector('.applies-value').value.trim()); div.classList.toggle('has-regexp', show); appliesTo.oninput = appliesTo.oninput || show && (event => { if ( event.target.matches('.applies-value') && - event.target.parentElement.querySelector('.applies-type').value == 'regexp' + event.target.parentElement.querySelector('.applies-type').value === 'regexp' ) { showRegExpTester(null, div); } @@ -666,7 +666,7 @@ function setupGlobalSearch() { let curState; // cm.state.search for last used 'find' function shouldIgnoreCase(query) { // treat all-lowercase non-regexp queries as case-insensitive - return typeof query == 'string' && query == query.toLowerCase(); + return typeof query === 'string' && query === query.toLowerCase(); } function updateState(cm, newState) { @@ -701,7 +701,7 @@ function setupGlobalSearch() { function focusClosestCM(activeCM) { editors.lastActive = activeCM; const cm = getEditorInSight(); - if (cm != activeCM) { + if (cm !== activeCM) { cm.focus(); } return cm; @@ -712,16 +712,16 @@ function setupGlobalSearch() { customizeOpenDialog(activeCM, template.find, function (query) { this(query); curState = activeCM.state.search; - if (editors.length == 1 || !curState.query) { + if (editors.length === 1 || !curState.query) { return; } editors.forEach(cm => { - if (cm != activeCM) { + if (cm !== activeCM) { cm.execCommand('clearSearch'); updateState(cm, curState); } }); - if (CodeMirror.cmpPos(curState.posFrom, curState.posTo) == 0) { + if (CodeMirror.cmpPos(curState.posFrom, curState.posTo) === 0) { findNext(activeCM); } }); @@ -737,12 +737,12 @@ function setupGlobalSearch() { let pos = activeCM.getCursor(reverse ? 'from' : 'to'); activeCM.setSelection(activeCM.getCursor()); // clear the selection, don't move the cursor - const rxQuery = typeof state.query == 'object' + const rxQuery = typeof state.query === 'object' ? state.query : stringAsRegExp(state.query, shouldIgnoreCase(state.query) ? 'i' : ''); if ( document.activeElement && - document.activeElement.name == 'applies-value' && + document.activeElement.name === 'applies-value' && searchAppliesTo(activeCM) ) { return; @@ -864,7 +864,7 @@ function setupGlobalSearch() { wrapAround |= cmp <= 0; const dlg = cm.getWrapperElement().querySelector('.CodeMirror-dialog'); - if (!dlg || cmp == 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) { + if (!dlg || cmp === 0 || wrapAround && CodeMirror.cmpPos(cm.getCursor(), origPos) >= 0) { if (dlg) { dlg.remove(); } @@ -1006,7 +1006,7 @@ function getEditorInSight(nearbyElement) { } function updateLintReport(cm, delay) { - if (delay == 0) { + if (delay === 0) { // immediately show pending csslint messages in onbeforeunload and save update(cm); return; @@ -1024,7 +1024,7 @@ function updateLintReport(cm, delay) { // or update it as soon as possible (default: 500ms lint + 100ms) in case an existing issue was just fixed clearTimeout(state.reportTimeout); state.reportTimeout = setTimeout(update, state.options.delay + 100, cm); - state.postponeNewIssues = delay == undefined || delay === null; + state.postponeNewIssues = delay === undefined || delay === null; function update(cm) { const scope = cm ? [cm] : editors; @@ -1034,16 +1034,16 @@ function updateLintReport(cm, delay) { const scopedState = cm.state.lint || {}; const oldMarkers = scopedState.markedLast || {}; const newMarkers = {}; - const html = !scopedState.marked || scopedState.marked.length == 0 ? '' : '' + + const html = !scopedState.marked || scopedState.marked.length === 0 ? '' : '' + scopedState.marked.map(mark => { const info = mark.__annotation; - const isActiveLine = info.from.line == cm.getCursor().line; + const isActiveLine = info.from.line === cm.getCursor().line; const pos = isActiveLine ? 'cursor' : (info.from.line + ',' + info.from.ch); let message = escapeHtml(info.message.replace(/ at line \d.+$/, '')); if (message.length > 100) { message = message.substr(0, 100) + '...'; } - if (isActiveLine || oldMarkers[pos] == message) { + if (isActiveLine || oldMarkers[pos] === message) { delete oldMarkers[pos]; } newMarkers[pos] = message; @@ -1057,7 +1057,7 @@ function updateLintReport(cm, delay) { }).join('') + ''; scopedState.markedLast = newMarkers; fixedOldIssues |= scopedState.reportDisplayed && Object.keys(oldMarkers).length > 0; - if (scopedState.html != html) { + if (scopedState.html !== html) { scopedState.html = html; changed = true; } @@ -1094,12 +1094,12 @@ function renderLintReport(someBlockChanged) { issueCount += newBlock.rows.length; const block = content.children[newContent.children.length - 1]; - const blockChanged = !block || cm != block.cm || html != block.innerHTML; + const blockChanged = !block || cm !== block.cm || html !== block.innerHTML; someBlockChanged |= blockChanged; cm.state.lint.reportDisplayed = blockChanged; } }); - if (someBlockChanged || newContent.children.length != content.children.length) { + if (someBlockChanged || newContent.children.length !== content.children.length) { document.getElementById('issue-count').textContent = issueCount; container.replaceChild(newContent, content); container.style.display = newContent.children.length ? 'block' : 'none'; @@ -1112,7 +1112,7 @@ function resizeLintReport(event, content) { if (content.children.length) { const bounds = content.getBoundingClientRect(); const newMaxHeight = bounds.bottom <= innerHeight ? '' : (innerHeight - bounds.top) + 'px'; - if (newMaxHeight != content.style.maxHeight) { + if (newMaxHeight !== content.style.maxHeight) { content.style.maxHeight = newMaxHeight; } } @@ -1167,7 +1167,7 @@ function beautify(event) { '
    '); const undoButton = document.querySelector('#help-popup button[role="undo"]'); - undoButton.textContent = t(scope.length == 1 ? 'undo' : 'undoGlobal'); + undoButton.textContent = t(scope.length === 1 ? 'undo' : 'undoGlobal'); undoButton.addEventListener('click', () => { let undoable = false; scope.forEach(cm => { @@ -1188,7 +1188,7 @@ function beautify(event) { [Object.assign({}, r.anchor), Object.assign({}, r.head)])); const text = cm.getValue(); const newText = exports.css_beautify(text, options); - if (newText != text) { + if (newText !== text) { if (!cm.beautifyChange || !cm.beautifyChange[cm.changeGeneration()]) { // clear the list if last change wasn't a css-beautify cm.beautifyChange = {}; @@ -1206,7 +1206,7 @@ function beautify(event) { }); document.querySelector('.beautify-options').onchange = ({target}) => { - const value = target.type == 'checkbox' ? target.checked : target.selectedIndex > 0; + const value = target.type === 'checkbox' ? target.checked : target.selectedIndex > 0; prefs.set('editor.beautify', Object.assign(options, {[target.dataset.option]: value})); if (target.parentNode.hasAttribute('newline')) { target.parentNode.setAttribute('newline', value.toString()); @@ -1264,7 +1264,7 @@ function init() { window.onload = null; initWithStyle({style}); }; - if (document.readyState != 'loading') { + if (document.readyState !== 'loading') { window.onload(); } }); @@ -1346,10 +1346,10 @@ function initHooks() { function toggleContextMenuDelete(event) { - if (event.button == 2 && prefs.get('editor.contextDelete')) { + if (event.button === 2 && prefs.get('editor.contextDelete')) { chrome.contextMenus.update('editor.contextDelete', { enabled: Boolean( - this.selectionStart != this.selectionEnd || + this.selectionStart !== this.selectionEnd || this.somethingSelected && this.somethingSelected() ), }, ignoreChromeError); @@ -1412,20 +1412,20 @@ function updateTitle() { function validate() { const name = document.getElementById('name').value; - if (name == '') { + if (name === '') { return t('styleMissingName'); } // validate the regexps if (document.querySelectorAll('.applies-to-list').some(list => { list.childNodes.some(li => { - if (li.className == template.appliesToEverything.className) { + if (li.className === template.appliesToEverything.className) { return false; } const valueElement = li.querySelector('[name=applies-value]'); const type = li.querySelector('[name=applies-type]').value; const value = valueElement.value; if (type && value) { - if (type == 'regexp') { + if (type === 'regexp') { try { new RegExp(value); } catch (ex) { @@ -1472,7 +1472,7 @@ function getSectionsHashes() { getSections().forEach(div => { const meta = getMeta(div); const code = div.CodeMirror.getValue(); - if (/^\s*$/.test(code) && Object.keys(meta).length == 0) { + if (/^\s*$/.test(code) && Object.keys(meta).length === 0) { return; } meta.code = code; @@ -1484,7 +1484,7 @@ function getSectionsHashes() { function getMeta(e) { const meta = {urls: [], urlPrefixes: [], domains: [], regexps: []}; e.querySelector('.applies-to-list').childNodes.forEach(li => { - if (li.className == template.appliesToEverything.className) { + if (li.className === template.appliesToEverything.className) { return; } const type = li.querySelector('[name=applies-type]').value; @@ -1502,7 +1502,7 @@ function saveComplete(style) { setCleanGlobal(); // Go from new style URL to edit style URL - if (location.href.indexOf('id=') == -1) { + if (location.href.indexOf('id=') === -1) { history.replaceState({}, document.title, 'edit.html?id=' + style.id); tE('heading', 'editStyleHeading', null, false); } @@ -1551,7 +1551,7 @@ function fromMozillaFormat() { }); function doImport() { - const replaceOldStyle = this.name == 'import-replace'; + const replaceOldStyle = this.name === 'import-replace'; popup.querySelector('.dismiss').onclick(); const mozStyle = trimNewLines(popup.codebox.getValue()); const parser = new parserlib.css.Parser(); @@ -1578,7 +1578,7 @@ function fromMozillaFormat() { e.functions.forEach(f => { const m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/); const aType = CssToProperty[m[1]]; - const aValue = aType != 'regexps' ? m[3] : m[3].replace(/\\\\/g, '\\'); + const aValue = aType !== 'regexps' ? m[3] : m[3].replace(/\\\\/g, '\\'); (section[aType] = section[aType] || []).push(aValue); }); sectionStack.push(section); @@ -1600,7 +1600,7 @@ function fromMozillaFormat() { delete maximizeCodeHeight.stats; editors.forEach(cm => { - maximizeCodeHeight(cm.getSection(), cm == editors.last); + maximizeCodeHeight(cm.getSection(), cm === editors.last); }); makeSectionVisible(firstAddedCM); @@ -1622,7 +1622,7 @@ function fromMozillaFormat() { const C1 = start.col - 1; const L2 = end.line - 1; const C2 = end.col - 1; - if (L1 == L2) { + if (L1 === L2) { return lines[L1].substr(C1, C2 - C1 + 1); } else { const middle = lines.slice(L1 + 1, L2).join('\n'); @@ -1673,7 +1673,7 @@ function fromMozillaFormat() { function backtrackTo(parser, tokenType, startEnd) { const tokens = parser._tokenStream._lt; for (let i = parser._tokenStream._ltIndex - 1; i >= 0; --i) { - if (tokens[i].type == tokenType) { + if (tokens[i].type === tokenType) { return {line: tokens[i][startEnd + 'Line'], col: tokens[i][startEnd + 'Col']}; } } @@ -1704,7 +1704,7 @@ function showKeyMapHelp() { const keyMapSorted = Object.keys(keyMap) .map(key => ({key: key, cmd: keyMap[key]})) .concat([{key: 'Shift-Ctrl-Wheel', cmd: 'scrollWindow'}]) - .sort((a, b) => (a.cmd < b.cmd || (a.cmd == b.cmd && a.key < b.key) ? -1 : 1)); + .sort((a, b) => (a.cmd < b.cmd || (a.cmd === b.cmd && a.key < b.key) ? -1 : 1)); showHelp(t('cm_keyMap') + ': ' + prefs.get('editor.keyMap'), '' + '' + @@ -1724,7 +1724,7 @@ function showKeyMapHelp() { function hotkeyHandler(event) { const keyName = CodeMirror.keyName(event); - if (keyName == 'Esc' || keyName == 'Tab' || keyName == 'Shift-Tab') { + if (keyName === 'Esc' || keyName === 'Tab' || keyName === 'Shift-Tab') { return; } event.preventDefault(); @@ -1754,14 +1754,14 @@ function showKeyMapHelp() { } function mergeKeyMaps(merged, ...more) { more.forEach(keyMap => { - if (typeof keyMap == 'string') { + if (typeof keyMap === 'string') { keyMap = CodeMirror.keyMap[keyMap]; } Object.keys(keyMap).forEach(key => { let cmd = keyMap[key]; // filter out '...', 'attach', etc. (hotkeys start with an uppercase letter) - if (!merged[key] && !key.match(/^[a-z]/) && cmd != '...') { - if (typeof cmd == 'function') { + if (!merged[key] && !key.match(/^[a-z]/) && cmd !== '...') { + if (typeof cmd === 'function') { // for 'emacs' keymap: provide at least something meaningful (hotkeys and the function body) // for 'vim*' keymaps: almost nothing as it doesn't rely on CM keymap mechanism cmd = cmd.toString().replace(/^function.*?\{[\s\r\n]*([\s\S]+?)[\s\r\n]*\}$/, '$1'); @@ -1795,7 +1795,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) { const regexps = [...section.querySelector('.applies-to-list').children] .map(item => !item.matches('.applies-to-everything') && - item.querySelector('.applies-type').value == 'regexp' && + item.querySelector('.applies-type').value === 'regexp' && item.querySelector('.applies-value').value.trim()) .filter(item => item) .map(text => { @@ -1857,7 +1857,7 @@ function showRegExpTester(event, section = getSectionForChild(this)) { ? OWN_ICON : GET_FAVICON_URL + new URL(url).hostname; const icon = ``; - if (match.length == url.length) { + if (match.length === url.length) { full.push(`
    ${icon + url}
    `); } else { partial.push(`
    ${icon}${match}` + @@ -1898,7 +1898,7 @@ function showHelp(title, text) { div.querySelector('.contents').innerHTML = text; div.querySelector('.title').innerHTML = title; - if (getComputedStyle(div).display == 'none') { + if (getComputedStyle(div).display === 'none') { document.addEventListener('keydown', closeHelp); div.querySelector('.dismiss').onclick = closeHelp; // avoid chaining on multiple showHelp() calls } @@ -1909,8 +1909,8 @@ function showHelp(title, text) { function closeHelp(e) { if ( !e || - e.type == 'click' || - ((e.keyCode || e.which) == 27 && !e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey) + e.type === 'click' || + ((e.keyCode || e.which) === 27 && !e.altKey && !e.ctrlKey && !e.shiftKey && !e.metaKey) ) { div.style.display = ''; document.querySelector('.contents').innerHTML = ''; @@ -1944,7 +1944,7 @@ function showCodeMirrorPopup(title, html, options) { function getParams() { const params = {}; const urlParts = location.href.split('?', 2); - if (urlParts.length == 1) { + if (urlParts.length === 1) { return params; } urlParts[1].split('&').forEach(keyValue => { @@ -1959,7 +1959,7 @@ chrome.runtime.onMessage.addListener(onRuntimeMessage); function onRuntimeMessage(request) { switch (request.method) { case 'styleUpdated': - if (styleId && styleId == request.style.id && request.reason != 'editSave') { + if (styleId && styleId === request.style.id && request.reason !== 'editSave') { if ((request.style.sections[0] || {}).code === null) { // the code-less style came from notifyAllTabs onBackgroundReady().then(() => { @@ -1972,7 +1972,7 @@ function onRuntimeMessage(request) { } break; case 'styleDeleted': - if (styleId && styleId == request.id) { + if (styleId && styleId === request.id) { window.onbeforeunload = () => {}; window.close(); break; diff --git a/js/dom.js b/js/dom.js index 88fd44b6..6a71a10a 100644 --- a/js/dom.js +++ b/js/dom.js @@ -27,7 +27,7 @@ navigator.userAgent.includes('Firefox') && setTimeout(() => { function onDOMready() { - if (document.readyState != 'loading') { + if (document.readyState !== 'loading') { return Promise.resolve(); } return new Promise(resolve => { @@ -79,9 +79,9 @@ function enforceInputRange(element) { const max = Number(element.max); const doNotify = () => element.dispatchEvent(new Event('change', {bubbles: true})); const onChange = ({type}) => { - if (type == 'input' && element.checkValidity()) { + if (type === 'input' && element.checkValidity()) { doNotify(); - } else if (type == 'change' && !element.checkValidity()) { + } else if (type === 'change' && !element.checkValidity()) { element.value = Math.max(min, Math.min(max, Number(element.value))); doNotify(); } @@ -113,7 +113,7 @@ function $element(opt) { ? opt.tag.split('#') : [null, opt.tag]; const element = ns - ? document.createElementNS(ns == 'SVG' || ns == 'svg' ? 'http://www.w3.org/2000/svg' : ns, tag) + ? document.createElementNS(ns === 'SVG' || ns === 'svg' ? 'http://www.w3.org/2000/svg' : ns, tag) : document.createElement(tag || 'div'); (opt.appendChild instanceof Array ? opt.appendChild : [opt.appendChild]) .forEach(child => child && element.appendChild(child)); diff --git a/js/localization.js b/js/localization.js index 0c5f578c..1db7577b 100644 --- a/js/localization.js +++ b/js/localization.js @@ -7,7 +7,7 @@ tDocLoader(); function t(key, params) { const cache = !params && t.cache[key]; const s = cache || chrome.i18n.getMessage(key, params); - if (s == '') { + if (s === '') { throw `Missing string "${key}"`; } if (!params && !cache) { @@ -20,7 +20,7 @@ function t(key, params) { function tE(id, key, attr, esc) { if (attr) { document.getElementById(id).setAttribute(attr, t(key)); - } else if (typeof esc == 'undefined' || esc) { + } else if (typeof esc === 'undefined' || esc) { document.getElementById(id).appendChild(document.createTextNode(t(key))); } else { document.getElementById(id).innerHTML = t(key); @@ -43,10 +43,10 @@ function tNodeList(nodes) { for (let n = nodes.length; --n >= 0;) { const node = nodes[n]; // skip non-ELEMENT_NODE - if (node.nodeType != 1) { + if (node.nodeType !== 1) { continue; } - if (node.localName == 'template') { + if (node.localName === 'template') { const elements = node.content.querySelectorAll('*'); tNodeList(elements); template[node.dataset.id] = elements[0]; @@ -94,7 +94,7 @@ function tDocLoader() { // reset L10N cache on UI language change const UIlang = chrome.i18n.getUILanguage(); - if (t.cache.browserUIlanguage != UIlang) { + if (t.cache.browserUIlanguage !== UIlang) { t.cache = {browserUIlanguage: UIlang}; localStorage.L10N = JSON.stringify(t.cache); } @@ -114,7 +114,7 @@ function tDocLoader() { const onLoad = () => { tDocLoader.stop(); process(observer.takeRecords()); - if (cacheLength != Object.keys(t.cache).length) { + if (cacheLength !== Object.keys(t.cache).length) { localStorage.L10N = JSON.stringify(t.cache); } }; diff --git a/js/messaging.js b/js/messaging.js index a1e1c4b0..386f7409 100644 --- a/js/messaging.js +++ b/js/messaging.js @@ -35,7 +35,7 @@ const URLS = { let BG = chrome.extension.getBackgroundPage(); -if (!BG || BG != window) { +if (!BG || BG !== window) { document.documentElement.classList.toggle('firefox', FIREFOX); document.documentElement.classList.toggle('opera', OPERA); // TODO: remove once our manifest's minimum_chrome_version is 50+ @@ -47,7 +47,7 @@ if (!BG || BG != window) { function notifyAllTabs(msg) { const originalMessage = msg; - if (msg.method == 'styleUpdated' || msg.method == 'styleAdded') { + if (msg.method === 'styleUpdated' || msg.method === 'styleAdded') { // apply/popup/manage use only meta for these two methods, // editor may need the full code but can fetch it directly, // so we send just the meta to avoid spamming lots of tabs with huge styles @@ -86,11 +86,11 @@ function notifyAllTabs(msg) { }); } // notify self: the message no longer is sent to the origin in new Chrome - if (typeof onRuntimeMessage != 'undefined') { + if (typeof onRuntimeMessage !== 'undefined') { onRuntimeMessage(originalMessage); } // notify apply.js on own pages - if (typeof applyOnMessage != 'undefined') { + if (typeof applyOnMessage !== 'undefined') { applyOnMessage(originalMessage); } // notify background page and all open popups @@ -134,7 +134,7 @@ function getActiveTabRealURL() { function getTabRealURL(tab) { return new Promise(resolve => { - if (tab.url != 'chrome://newtab/') { + if (tab.url !== 'chrome://newtab/') { resolve(tab.url); } else { chrome.webNavigation.getFrame({tabId: tab.id, frameId: 0, processId: -1}, frame => { @@ -159,13 +159,13 @@ function openURL({url, currentWindow = true}) { const urlQuery = url.startsWith('moz-extension') ? undefined : url.replace(/#.*/, ''); queryTabs({url: urlQuery, currentWindow}).then(tabs => { for (const tab of tabs) { - if (tab.url == url) { + if (tab.url === url) { activateTab(tab).then(resolve); return; } } getActiveTab().then(tab => { - if (tab && tab.url == 'chrome://newtab/' + if (tab && tab.url === 'chrome://newtab/' // prevent redirecting incognito NTP to a chrome URL as it crashes Chrome && (!url.startsWith('chrome') || !tab.incognito)) { chrome.tabs.update({url}, resolve); @@ -250,14 +250,14 @@ const debounce = Object.assign((fn, delay, ...args) => { function deepCopy(obj) { - return obj !== null && obj !== undefined && typeof obj == 'object' - ? deepMerge(typeof obj.slice == 'function' ? [] : {}, obj) + return obj !== null && obj !== undefined && typeof obj === 'object' + ? deepMerge(typeof obj.slice === 'function' ? [] : {}, obj) : obj; } function deepMerge(target, ...args) { - const isArray = typeof target.slice == 'function'; + const isArray = typeof target.slice === 'function'; for (const obj of args) { if (isArray && obj !== null && obj !== undefined) { for (const element of obj) { @@ -267,7 +267,7 @@ function deepMerge(target, ...args) { } for (const k in obj) { const value = obj[k]; - if (k in target && typeof value == 'object' && value !== null) { + if (k in target && typeof value === 'object' && value !== null) { deepMerge(target[k], value); } else { target[k] = deepCopy(value); @@ -346,7 +346,7 @@ function download(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.timeout = 10e3; - xhr.onloadend = () => (xhr.status == 200 + xhr.onloadend = () => (xhr.status === 200 ? resolve(xhr.responseText) : reject(xhr.status)); const [mainUrl, query] = url.split('?'); diff --git a/js/prefs.js b/js/prefs.js index c34a0546..2326036b 100644 --- a/js/prefs.js +++ b/js/prefs.js @@ -115,10 +115,10 @@ var prefs = new function Prefs() { defineReadonlyProperty(this.readOnlyValues, key, value); const hasChanged = !equal(value, oldValue); if (!fromBroadcast) { - if (BG && BG != window) { + if (BG && BG !== window) { BG.prefs.set(key, BG.deepCopy(value), {broadcast, sync}); } else { - localStorage[key] = typeof defaults[key] == 'object' + localStorage[key] = typeof defaults[key] === 'object' ? JSON.stringify(value) : value; if (broadcast && hasChanged) { @@ -166,7 +166,7 @@ var prefs = new function Prefs() { for (const key in defaults) { const defaultValue = defaults[key]; let value = localStorage[key]; - if (typeof value == 'string') { + if (typeof value === 'string') { switch (typeof defaultValue) { case 'boolean': value = value.toLowerCase() === 'true'; @@ -181,7 +181,7 @@ var prefs = new function Prefs() { } else { value = defaultValue; } - if (BG == window) { + if (BG === window) { // when in bg page, .set() will write to localStorage this.set(key, value, {broadcast: false, sync: false}); } else { @@ -190,13 +190,13 @@ var prefs = new function Prefs() { } } - if (!BG || BG == window) { + if (!BG || BG === window) { affectsIcon.forEach(key => this.broadcast(key, values[key], {sync: false})); getSync().get('settings', ({settings: synced} = {}) => { if (synced) { for (const key in defaults) { - if (key == 'popupWidth' && synced[key] != values.popupWidth) { + if (key === 'popupWidth' && synced[key] !== values.popupWidth) { // this is a fix for the period when popupWidth wasn't synced // TODO: remove it in a couple of months continue; @@ -209,7 +209,7 @@ var prefs = new function Prefs() { }); chrome.storage.onChanged.addListener((changes, area) => { - if (area == 'sync' && 'settings' in changes) { + if (area === 'sync' && 'settings' in changes) { const synced = changes.settings.newValue; if (synced) { for (const key in defaults) { @@ -283,21 +283,21 @@ var prefs = new function Prefs() { function defineReadonlyProperty(obj, key, value) { const copy = deepCopy(value); - if (typeof copy == 'object') { + if (typeof copy === 'object') { Object.freeze(copy); } Object.defineProperty(obj, key, {value: copy, configurable: true}); } function equal(a, b) { - if (!a || !b || typeof a != 'object' || typeof b != 'object') { + if (!a || !b || typeof a !== 'object' || typeof b !== 'object') { return a === b; } - if (Object.keys(a).length != Object.keys(b).length) { + if (Object.keys(a).length !== Object.keys(b).length) { return false; } for (const k in a) { - if (typeof a[k] == 'object') { + if (typeof a[k] === 'object') { if (!equal(a[k], b[k])) { return false; } @@ -315,7 +315,7 @@ var prefs = new function Prefs() { // Chrome and co. /Safari\/[\d.]+$/.test(navigator.userAgent) && // skip forks with Flash as those are likely to have the menu e.g. CentBrowser - !Array.from(navigator.plugins).some(p => p.name == 'Shockwave Flash') + !Array.from(navigator.plugins).some(p => p.name === 'Shockwave Flash') ); } }(); @@ -330,7 +330,7 @@ function setupLivePrefs( const checkedProps = {}; for (const id of IDs) { const element = document.getElementById(id); - checkedProps[id] = element.type == 'checkbox' ? 'checked' : 'value'; + checkedProps[id] = element.type === 'checkbox' ? 'checked' : 'value'; updateElement({id, element, force: true}); element.addEventListener('change', onChange); } @@ -338,7 +338,7 @@ function setupLivePrefs( function onChange() { const value = this[checkedProps[this.id]]; - if (prefs.get(this.id) != value) { + if (prefs.get(this.id) !== value) { prefs.set(this.id, value); } } @@ -349,7 +349,7 @@ function setupLivePrefs( force, }) { const prop = checkedProps[id]; - if (force || element[prop] != value) { + if (force || element[prop] !== value) { element[prop] = value; element.dispatchEvent(new Event('change', {bubbles: true, cancelable: true})); } diff --git a/manage/fileSaveLoad.js b/manage/fileSaveLoad.js index 9d37fc1b..ec54517d 100644 --- a/manage/fileSaveLoad.js +++ b/manage/fileSaveLoad.js @@ -53,7 +53,7 @@ function importFromString(jsonString) { } // create objects in background context const json = BG.tryJSONparse(jsonString) || []; - if (typeof json.slice != 'function') { + if (typeof json.slice !== 'function') { json.length = 0; } const oldStyles = json.length && BG.deepCopy(BG.cachedStyles.list || []); @@ -94,8 +94,8 @@ function importFromString(jsonString) { } function analyze(item) { - if (!item || !item.name || !item.name.trim() || typeof item != 'object' - || (item.sections && typeof item.sections.slice != 'function')) { + if (!item || !item.name || !item.name.trim() || typeof item !== 'object' + || (item.sections && typeof item.sections.slice !== 'function')) { stats.invalid.names.push(`#${index}: ${limitString(item && item.name || '')}`); return; } @@ -117,8 +117,8 @@ function importFromString(jsonString) { } const oldStyleKeys = oldStyle && Object.keys(oldStyle); const metaEqual = oldStyleKeys && - oldStyleKeys.length == Object.keys(item).length && - oldStyleKeys.every(k => k == 'sections' || oldStyle[k] === item[k]); + oldStyleKeys.length === Object.keys(item).length && + oldStyleKeys.every(k => k === 'sections' || oldStyle[k] === item[k]); const codeEqual = oldStyle && BG.styleSectionsEqual(oldStyle, item); if (metaEqual && codeEqual) { stats.unchanged.names.push(oldStyle.name); @@ -131,7 +131,7 @@ function importFromString(jsonString) { function sameStyle(oldStyle, newStyle) { return oldStyle.name.trim() === newStyle.name.trim() || ['updateUrl', 'originalMd5', 'originalDigest'] - .some(field => oldStyle[field] && oldStyle[field] == newStyle[field]); + .some(field => oldStyle[field] && oldStyle[field] === newStyle[field]); } function account({style, info, resolve}) { @@ -196,7 +196,7 @@ function importFromString(jsonString) { buttons: [t('confirmOK'), numChanged && t('undo')], onshow: bindClick, }).then(({button, enter, esc}) => { - if (button == 1) { + if (button === 1) { undo(); } }); @@ -224,7 +224,7 @@ function importFromString(jsonString) { buttons: [t('confirmOK')], })); function undoNextId() { - if (index == newIds.length) { + if (index === newIds.length) { resolve(); return; } @@ -250,7 +250,7 @@ function importFromString(jsonString) { } }; for (const block of $$('details')) { - if (block.dataset.id != 'invalid') { + if (block.dataset.id !== 'invalid') { block.style.cursor = 'pointer'; block.onclick = highlightElement; } @@ -262,7 +262,7 @@ function importFromString(jsonString) { } function reportNameChange(oldStyle, newStyle) { - return newStyle.name != oldStyle.name + return newStyle.name !== oldStyle.name ? oldStyle.name + ' —> ' + newStyle.name : oldStyle.name; } @@ -278,21 +278,21 @@ function importFromString(jsonString) { for (const tab of tabs) { // skip lazy-loaded aka unloaded tabs that seem to start loading on message in FF if (FIREFOX && !tab.width) { - if (tab == lastTab) { + if (tab === lastTab) { resolve(); } continue; } getStylesSafe({matchUrl: tab.url, enabled: true, asHash: true}).then(styles => { const message = {method: 'styleReplaceAll', styles}; - if (tab.id == ownTab.id) { + if (tab.id === ownTab.id) { applyOnMessage(message); } else { - invokeOrPostpone(tab.id == activeTab.id, + invokeOrPostpone(tab.id === activeTab.id, chrome.tabs.sendMessage, tab.id, message, ignoreChromeError); } setTimeout(BG.updateIcon, 0, tab, styles); - if (tab == lastTab) { + if (tab === lastTab) { resolve(); } }); @@ -359,7 +359,7 @@ $('#unfile-all-styles').onclick = () => { Object.assign(document.body, { ondragover(event) { const hasFiles = event.dataTransfer.types.includes('Files'); - event.dataTransfer.dropEffect = hasFiles || event.target.type == 'search' ? 'copy' : 'none'; + event.dataTransfer.dropEffect = hasFiles || event.target.type === 'search' ? 'copy' : 'none'; this.classList.toggle('dropzone', hasFiles); if (hasFiles) { event.preventDefault(); diff --git a/manage/manage.js b/manage/manage.js index e8fcb481..124c7d72 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -73,7 +73,7 @@ function initGlobalEvents() { // focus search field on / key document.onkeypress = event => { - if ((event.keyCode || event.which) == 47 + if ((event.keyCode || event.which) === 47 && !event.altKey && !event.shiftKey && !event.ctrlKey && !event.metaKey && !event.target.matches('[type="text"], [type="search"]')) { event.preventDefault(); @@ -114,7 +114,7 @@ function initGlobalEvents() { function showStyles(styles = []) { const sorted = styles .map(style => ({name: style.name.toLocaleLowerCase(), style})) - .sort((a, b) => (a.name < b.name ? -1 : a.name == b.name ? 0 : 1)); + .sort((a, b) => (a.name < b.name ? -1 : a.name === b.name ? 0 : 1)); let index = 0; const scrollY = (history.state || {}).scrollY; const shouldRenderAll = scrollY > window.innerHeight || sessionStorage.justEditedStyleId; @@ -228,18 +228,18 @@ function createStyleTargetsElement({entry, style, postponeFavicons}) { displayed.add(targetValue); const element = template.appliesToTarget.cloneNode(true); if (!newUI.enabled) { - if (numTargets == 10) { + if (numTargets === 10) { container = container.appendChild(template.extraAppliesTo.cloneNode(true)); } else if (numTargets > 1) { container.appendChild(template.appliesToSeparator.cloneNode(true)); } } else if (newUI.favicons) { let favicon = ''; - if (type == 'domains') { + if (type === 'domains') { favicon = GET_FAVICON_URL + targetValue; } else if (targetValue.startsWith('chrome-extension:')) { favicon = OWN_ICON; - } else if (type != 'regexps') { + } else if (type !== 'regexps') { favicon = targetValue.includes('://') && targetValue.match(/^.*?:\/\/([^/]+)/); favicon = favicon ? GET_FAVICON_URL + favicon[1] : ''; } @@ -292,7 +292,7 @@ Object.assign(handleEvent, { const target = event.target; const entry = target.closest('.entry'); for (const selector in handleEvent.ENTRY_ROUTES) { - for (let el = target; el && el != entry; el = el.parentElement) { + for (let el = target; el && el !== entry; el = el.parentElement) { if (el.matches(selector)) { const handler = handleEvent.ENTRY_ROUTES[selector]; return handleEvent[handler].call(el, event, entry); @@ -307,8 +307,8 @@ Object.assign(handleEvent, { } event.preventDefault(); event.stopPropagation(); - const left = event.button == 0; - const middle = event.button == 1; + const left = event.button === 0; + const middle = event.button === 1; const shift = event.shiftKey; const ctrl = event.ctrlKey; const openWindow = left && shift && !ctrl; @@ -361,7 +361,7 @@ Object.assign(handleEvent, { buttons: [t('confirmDelete'), t('confirmCancel')], }) .then(({button, enter, esc}) => { - if (button == 0 || enter) { + if (button === 0 || enter) { deleteStyleSafe({id}); } }); @@ -386,10 +386,10 @@ Object.assign(handleEvent, { }, filterOnChange({target: el, forceRefilter}) { - const getValue = el => (el.type == 'checkbox' ? el.checked : el.value.trim()); + const getValue = el => (el.type === 'checkbox' ? el.checked : el.value.trim()); if (!forceRefilter) { const value = getValue(el); - if (value == el.lastValue) { + if (value === el.lastValue) { return; } el.lastValue = value; @@ -415,22 +415,22 @@ Object.assign(handleEvent, { function handleUpdate(style, {reason, method} = {}) { let entry; let oldEntry = $(ENTRY_ID_PREFIX + style.id); - if (oldEntry && method == 'styleUpdated') { + if (oldEntry && method === 'styleUpdated') { handleToggledOrCodeOnly(); } entry = entry || createStyleElement({style}); if (oldEntry) { - if (oldEntry.styleNameLowerCase == entry.styleNameLowerCase) { + if (oldEntry.styleNameLowerCase === entry.styleNameLowerCase) { installed.replaceChild(entry, oldEntry); } else { oldEntry.remove(); } } - if (reason == 'update' && entry.matches('.updatable')) { + if (reason === 'update' && entry.matches('.updatable')) { handleUpdateInstalled(); } filterAndAppend({entry}); - if (!entry.matches('.hidden') && reason != 'import') { + if (!entry.matches('.hidden') && reason !== 'import') { animateElement(entry); scrollElementIntoView(entry); } @@ -438,12 +438,12 @@ function handleUpdate(style, {reason, method} = {}) { function handleToggledOrCodeOnly() { const newStyleMeta = getStyleWithNoCode(style); const diff = objectDiff(oldEntry.styleMeta, newStyleMeta); - if (diff.length == 0) { + if (diff.length === 0) { // only code was modified entry = oldEntry; oldEntry = null; } - if (diff.length == 1 && diff[0].key == 'enabled') { + if (diff.length === 1 && diff[0].key === 'enabled') { oldEntry.classList.toggle('enabled', style.enabled); oldEntry.classList.toggle('disabled', !style.enabled); $$('.checker', oldEntry).forEach(el => (el.checked = style.enabled)); @@ -481,8 +481,8 @@ function switchUI({styleOnly} = {}) { // ensure the global option is processed first for (const el of [$('#manage.newUI'), ...$$('[id^="manage.newUI."]')]) { const id = el.id.replace(/^manage\.newUI\.?/, '') || 'enabled'; - const value = el.type == 'checkbox' ? el.checked : Number(el.value); - const valueChanged = value !== newUI[id] && (id == 'enabled' || current.enabled); + const value = el.type === 'checkbox' ? el.checked : Number(el.value); + const valueChanged = value !== newUI[id] && (id === 'enabled' || current.enabled); current[id] = value; changed[id] = valueChanged; someChanged |= valueChanged; @@ -568,7 +568,7 @@ function checkUpdateAll() { $('#apply-all-updates').classList.add('hidden'); $('#update-all-no-updates').classList.add('hidden'); - const ignoreDigest = this && this.id == 'check-all-updates-force'; + const ignoreDigest = this && this.id === 'check-all-updates-force'; $$('.updatable:not(.can-update)' + (ignoreDigest ? '' : ':not(.update-problem)')) .map(el => checkUpdate(el, {single: false})); @@ -585,7 +585,7 @@ function checkUpdateAll() { total = value; break; case BG.updater.UPDATED: - if (++updated == 1) { + if (++updated === 1) { $('#apply-all-updates').disabled = true; $('#apply-all-updates').classList.remove('hidden'); } @@ -593,7 +593,7 @@ function checkUpdateAll() { // fallthrough case BG.updater.SKIPPED: checked++; - if (details == BG.updater.EDITED || details == BG.updater.MAYBE_EDITED) { + if (details === BG.updater.EDITED || details === BG.updater.MAYBE_EDITED) { skippedEdited++; } reportUpdateState(state, value, details); @@ -606,13 +606,13 @@ function checkUpdateAll() { function done() { document.body.classList.remove('update-in-progress'); - $('#check-all-updates').disabled = total == 0; + $('#check-all-updates').disabled = total === 0; $('#apply-all-updates').disabled = false; renderUpdatesOnlyFilter({check: updated + skippedEdited > 0}); if (!updated) { $('#update-all-no-updates').dataset.skippedEdited = skippedEdited > 0; $('#update-all-no-updates').classList.remove('hidden'); - $('#check-all-updates-force').classList.toggle('hidden', skippedEdited == 0); + $('#check-all-updates-force').classList.toggle('hidden', skippedEdited === 0); } } } @@ -648,16 +648,16 @@ function reportUpdateState(state, style, details) { if (entry.classList.contains('can-update')) { break; } - const same = details == BG.updater.SAME_MD5 || details == BG.updater.SAME_CODE; - const edited = details == BG.updater.EDITED || details == BG.updater.MAYBE_EDITED; + const same = details === BG.updater.SAME_MD5 || details === BG.updater.SAME_CODE; + const edited = details === BG.updater.EDITED || details === BG.updater.MAYBE_EDITED; entry.dataset.details = details; if (!details) { details = t('updateCheckFailServerUnreachable'); - } else if (typeof details == 'number') { + } else if (typeof details === 'number') { details = t('updateCheckFailBadResponseCode', [details]); - } else if (details == BG.updater.EDITED) { + } else if (details === BG.updater.EDITED) { details = t('updateCheckSkippedLocallyEdited') + '\n' + t('updateCheckManualUpdateHint'); - } else if (details == BG.updater.MAYBE_EDITED) { + } else if (details === BG.updater.MAYBE_EDITED) { details = t('updateCheckSkippedMaybeLocallyEdited') + '\n' + t('updateCheckManualUpdateHint'); } const message = same ? t('updateCheckSucceededNoUpdate') : details; @@ -719,7 +719,7 @@ function searchStyles({immediately, container}) { const searchElement = $('#search'); const query = searchElement.value.toLocaleLowerCase(); const queryPrev = searchElement.lastValue || ''; - if (query == queryPrev && !immediately && !container) { + if (query === queryPrev && !immediately && !container) { return; } if (!immediately) { @@ -741,7 +741,7 @@ function searchStyles({immediately, container}) { style.url && isMatchingText(style.url) || isMatchingStyle(style))); } - if (entry.classList.contains('not-matching') != !isMatching) { + if (entry.classList.contains('not-matching') !== !isMatching) { entry.classList.toggle('not-matching', !isMatching); needsRefilter = true; } @@ -850,7 +850,7 @@ function reapplyFilter(container = installed) { shuffle(false); setTimeout(shuffle, 0, true); // single-element job from handleEvent(): add the last wraith - if (toHide.length == 1 && toHide[0].parentElement != installed) { + if (toHide.length === 1 && toHide[0].parentElement !== installed) { installed.appendChild(toHide[0]); } return; @@ -885,7 +885,7 @@ function reapplyFilter(container = installed) { const skipGroup = state => { const start = i; const first = entry; - while (entry && entry.classList.contains('hidden') == state) { + while (entry && entry.classList.contains('hidden') === state) { entry = entry.nextElementSibling; i++; } @@ -978,19 +978,19 @@ function objectDiff(first, second, path = '') { diff.push({path, key, values: [a], type: 'removed'}); continue; } - if (a && typeof a.filter == 'function' && b && typeof b.filter == 'function') { + if (a && typeof a.filter === 'function' && b && typeof b.filter === 'function') { if ( - a.length != b.length || + a.length !== b.length || a.some((el, i) => { - const result = !el || typeof el != 'object' - ? el != b[i] + const result = !el || typeof el !== 'object' + ? el !== b[i] : objectDiff(el, b[i], path + key + '[' + i + '].').length; return result; }) ) { diff.push({path, key, values: [a, b], type: 'changed'}); } - } else if (typeof a == 'object' && typeof b == 'object') { + } else if (typeof a === 'object' && typeof b === 'object') { diff.push(...objectDiff(a, b, path + key + '.')); } else { diff.push({path, key, values: [a, b], type: 'changed'}); diff --git a/msgbox/msgbox.js b/msgbox/msgbox.js index a7ebbe2a..8faf8d60 100644 --- a/msgbox/msgbox.js +++ b/msgbox/msgbox.js @@ -30,9 +30,9 @@ function messageBox({ key(event) { const keyCode = event.keyCode || event.which; if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey - && (keyCode == 13 || keyCode == 27)) { + && (keyCode === 13 || keyCode === 27)) { event.preventDefault(); - resolveWith(keyCode == 13 ? {enter: true} : {esc: true}); + resolveWith(keyCode === 13 ? {enter: true} : {esc: true}); } }, scroll() { @@ -52,7 +52,7 @@ function messageBox({ unbindAndRemoveSelf(); } const id = 'message-box'; - const putAs = typeof contents == 'string' ? 'innerHTML' : 'appendChild'; + const putAs = typeof contents === 'string' ? 'innerHTML' : 'appendChild'; messageBox.element = $element({id, className, appendChild: [ $element({appendChild: [ $element({id: `${id}-title`, innerHTML: title}), diff --git a/options/index.js b/options/index.js index 6404eefb..10404e5b 100644 --- a/options/index.js +++ b/options/index.js @@ -67,7 +67,7 @@ function setupRadioButtons() { const sets = {}; const onChange = function () { const newValue = sets[this.name].indexOf(this); - if (newValue >= 0 && prefs.get(this.name) != newValue) { + if (newValue >= 0 && prefs.get(this.name) !== newValue) { prefs.set(this.name, newValue); } }; diff --git a/popup/popup.js b/popup/popup.js index 42dd69e3..52accdf1 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -278,7 +278,7 @@ Object.assign(handleEvent, { toggle(event) { saveStyleSafe({ id: handleEvent.getClickedStyleId(event), - enabled: this.type == 'checkbox' ? this.checked : this.matches('.enable'), + enabled: this.type === 'checkbox' ? this.checked : this.matches('.enable'), }); }, @@ -293,9 +293,9 @@ Object.assign(handleEvent, { window.onkeydown = event => { const keyCode = event.keyCode || event.which; if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey - && (keyCode == 13 || keyCode == 27)) { + && (keyCode === 13 || keyCode === 27)) { event.preventDefault(); - confirm(keyCode == 13); + confirm(keyCode === 13); } }; function confirm(ok) { @@ -342,9 +342,9 @@ Object.assign(handleEvent, { maybeEdit(event) { if (!( - event.button == 0 && (event.ctrlKey || event.metaKey) || - event.button == 1 || - event.button == 2)) { + event.button === 0 && (event.ctrlKey || event.metaKey) || + event.button === 1 || + event.button === 2)) { return; } // open an editor on middleclick @@ -401,10 +401,10 @@ function detectSloppyRegexps({entry, style}) { for (const section of style.sections) { for (const regexp of section.regexps) { for (let pass = 1; pass <= 2; pass++) { - const cacheKey = pass == 1 ? regexp : BG.SLOPPY_REGEXP_PREFIX + regexp; + const cacheKey = pass === 1 ? regexp : BG.SLOPPY_REGEXP_PREFIX + regexp; if (!rxCache.has(cacheKey)) { // according to CSS4 @document specification the entire URL must match - const anchored = pass == 1 ? '^(?:' + regexp + ')$' : '^' + regexp + '$'; + const anchored = pass === 1 ? '^(?:' + regexp + ')$' : '^' + regexp + '$'; const rx = tryRegExp(anchored); rxCache.set(cacheKey, rx || false); } From 8cfb37351d94cbb39a43b2979d0b23324f665774 Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 14:40:13 -0500 Subject: [PATCH 92/94] Remove unused variables --- background/background.js | 2 +- edit/edit.js | 4 ++-- manage/fileSaveLoad.js | 6 +++--- manage/manage.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/background/background.js b/background/background.js index 3b4f1aa7..13d12e2f 100644 --- a/background/background.js +++ b/background/background.js @@ -26,7 +26,7 @@ chrome.webNavigation.onHistoryStateUpdated.addListener(data => chrome.webNavigation.onReferenceFragmentUpdated.addListener(data => webNavigationListener('styleReplaceAll', data)); -chrome.tabs.onAttached.addListener((tabId, data) => { +chrome.tabs.onAttached.addListener(tabId => { // When an edit page gets attached or detached, remember its state // so we can do the same to the next one to open. chrome.tabs.get(tabId, tab => { diff --git a/edit/edit.js b/edit/edit.js index 8afb891e..d7edd6cc 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -831,8 +831,8 @@ function setupGlobalSearch() { return; } // hide the first two dialogs (replace, replaceWith) - cm.openDialog = (tmpl, callback, opt) => { - cm.openDialog = (tmpl, callback, opt) => { + cm.openDialog = (tmpl, callback) => { + cm.openDialog = (tmpl, callback) => { cm.openDialog = originalOpenDialog; if (all) { callback(replacement); diff --git a/manage/fileSaveLoad.js b/manage/fileSaveLoad.js index ec54517d..4a8397ec 100644 --- a/manage/fileSaveLoad.js +++ b/manage/fileSaveLoad.js @@ -195,7 +195,7 @@ function importFromString(jsonString) { contents: report.length ? report : t('importReportUnchanged'), buttons: [t('confirmOK'), numChanged && t('undo')], onshow: bindClick, - }).then(({button, enter, esc}) => { + }).then(({button}) => { if (button === 1) { undo(); } @@ -241,7 +241,7 @@ function importFromString(jsonString) { } } - function bindClick(box) { + function bindClick() { const highlightElement = event => { const styleElement = $('#style-' + event.target.dataset.id); if (styleElement) { @@ -367,7 +367,7 @@ Object.assign(document.body, { this.classList.remove('fadeout'); } }, - ondragend(event) { + ondragend() { animateElement(this, {className: 'fadeout', removeExtraClasses: ['dropzone']}).then(() => { this.style.animationDuration = ''; }); diff --git a/manage/manage.js b/manage/manage.js index 124c7d72..3d11308a 100644 --- a/manage/manage.js +++ b/manage/manage.js @@ -360,7 +360,7 @@ Object.assign(handleEvent, { className: 'danger center', buttons: [t('confirmDelete'), t('confirmCancel')], }) - .then(({button, enter, esc}) => { + .then(({button, enter}) => { if (button === 0 || enter) { deleteStyleSafe({id}); } From a46684f8926f84e77fe183e1eb96a03987a57f7d Mon Sep 17 00:00:00 2001 From: Rob Garrison Date: Sun, 16 Jul 2017 15:04:40 -0500 Subject: [PATCH 93/94] Style options cursor --- options/index.css | 1 + 1 file changed, 1 insertion(+) diff --git a/options/index.css b/options/index.css index fbc0e803..1b9508f7 100644 --- a/options/index.css +++ b/options/index.css @@ -81,6 +81,7 @@ label:not([disabled]) > :first-child { label:not([disabled]):hover > :first-child { text-shadow: 0 0 0.01px rgba(0, 0, 0, .25); + cursor: pointer; } button, From b50c19a802290e26d9813118e21b2e1c0e0f33a2 Mon Sep 17 00:00:00 2001 From: tophf Date: Wed, 19 Jul 2017 15:09:29 +0300 Subject: [PATCH 94/94] editor import: warn about invalid -moz-document functions * fixes #118 * alleviates #116 by switching showRegExpTester() from innerHTML to DOM --- edit/edit.js | 101 ++++++++++++++++++++++++++++++++++++++------------- js/dom.js | 10 +++-- 2 files changed, 82 insertions(+), 29 deletions(-) diff --git a/edit/edit.js b/edit/edit.js index d7edd6cc..dbd873fd 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -1557,7 +1557,7 @@ function fromMozillaFormat() { const parser = new parserlib.css.Parser(); const lines = mozStyle.split('\n'); const sectionStack = [{code: '', start: {line: 1, col: 1}}]; - let errors = ''; + const errors = []; // let oldSectionCount = editors.length; let firstAddedCM; @@ -1575,12 +1575,16 @@ function fromMozillaFormat() { doAddSection(sectionStack.last); sectionStack.last.code = ''; } - e.functions.forEach(f => { - const m = f.match(/^(url|url-prefix|domain|regexp)\((['"]?)(.+?)\2?\)$/); + for (const f of e.functions) { + const m = f && f.match(/^([\w-]*)\((['"]?)(.+?)\2?\)$/); + if (!m || !/^(url|url-prefix|domain|regexp)$/.test(m[1])) { + errors.push(`${e.line}:${e.col + 1} invalid function "${m ? m[1] : f || ''}"`); + continue; + } const aType = CssToProperty[m[1]]; const aValue = aType !== 'regexps' ? m[3] : m[3].replace(/\\\\/g, '\\'); (section[aType] = section[aType] || []).push(aValue); - }); + } sectionStack.push(section); }); @@ -1607,12 +1611,16 @@ function fromMozillaFormat() { firstAddedCM.focus(); if (errors) { - showHelp(t('issues'), errors); + showHelp(t('issues'), $element({ + tag: 'pre', + textContent: errors.join('\n'), + })); } }); parser.addListener('error', e => { - errors += e.line + ':' + e.col + ' ' + e.message.replace(/ at line \d.+$/, '') + '
    '; + errors.push(e.line + ':' + e.col + ' ' + + e.message.replace(/ at line \d.+$/, '')); }); parser.parse(mozStyle); @@ -1834,13 +1842,16 @@ function showRegExpTester(event, section = getSectionForChild(this)) { rxData.urls = urlsNow; } } - const moreInfoLink = template.regexpTestPartial.outerHTML; const stats = { full: {data: [], label: t('styleRegexpTestFull')}, - partial: {data: [], label: t('styleRegexpTestPartial') + moreInfoLink}, + partial: {data: [], label: [ + t('styleRegexpTestPartial'), + template.regexpTestPartial.cloneNode(true), + ]}, none: {data: [], label: t('styleRegexpTestNone')}, invalid: {data: [], label: t('styleRegexpTestInvalid')}, }; + // collect stats for (const {text, rx, urls} of regexps) { if (!rx) { stats.invalid.data.push({text}); @@ -1856,12 +1867,18 @@ function showRegExpTester(event, section = getSectionForChild(this)) { const faviconUrl = url.startsWith(URLS.ownOrigin) ? OWN_ICON : GET_FAVICON_URL + new URL(url).hostname; - const icon = ``; + const icon = $element({tag: 'img', src: faviconUrl}); if (match.length === url.length) { - full.push(`
    ${icon + url}
    `); + full.push($element({appendChild: [ + icon, + url, + ]})); } else { - partial.push(`
    ${icon}${match}` + - url.substr(match.length) + '
    '); + partial.push($element({appendChild: [ + icon, + $element({tag: 'mark', textContent: match}), + url.substr(match.length), + ]})); } } if (full.length) { @@ -1871,17 +1888,42 @@ function showRegExpTester(event, section = getSectionForChild(this)) { stats.partial.data.push({text, urls: partial}); } } - showHelp(t('styleRegexpTestTitle'), - '
    ' + - Object.keys(stats).map(type => (!stats[type].data.length ? '' : - `
    - ${stats[type].label}` + - stats[type].data.map(({text, urls}) => (!urls ? text : - `
    ${text}${urls.join('')}
    ` - )).join('
    ') + - '
    ' - )).join('') + - '
    '); + // render stats + const report = $element({className: 'regexp-report'}); + const br = $element({tag: 'br'}); + for (const type in stats) { + // top level groups: full, partial, none, invalid + const {label, data} = stats[type]; + if (!data.length) { + continue; + } + // 2nd level: regexp text + const summary = $element({tag: 'summary', appendChild: label}); + const block = [summary]; + for (const {text, urls} of data) { + if (!urls) { + block.push(text, br.cloneNode()); + continue; + } + block.push($element({ + tag: 'details', + open: true, + appendChild: [ + $element({tag: 'summary', textContent: text}), + // 3rd level: tab urls + ...urls, + ], + })); + } + report.appendChild($element({ + tag: 'details', + open: true, + dataset: {type}, + appendChild: block, + })); + } + showHelp(t('styleRegexpTestTitle'), report); + document.querySelector('.regexp-report').onclick = event => { const target = event.target.closest('a, .regexp-report div'); if (target) { @@ -1893,10 +1935,17 @@ function showRegExpTester(event, section = getSectionForChild(this)) { } function showHelp(title, text) { - const div = document.getElementById('help-popup'); + const div = $('#help-popup'); div.classList.remove('big'); - div.querySelector('.contents').innerHTML = text; - div.querySelector('.title').innerHTML = title; + + const contents = $('.contents', div); + if (text instanceof HTMLElement) { + contents.textContent = ''; + contents.appendChild(text); + } else { + contents.innerHTML = text; + } + $('.title', div).textContent = title; if (getComputedStyle(div).display === 'none') { document.addEventListener('keydown', closeHelp); diff --git a/js/dom.js b/js/dom.js index 6a71a10a..ced73414 100644 --- a/js/dom.js +++ b/js/dom.js @@ -106,7 +106,7 @@ function $$(selector, base = document) { function $element(opt) { // tag: string, default 'div', may include namespace like 'ns#tag' - // appendChild: element or an array of elements + // appendChild: element/string or an array of elements/strings // dataset: object // any DOM property: assigned as is const [ns, tag] = opt.tag && opt.tag.includes('#') @@ -115,8 +115,12 @@ function $element(opt) { const element = ns ? document.createElementNS(ns === 'SVG' || ns === 'svg' ? 'http://www.w3.org/2000/svg' : ns, tag) : document.createElement(tag || 'div'); - (opt.appendChild instanceof Array ? opt.appendChild : [opt.appendChild]) - .forEach(child => child && element.appendChild(child)); + const children = opt.appendChild instanceof Array ? opt.appendChild : [opt.appendChild]; + for (const child of children) { + if (child) { + element.appendChild(child instanceof Node ? child : document.createTextNode(child)); + } + } delete opt.appendChild; delete opt.tag; if (opt.dataset) {