diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 3c5964f3..87a5a533 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -315,6 +315,15 @@ "message": "Enable", "description": "Label for the button to enable a style" }, + "excludeStyleByDomainLabel": { + "message": "Exclude the current domain" + }, + "excludeStyleByUrlLabel": { + "message": "Exclude the current URL" + }, + "excludeStyleByUrlRedundant": { + "message": "The current URL is the domain page" + }, "exportLabel": { "message": "Export", "description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)" @@ -1026,6 +1035,10 @@ "message": "Stylus failed to parse usercss:", "description": "The error message to show when stylus failed to parse usercss" }, + "popupAutoResort": { + "message": "Resort styles in popup after toggling", + "description": "Label for the checkbox controlling popup resorting." + }, "popupBorders": { "message": "Add white borders on the sides" }, @@ -1044,6 +1057,10 @@ "message": "Shift-click or right-click opens manager with styles applicable for current site", "description": "Tooltip for the 'Manage' button in the popup." }, + "popupMenuButtonTooltip": { + "message": "Action menu", + "description": "Tooltip for menu button in popup." + }, "popupOpenEditInWindow": { "message": "Open editor in a new window", "description": "Label for the checkbox controlling 'edit' action behavior in the popup." @@ -1056,10 +1073,6 @@ "message": "Styles before commands", "description": "Label for the checkbox controlling section order in the popup." }, - "popupAutoResort": { - "message": "Resort styles in popup after toggling", - "description": "Label for the checkbox controlling popup resorting." - }, "prefShowBadge": { "message": "Number of styles active for the current site", "description": "Label for the checkbox controlling toolbar badge text." diff --git a/background/background.js b/background/background.js index a3542665..b74067f3 100644 --- a/background/background.js +++ b/background/background.js @@ -22,6 +22,11 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, { styleExists: styleManager.styleExists, toggleStyle: styleManager.toggleStyle, + addInclusion: styleManager.addInclusion, + removeInclusion: styleManager.removeInclusion, + addExclusion: styleManager.addExclusion, + removeExclusion: styleManager.removeExclusion, + getTabUrlPrefix() { return this.sender.tab.url.match(/^([\w-]+:\/+[^/#]+)/)[1]; }, diff --git a/background/style-manager.js b/background/style-manager.js index c2b92382..1560f13e 100644 --- a/background/style-manager.js +++ b/background/style-manager.js @@ -57,10 +57,13 @@ const styleManager = (() => { importStyle, importMany, toggleStyle, - setStyleExclusions, getAllStyles, // used by import-export getStylesByUrl, // used by popup styleExists, + addExclusion, + removeExclusion, + addInclusion, + removeInclusion }); function handleLivePreviewConnections() { @@ -92,6 +95,11 @@ const styleManager = (() => { }); } + function escapeRegExp(text) { + // https://github.com/lodash/lodash/blob/0843bd46ef805dd03c0c8d804630804f3ba0ca3c/lodash.js#L152 + return text.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&'); + } + function get(id, noCode = false) { const data = styles.get(id).data; return noCode ? getStyleWithNoCode(data) : data; @@ -182,10 +190,46 @@ const styleManager = (() => { .then(newData => handleSave(newData, 'editSave')); } - function setStyleExclusions(id, exclusions) { - const data = Object.assign({}, styles.get(id).data, {exclusions}); + function addIncludeExclude(id, rule, type) { + const data = Object.assign({}, styles.get(id).data); + if (!data[type]) { + data[type] = []; + } + if (data[type].includes(rule)) { + throw new Error('The rule already exists'); + } + data[type] = data[type].concat([rule]); return saveStyle(data) - .then(newData => handleSave(newData, 'exclusions')); + .then(newData => handleSave(newData, 'styleSettings')); + } + + function removeIncludeExclude(id, rule, type) { + const data = Object.assign({}, styles.get(id).data); + if (!data[type]) { + return; + } + if (!data[type].includes(rule)) { + return; + } + data[type] = data[type].filter(r => r !== rule); + return saveStyle(data) + .then(newData => handleSave(newData, 'styleSettings')); + } + + function addExclusion(id, rule) { + return addIncludeExclude(id, rule, 'exclusions'); + } + + function removeExclusion(id, rule) { + return removeIncludeExclude(id, rule, 'exclusions'); + } + + function addInclusion(id, rule) { + return addIncludeExclude(id, rule, 'inclusions'); + } + + function removeInclusion(id, rule) { + return removeIncludeExclude(id, rule, 'inclusions'); } function deleteStyle(id) { @@ -479,14 +523,7 @@ const styleManager = (() => { } function buildGlob(text) { - const prefix = text[0] === '^' ? '' : '\\b'; - const suffix = text[text.length - 1] === '$' ? '' : '\\b'; - return `${prefix}${escape(text)}${suffix}`; - - function escape(text) { - // FIXME: using .* everywhere is slow - return text.replace(/[.*]/g, m => m === '.' ? '\\.' : '.*'); - } + return '^' + escapeRegExp(text).replace(/\\\\\\\*|\\\*/g, m => m.length > 2 ? m : '.*') + '$'; } function getDomain(url) { diff --git a/popup.html b/popup.html index baf48db3..c9d4f720 100644 --- a/popup.html +++ b/popup.html @@ -24,25 +24,55 @@