diff --git a/.eslintrc b/.eslintrc
index 3d844c56..6eb52b33 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -55,7 +55,8 @@ globals:
animateElement: false
$: false
$$: false
- $element: false
+ $create: false
+ $createLink: false
# prefs.js
prefs: false
setupLivePrefs: false
@@ -236,7 +237,7 @@ rules:
one-var: [0]
operator-assignment: [2, always]
operator-linebreak: [2, after, overrides: {"?": ignore, ":": ignore, "&&": ignore, "||": ignore}]
- padded-blocks: [2, never]
+ padded-blocks: [0]
prefer-numeric-literals: [2]
prefer-rest-params: [0]
prefer-const: [1, {destructuring: any, ignoreReadBeforeAssign: true}]
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 6128364a..d57ea719 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -377,6 +377,10 @@
"message": "Open this style on userstyles.org to customize via 'Advanced Style Settings'",
"description": "Tooltip for a button that opens style on userstyles.org for customizing"
},
+ "filteredStylesAllHidden": {
+ "message": "Currently applied filters match no styles",
+ "description": "Text shown when no styles match currently applied filter in the style manager"
+ },
"findStylesForSite": {
"message": "Find styles",
"description": "Text for a link that gets a list of styles for the current site"
@@ -774,6 +778,10 @@
"message": "Invalid regexps skipped",
"description": "RegExp test report: label for the invalid expressions"
},
+ "styleRegexpTestNote": {
+ "message": "Note: use a single \\ for escaping in the regexp input field, which will be automatically converted to \\\\ in the style code as per specification for quoted strings in CSS.",
+ "description": "RegExp test report: a note displayed at the bottom of the dialog"
+ },
"styleRegexpPartialExplanation": {
"message": "This style uses partially matching regexps in violation of CSS4 @document specification which requires a full URL match. The affected CSS sections were not applied to the page. This style was probably created in Stylish-for-Chrome which incorrectly checks 'regexp()' rules since the very first version (known bug)."
},
diff --git a/_locales/zh_TW/messages.json b/_locales/zh_TW/messages.json
index eb2bf237..0c6fd026 100644
--- a/_locales/zh_TW/messages.json
+++ b/_locales/zh_TW/messages.json
@@ -36,7 +36,7 @@
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
},
"installButton": {
- "message": "安裝",
+ "message": "安裝樣式",
"description": "Label for install button"
},
"styleMetaErrorCheckbox": {
@@ -47,6 +47,10 @@
"message": "無效的 JSON 格式",
"description": "Setting linter config with invalid JSON"
},
+ "popupHotkeysTooltip": {
+ "message": "點選以檢視可用的快捷鍵",
+ "description": "Tooltip displayed when hovering the right edge of the extension popup"
+ },
"optionsBadgeNormal": {
"message": "背景顏色",
"description": ""
@@ -330,6 +334,10 @@
"message": "顯示生效的樣式數目",
"description": "Label (must be very short) for the checkbox in the toolbar button context menu controlling toolbar badge text."
},
+ "popupHotkeysInfo": {
+ "message": "<1>-<9>、<0>,數字鍵盤也可以 — 切換第 N 個樣式(0 是切換到第 10 個)\n- 切換以該字母為名稱第一個字的樣式\n 開啟編輯器而非切換\n 啟用列出的樣式\n 停用列出的樣式\n 與 <`> (倒引號)— 切換初始啟用的樣式;不要在彈出式視窗開啟時套用到後來啟用的樣式,這樣您就可以在測試完後復原初始選擇:僅停用全部,然後切換。 \n更多資訊請見 wiki",
+ "description": "NOTE1: preserve < and > symbols so that is styled as a key.\nNOTE2: the last line is displayed as a text of the link to the wiki page.\nNOTE3: this is the list of hotkeys displayed after clicking the right edge of the extension popup."
+ },
"cm_lineWrapping": {
"message": "自動換行",
"description": "Label for the checkbox controlling word wrap option for the style editor."
@@ -934,7 +942,7 @@
"description": "Label for the checkbox in the style editor."
},
"installButtonReinstall": {
- "message": "重新安裝",
+ "message": "重新安裝樣式",
"description": "Label for reinstall button"
},
"linterInvalidConfigError": {
@@ -1036,7 +1044,7 @@
"description": ""
},
"installButtonUpdate": {
- "message": "更新",
+ "message": "更新樣式",
"description": "Label for update button"
},
"backupButtons": {
@@ -1052,7 +1060,7 @@
"description": "Label for the button to go to the edit style page"
},
"installButtonInstalled": {
- "message": "已安裝",
+ "message": "樣式已安裝",
"description": "Text displayed when the style is successfully installed"
},
"author": {
diff --git a/background/storage.js b/background/storage.js
index eee6a011..3d728473 100644
--- a/background/storage.js
+++ b/background/storage.js
@@ -238,6 +238,9 @@ function getStyles(options) {
cachedStyles.byId.clear();
for (const style of cachedStyles.list) {
cachedStyles.byId.set(style.id, style);
+ if (!style.name) {
+ style.name = 'ID: ' + style.id;
+ }
}
cachedStyles.mutex.inProgress = false;
diff --git a/background/update.js b/background/update.js
index e9018d55..945db534 100644
--- a/background/update.js
+++ b/background/update.js
@@ -56,26 +56,26 @@ var updater = {
'ignoreDigest' option is set on the second manual individual update check on the manage page.
*/
- const maybeUpdate = style.usercssData ? maybeUpdateUsercss : maybeUpdateUSO;
- return (ignoreDigest ? Promise.resolve() : calcStyleDigest(style))
- .then(checkIfEdited)
- .then(maybeUpdate)
- .then(maybeValidate)
+ return Promise.resolve(style)
+ .then([calcStyleDigest][!ignoreDigest ? 0 : 'skip'])
+ .then([checkIfEdited][!ignoreDigest ? 0 : 'skip'])
+ .then([maybeUpdateUSO, maybeUpdateUsercss][style.usercssData ? 1 : 0])
.then(maybeSave)
- .then(saved => {
- observer(updater.UPDATED, saved);
- updater.log(updater.UPDATED + ` #${saved.id} ${saved.name}`);
- })
- .catch(err => {
- observer(updater.SKIPPED, style, err);
- err = err === 0 ? 'server unreachable' : err;
- updater.log(updater.SKIPPED + ` (${err}) #${style.id} ${style.name}`);
- });
+ .then(reportSuccess)
+ .catch(reportFailure);
+
+ function reportSuccess(saved) {
+ observer(updater.UPDATED, saved);
+ updater.log(updater.UPDATED + ` #${saved.id} ${saved.name}`);
+ }
+
+ function reportFailure(err) {
+ observer(updater.SKIPPED, style, err);
+ err = err === 0 ? 'server unreachable' : err;
+ updater.log(updater.SKIPPED + ` (${err}) #${style.id} ${style.name}`);
+ }
function checkIfEdited(digest) {
- if (ignoreDigest) {
- return;
- }
if (style.originalDigest && style.originalDigest !== digest) {
return Promise.reject(updater.EDITED);
}
@@ -95,6 +95,7 @@ var updater = {
}
function maybeUpdateUsercss() {
+ // TODO: when sourceCode is > 100kB use http range request(s) for version check
return download(style.updateUrl).then(text => {
const json = usercss.buildMeta(text);
const {usercssData: {version}} = style;
@@ -104,6 +105,8 @@ var updater = {
// re-install is invalid in a soft upgrade
if (!ignoreDigest) {
return Promise.reject(updater.SAME_VERSION);
+ } else if (text === style.sourceCode) {
+ return Promise.reject(updater.SAME_CODE);
}
break;
case 1:
@@ -114,38 +117,31 @@ var updater = {
});
}
- function maybeValidate(json) {
- if (json.usercssData) {
- // usercss is already validated while building
- return json;
- }
- if (!styleJSONseemsValid(json)) {
+ function maybeSave(json = {}) {
+ // usercss is already validated while building
+ if (!json.usercssData && !styleJSONseemsValid(json)) {
return Promise.reject(updater.ERROR_JSON);
}
- return json;
- }
-
- function maybeSave(json) {
json.id = style.id;
json.updateDate = Date.now();
+ json.reason = 'update';
+ // keep current state
+ delete json.enabled;
+ // keep local name customizations
+ delete json.name;
+
if (styleSectionsEqual(json, style)) {
- // JSONs may have different order of items even if sections are effectively equal
- // so we'll update the digest anyway
- // always update digest even if (save === false)
+ // update digest even if save === false as there might be just a space added etc.
saveStyle(Object.assign(json, {reason: 'update-digest'}));
return Promise.reject(updater.SAME_CODE);
} else if (!style.originalDigest && !ignoreDigest) {
return Promise.reject(updater.MAYBE_EDITED);
}
- if (!save) {
- return json;
- }
- json.reason = 'update';
- if (json.usercssData) {
- return usercssHelper.save(json);
- }
- json.name = null; // keep local name customizations
- return saveStyle(json);
+
+ return !save ? json :
+ json.usercssData
+ ? usercssHelper.save(json)
+ : saveStyle(json);
}
function styleJSONseemsValid(json) {
diff --git a/content/apply.js b/content/apply.js
index e2f52124..31320aa7 100644
--- a/content/apply.js
+++ b/content/apply.js
@@ -386,6 +386,7 @@
let restorationCounter = 0;
let observing = false;
let sorting = false;
+ let timer;
// allow any types of elements between ours, except for the following:
const ORDERED_TAGS = ['head', 'body', 'style', 'link'];
@@ -395,6 +396,10 @@
function init() {
docRootObserver = new MutationObserver(sortStyleElements);
Object.assign(docRootObserver, {start, stop});
+ if (!chrome.app) {
+ // compensate for Firefox missing a step when loading the tab in background
+ setTimeout(sortStyleElements);
+ }
}
function start({sort = false} = {}) {
if (sort && sortStyleMap()) {
@@ -453,8 +458,8 @@
if (sorting) {
sorting = false;
docRootObserver.takeRecords();
- setTimeout(start);
- //docRootObserver.start();
+ clearTimeout(timer);
+ timer = setTimeout(start);
}
}
function isMovable(el) {
diff --git a/edit.html b/edit.html
index 008a8cc7..7efc20ce 100644
--- a/edit.html
+++ b/edit.html
@@ -3,6 +3,9 @@
+
+
+