expose style name (#1403)
This commit is contained in:
parent
b86cb6a36c
commit
10de02f04d
|
@ -1089,6 +1089,12 @@
|
||||||
"message": "Exposes the top site domain in each iframe.\nEnables writing iframe-specific CSS like this:\nhtml[stylus-iframe$$=\"twitter.com\"] h1 { display:none }",
|
"message": "Exposes the top site domain in each iframe.\nEnables writing iframe-specific CSS like this:\nhtml[stylus-iframe$$=\"twitter.com\"] h1 { display:none }",
|
||||||
"description": "Add attribute to iframe; make sure to include the double $$ in the css example, or the `$=` will be omitted in the displayed text."
|
"description": "Add attribute to iframe; make sure to include the double $$ in the css example, or the `$=` will be omitted in the displayed text."
|
||||||
},
|
},
|
||||||
|
"optionsAdvancedExposeStyleName": {
|
||||||
|
"message": "Expose style name"
|
||||||
|
},
|
||||||
|
"optionsAdvancedExposeStyleNameNote": {
|
||||||
|
"message": "Exposes the style name in the page to facilitate debugging of styles in devtools. Please reload the tab(s) to apply the new setting."
|
||||||
|
},
|
||||||
"optionsAdvancedNewStyleAsUsercss": {
|
"optionsAdvancedNewStyleAsUsercss": {
|
||||||
"message": "Write new style as usercss"
|
"message": "Write new style as usercss"
|
||||||
},
|
},
|
||||||
|
|
|
@ -184,6 +184,8 @@ const styleMan = (() => {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// TODO: enable in FF when it supports sourceURL comment in style elements (also options.html)
|
||||||
|
const {exposeStyleName} = CHROME && prefs.__values;
|
||||||
const sender = CHROME && this && this.sender || {};
|
const sender = CHROME && this && this.sender || {};
|
||||||
if (sender.frameId === 0) {
|
if (sender.frameId === 0) {
|
||||||
/* Chrome hides text frament from location.href of the page e.g. #:~:text=foo
|
/* Chrome hides text frament from location.href of the page e.g. #:~:text=foo
|
||||||
|
@ -202,9 +204,9 @@ const styleMan = (() => {
|
||||||
} else if (cache.maybeMatch.size) {
|
} else if (cache.maybeMatch.size) {
|
||||||
buildCache(cache, url, Array.from(cache.maybeMatch, id2data).filter(Boolean));
|
buildCache(cache, url, Array.from(cache.maybeMatch, id2data).filter(Boolean));
|
||||||
}
|
}
|
||||||
return id
|
return Object.assign({cfg: {exposeStyleName, order}},
|
||||||
? cache.sections[id] ? {[id]: cache.sections[id]} : {}
|
id ? mapObj(cache.sections, null, [id])
|
||||||
: Object.assign({cfg: {order}}, cache.sections);
|
: cache.sections);
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @returns {Promise<StyleObj>} */
|
/** @returns {Promise<StyleObj>} */
|
||||||
|
@ -429,7 +431,7 @@ const styleMan = (() => {
|
||||||
const code = getAppliedCode(createMatchQuery(url), style);
|
const code = getAppliedCode(createMatchQuery(url), style);
|
||||||
if (code) {
|
if (code) {
|
||||||
updated.add(url);
|
updated.add(url);
|
||||||
cache.sections[id] = {id, code};
|
buildCacheEntry(cache, style, code);
|
||||||
} else {
|
} else {
|
||||||
excluded.add(url);
|
excluded.add(url);
|
||||||
delete cache.sections[id];
|
delete cache.sections[id];
|
||||||
|
@ -703,13 +705,20 @@ const styleMan = (() => {
|
||||||
for (const {style, appliesTo, preview} of styleList) {
|
for (const {style, appliesTo, preview} of styleList) {
|
||||||
const code = getAppliedCode(query, preview || style);
|
const code = getAppliedCode(query, preview || style);
|
||||||
if (code) {
|
if (code) {
|
||||||
const id = style.id;
|
buildCacheEntry(cache, style, code);
|
||||||
cache.sections[id] = {id, code};
|
|
||||||
appliesTo.add(url);
|
appliesTo.add(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildCacheEntry(cache, style, code = style.code) {
|
||||||
|
cache.sections[style.id] = {
|
||||||
|
code,
|
||||||
|
id: style.id,
|
||||||
|
name: style.customName || style.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** @returns {StyleObj[]} */
|
/** @returns {StyleObj[]} */
|
||||||
function getAllAsArray() {
|
function getAllAsArray() {
|
||||||
return Array.from(dataMap.values(), v => v.style);
|
return Array.from(dataMap.values(), v => v.style);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* global API */// msg.js
|
/* global API */// msg.js
|
||||||
/* global CHROME ignoreChromeError */// toolbox.js
|
/* global CHROME URLS ignoreChromeError */// toolbox.js
|
||||||
/* global prefs */
|
/* global prefs */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -49,6 +49,12 @@
|
||||||
if (CHROME && !off) {
|
if (CHROME && !off) {
|
||||||
chrome.webNavigation.onCommitted.addListener(injectData, {url: [{urlPrefix: 'http'}]});
|
chrome.webNavigation.onCommitted.addListener(injectData, {url: [{urlPrefix: 'http'}]});
|
||||||
}
|
}
|
||||||
|
if (CHROME) {
|
||||||
|
chrome.webRequest.onBeforeRequest.addListener(openNamedStyle, {
|
||||||
|
urls: [URLS.ownOrigin + 'virtual/*.css'],
|
||||||
|
types: ['main_frame'],
|
||||||
|
}, ['blocking']);
|
||||||
|
}
|
||||||
state.csp = csp;
|
state.csp = csp;
|
||||||
state.off = off;
|
state.off = off;
|
||||||
state.xhr = xhr;
|
state.xhr = xhr;
|
||||||
|
@ -146,6 +152,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {chrome.webRequest.WebRequestBodyDetails} req */
|
||||||
|
function openNamedStyle(req) {
|
||||||
|
chrome.tabs.update(req.tabId, {url: 'edit.html?id=' + req.url.split('#')[1]});
|
||||||
|
return {cancel: true};
|
||||||
|
}
|
||||||
|
|
||||||
function req2key(req) {
|
function req2key(req) {
|
||||||
return req.tabId + ':' + req.frameId;
|
return req.tabId + ':' + req.frameId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,6 @@
|
||||||
if (styles.cfg) {
|
if (styles.cfg) {
|
||||||
isDisabled = styles.cfg.disableAll;
|
isDisabled = styles.cfg.disableAll;
|
||||||
Object.assign(order, styles.cfg.order);
|
Object.assign(order, styles.cfg.order);
|
||||||
delete styles.cfg;
|
|
||||||
}
|
}
|
||||||
hasStyles = !isDisabled;
|
hasStyles = !isDisabled;
|
||||||
if (hasStyles) {
|
if (hasStyles) {
|
||||||
|
@ -181,7 +180,6 @@
|
||||||
if (!hasStyles && isDisabled || matchUrl === request.url) break;
|
if (!hasStyles && isDisabled || matchUrl === request.url) break;
|
||||||
matchUrl = request.url;
|
matchUrl = request.url;
|
||||||
API.styles.getSectionsByUrl(matchUrl).then(sections => {
|
API.styles.getSectionsByUrl(matchUrl).then(sections => {
|
||||||
delete sections.cfg;
|
|
||||||
hasStyles = true;
|
hasStyles = true;
|
||||||
styleInjector.replace(sections);
|
styleInjector.replace(sections);
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,10 +11,12 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
||||||
const ORDERED_TAGS = new Set(['head', 'body', 'frameset', 'style', 'link']);
|
const ORDERED_TAGS = new Set(['head', 'body', 'frameset', 'style', 'link']);
|
||||||
const docRewriteObserver = RewriteObserver(_sort);
|
const docRewriteObserver = RewriteObserver(_sort);
|
||||||
const docRootObserver = RootObserver(_sortIfNeeded);
|
const docRootObserver = RootObserver(_sortIfNeeded);
|
||||||
|
const toSafeChar = c => String.fromCharCode(0xFF00 + c.charCodeAt(0) - 0x20);
|
||||||
const list = [];
|
const list = [];
|
||||||
const table = new Map();
|
const table = new Map();
|
||||||
let isEnabled = true;
|
let isEnabled = true;
|
||||||
let isTransitionPatched;
|
let isTransitionPatched;
|
||||||
|
let exposeStyleName;
|
||||||
// will store the original method refs because the page can override them
|
// will store the original method refs because the page can override them
|
||||||
let creationDoc, createElement, createElementNS;
|
let creationDoc, createElement, createElementNS;
|
||||||
|
|
||||||
|
@ -83,7 +85,7 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
||||||
};
|
};
|
||||||
|
|
||||||
function _add(style) {
|
function _add(style) {
|
||||||
const el = style.el = _createStyle(style.id, style.code);
|
const el = style.el = _createStyle(style);
|
||||||
const i = list.findIndex(item => compare(item, style) > 0);
|
const i = list.findIndex(item => compare(item, style) > 0);
|
||||||
table.set(style.id, style);
|
table.set(style.id, style);
|
||||||
if (isEnabled) {
|
if (isEnabled) {
|
||||||
|
@ -116,18 +118,18 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
||||||
!styles.some(s => s.code.includes('transition'))) {
|
!styles.some(s => s.code.includes('transition'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const el = _createStyle(PATCH_ID, `
|
const el = _createStyle({id: PATCH_ID, code: `
|
||||||
:root:not(#\\0):not(#\\0) * {
|
:root:not(#\\0):not(#\\0) * {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
}
|
}
|
||||||
`);
|
`});
|
||||||
document.documentElement.appendChild(el);
|
document.documentElement.appendChild(el);
|
||||||
// wait for the next paint to complete
|
// wait for the next paint to complete
|
||||||
// note: requestAnimationFrame won't fire in inactive tabs
|
// note: requestAnimationFrame won't fire in inactive tabs
|
||||||
requestAnimationFrame(() => setTimeout(() => el.remove()));
|
requestAnimationFrame(() => setTimeout(() => el.remove()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createStyle(id, code = '') {
|
function _createStyle({id, code = '', name} = {}) {
|
||||||
if (!creationDoc) _initCreationDoc();
|
if (!creationDoc) _initCreationDoc();
|
||||||
let el;
|
let el;
|
||||||
if (document.documentElement instanceof SVGSVGElement) {
|
if (document.documentElement instanceof SVGSVGElement) {
|
||||||
|
@ -145,6 +147,11 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
||||||
const oldEl = document.getElementById(el.id);
|
const oldEl = document.getElementById(el.id);
|
||||||
if (oldEl) oldEl.id += '-superseded-by-Stylus';
|
if (oldEl) oldEl.id += '-superseded-by-Stylus';
|
||||||
}
|
}
|
||||||
|
if (exposeStyleName && name) {
|
||||||
|
el.dataset.name = name;
|
||||||
|
name = encodeURIComponent(name.replace(/[#%/@:']/g, toSafeChar));
|
||||||
|
code += `\n/*# sourceURL=${chrome.runtime.getURL('')}virtual/${name}.css#${id} */`;
|
||||||
|
}
|
||||||
el.type = 'text/css';
|
el.type = 'text/css';
|
||||||
// SVG className is not a string, but an instance of SVGAnimatedString
|
// SVG className is not a string, but an instance of SVGAnimatedString
|
||||||
el.classList.add('stylus');
|
el.classList.add('stylus');
|
||||||
|
@ -224,9 +231,12 @@ window.StyleInjector = window.INJECTED === 1 ? window.StyleInjector : ({
|
||||||
}
|
}
|
||||||
|
|
||||||
function _styleMapToArray(styleMap) {
|
function _styleMapToArray(styleMap) {
|
||||||
return Object.values(styleMap).map(s => ({
|
({exposeStyleName} = styleMap.cfg || {});
|
||||||
id: s.id,
|
delete styleMap.cfg;
|
||||||
code: s.code.join(''),
|
return Object.values(styleMap).map(({id, code, name}) => ({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
code: code.join(''),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
'show-badge': true, // display text on popup menu icon
|
'show-badge': true, // display text on popup menu icon
|
||||||
'disableAll': false, // boss key
|
'disableAll': false, // boss key
|
||||||
'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes
|
'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes
|
||||||
|
'exposeStyleName': false, // Add style name to the style for better devtools experience
|
||||||
'newStyleAsUsercss': false, // create new style in usercss format
|
'newStyleAsUsercss': false, // create new style in usercss format
|
||||||
'styleViaXhr': false, // early style injection to avoid FOUC
|
'styleViaXhr': false, // early style injection to avoid FOUC
|
||||||
'patchCsp': false, // add data: and popular image hosting sites to strict CSP
|
'patchCsp': false, // add data: and popular image hosting sites to strict CSP
|
||||||
|
|
12
options.html
12
options.html
|
@ -269,6 +269,18 @@
|
||||||
<span></span>
|
<span></span>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="chromium-only">
|
||||||
|
<span i18n-text="optionsAdvancedExposeStyleName">
|
||||||
|
<a i18n-title="optionsAdvancedExposeStyleNameNote"
|
||||||
|
data-cmd="note" class="svg-inline-wrapper" tabindex="0">
|
||||||
|
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
<span class="onoffswitch">
|
||||||
|
<input type="checkbox" id="exposeStyleName" class="slider">
|
||||||
|
<span></span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
<label class="chromium-only">
|
<label class="chromium-only">
|
||||||
<span i18n-text="optionsAdvancedContextDelete"></span>
|
<span i18n-text="optionsAdvancedContextDelete"></span>
|
||||||
<span class="onoffswitch">
|
<span class="onoffswitch">
|
||||||
|
|
|
@ -105,6 +105,11 @@ a:hover .svg-icon,
|
||||||
.chromium-only.chrome-no-popup-border {
|
.chromium-only.chrome-no-popup-border {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
label.chromium-only > :first-child::after {
|
||||||
|
content: '(Chrome)';
|
||||||
|
color: #888;
|
||||||
|
margin-left: .5ex;
|
||||||
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -228,7 +233,7 @@ input[type="color"] {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
[data-cmd="note"] {
|
[data-cmd="note"] {
|
||||||
padding: .5em 1em .5em 0;
|
padding: .5em 0 .5em 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.update-in-progress [data-cmd="check-updates"] {
|
.update-in-progress [data-cmd="check-updates"] {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user