Add: user-frendly exclusions (#666)
* WIP: popup UI * Fix: use simple menu toggle * Add: inclusion/exclusion API * Add: hook exclusion UI * Fix: minor * Fix: don't self-edit * Icons and accessibility * Icons and accessibility * Fix: disable redundant exclude-by-url checkbox * Disabled cursor and delete leftover code * Generic menu button tooltip and tweak menu item cursors * Generic menu button tooltip and tweak menu item cursors * Generic menu button tooltip and tweak menu item cursors
This commit is contained in:
parent
1ff34fc449
commit
cdc7f98150
|
@ -315,6 +315,15 @@
|
||||||
"message": "Enable",
|
"message": "Enable",
|
||||||
"description": "Label for the button to enable a style"
|
"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": {
|
"exportLabel": {
|
||||||
"message": "Export",
|
"message": "Export",
|
||||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
"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:",
|
"message": "Stylus failed to parse usercss:",
|
||||||
"description": "The error message to show when 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": {
|
"popupBorders": {
|
||||||
"message": "Add white borders on the sides"
|
"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",
|
"message": "Shift-click or right-click opens manager with styles applicable for current site",
|
||||||
"description": "Tooltip for the 'Manage' button in the popup."
|
"description": "Tooltip for the 'Manage' button in the popup."
|
||||||
},
|
},
|
||||||
|
"popupMenuButtonTooltip": {
|
||||||
|
"message": "Action menu",
|
||||||
|
"description": "Tooltip for menu button in popup."
|
||||||
|
},
|
||||||
"popupOpenEditInWindow": {
|
"popupOpenEditInWindow": {
|
||||||
"message": "Open editor in a new window",
|
"message": "Open editor in a new window",
|
||||||
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
"description": "Label for the checkbox controlling 'edit' action behavior in the popup."
|
||||||
|
@ -1056,10 +1073,6 @@
|
||||||
"message": "Styles before commands",
|
"message": "Styles before commands",
|
||||||
"description": "Label for the checkbox controlling section order in the popup."
|
"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": {
|
"prefShowBadge": {
|
||||||
"message": "Number of styles active for the current site",
|
"message": "Number of styles active for the current site",
|
||||||
"description": "Label for the checkbox controlling toolbar badge text."
|
"description": "Label for the checkbox controlling toolbar badge text."
|
||||||
|
|
|
@ -22,6 +22,11 @@ window.API_METHODS = Object.assign(window.API_METHODS || {}, {
|
||||||
styleExists: styleManager.styleExists,
|
styleExists: styleManager.styleExists,
|
||||||
toggleStyle: styleManager.toggleStyle,
|
toggleStyle: styleManager.toggleStyle,
|
||||||
|
|
||||||
|
addInclusion: styleManager.addInclusion,
|
||||||
|
removeInclusion: styleManager.removeInclusion,
|
||||||
|
addExclusion: styleManager.addExclusion,
|
||||||
|
removeExclusion: styleManager.removeExclusion,
|
||||||
|
|
||||||
getTabUrlPrefix() {
|
getTabUrlPrefix() {
|
||||||
return this.sender.tab.url.match(/^([\w-]+:\/+[^/#]+)/)[1];
|
return this.sender.tab.url.match(/^([\w-]+:\/+[^/#]+)/)[1];
|
||||||
},
|
},
|
||||||
|
|
|
@ -57,10 +57,13 @@ const styleManager = (() => {
|
||||||
importStyle,
|
importStyle,
|
||||||
importMany,
|
importMany,
|
||||||
toggleStyle,
|
toggleStyle,
|
||||||
setStyleExclusions,
|
|
||||||
getAllStyles, // used by import-export
|
getAllStyles, // used by import-export
|
||||||
getStylesByUrl, // used by popup
|
getStylesByUrl, // used by popup
|
||||||
styleExists,
|
styleExists,
|
||||||
|
addExclusion,
|
||||||
|
removeExclusion,
|
||||||
|
addInclusion,
|
||||||
|
removeInclusion
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleLivePreviewConnections() {
|
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) {
|
function get(id, noCode = false) {
|
||||||
const data = styles.get(id).data;
|
const data = styles.get(id).data;
|
||||||
return noCode ? getStyleWithNoCode(data) : data;
|
return noCode ? getStyleWithNoCode(data) : data;
|
||||||
|
@ -182,10 +190,46 @@ const styleManager = (() => {
|
||||||
.then(newData => handleSave(newData, 'editSave'));
|
.then(newData => handleSave(newData, 'editSave'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStyleExclusions(id, exclusions) {
|
function addIncludeExclude(id, rule, type) {
|
||||||
const data = Object.assign({}, styles.get(id).data, {exclusions});
|
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)
|
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) {
|
function deleteStyle(id) {
|
||||||
|
@ -479,14 +523,7 @@ const styleManager = (() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildGlob(text) {
|
function buildGlob(text) {
|
||||||
const prefix = text[0] === '^' ? '' : '\\b';
|
return '^' + escapeRegExp(text).replace(/\\\\\\\*|\\\*/g, m => m.length > 2 ? m : '.*') + '$';
|
||||||
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 === '.' ? '\\.' : '.*');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDomain(url) {
|
function getDomain(url) {
|
||||||
|
|
36
popup.html
36
popup.html
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
<template data-id="style">
|
<template data-id="style">
|
||||||
<div class="entry">
|
<div class="entry">
|
||||||
|
<div class="entry-content">
|
||||||
<div class="main-controls">
|
<div class="main-controls">
|
||||||
<label class="style-name">
|
<label class="style-name">
|
||||||
<input class="checker" type="checkbox">
|
<input class="checker" type="checkbox">
|
||||||
|
@ -39,10 +40,39 @@
|
||||||
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"/>
|
<path fill-rule="evenodd" d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
<a href="#" class="delete" i18n-title="deleteStyleLabel" tabindex="0">
|
<a href="#" class="menu-button" i18n-title="popupMenuButtonTooltip" tabindex="0">
|
||||||
|
<svg class="svg-icon menu-button-icon" viewBox="0 0 3 16">
|
||||||
|
<path fill-rule="evenodd" d="M0 2.5a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0zm0 5a1.5 1.5 0 1 0 3 0 1.5 1.5 0 0 0-3 0zM1.5 14a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menu">
|
||||||
|
<label class="menu-item exclude-by-domain button">
|
||||||
|
<div class="menu-icon">
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input type="checkbox" class="exclude-by-domain-checkbox">
|
||||||
|
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span i18n-text="excludeStyleByDomainLabel"></span>
|
||||||
|
</label>
|
||||||
|
<label class="menu-item exclude-by-url button">
|
||||||
|
<div class="menu-icon">
|
||||||
|
<div class="checkbox-container">
|
||||||
|
<input type="checkbox" class="exclude-by-url-checkbox">
|
||||||
|
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span i18n-text="excludeStyleByUrlLabel"></span>
|
||||||
|
</label>
|
||||||
|
<a href="#" class="menu-item delete">
|
||||||
|
<div class="menu-icon">
|
||||||
<svg class="svg-icon remove" viewBox="0 0 14 16">
|
<svg class="svg-icon remove" viewBox="0 0 14 16">
|
||||||
<path fill-rule="evenodd" d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"/>
|
<path fill-rule="evenodd" d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span i18n-text="deleteStyleLabel"></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -240,8 +270,8 @@
|
||||||
<path d="M6.2,0C5.8,0,5.4,0.4,5.4,0.8v0.7C5,1.7,4.6,1.8,4.3,2L3.8,1.5C3.6,1.4,3.4,1.3,3.2,1.3S2.7,1.4,2.6,1.5L1.5,2.6c-0.3,0.3-0.3,0.9,0,1.2L2,4.3C1.8,4.6,1.7,5,1.5,5.4H0.8C0.4,5.4,0,5.8,0,6.2v1.5c0,0.5,0.4,0.8,0.8,0.8h0.7C1.7,9,1.8,9.4,2,9.7l-0.5,0.5c-0.3,0.3-0.3,0.8,0,1.2l1.1,1.1c0.3,0.3,0.9,0.3,1.2,0L4.3,12c0.4,0.2,0.8,0.4,1.2,0.5v0.7c0,0.5,0.4,0.8,0.8,0.8h1.5c0.5,0,0.8-0.4,0.8-0.8v-0.7C9,12.3,9.4,12.2,9.7,12l0.5,0.5c0.3,0.3,0.9,0.3,1.2,0l1.1-1.1c0.3-0.3,0.3-0.8,0-1.2L12,9.7c0.2-0.4,0.4-0.8,0.5-1.2h0.7c0.5,0,0.8-0.4,0.8-0.8V6.2c0-0.5-0.4-0.8-0.8-0.8h-0.7C12.3,5,12.2,4.6,12,4.3l0.5-0.5c0.3-0.3,0.3-0.9,0-1.2l-1.1-1.1c-0.2-0.2-0.4-0.2-0.6-0.2s-0.4,0.1-0.6,0.2L9.7,2C9.4,1.8,9,1.7,8.6,1.5V0.8C8.6,0.4,8.2,0,7.8,0L6.2,0z M6.8,0.8h0.4c0.2,0,0.4,0.2,0.4,0.4v1.2c0.8,0.1,1.6,0.4,2.3,0.9l0.8-0.8c0.2-0.2,0.4-0.2,0.6,0l0.3,0.3c0.2,0.2,0.2,0.4,0,0.6l-0.8,0.8c0.5,0.7,0.8,1.4,0.9,2.3h1.2c0.2,0,0.4,0.2,0.4,0.4v0.4c0,0.2-0.2,0.4-0.4,0.4h-1.2c-0.1,0.8-0.4,1.6-0.9,2.3l0.8,0.8c0.2,0.2,0.2,0.4,0,0.6l-0.3,0.3c-0.2,0.2-0.4,0.2-0.6,0l-0.8-0.8c-0.7,0.5-1.4,0.8-2.3,0.9v1.2c0,0.2-0.2,0.4-0.4,0.4H6.8c-0.2,0-0.4-0.2-0.4-0.4v-1.2c-0.8-0.1-1.6-0.4-2.3-0.9l-0.8,0.8c-0.2,0.2-0.4,0.2-0.6,0l-0.3-0.3c-0.2-0.2-0.2-0.4,0-0.6l0.8-0.8C2.8,9.2,2.5,8.4,2.4,7.6H1.2C1,7.6,0.8,7.4,0.8,7.2V6.8c0-0.2,0.2-0.4,0.4-0.4h1.2c0.1-0.8,0.4-1.6,0.9-2.3L2.5,3.3c-0.2-0.2-0.2-0.4,0-0.6l0.3-0.3c0.2-0.2,0.4-0.2,0.6,0l0.8,0.8c0.7-0.5,1.4-0.8,2.3-0.9V1.2C6.4,1,6.6,0.8,6.8,0.8L6.8,0.8z M7,3.6C5.1,3.6,3.6,5.1,3.6,7c0,0,0,0,0,0c0,1.9,1.5,3.4,3.4,3.4c1.9,0,3.4-1.5,3.4-3.4C10.4,5.1,8.9,3.6,7,3.6C7,3.6,7,3.6,7,3.6z M7,4.8c1.2,0,2.2,1,2.2,2.2c0,1.2-1,2.2-2.2,2.2c-1.2,0-2.2-1-2.2-2.2C4.8,5.8,5.8,4.8,7,4.8z"/>
|
<path d="M6.2,0C5.8,0,5.4,0.4,5.4,0.8v0.7C5,1.7,4.6,1.8,4.3,2L3.8,1.5C3.6,1.4,3.4,1.3,3.2,1.3S2.7,1.4,2.6,1.5L1.5,2.6c-0.3,0.3-0.3,0.9,0,1.2L2,4.3C1.8,4.6,1.7,5,1.5,5.4H0.8C0.4,5.4,0,5.8,0,6.2v1.5c0,0.5,0.4,0.8,0.8,0.8h0.7C1.7,9,1.8,9.4,2,9.7l-0.5,0.5c-0.3,0.3-0.3,0.8,0,1.2l1.1,1.1c0.3,0.3,0.9,0.3,1.2,0L4.3,12c0.4,0.2,0.8,0.4,1.2,0.5v0.7c0,0.5,0.4,0.8,0.8,0.8h1.5c0.5,0,0.8-0.4,0.8-0.8v-0.7C9,12.3,9.4,12.2,9.7,12l0.5,0.5c0.3,0.3,0.9,0.3,1.2,0l1.1-1.1c0.3-0.3,0.3-0.8,0-1.2L12,9.7c0.2-0.4,0.4-0.8,0.5-1.2h0.7c0.5,0,0.8-0.4,0.8-0.8V6.2c0-0.5-0.4-0.8-0.8-0.8h-0.7C12.3,5,12.2,4.6,12,4.3l0.5-0.5c0.3-0.3,0.3-0.9,0-1.2l-1.1-1.1c-0.2-0.2-0.4-0.2-0.6-0.2s-0.4,0.1-0.6,0.2L9.7,2C9.4,1.8,9,1.7,8.6,1.5V0.8C8.6,0.4,8.2,0,7.8,0L6.2,0z M6.8,0.8h0.4c0.2,0,0.4,0.2,0.4,0.4v1.2c0.8,0.1,1.6,0.4,2.3,0.9l0.8-0.8c0.2-0.2,0.4-0.2,0.6,0l0.3,0.3c0.2,0.2,0.2,0.4,0,0.6l-0.8,0.8c0.5,0.7,0.8,1.4,0.9,2.3h1.2c0.2,0,0.4,0.2,0.4,0.4v0.4c0,0.2-0.2,0.4-0.4,0.4h-1.2c-0.1,0.8-0.4,1.6-0.9,2.3l0.8,0.8c0.2,0.2,0.2,0.4,0,0.6l-0.3,0.3c-0.2,0.2-0.4,0.2-0.6,0l-0.8-0.8c-0.7,0.5-1.4,0.8-2.3,0.9v1.2c0,0.2-0.2,0.4-0.4,0.4H6.8c-0.2,0-0.4-0.2-0.4-0.4v-1.2c-0.8-0.1-1.6-0.4-2.3-0.9l-0.8,0.8c-0.2,0.2-0.4,0.2-0.6,0l-0.3-0.3c-0.2-0.2-0.2-0.4,0-0.6l0.8-0.8C2.8,9.2,2.5,8.4,2.4,7.6H1.2C1,7.6,0.8,7.4,0.8,7.2V6.8c0-0.2,0.2-0.4,0.4-0.4h1.2c0.1-0.8,0.4-1.6,0.9-2.3L2.5,3.3c-0.2-0.2-0.2-0.4,0-0.6l0.3-0.3c0.2-0.2,0.4-0.2,0.6,0l0.8,0.8c0.7-0.5,1.4-0.8,2.3-0.9V1.2C6.4,1,6.6,0.8,6.8,0.8L6.8,0.8z M7,3.6C5.1,3.6,3.6,5.1,3.6,7c0,0,0,0,0,0c0,1.9,1.5,3.4,3.4,3.4c1.9,0,3.4-1.5,3.4-3.4C10.4,5.1,8.9,3.6,7,3.6C7,3.6,7,3.6,7,3.6z M7,4.8c1.2,0,2.2,1,2.2,2.2c0,1.2-1,2.2-2.2,2.2c-1.2,0-2.2-1-2.2-2.2C4.8,5.8,5.8,4.8,7,4.8z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
||||||
<symbol id="svg-icon-config-uso" viewBox="0 0 14 14">
|
<symbol id="svg-icon-config-uso" viewBox="0 0 20 20">
|
||||||
<path d="M2,3h4v2H4v6h6V9h2v4H2V3z M8,1h6v6l-2.2-2.2l-4,4L6.2,7.2l4-4L8,1z"/>
|
<path d="M4,4h5v2H6v8h8v-3h2v5H4V4z M11,3h6v6l-2-2l-4,4L9,9l4-4L11,3z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
||||||
<symbol id="svg-icon-help" viewBox="0 0 14 16">
|
<symbol id="svg-icon-help" viewBox="0 0 14 16">
|
||||||
|
|
105
popup/popup.css
105
popup/popup.css
|
@ -173,16 +173,17 @@ body.blocked > DIV {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* entry */
|
/* entry */
|
||||||
|
|
||||||
.entry {
|
.entry {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.entry-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 26px;
|
height: 26px;
|
||||||
padding: 0 14px 0 0;
|
padding: 0 14px 0 0;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html[style] .entry {
|
html[style] .entry-content {
|
||||||
padding: 0 16px 0 0;
|
padding: 0 16px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +193,7 @@ html[style] .entry {
|
||||||
|
|
||||||
.entry .actions {
|
.entry .actions {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.style-name {
|
.style-name {
|
||||||
|
@ -264,9 +266,34 @@ html[style*="border"] .entry:nth-child(11):before {
|
||||||
}
|
}
|
||||||
|
|
||||||
.entry .actions > * {
|
.entry .actions > * {
|
||||||
display: inline-block;
|
height: 26px;
|
||||||
padding: 0 1px;
|
width: 18px;
|
||||||
margin: 0 1px;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .actions > .menu-button {
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .actions > a.configure {
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entry .actions > a.configure[target="_blank"] {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.svg-icon.config {
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.configure[target="_blank"] .svg-icon.config {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.not-applied .checker,
|
.not-applied .checker,
|
||||||
|
@ -286,6 +313,72 @@ html[style*="border"] .entry:nth-child(11):before {
|
||||||
color: darkred;
|
color: darkred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* entry menu */
|
||||||
|
.entry .menu {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
top: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 0;
|
||||||
|
transition: height .25s ease-out, opacity .5s ease-in;
|
||||||
|
overflow: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.entry.menu-active .menu {
|
||||||
|
/* FIXME: avoid hard coded height */
|
||||||
|
height: 72px;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
/* accessibility */
|
||||||
|
.menu-item {
|
||||||
|
display: none;
|
||||||
|
border: none;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 0 0 20px;
|
||||||
|
height: 24px;
|
||||||
|
background: none;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.entry.menu-active.accessible-items .menu-item {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.entry .menu-item.delete {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.entry .menu-item.delete:hover {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.entry .menu-item > span {
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
.entry .menu-item:hover,
|
||||||
|
.entry .menu-item:active {
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
transition: background-color .25s;
|
||||||
|
}
|
||||||
|
.entry .menu-icon {
|
||||||
|
width: 26px;
|
||||||
|
}
|
||||||
|
.entry .menu-icon > * {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.entry .menu-item.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* checkbox */
|
||||||
|
.checkbox-container {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.regexp-problem-indicator {
|
.regexp-problem-indicator {
|
||||||
background-color: #d00;
|
background-color: #d00;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
|
|
|
@ -309,6 +309,11 @@ function createStyleElement(style) {
|
||||||
indicator.appendChild(document.createTextNode('!'));
|
indicator.appendChild(document.createTextNode('!'));
|
||||||
indicator.onclick = handleEvent.indicator;
|
indicator.onclick = handleEvent.indicator;
|
||||||
$('.main-controls', entry).appendChild(indicator);
|
$('.main-controls', entry).appendChild(indicator);
|
||||||
|
|
||||||
|
$('.menu-button', entry).onclick = handleEvent.toggleMenu;
|
||||||
|
|
||||||
|
$('.exclude-by-domain-checkbox', entry).onchange = e => handleEvent.toggleExclude(e, 'domain');
|
||||||
|
$('.exclude-by-url-checkbox', entry).onchange = e => handleEvent.toggleExclude(e, 'url');
|
||||||
}
|
}
|
||||||
|
|
||||||
style = Object.assign(entry.styleMeta, style);
|
style = Object.assign(entry.styleMeta, style);
|
||||||
|
@ -329,9 +334,35 @@ function createStyleElement(style) {
|
||||||
entry.classList.toggle('not-applied', style.excluded || style.sloppy);
|
entry.classList.toggle('not-applied', style.excluded || style.sloppy);
|
||||||
entry.classList.toggle('regexp-partial', style.sloppy);
|
entry.classList.toggle('regexp-partial', style.sloppy);
|
||||||
|
|
||||||
|
$('.exclude-by-domain-checkbox', entry).checked = styleExcluded(style, 'domain');
|
||||||
|
|
||||||
|
const excludeByUrlCheckbox = $('.exclude-by-url-checkbox', entry);
|
||||||
|
const isRedundant = getExcludeRule('domain') === getExcludeRule('url');
|
||||||
|
excludeByUrlCheckbox.checked = !isRedundant && styleExcluded(style, 'url');
|
||||||
|
excludeByUrlCheckbox.disabled = isRedundant;
|
||||||
|
|
||||||
|
const excludeByUrlLabel = $('.exclude-by-url', entry);
|
||||||
|
excludeByUrlLabel.classList.toggle('disabled', isRedundant);
|
||||||
|
excludeByUrlLabel.title = isRedundant ?
|
||||||
|
chrome.i18n.getMessage('excludeStyleByUrlRedundant') : '';
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function styleExcluded({exclusions}, type) {
|
||||||
|
if (!exclusions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const rule = getExcludeRule(type);
|
||||||
|
return exclusions.includes(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExcludeRule(type) {
|
||||||
|
if (type === 'domain') {
|
||||||
|
return new URL(tabURL).origin + '/*';
|
||||||
|
}
|
||||||
|
return tabURL + '*';
|
||||||
|
}
|
||||||
|
|
||||||
Object.assign(handleEvent, {
|
Object.assign(handleEvent, {
|
||||||
|
|
||||||
|
@ -356,10 +387,29 @@ Object.assign(handleEvent, {
|
||||||
.then(sortStylesInPlace);
|
.then(sortStylesInPlace);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
toggleExclude(event, type) {
|
||||||
|
const entry = handleEvent.getClickedStyleElement(event);
|
||||||
|
if (event.target.checked) {
|
||||||
|
API.addExclusion(entry.styleMeta.id, getExcludeRule(type));
|
||||||
|
} else {
|
||||||
|
API.removeExclusion(entry.styleMeta.id, getExcludeRule(type));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleMenu(event) {
|
||||||
|
const entry = handleEvent.getClickedStyleElement(event);
|
||||||
|
entry.classList.toggle('menu-active');
|
||||||
|
setTimeout(() => {
|
||||||
|
entry.classList.toggle('accessible-items');
|
||||||
|
}, 250);
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
|
||||||
delete(event) {
|
delete(event) {
|
||||||
const entry = handleEvent.getClickedStyleElement(event);
|
const entry = handleEvent.getClickedStyleElement(event);
|
||||||
const id = entry.styleId;
|
const id = entry.styleId;
|
||||||
const box = $('#confirm');
|
const box = $('#confirm');
|
||||||
|
const cancel = $('[data-cmd="cancel"]');
|
||||||
box.dataset.display = true;
|
box.dataset.display = true;
|
||||||
box.style.cssText = '';
|
box.style.cssText = '';
|
||||||
$('b', box).textContent = $('.style-name', entry).textContent;
|
$('b', box).textContent = $('.style-name', entry).textContent;
|
||||||
|
@ -368,7 +418,7 @@ Object.assign(handleEvent, {
|
||||||
$('[data-cmd="cancel"]', box).onclick = () => confirm(false);
|
$('[data-cmd="cancel"]', box).onclick = () => confirm(false);
|
||||||
window.onkeydown = event => {
|
window.onkeydown = event => {
|
||||||
const keyCode = event.keyCode || event.which;
|
const keyCode = event.keyCode || event.which;
|
||||||
if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
|
if (document.activeElement !== cancel && !event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
|
||||||
&& (keyCode === 13 || keyCode === 27)) {
|
&& (keyCode === 13 || keyCode === 27)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
confirm(keyCode === 13);
|
confirm(keyCode === 13);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user