Revert: exclusions
This commit is contained in:
parent
7a29d90d6f
commit
f45f95fd02
|
@ -315,55 +315,6 @@
|
|||
"message": "Enable",
|
||||
"description": "Label for the button to enable a style"
|
||||
},
|
||||
"excludedDomain": {
|
||||
"message": "Domain",
|
||||
"description": "Label for a domain or subdomain portion of an URL used to exclude a style"
|
||||
},
|
||||
"excludedPrefix": {
|
||||
"message": "Prefix",
|
||||
"description": "Label for a full url with a subdirectory to be used as the beginning portion of a URL to match to exclude a style"
|
||||
},
|
||||
"exclusionsAddTitle": {
|
||||
"message": "Add exclusion",
|
||||
"description": "Title of popup to add an excluded site or page (URL)"
|
||||
},
|
||||
"exclusionsHeader": {
|
||||
"message": "Excluded",
|
||||
"description": "Title of user configurable lists of site urls to exclude per style"
|
||||
},
|
||||
"exclusionsHelp": {
|
||||
"message": "Exclusion entries are only checked when a style is set to be applied to a page, and if an exclusion is found, the given style (and all internal sections) will not be applied to that page.\n\nThe list of exclusions is set separately from the userstyle so that it will not be effected when updating or editing the style itself. This is useful because you can exclude pages that would be otherwise be effected by a global style.\n\nAdd one or more exclusion entries for each style. An exclusion entry string contains a pattern that will match a web location (URL). This string may contain wildcards (\"*\") to match any portion of a URL, e.g. \"forum.*.com\" will exclude the forum sub-domains of all top level dot-com domains. Regular expressions are allowed, except `.` and `*` are altered, and are saved as a string so character classes must be doubly escaped (e.g. `\\\\w`).\n\nExcluded pages are automatically updated while typing; invalid entries will be removed on page reload!",
|
||||
"description": "Help text for user set style exclusions"
|
||||
},
|
||||
"exclusionsHelpTitle": {
|
||||
"message": "Set Style Exclusions",
|
||||
"description": "Header text for help modal"
|
||||
},
|
||||
"exclusionsvalidateEntry": {
|
||||
"message": "Enter a unique and valid URL",
|
||||
"description": "Text for an alert notifying the user that an entered URL is not unique or invalid"
|
||||
},
|
||||
"exclusionsPopupTitle": {
|
||||
"message": "Exclude the site or page",
|
||||
"description": "Title of exclusion popup dialog within the extension popup"
|
||||
},
|
||||
"exclusionsPopupTip": {
|
||||
"message": "Right-click to edit exclusions on this page",
|
||||
"description": "Title on the checkbox in the popup to let the user know how to edit exclusions on the current page"
|
||||
},
|
||||
"exclusionsPrefix": {
|
||||
"message": "Excluded on: ",
|
||||
"description": "Prefix label added to the applies to column in the style manager"
|
||||
},
|
||||
"exclusionsStatus": {
|
||||
"message": "$number$ pages",
|
||||
"description": "Label added next to the Excluded Pages header when 'number' is not zero",
|
||||
"placeholders": {
|
||||
"number": {
|
||||
"content": "$1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"exportLabel": {
|
||||
"message": "Export",
|
||||
"description": "Label for the button to export a style ('edit' page) or all styles ('manage' page)"
|
||||
|
|
25
edit.html
25
edit.html
|
@ -88,7 +88,6 @@
|
|||
<script src="edit/applies-to-line-widget.js"></script>
|
||||
<script src="edit/reroute-hotkeys.js"></script>
|
||||
<script src="edit/codemirror-factory.js"></script>
|
||||
<script src="edit/exclusions.js"></script>
|
||||
<script src="edit/colorpicker-helper.js"></script>
|
||||
<script src="edit/beautify.js"></script>
|
||||
<script src="edit/show-keymap-help.js"></script>
|
||||
|
@ -200,16 +199,6 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template data-id="exclusionEntry">
|
||||
<div class="exclusion-entry">
|
||||
<input class="exclusion-input" placeholder="*://*.google.com/*foo*">
|
||||
<button class="exclusion-add" i18n-title="exclusionsAddTitle">+</button>
|
||||
<button class="exclusion-delete" i18n-title="confirmDelete">
|
||||
<svg class="svg-icon"><use xlink:href="#svg-icon-delete"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template data-id="find">
|
||||
<div data-type="content">
|
||||
<div data-type="input-wrapper">
|
||||
|
@ -438,16 +427,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<details id="exclusions">
|
||||
<summary>
|
||||
<h2 i18n-text="exclusionsHeader"></h2>
|
||||
<a id="excluded-list-help" href="#" class="svg-inline-wrapper">
|
||||
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
||||
</a>
|
||||
<span id="excluded-stats"></span>
|
||||
</summary>
|
||||
<div id="excluded-wrap"></div>
|
||||
</details>
|
||||
<details id="lint" class="hidden" data-pref="editor.lint.expanded">
|
||||
<summary>
|
||||
<h2 i18n-text="linterIssues">: <span id="issue-count"></span>
|
||||
|
@ -518,10 +497,6 @@
|
|||
<path fill-rule="evenodd" d="M0 3v2h8v-2h-8z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-icon-delete" 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"/>
|
||||
</symbol>
|
||||
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -76,48 +76,11 @@ label {
|
|||
min-height: 1.4rem;
|
||||
}
|
||||
|
||||
#excluded-wrap {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#exclusions h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#exclusions .exclusion-input {
|
||||
flex: auto;
|
||||
}
|
||||
|
||||
#exclusions button {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
#exclusions .exclusion-input:invalid {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
#exclusions .exclusion-delete .svg-icon {
|
||||
pointer-events: none;
|
||||
vertical-align: text-top;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
#excluded-stats:not(:empty) {
|
||||
background-color: darkcyan;
|
||||
border-color: darkcyan;
|
||||
color: white;
|
||||
font-size: 0.7rem;
|
||||
font-weight: normal;
|
||||
padding: 2px 5px;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
/* basic info */
|
||||
#basic-info {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
#name, #excluded-input {
|
||||
#name {
|
||||
width: 100%;
|
||||
}
|
||||
#basic-info-name {
|
||||
|
@ -478,7 +441,7 @@ body[data-match-highlight="selection"] .CodeMirror-selection-highlight-scrollbar
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.applies-to li, .exclusion-entry {
|
||||
.applies-to li {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
list-style-type: none;
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
/* global showHelp $ $$ debounce API template t */
|
||||
'use strict';
|
||||
|
||||
const exclusions = (() => {
|
||||
|
||||
// `\S*\*\S*` => `foo*`, `*bar`, `f*bar`
|
||||
// `\S+\.\S+` => `foo.bar`, `f.b`
|
||||
// see https://regex101.com/r/NUuwiu/2
|
||||
const validExclusionRegex = /^(\S*\*\S*|\S+\.\S+)$/;
|
||||
// ms to wait before validating user input
|
||||
const saveDelay = 250;
|
||||
|
||||
// get exclusions from a select element
|
||||
function get() {
|
||||
const list = {};
|
||||
$$('#excluded-wrap input').forEach(input => {
|
||||
const url = input.value;
|
||||
if (url && validExclusionRegex.test(url)) {
|
||||
list[url] = createRegExp(url);
|
||||
}
|
||||
});
|
||||
exclusions.list = Object.keys(list).sort().reduce((acc, ex) => {
|
||||
acc[ex] = list[ex];
|
||||
return acc;
|
||||
}, {});
|
||||
return exclusions.list;
|
||||
}
|
||||
|
||||
function createRegExp(url) {
|
||||
// Include boundaries to prevent `e.c` from matching `google.com`
|
||||
const prefix = url.startsWith('^') ? '' : '\\b';
|
||||
const suffix = url.endsWith('$') ? '' : '\\b';
|
||||
// Only escape `.`; alter `*`; all other regex allowed
|
||||
return `${prefix}${url.replace(/\./g, '\\.').replace(/\*/g, '.*?')}${suffix}`;
|
||||
}
|
||||
|
||||
function addExclusionEntry({container, value, insertAfter}) {
|
||||
const item = template.exclusionEntry.cloneNode(true);
|
||||
const input = $('input', item);
|
||||
const regex = validExclusionRegex.toString();
|
||||
input.value = value;
|
||||
input.setAttribute('pattern', regex.substring(1, regex.length - 1));
|
||||
if (insertAfter) {
|
||||
insertAfter.insertAdjacentElement('afterend', item);
|
||||
} else {
|
||||
container.appendChild(item);
|
||||
}
|
||||
input.focus();
|
||||
}
|
||||
|
||||
function populateList() {
|
||||
// List should never be empty - need to add an empty input
|
||||
const list = exclusions.list.length ? exclusions.list : [''];
|
||||
const block = $('#excluded-wrap');
|
||||
block.textContent = '';
|
||||
const container = document.createDocumentFragment();
|
||||
list.sort().forEach(value => {
|
||||
addExclusionEntry({container, value});
|
||||
});
|
||||
block.appendChild(container);
|
||||
}
|
||||
|
||||
function validateEntry(input) {
|
||||
const lists = Object.keys(get());
|
||||
const url = input.value;
|
||||
const index = $$('.exclusion-entry input:valid').indexOf(input);
|
||||
// Generic URL globs; e.g. "https://test.com/*" & "*.test.com"
|
||||
return !(lists.includes(url) && lists.indexOf(url) !== index) &&
|
||||
validExclusionRegex.test(url);
|
||||
}
|
||||
|
||||
function updateList() {
|
||||
const list = get();
|
||||
const keys = Object.keys(list);
|
||||
if (exclusions.savedValue !== keys.join(',')) {
|
||||
exclusions.saveValue = keys.join(',');
|
||||
exclusions.list = list;
|
||||
}
|
||||
debounce(save, 100, {});
|
||||
updateStats();
|
||||
}
|
||||
|
||||
function deleteExclusions(entry) {
|
||||
if ($('#excluded-wrap').children.length === 1) {
|
||||
const input = $('.exclusion-input', entry);
|
||||
input.value = '';
|
||||
input.focus();
|
||||
} else {
|
||||
const nextFocus = entry.previousElementSibling || entry.nextElementSibling;
|
||||
entry.parentNode.removeChild(entry);
|
||||
if (nextFocus) {
|
||||
$('input', nextFocus).focus();
|
||||
}
|
||||
}
|
||||
updateList();
|
||||
}
|
||||
|
||||
function excludeAction(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const entry = target.closest('.exclusion-entry');
|
||||
if (target.classList.contains('exclusion-add')) {
|
||||
addExclusionEntry({
|
||||
container: $('#excluded-wrap'),
|
||||
value: '',
|
||||
insertAfter: entry
|
||||
});
|
||||
} else if (target.classList.contains('exclusion-delete')) {
|
||||
deleteExclusions(entry);
|
||||
}
|
||||
}
|
||||
|
||||
function excludeValidate(event) {
|
||||
const target = event.target;
|
||||
target.setCustomValidity('');
|
||||
target.title = '';
|
||||
if (target.matches(':valid')) {
|
||||
if (!validateEntry(target)) {
|
||||
target.setCustomValidity(t('exclusionsvalidateEntry'));
|
||||
target.title = t('exclusionsvalidateEntry');
|
||||
} else {
|
||||
updateList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateStats() {
|
||||
const total = Object.keys(exclusions.list).length;
|
||||
$('#excluded-stats').textContent = total ? t('exclusionsStatus', [total]) : '';
|
||||
}
|
||||
|
||||
function showExclusionHelp(event) {
|
||||
event.preventDefault();
|
||||
showHelp(t('exclusionsHelpTitle'), t('exclusionsHelp').replace(/\n/g, '<br>'), 'info');
|
||||
}
|
||||
|
||||
function onRuntimeMessage(msg) {
|
||||
if (msg.method === 'exclusionsUpdated' && msg.style && msg.style.exclusions) {
|
||||
update({list: Object.keys(msg.style.exclusions), isUpdating: true});
|
||||
// update popup, if loaded
|
||||
// if (typeof popupExclusions !== 'undefined') {
|
||||
// popupExclusions.selectExclusions(msg.style.exclusions);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
function update({list = exclusions.list, isUpdating}) {
|
||||
if (!isUpdating) {
|
||||
exclusions.list = list;
|
||||
populateList();
|
||||
}
|
||||
updateStats();
|
||||
}
|
||||
|
||||
function save({id, exclusionList = get()}) {
|
||||
// get last saved version
|
||||
API.getStyles({id: id || exclusions.id}).then(([style]) => {
|
||||
style.exclusions = exclusionList;
|
||||
style.reason = 'exclusionsUpdated';
|
||||
API.saveStyle(style);
|
||||
});
|
||||
}
|
||||
|
||||
function init(style) {
|
||||
const block = $('#exclusions');
|
||||
const list = Object.keys(style.exclusions || {});
|
||||
const size = list.length;
|
||||
exclusions.id = style.id;
|
||||
exclusions.savedValue = list.join(',');
|
||||
exclusions.list = list;
|
||||
if (size) {
|
||||
block.setAttribute('open', true);
|
||||
} else {
|
||||
block.removeAttribute('open');
|
||||
}
|
||||
update({});
|
||||
|
||||
$('#excluded-wrap').onclick = excludeAction;
|
||||
$('#excluded-wrap').oninput = event => debounce(excludeValidate, saveDelay, event);
|
||||
$('#excluded-list-help').onclick = showExclusionHelp;
|
||||
chrome.runtime.onMessage.addListener(onRuntimeMessage);
|
||||
}
|
||||
|
||||
return {init, get, update, save, createRegExp};
|
||||
})();
|
|
@ -234,17 +234,11 @@ function createSourceEditor(style) {
|
|||
function save() {
|
||||
if (!dirty.isDirty()) return;
|
||||
const code = cm.getValue();
|
||||
// const exclusionList = exclusions.get();
|
||||
// exclusions.save({
|
||||
// id: style.id,
|
||||
// exclusionList
|
||||
// });
|
||||
return ensureUniqueStyle(code)
|
||||
.then(() => API.editSaveUsercss({
|
||||
id: style.id,
|
||||
enabled: style.enabled,
|
||||
sourceCode: code,
|
||||
// exclusions: exclusionList
|
||||
}))
|
||||
.then(replaceStyle)
|
||||
.catch(err => {
|
||||
|
|
|
@ -146,13 +146,6 @@
|
|||
</details>
|
||||
</template>
|
||||
|
||||
<template data-id="excludedOn">
|
||||
<p class="excluded-on">
|
||||
<label i18n-text="exclusionsPrefix"></label>
|
||||
<span class="targets"></span>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script src="js/promisify.js"></script>
|
||||
<script src="js/dom.js"></script>
|
||||
<script src="js/messaging.js"></script>
|
||||
|
|
|
@ -184,7 +184,6 @@ a:hover {
|
|||
}
|
||||
|
||||
.applies-to,
|
||||
.excluded-on,
|
||||
.actions {
|
||||
padding-left: 15px;
|
||||
margin-bottom: 0;
|
||||
|
@ -643,14 +642,6 @@ a:hover {
|
|||
line-height: 18px;
|
||||
}
|
||||
|
||||
.target[data-type="exclusions"] {
|
||||
color: #d22;
|
||||
}
|
||||
|
||||
.newUI .target[data-type="exclusions"] img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.newUI .applies-to .expander {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
|
|
@ -28,7 +28,7 @@ const newUI = {
|
|||
newUI.renderClass();
|
||||
requestAnimationFrame(usePrefsDuringPageLoad);
|
||||
|
||||
const TARGET_TYPES = ['domains', 'urls', 'urlPrefixes', 'regexps', 'exclusions'];
|
||||
const TARGET_TYPES = ['domains', 'urls', 'urlPrefixes', 'regexps'];
|
||||
const GET_FAVICON_URL = 'https://www.google.com/s2/favicons?domain=';
|
||||
const OWN_ICON = chrome.runtime.getManifest().icons['16'];
|
||||
|
||||
|
@ -249,17 +249,8 @@ function createStyleTargetsElement({entry, style}) {
|
|||
let numTargets = 0;
|
||||
const displayed = new Set();
|
||||
for (const type of TARGET_TYPES) {
|
||||
// FIXME: what does it do?
|
||||
const isExcluded = type === 'exclusions';
|
||||
const sections = isExcluded ? [''] : style.sections;
|
||||
if (isExcluded && !newUI.enabled && Object.keys(style.exclusions || {}).length > 0) {
|
||||
$('.applies-to', entry).insertAdjacentElement('afterend', template.excludedOn.cloneNode(true));
|
||||
container = $('.excluded-on .targets', entry);
|
||||
numTargets = 1;
|
||||
}
|
||||
for (const section of sections) {
|
||||
const target = isExcluded ? Object.keys(style.exclusions || {}) : section[type] || [];
|
||||
for (const targetValue of target) {
|
||||
for (const section of style.sections) {
|
||||
for (const targetValue of target[type] || []) {
|
||||
if (displayed.has(targetValue)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -317,7 +308,7 @@ function getFaviconImgSrc(container = installed) {
|
|||
favicon = GET_FAVICON_URL + targetValue;
|
||||
} else if (targetValue.includes('chrome-extension:') || targetValue.includes('moz-extension:')) {
|
||||
favicon = OWN_ICON;
|
||||
} else if (type === 'regexps' || type === 'exclusions') {
|
||||
} else if (type === 'regexps') {
|
||||
favicon = targetValue
|
||||
.replace(regexpRemoveNegativeLookAhead, '')
|
||||
.replace(regexpReplaceExtraCharacters, '')
|
||||
|
@ -602,9 +593,6 @@ function switchUI({styleOnly} = {}) {
|
|||
.newUI .targets {
|
||||
max-height: ${newUI.targets * 18}px;
|
||||
}
|
||||
.newUI .target[data-type="exclusions"]:before {
|
||||
content: '${t('exclusionsPrefix')}';
|
||||
}
|
||||
` + (newUI.faviconsGray ? `
|
||||
.newUI .target img {
|
||||
-webkit-filter: grayscale(1);
|
||||
|
|
|
@ -40,8 +40,7 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
#message-box.center #message-box-contents pre,
|
||||
#message-box.center.content-left #message-box-contents {
|
||||
#message-box.center #message-box-contents pre {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
@ -56,10 +55,6 @@
|
|||
text-align: left;
|
||||
}
|
||||
|
||||
#message-box-contents h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#message-box-title {
|
||||
font-weight: bold;
|
||||
background-color: rgb(145, 208, 198);
|
||||
|
|
13
popup.html
13
popup.html
|
@ -166,7 +166,6 @@
|
|||
<script src="popup/hotkeys.js"></script>
|
||||
<script src="js/script-loader.js" async></script>
|
||||
<script src="js/storage-util.js" async></script>
|
||||
<script src="popup/popup-exclusions.js"></script>
|
||||
</head>
|
||||
|
||||
<body id="stylus-popup">
|
||||
|
@ -182,18 +181,6 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div id="exclude">
|
||||
<div>
|
||||
<strong>Style's Name</strong>
|
||||
<span i18n-text="exclusionsPopupTitle"></span>
|
||||
<select id="popup-exclusions" size="0" multiple></select>
|
||||
<div>
|
||||
<button i18n-text="confirmOK" data-cmd="ok"></button>
|
||||
<button i18n-text="confirmCancel" data-cmd="cancel"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="installed">
|
||||
<aside id="hotkey-info" i18n-title="popupHotkeysTooltip"></aside>
|
||||
</div>
|
||||
|
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
global messageBox t $create getActiveTab tryRegExp animateElement $ API
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/* exported popupExclusions */
|
||||
const popupExclusions = (() => {
|
||||
|
||||
// return matches on url ending to prevent duplicates in the exclusion list
|
||||
// e.g. http://test.com and http://test.com/* are equivalent
|
||||
// this function would return ['', '/*']
|
||||
function exclusionExists(array, value) {
|
||||
const match = [];
|
||||
['', '*', '/', '/*'].forEach(ending => {
|
||||
if (array.includes(value + ending)) {
|
||||
match.push(ending);
|
||||
}
|
||||
});
|
||||
return match;
|
||||
}
|
||||
|
||||
/* Modal in Popup.html */
|
||||
function processURL(url) {
|
||||
const results = [];
|
||||
const protocol = url.match(/\w+:\/\//);
|
||||
// remove ending '/', protocol, hash & search strings
|
||||
const parts = url.replace(/\/$/, '').replace(/(\w+:\/\/|[#?].*$)/g, '').split('/');
|
||||
const domain = parts[0].split('.');
|
||||
/*
|
||||
Domain: a.b.com
|
||||
Domain: b.com
|
||||
Prefix: https://a.b.com
|
||||
Prefix: https://a.b.com/current
|
||||
Prefix: https://a.b.com/current/page
|
||||
*/
|
||||
while (parts.length > 1) {
|
||||
results.push([t('excludedPrefix'), protocol + parts.join('/')]);
|
||||
parts.pop();
|
||||
}
|
||||
while (domain.length > 1) {
|
||||
results.push([t('excludedDomain'), domain.join('.')]);
|
||||
domain.shift();
|
||||
}
|
||||
return results.reverse();
|
||||
}
|
||||
|
||||
function shortenURL(text) {
|
||||
const len = text.length;
|
||||
let prefix = '\u2026';
|
||||
// account for URL that end with a '/'
|
||||
let index = (text.endsWith('/') ? text.substring(0, len - 1) : text).lastIndexOf('/');
|
||||
if (index < 0 || len - index < 2) {
|
||||
index = 0;
|
||||
prefix = '';
|
||||
}
|
||||
return prefix + text.substring(index, len);
|
||||
}
|
||||
|
||||
function createOption(option) {
|
||||
// ["Domain/Prefix", "{url}"]
|
||||
return $create('option', {
|
||||
value: option[1],
|
||||
title: option[1],
|
||||
textContent: `${option[0]}: ${shortenURL(option[1])}`
|
||||
});
|
||||
}
|
||||
|
||||
function getMultiOptions({select, selectedOnly} = {}) {
|
||||
return [...select.children].reduce((acc, opt) => {
|
||||
if (selectedOnly && opt.selected || !selectedOnly) {
|
||||
acc.push(opt.value);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function updatePopupContent(url) {
|
||||
const options = processURL(url);
|
||||
const renderBin = document.createDocumentFragment();
|
||||
options.map(option => renderBin.appendChild(createOption(option)));
|
||||
$('#popup-exclusions').textContent = '';
|
||||
$('#popup-exclusions').appendChild(renderBin);
|
||||
}
|
||||
|
||||
function getIframeURLs(style) {
|
||||
getActiveTab().then(tab => {
|
||||
if (tab && tab.status === 'complete') {
|
||||
chrome.webNavigation.getAllFrames({
|
||||
tabId: tab.id
|
||||
}, frames => {
|
||||
const urls = frames.reduce((acc, frame) => [...acc, ...processURL(frame.url)], []);
|
||||
updateSelections(style, urls);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function selectExclusions(exclusions) {
|
||||
const select = $('#exclude select');
|
||||
const excludes = Object.keys(exclusions || {});
|
||||
[...select.children].forEach(option => {
|
||||
if (exclusionExists(excludes, option.value).length) {
|
||||
option.selected = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateSelections(style, newOptions = []) {
|
||||
const wrap = $('#exclude');
|
||||
const select = $('select', wrap);
|
||||
if (newOptions.length) {
|
||||
const currentOptions = [...select.children].map(opt => opt.value);
|
||||
newOptions.forEach(opt => {
|
||||
if (!currentOptions.includes(opt[1])) {
|
||||
select.appendChild(createOption(opt));
|
||||
// newOptions may have duplicates (e.g. multiple iframes from same source)
|
||||
currentOptions.push(opt[1]);
|
||||
}
|
||||
});
|
||||
select.size = select.children.length;
|
||||
// hide select, then calculate & adjust height
|
||||
select.style.height = '0';
|
||||
document.body.style.height = `${select.scrollHeight + wrap.offsetHeight}px`;
|
||||
select.style.height = '';
|
||||
}
|
||||
selectExclusions(style.exclusions);
|
||||
}
|
||||
|
||||
function isExcluded(matchUrl, exclusions = {}) {
|
||||
const values = Object.values(exclusions);
|
||||
return values.length && values.some(exclude => tryRegExp(exclude).test(matchUrl));
|
||||
}
|
||||
|
||||
function openPopupDialog(entry, tabURL) {
|
||||
const style = entry.styleMeta;
|
||||
updateSelections(style, updatePopupContent(tabURL));
|
||||
getIframeURLs(style);
|
||||
const box = $('#exclude');
|
||||
box.dataset.display = true;
|
||||
box.style.cssText = '';
|
||||
$('strong', box).textContent = style.name;
|
||||
$('[data-cmd="ok"]', box).focus();
|
||||
$('[data-cmd="ok"]', box).onclick = () => confirm(true);
|
||||
$('[data-cmd="cancel"]', box).onclick = () => confirm(false);
|
||||
window.onkeydown = event => {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
if (!event.shiftKey && !event.ctrlKey && !event.altKey && !event.metaKey
|
||||
&& (keyCode === 13 || keyCode === 27)) {
|
||||
event.preventDefault();
|
||||
confirm(keyCode === 13);
|
||||
}
|
||||
};
|
||||
function confirm(ok) {
|
||||
window.onkeydown = null;
|
||||
animateElement(box, {
|
||||
className: 'lights-on',
|
||||
onComplete: () => (box.dataset.display = false),
|
||||
});
|
||||
document.body.style.height = '';
|
||||
const excluded = isExcluded(tabURL, style.exclusions);
|
||||
if (ok) {
|
||||
handlePopupSave(style);
|
||||
entry.styleMeta = style;
|
||||
entry.classList.toggle('excluded', excluded);
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function handlePopupSave(style) {
|
||||
if (!Array.isArray(style.exclusions)) {
|
||||
style.exclusions = [];
|
||||
}
|
||||
const current = new Set(style.exclusions);
|
||||
const select = $('#popup-exclusions', messageBox.element);
|
||||
const all = getMultiOptions({select});
|
||||
const selected = new Set(getMultiOptions({select, selectedOnly: true}));
|
||||
for (const value of all) {
|
||||
if (current.has(value) && !selected.has(value)) {
|
||||
const index = style.exclusions.indexOf(value);
|
||||
style.exclusions.splice(index, 1);
|
||||
}
|
||||
if (!current.has(value) && selected.has(value)) {
|
||||
style.exclusions.push(value);
|
||||
}
|
||||
}
|
||||
API.setStyleExclusions(style.id, style.exclusions);
|
||||
}
|
||||
|
||||
return {openPopupDialog, selectExclusions, isExcluded};
|
||||
})();
|
|
@ -89,6 +89,7 @@ body > div:not(#installed):not(#message-box):not(.colorpicker-popup) {
|
|||
position: absolute;
|
||||
top: 7px;
|
||||
left: var(--outer-padding);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#disable-all-wrapper {
|
||||
|
@ -117,21 +118,6 @@ body > div:not(#installed):not(#message-box):not(.colorpicker-popup) {
|
|||
margin-right: .5em;
|
||||
}
|
||||
|
||||
#popup-exclusions-title {
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#popup-exclusions {
|
||||
height: auto;
|
||||
overflow-y: auto;
|
||||
max-width: 98%;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
#popup-exclusions option {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.checker {
|
||||
display: inline;
|
||||
}
|
||||
|
@ -249,10 +235,6 @@ html[style] .entry {
|
|||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.entry.excluded .style-name {
|
||||
color: #d22;
|
||||
}
|
||||
|
||||
.entry:nth-child(even) {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
@ -504,7 +486,7 @@ body.blocked .actions > .main-controls {
|
|||
|
||||
/* confirm */
|
||||
|
||||
#confirm, #exclude {
|
||||
#confirm {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2147483647;
|
||||
|
@ -521,26 +503,21 @@ body.blocked .actions > .main-controls {
|
|||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
#confirm.lights-on,
|
||||
#exclude.lights-on {
|
||||
#confirm.lights-on {
|
||||
animation: lights-on .25s ease-in-out;
|
||||
animation-fill-mode: both;
|
||||
}
|
||||
|
||||
#confirm.lights-on,
|
||||
#confirm.lights-on > div,
|
||||
#exclude.lights-on,
|
||||
#exclude.lights-on > div {
|
||||
#confirm.lights-on > div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#confirm[data-display=true],
|
||||
#exclude[data-display=true] {
|
||||
#confirm[data-display=true] {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#confirm > div,
|
||||
#exclude > div {
|
||||
#confirm > div {
|
||||
width: 80%;
|
||||
max-height: 80%;
|
||||
min-height: 6em;
|
||||
|
@ -555,23 +532,16 @@ body.blocked .actions > .main-controls {
|
|||
padding-bottom: .5em;
|
||||
}
|
||||
|
||||
#exclude select {
|
||||
margin: .5em 0;
|
||||
}
|
||||
|
||||
#confirm > div > div,
|
||||
#exclude > div > div {
|
||||
#confirm > div > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.non-windows #confirm > div > div,
|
||||
.non-windows #exclude > div > div {
|
||||
.non-windows #confirm > div > div {
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#confirm > button,
|
||||
#exclude > button {
|
||||
#confirm > button {
|
||||
/* add a gap between buttons both for horizontal
|
||||
or vertical (when the label is wide) layout */
|
||||
margin: 0 .25em .25em 0;
|
||||
|
|
|
@ -51,7 +51,6 @@ function onRuntimeMessage(msg) {
|
|||
switch (msg.method) {
|
||||
case 'styleAdded':
|
||||
case 'styleUpdated':
|
||||
case 'exclusionsUpdated':
|
||||
if (msg.reason === 'editPreview' || msg.reason === 'editPreviewEnd') return;
|
||||
handleUpdate(msg);
|
||||
break;
|
||||
|
@ -258,9 +257,9 @@ function createStyleElement({
|
|||
const checkbox = $('.checker', entry);
|
||||
Object.assign(checkbox, {
|
||||
id: ENTRY_ID_PREFIX_RAW + style.id,
|
||||
title: t('exclusionsPopupTip'),
|
||||
// title: t('exclusionsPopupTip'),
|
||||
onclick: handleEvent.toggle,
|
||||
oncontextmenu: handleEvent.openExcludeMenu
|
||||
// oncontextmenu: handleEvent.openExcludeMenu
|
||||
});
|
||||
const editLink = $('.style-edit-link', entry);
|
||||
Object.assign(editLink, {
|
||||
|
@ -294,15 +293,9 @@ function createStyleElement({
|
|||
|
||||
style = Object.assign(entry.styleMeta, style);
|
||||
|
||||
if (style.enabled) {
|
||||
entry.classList.remove('disabled');
|
||||
entry.classList.add('enabled');
|
||||
$('.checker', entry).checked = true;
|
||||
} else {
|
||||
entry.classList.add('disabled');
|
||||
entry.classList.remove('enabled');
|
||||
$('.checker', entry).checked = false;
|
||||
}
|
||||
entry.classList.toggle('disabled', !style.enabled);
|
||||
entry.classList.toggle('enabled', style.enabled);
|
||||
$('.checker', entry).checked = style.enabled;
|
||||
|
||||
const styleName = $('.style-name', entry);
|
||||
styleName.lastChild.textContent = style.name;
|
||||
|
@ -324,7 +317,6 @@ function createStyleElement({
|
|||
style.usercssData && Object.keys(style.usercssData.vars || {}).length ?
|
||||
'' : 'none';
|
||||
|
||||
// entry.classList.toggle('excluded', style.excluded);
|
||||
entry.classList.toggle('not-applied', style.excluded || style.sloppy);
|
||||
entry.classList.toggle('regexp-partial', style.sloppy);
|
||||
|
||||
|
@ -434,12 +426,6 @@ Object.assign(handleEvent, {
|
|||
event.button === 2)) {
|
||||
return;
|
||||
}
|
||||
// open exclude page config dialog on right-click
|
||||
if (event.target.classList.contains('checker')) {
|
||||
this.oncontextmenu = handleEvent.openExcludeMenu;
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
// open an editor on middleclick
|
||||
if (event.target.matches('.entry, .style-name, .style-edit-link')) {
|
||||
this.onmouseup = () => $('.style-edit-link', this).click();
|
||||
|
@ -481,21 +467,6 @@ Object.assign(handleEvent, {
|
|||
handleEvent.openURLandHide.call(this, event);
|
||||
}
|
||||
},
|
||||
|
||||
openExcludeMenu(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const chkbox = this;
|
||||
const entry = event.target.closest('.entry');
|
||||
if (!chkbox.eventHandled) {
|
||||
chkbox.eventHandled = true;
|
||||
popupExclusions
|
||||
.openPopupDialog(entry, tabURL)
|
||||
.then(() => {
|
||||
chkbox.eventHandled = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user