Merge branch 'master' of https://github.com/openstyles/stylus
This commit is contained in:
commit
0c4f4844b6
|
@ -183,6 +183,13 @@
|
|||
"message": "Open color picker",
|
||||
"description": "Tooltip for the colored squares shown before CSS colors in the style editor."
|
||||
},
|
||||
"configOnChange": {
|
||||
"message": "on change",
|
||||
"description": "VERY SHORT label for the checkbox in style config dialog after the save button - when enabled the changes in the dialog are saved and applied automatically without the need to press the Save button"
|
||||
},
|
||||
"configOnChangeTooltip": {
|
||||
"message": "Autosave and apply changes automatically"
|
||||
},
|
||||
"dysfunctional": {
|
||||
"message": "Stylus cannot function in private windows because Firefox disallows direct connection to the internal background page context of the extension.",
|
||||
"description": "Displayed in Firefox when its settings make Stylus dysfunctional"
|
||||
|
|
|
@ -78,8 +78,8 @@ var usercssHelper = (() => {
|
|||
);
|
||||
}
|
||||
|
||||
function openInstallPage(tab, {url = tab.url, direct} = {}) {
|
||||
if (direct) {
|
||||
function openInstallPage(tab, {url = tab.url, direct, downloaded} = {}) {
|
||||
if (direct && !downloaded) {
|
||||
prefetchCodeForInstallation(tab.id, url);
|
||||
}
|
||||
return wrapReject(openURL({
|
||||
|
|
|
@ -312,7 +312,7 @@
|
|||
</summary>
|
||||
<div></div>
|
||||
</details>
|
||||
<div id="footer">
|
||||
<div id="footer" class="hidden">
|
||||
<a href="https://github.com/openstyles/stylus/wiki/Usercss"
|
||||
i18n-text="externalUsercssDocument"
|
||||
target="_blank"></a>
|
||||
|
|
|
@ -56,3 +56,7 @@
|
|||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.CodeMirror-activeline .applies-to ul {
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
|
@ -126,6 +126,9 @@ h2 .svg-icon, label .svg-icon {
|
|||
.svg-icon.settings:hover {
|
||||
fill: #000;
|
||||
}
|
||||
#options span .svg-icon {
|
||||
margin-top: -3px; /* inline info and config icons */
|
||||
}
|
||||
input:invalid {
|
||||
background-color: rgba(255, 0, 0, 0.1);
|
||||
color: darkred;
|
||||
|
@ -137,11 +140,6 @@ input:invalid {
|
|||
#enabled-label {
|
||||
vertical-align: middle;
|
||||
}
|
||||
/* actions */
|
||||
#actions > * {
|
||||
margin-right: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
/* collapsibles */
|
||||
#header summary {
|
||||
align-items: center;
|
||||
|
@ -166,6 +164,11 @@ input:invalid {
|
|||
#header summary svg {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
#actions {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
#options:not([open]) + #lint h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
@ -189,7 +192,8 @@ input:invalid {
|
|||
opacity: .15;
|
||||
}
|
||||
/* footer */
|
||||
#footer {
|
||||
.usercss #footer {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
@ -504,7 +508,8 @@ html:not(.usercss) .applies-to li:last-child .add-applies-to {
|
|||
/************ lint ************/
|
||||
#lint {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;}
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#lint > summary {
|
||||
/* workaround for overflow:auto to show the toggle triangle */
|
||||
position: absolute;
|
||||
|
@ -661,7 +666,7 @@ html:not(.usercss) .usercss-only,
|
|||
}
|
||||
|
||||
/************ reponsive layouts ************/
|
||||
@media(max-width:737px) {
|
||||
@media(max-width: 850px) {
|
||||
#header {
|
||||
width: auto;
|
||||
height: auto;
|
||||
|
@ -670,9 +675,11 @@ html:not(.usercss) .usercss-only,
|
|||
border-bottom: 1px dashed #AAA;
|
||||
min-height: var(--header-narrow-min-height);
|
||||
max-height: 50vh;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
}
|
||||
#header section:not(:last-child) {
|
||||
margin-bottom: 0.4rem;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
#header input[type="checkbox"] {
|
||||
vertical-align: middle;
|
||||
|
@ -684,6 +691,8 @@ html:not(.usercss) .usercss-only,
|
|||
#basic-info {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex: 1;
|
||||
margin-right: 2em;
|
||||
}
|
||||
#basic-info > * {
|
||||
flex: auto;
|
||||
|
@ -700,15 +709,35 @@ html:not(.usercss) .usercss-only,
|
|||
flex-grow: 99;
|
||||
}
|
||||
#actions {
|
||||
margin-top: 1rem;
|
||||
margin-top: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#actions > * {
|
||||
display: inline-block;
|
||||
}
|
||||
#options {
|
||||
-webkit-column-count: 2;
|
||||
-moz-column-count: 2;
|
||||
column-count: 2;
|
||||
-webkit-column-count: 3;
|
||||
-moz-column-count: 3;
|
||||
column-count: 3;
|
||||
width: 100%;
|
||||
}
|
||||
#options:not([open]),
|
||||
#lint:not([open]) {
|
||||
column-count: 1;
|
||||
overflow: initial;
|
||||
}
|
||||
#options:not([open]) + #lint:not([open]) {
|
||||
margin-top: -1em;
|
||||
}
|
||||
#lint {
|
||||
overflow: initial;
|
||||
}
|
||||
#lint summary {
|
||||
position: static;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#options summary {
|
||||
margin-top: -.25em;
|
||||
}
|
||||
#options h2 {
|
||||
margin: 0 0 .5em;
|
||||
|
@ -726,10 +755,10 @@ html:not(.usercss) .usercss-only,
|
|||
top: 0.2rem;
|
||||
}
|
||||
#options:not([open]) ~ #lint {
|
||||
margin-top: -1ex;
|
||||
margin-top: -1em;
|
||||
}
|
||||
#lint > div {
|
||||
max-height: 20vh;
|
||||
margin-top: 0;
|
||||
}
|
||||
#lint table {
|
||||
width: 100%;
|
||||
|
@ -737,6 +766,9 @@ html:not(.usercss) .usercss-only,
|
|||
#lint td[role="message"] {
|
||||
max-width: none;
|
||||
}
|
||||
#lint:not([open]) + #footer {
|
||||
margin: .25em 0 -1em .25em;
|
||||
}
|
||||
#sections {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
@ -746,9 +778,6 @@ html:not(.usercss) .usercss-only,
|
|||
#sections > *:not(h2) {
|
||||
padding-left: 0.4rem;
|
||||
}
|
||||
.applies-type {
|
||||
width: 30%;
|
||||
}
|
||||
.usercss .CodeMirror-scroll {
|
||||
max-height: calc(100vh - var(--header-narrow-min-height));
|
||||
}
|
||||
|
@ -760,13 +789,29 @@ html:not(.usercss) .usercss-only,
|
|||
left: 3rem;
|
||||
}
|
||||
}
|
||||
@media(max-width:500px) {
|
||||
|
||||
@media (max-width: 720px) {
|
||||
#options {
|
||||
-webkit-column-count: 2;
|
||||
-moz-column-count: 2;
|
||||
column-count: 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 450px) {
|
||||
#options {
|
||||
-webkit-column-count: 1;
|
||||
-moz-column-count: 1;
|
||||
column-count: 1;
|
||||
}
|
||||
#options #tabSize-label {
|
||||
position: static;
|
||||
#actions {
|
||||
flex-wrap: wrap;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (-moz-appearance: none) {
|
||||
#header button {
|
||||
padding: 0 3px 2px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -445,12 +445,11 @@ function setupLinterPopup(config) {
|
|||
function makeFooter() {
|
||||
return $create('div', [
|
||||
$create('p', [
|
||||
t('linterRulesLink') + ' ',
|
||||
$createLink(
|
||||
linter === 'stylelint'
|
||||
? 'https://stylelint.io/user-guide/rules/'
|
||||
: 'https://github.com/CSSLint/csslint/wiki/Rules-by-ID',
|
||||
linterTitle),
|
||||
t('linterRulesLink')),
|
||||
linter === 'csslint' ? ' ' + t('linterCSSLintSettings') : '',
|
||||
]),
|
||||
$create('button.save', {onclick: save, title: 'Ctrl-Enter'}, t('styleSaveLabel')),
|
||||
|
|
|
@ -129,6 +129,8 @@ function createSourceEditor(style) {
|
|||
style.enabled = value;
|
||||
};
|
||||
|
||||
$('#header').addEventListener('wheel', headerOnScroll, {passive: true});
|
||||
|
||||
cm.on('changes', () => {
|
||||
dirty.modify('sourceGeneration', savedGeneration, cm.changeGeneration());
|
||||
updateLintReportIfEnabled(cm);
|
||||
|
@ -333,6 +335,20 @@ function createSourceEditor(style) {
|
|||
}
|
||||
}
|
||||
|
||||
function headerOnScroll({deltaY, deltaMode, shiftKey}) {
|
||||
if (deltaY < 0 && this.scrollTop ||
|
||||
deltaY > 0 && this.scrollTop + this.clientHeight < this.scrollHeight) {
|
||||
return;
|
||||
}
|
||||
cm.display.scroller.scrollTop +=
|
||||
// WheelEvent.DOM_DELTA_LINE
|
||||
deltaMode === 1 ? deltaY * cm.display.cachedTextHeight :
|
||||
// WheelEvent.DOM_DELTA_PAGE
|
||||
deltaMode === 2 || shiftKey ? Math.sign(deltaY) * cm.display.scroller.clientHeight :
|
||||
// WheelEvent.DOM_DELTA_PIXEL
|
||||
deltaY;
|
||||
}
|
||||
|
||||
return {
|
||||
replaceStyle,
|
||||
save,
|
||||
|
|
|
@ -102,12 +102,7 @@ select {
|
|||
-moz-appearance: checkbox !important;
|
||||
}
|
||||
|
||||
.moz-appearance-bug button {
|
||||
padding-left: .75ex;
|
||||
padding-right: .75ex;
|
||||
}
|
||||
|
||||
::-moz-focus-inner {
|
||||
::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
<input type="checkbox">
|
||||
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
|
||||
<span></span>
|
||||
<p></p>
|
||||
</label>
|
||||
<label class="live-reload">
|
||||
<input type="checkbox">
|
||||
|
|
|
@ -193,6 +193,17 @@ h2.installed.active {
|
|||
min-width: 0;
|
||||
}
|
||||
|
||||
.set-update-url {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.set-update-url p {
|
||||
word-break: break-all;
|
||||
opacity: .5;
|
||||
width: 100%;
|
||||
margin: .25em 0 .25em;
|
||||
}
|
||||
|
||||
.external {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -283,24 +283,28 @@
|
|||
};
|
||||
|
||||
// set updateUrl
|
||||
const setUpdate = $('.set-update-url input[type=checkbox]');
|
||||
const updateUrl = new URL(params.get('updateUrl'));
|
||||
const checker = $('.set-update-url input[type=checkbox]');
|
||||
// prefer the installation URL unless drag'n'dropped on the manage page
|
||||
const installationUrl = (params.get('updateUrl') || '').replace(/^blob.+/, '');
|
||||
const updateUrl = new URL(installationUrl || style.updateUrl || 'foo:bar');
|
||||
$('.set-update-url > span').textContent = t('installUpdateFromLabel');
|
||||
if (dup && dup.updateUrl === updateUrl.href) {
|
||||
setUpdate.checked = true;
|
||||
checker.checked = true;
|
||||
// there is no way to "unset" updateUrl, you can only overwrite it.
|
||||
setUpdate.disabled = true;
|
||||
checker.disabled = true;
|
||||
} else if (updateUrl.protocol === 'foo:') {
|
||||
// drag'n'dropped on the manage page and the style doesn't have @updateURL
|
||||
checker.disabled = true;
|
||||
} else if (updateUrl.protocol !== 'file:') {
|
||||
setUpdate.checked = true;
|
||||
checker.checked = true;
|
||||
style.updateUrl = updateUrl.href;
|
||||
}
|
||||
setUpdate.onchange = e => {
|
||||
if (e.target.checked) {
|
||||
style.updateUrl = updateUrl.href;
|
||||
} else {
|
||||
delete style.updateUrl;
|
||||
}
|
||||
checker.onchange = () => {
|
||||
style.updateUrl = checker.checked ? updateUrl.href : null;
|
||||
};
|
||||
checker.onchange();
|
||||
$('.set-update-url p').textContent = updateUrl.href.length < 300 ? updateUrl.href :
|
||||
updateUrl.href.slice(0, 300) + '...';
|
||||
|
||||
if (!port) {
|
||||
return;
|
||||
|
|
|
@ -61,8 +61,13 @@ if (BG && !BG.getStyles && BG !== window) {
|
|||
BG = null;
|
||||
}
|
||||
if (!BG || BG !== window) {
|
||||
document.documentElement.classList.toggle('firefox', FIREFOX);
|
||||
document.documentElement.classList.toggle('opera', OPERA);
|
||||
if (FIREFOX) {
|
||||
document.documentElement.classList.add('firefox');
|
||||
} else if (OPERA) {
|
||||
document.documentElement.classList.add('opera');
|
||||
} else if (chrome.app && navigator.userAgent.includes('Vivaldi')) {
|
||||
document.documentElement.classList.add('vivaldi');
|
||||
}
|
||||
// TODO: remove once our manifest's minimum_chrome_version is 50+
|
||||
// Chrome 49 doesn't report own extension pages in webNavigation apparently
|
||||
if (CHROME && CHROME < 2661) {
|
||||
|
|
|
@ -11,6 +11,9 @@ var prefs = new function Prefs() {
|
|||
'exposeIframes': false, // Add 'stylus-iframe' attribute to HTML element in all iframes
|
||||
'newStyleAsUsercss': false, // create new style in usercss format
|
||||
|
||||
// checkbox in style config dialog
|
||||
'config.autosave': true,
|
||||
|
||||
'popup.breadcrumbs': true, // display 'New style' links as URL breadcrumbs
|
||||
'popup.breadcrumbs.usePath': false, // use URL path for 'this URL'
|
||||
'popup.enabledFirst': true, // display enabled styles before disabled styles
|
||||
|
|
122
js/usercss.js
122
js/usercss.js
|
@ -3,25 +3,34 @@
|
|||
|
||||
// eslint-disable-next-line no-var
|
||||
var usercss = (() => {
|
||||
// true for global, false for private
|
||||
const METAS = {
|
||||
__proto__: null,
|
||||
author: true,
|
||||
advanced: false,
|
||||
description: true,
|
||||
homepageURL: false,
|
||||
// icon: false,
|
||||
license: false,
|
||||
name: true,
|
||||
namespace: false,
|
||||
// noframes: false,
|
||||
preprocessor: false,
|
||||
supportURL: false,
|
||||
'var': false,
|
||||
version: false
|
||||
};
|
||||
|
||||
// true = global
|
||||
// false or 0 = private
|
||||
// <string> = global key name
|
||||
// <function> = (style, newValue)
|
||||
const KNOWN_META = new Map([
|
||||
['author', true],
|
||||
['advanced', 0],
|
||||
['description', true],
|
||||
['homepageURL', 'url'],
|
||||
['icon', 0],
|
||||
['license', 0],
|
||||
['name', true],
|
||||
['namespace', 0],
|
||||
//['noframes', 0],
|
||||
['preprocessor', 0],
|
||||
['supportURL', 0],
|
||||
['updateURL', (style, newValue) => {
|
||||
// always preserve locally installed style's updateUrl
|
||||
if (!/^file:/.test(style.updateUrl)) {
|
||||
style.updateUrl = newValue;
|
||||
}
|
||||
}],
|
||||
['var', 0],
|
||||
['version', 0],
|
||||
]);
|
||||
const MANDATORY_META = ['name', 'namespace', 'version'];
|
||||
const META_VARS = ['text', 'color', 'checkbox', 'select', 'dropdown', 'image'];
|
||||
const META_URLS = [...KNOWN_META.keys()].filter(k => k.endsWith('URL'));
|
||||
|
||||
const BUILDER = {
|
||||
default: {
|
||||
|
@ -221,7 +230,7 @@ var usercss = (() => {
|
|||
}
|
||||
}
|
||||
state.usercssData.vars[result.name] = result;
|
||||
validVar(result);
|
||||
validateVar(result);
|
||||
}
|
||||
|
||||
function createOption(label, value) {
|
||||
|
@ -407,28 +416,39 @@ var usercss = (() => {
|
|||
function doParse() {
|
||||
let match;
|
||||
while ((match = re.exec(text))) {
|
||||
state.key = match[1];
|
||||
if (!(state.key in METAS)) {
|
||||
const key = state.key = match[1];
|
||||
const route = KNOWN_META.get(key);
|
||||
if (route === undefined) {
|
||||
continue;
|
||||
}
|
||||
if (state.key === 'var' || state.key === 'advanced') {
|
||||
if (state.key === 'advanced') {
|
||||
if (key === 'var' || key === 'advanced') {
|
||||
if (key === 'advanced') {
|
||||
state.maybeUSO = true;
|
||||
}
|
||||
parseVar(state);
|
||||
} else {
|
||||
parseStringToEnd(state);
|
||||
usercssData[state.key] = state.value;
|
||||
usercssData[key] = state.value;
|
||||
}
|
||||
if (state.key === 'version') {
|
||||
usercssData[state.key] = normalizeVersion(usercssData[state.key]);
|
||||
validVersion(usercssData[state.key]);
|
||||
let value = state.value;
|
||||
if (key === 'version') {
|
||||
value = usercssData[key] = normalizeVersion(value);
|
||||
validateVersion(value);
|
||||
}
|
||||
if (METAS[state.key]) {
|
||||
style[state.key] = usercssData[state.key];
|
||||
if (META_URLS.includes(key)) {
|
||||
validateUrl(key, value);
|
||||
}
|
||||
if (state.key === 'homepageURL' || state.key === 'supportURL') {
|
||||
validUrl(usercssData[state.key]);
|
||||
switch (typeof route) {
|
||||
case 'function':
|
||||
route(style, value);
|
||||
break;
|
||||
case 'string':
|
||||
style[route] = value;
|
||||
break;
|
||||
default:
|
||||
if (route) {
|
||||
style[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -446,12 +466,8 @@ var usercss = (() => {
|
|||
if (state.maybeUSO && !usercssData.preprocessor) {
|
||||
usercssData.preprocessor = 'uso';
|
||||
}
|
||||
if (usercssData.homepageURL) {
|
||||
style.url = usercssData.homepageURL;
|
||||
}
|
||||
|
||||
validate(style);
|
||||
|
||||
validateStyle(style);
|
||||
return style;
|
||||
}
|
||||
|
||||
|
@ -505,42 +521,32 @@ var usercss = (() => {
|
|||
return va[prop];
|
||||
}
|
||||
|
||||
function validate(style) {
|
||||
const {usercssData: data} = style;
|
||||
// mandatory fields
|
||||
for (const prop of ['name', 'namespace', 'version']) {
|
||||
function validateStyle({usercssData: data}) {
|
||||
for (const prop of MANDATORY_META) {
|
||||
if (!data[prop]) {
|
||||
throw new Error(chrome.i18n.getMessage('styleMissingMeta', prop));
|
||||
}
|
||||
}
|
||||
// validate version
|
||||
validVersion(data.version);
|
||||
|
||||
// validate URLs
|
||||
validUrl(data.homepageURL);
|
||||
validUrl(data.supportURL);
|
||||
|
||||
// validate vars
|
||||
for (const key of Object.keys(data.vars)) {
|
||||
validVar(data.vars[key]);
|
||||
}
|
||||
validateVersion(data.version);
|
||||
META_URLS.forEach(k => validateUrl(k, data[k]));
|
||||
Object.keys(data.vars).forEach(k => validateVar(data.vars[k]));
|
||||
}
|
||||
|
||||
function validVersion(version) {
|
||||
function validateVersion(version) {
|
||||
semverCompare(version, '0.0.0');
|
||||
}
|
||||
|
||||
function validUrl(url) {
|
||||
function validateUrl(key, url) {
|
||||
if (!url) {
|
||||
return;
|
||||
}
|
||||
url = new URL(url);
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
throw new Error(`${url.protocol} is not a valid protocol`);
|
||||
if (!/^https?:/.test(url.protocol)) {
|
||||
throw new Error(`${url.protocol} is not a valid protocol in ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
function validVar(va, value = 'default') {
|
||||
function validateVar(va, value = 'default') {
|
||||
if (va.type === 'select' || va.type === 'dropdown') {
|
||||
if (va.options.every(o => o.name !== va[value])) {
|
||||
throw new Error(chrome.i18n.getMessage('styleMetaErrorSelectValueMismatch'));
|
||||
|
@ -560,7 +566,7 @@ var usercss = (() => {
|
|||
if (oldVars[key] && oldVars[key].value) {
|
||||
vars[key].value = oldVars[key].value;
|
||||
try {
|
||||
validVar(vars[key], 'value');
|
||||
validateVar(vars[key], 'value');
|
||||
} catch (e) {
|
||||
vars[key].value = null;
|
||||
}
|
||||
|
@ -573,7 +579,7 @@ var usercss = (() => {
|
|||
worker.instance = new Worker('/vendor-overwrites/csslint/csslint-worker.js');
|
||||
worker.queue = [];
|
||||
worker.instance.onmessage = ({data}) => {
|
||||
worker.queue.shift().resolve(data);
|
||||
worker.queue.shift().resolve(data.__ERROR__ ? Promise.reject(data.__ERROR__) : data);
|
||||
if (worker.queue.length) {
|
||||
worker.instance.postMessage(worker.queue[0].message);
|
||||
}
|
||||
|
|
10
manage.html
10
manage.html
|
@ -93,9 +93,7 @@
|
|||
|
||||
<template data-id="configureIcon">
|
||||
<span class="configure-usercss" i18n-title="configureStyle">
|
||||
<svg class="svg-icon configure" viewBox="0 0 16 16">
|
||||
<path d="M8,0C7.6,0,7.3,0,6.9,0.1v2.2C6.1,2.5,5.4,2.8,4.8,3.2L3.2,1.6c-0.6,0.4-1.1,1-1.6,1.6l1.6,1.6C2.8,5.4,2.5,6.1,2.3,6.9H0.1C0,7.3,0,7.6,0,8c0,0.4,0,0.7,0.1,1.1h2.2c0.1,0.8,0.4,1.5,0.9,2.1l-1.6,1.6c0.4,0.6,1,1.1,1.6,1.6l1.6-1.6c0.6,0.4,1.4,0.7,2.1,0.9v2.2C7.3,16,7.6,16,8,16c0.4,0,0.7,0,1.1-0.1v-2.2c0.8-0.1,1.5-0.4,2.1-0.9l1.6,1.6c0.6-0.4,1.1-1,1.6-1.6l-1.6-1.6c0.4-0.6,0.7-1.4,0.9-2.1h2.2C16,8.7,16,8.4,16,8c0-0.4,0-0.7-0.1-1.1h-2.2c-0.1-0.8-0.4-1.5-0.9-2.1l1.6-1.6c-0.4-0.6-1-1.1-1.6-1.6l-1.6,1.6c-0.6-0.4-1.4-0.7-2.1-0.9V0.1C8.7,0,8.4,0,8,0z M8,4.3c2.1,0,3.7,1.7,3.7,3.7c0,0,0,0,0,0c0,2.1-1.7,3.7-3.7,3.7c0,0,0,0,0,0c-2.1,0-3.7-1.7-3.7-3.7c0,0,0,0,0,0C4.3,5.9,5.9,4.3,8,4.3C8,4.3,8,4.3,8,4.3z"></path>
|
||||
</svg>
|
||||
<svg class="svg-icon config"><use xlink:href="#svg-icon-config"></use></svg>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
@ -229,7 +227,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<label id="onlyUpdates" class="hidden">
|
||||
<label id="only-updates" class="hidden">
|
||||
<input type="checkbox"
|
||||
data-filter=".can-update, .update-problem, .update-done"
|
||||
data-filter-hide=":not(.updatable):not(.update-done), .no-update:not(.update-problem)">
|
||||
|
@ -356,6 +354,10 @@
|
|||
<title i18n-text="helpAlt"></title>
|
||||
<path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-icon-config" viewBox="0 0 14 14">
|
||||
<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>
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
/* config dialog */
|
||||
.config-dialog .config-heading {
|
||||
#stylus-popup #message-box-contents {
|
||||
padding: .25rem .75rem;
|
||||
}
|
||||
|
||||
#stylus-popup .config-body label {
|
||||
padding: .5em 0;
|
||||
}
|
||||
|
||||
#stylus-popup .config-body label > :first-child {
|
||||
max-width: 140px;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.config-heading {
|
||||
float: right;
|
||||
margin: -1.25rem 0 0 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.config-dialog label {
|
||||
.config-body label {
|
||||
display: flex;
|
||||
padding: .75em 0;
|
||||
align-items: center;
|
||||
|
@ -15,32 +27,27 @@
|
|||
position: static;
|
||||
}
|
||||
|
||||
.config-dialog label:first-child {
|
||||
.config-body label:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.config-dialog label:last-child {
|
||||
.config-body label:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.config-dialog label:not(:first-child) {
|
||||
.config-body label:not(:first-child) {
|
||||
border-top: 1px dotted #ccc;
|
||||
}
|
||||
|
||||
.config-dialog label > :first-child {
|
||||
.config-body label > :first-child {
|
||||
margin-right: 8px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.config-dialog label:not([disabled]) > :first-child {
|
||||
.config-body label:not([disabled]) > :first-child {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.config-dialog label:not([disabled]):hover > :first-child {
|
||||
text-shadow: 0 0 0.01px rgba(0, 0, 0, .25);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.config-dialog .dirty:after {
|
||||
content: "*";
|
||||
position: absolute;
|
||||
|
@ -51,18 +58,19 @@
|
|||
font-style: italic;
|
||||
}
|
||||
|
||||
.config-dialog input,
|
||||
.config-dialog select,
|
||||
.config-dialog .onoffswitch {
|
||||
.config-body input,
|
||||
.config-body select,
|
||||
.config-body .onoffswitch {
|
||||
width: var(--onoffswitch-width);
|
||||
margin: 0;
|
||||
height: 2em;
|
||||
height: 22px;
|
||||
box-sizing: border-box;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.config-dialog .select-resizer,
|
||||
.config-dialog select {
|
||||
.config-body input[type="text"],
|
||||
.config-body .select-resizer,
|
||||
.config-body select {
|
||||
width: auto;
|
||||
min-width: var(--onoffswitch-width);
|
||||
max-width: 124px;
|
||||
|
@ -70,24 +78,30 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.config-dialog .onoffswitch {
|
||||
.config-body .onoffswitch {
|
||||
height: auto;
|
||||
margin: calc((2em - 12px) / 2) 0;
|
||||
}
|
||||
|
||||
.config-dialog input[type="text"] {
|
||||
.config-body input[type="text"] {
|
||||
padding-left: 0.25em;
|
||||
}
|
||||
|
||||
.config-dialog label > :last-child {
|
||||
.config-body label > :last-child {
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.config-dialog label > :last-child:not(.onoffswitch):not(.select-resizer) > :not(:last-child) {
|
||||
.config-body label > :last-child:not(.onoffswitch):not(.select-resizer) > :not(:last-child) {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#config-autosave-wrapper {
|
||||
position: relative;
|
||||
padding: 0 0 0 16px;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.cm-colorview::before,
|
||||
.color-swatch {
|
||||
width: var(--onoffswitch-width) !important;
|
||||
|
|
|
@ -30,11 +30,7 @@ function configDialog(style) {
|
|||
{textContent: t('confirmClose'), dataset: {cmd: 'close'}},
|
||||
],
|
||||
onshow,
|
||||
}).then(() => {
|
||||
document.body.style.minWidth = '';
|
||||
document.body.style.minHeight = '';
|
||||
colorpicker.hide();
|
||||
});
|
||||
}).then(onhide);
|
||||
|
||||
function getInitialValues(source) {
|
||||
const data = {};
|
||||
|
@ -46,10 +42,22 @@ function configDialog(style) {
|
|||
}
|
||||
|
||||
function onshow(box) {
|
||||
$('button', box).insertAdjacentElement('afterend',
|
||||
$create('label#config-autosave-wrapper', {
|
||||
title: t('configOnChangeTooltip'),
|
||||
}, [
|
||||
$create('input', {id: 'config.autosave', type: 'checkbox'}),
|
||||
$create('SVG:svg.svg-icon.checked',
|
||||
$create('SVG:use', {'xlink:href': '#svg-icon-checked'})),
|
||||
t('configOnChange'),
|
||||
]));
|
||||
setupLivePrefs(['config.autosave']);
|
||||
|
||||
if (isPopup) {
|
||||
adjustSizeForPopup(box);
|
||||
box.style.animationDuration = '0s';
|
||||
}
|
||||
|
||||
box.addEventListener('change', onchange);
|
||||
buttons.save = $('[data-cmd="save"]', box);
|
||||
buttons.default = $('[data-cmd="default"]', box);
|
||||
|
@ -57,13 +65,23 @@ function configDialog(style) {
|
|||
updateButtons();
|
||||
}
|
||||
|
||||
function onhide() {
|
||||
document.body.style.minWidth = '';
|
||||
document.body.style.minHeight = '';
|
||||
colorpicker.hide();
|
||||
}
|
||||
|
||||
function onchange({target}) {
|
||||
// invoked after element's own onchange so 'va' contains the updated value
|
||||
const va = target.va;
|
||||
if (va) {
|
||||
va.dirty = varsInitial[va.name] !== (isDefault(va) ? va.default : va.value);
|
||||
target.closest('label').classList.toggle('dirty', va.dirty);
|
||||
updateButtons();
|
||||
if (prefs.get('config.autosave')) {
|
||||
debounce(save);
|
||||
} else {
|
||||
target.closest('label').classList.toggle('dirty', va.dirty);
|
||||
updateButtons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +131,7 @@ function configDialog(style) {
|
|||
}
|
||||
}
|
||||
if (invalid.length) {
|
||||
onhide();
|
||||
messageBox.alert([
|
||||
$create('div', {style: 'max-width: 34em'}, t('usercssConfigIncomplete')),
|
||||
$create('ol', {style: 'text-align: left'},
|
||||
|
@ -120,11 +139,16 @@ function configDialog(style) {
|
|||
$create({tag: 'li', appendChild: msg}))),
|
||||
]);
|
||||
}
|
||||
return numValid && BG.usercssHelper.save(style).then(saved => {
|
||||
varsInitial = getInitialValues(deepCopy(saved.usercssData.vars));
|
||||
vars.forEach(va => onchange({target: va.input}));
|
||||
updateButtons();
|
||||
});
|
||||
if (!numValid) {
|
||||
return;
|
||||
}
|
||||
return BG.usercssHelper.save(style)
|
||||
.then(saved => {
|
||||
varsInitial = getInitialValues(deepCopy(saved.usercssData.vars));
|
||||
vars.forEach(va => onchange({target: va.input}));
|
||||
updateButtons();
|
||||
})
|
||||
.catch(errors => onhide() + messageBox.alert(Array.isArray(errors) ? errors.join('\n') : errors));
|
||||
}
|
||||
|
||||
function useDefault() {
|
||||
|
@ -256,10 +280,10 @@ function configDialog(style) {
|
|||
}
|
||||
|
||||
function adjustSizeForPopup(box) {
|
||||
box.style = 'white-space: nowrap !important';
|
||||
box.firstElementChild.style = 'max-width: none; max-height: none;'.replace(/;/g, '!important;');
|
||||
const {offsetWidth, offsetHeight} = box.firstElementChild;
|
||||
box.style = box.firstElementChild.style = '';
|
||||
const contents = box.firstElementChild;
|
||||
contents.style = 'max-width: none; max-height: none;'.replace(/;/g, '!important;');
|
||||
let {offsetWidth: width, offsetHeight: height} = contents;
|
||||
contents.style = '';
|
||||
|
||||
const colorpicker = document.body.appendChild(
|
||||
$create('.colorpicker-popup', {style: 'display: none!important'}));
|
||||
|
@ -267,8 +291,8 @@ function configDialog(style) {
|
|||
const MIN_HEIGHT = 250;
|
||||
colorpicker.remove();
|
||||
|
||||
const width = Math.max(Math.min(offsetWidth / 0.9 + 2, 800), MIN_WIDTH);
|
||||
const height = Math.max(Math.min(offsetHeight / 0.9 + 2, 600), MIN_HEIGHT);
|
||||
width = Math.max(Math.min(width / 0.9 + 2, 800), MIN_WIDTH);
|
||||
height = Math.max(Math.min(height / 0.9 + 2, 600), MIN_HEIGHT);
|
||||
document.body.style.setProperty('min-width', width + 'px', 'important');
|
||||
document.body.style.setProperty('min-height', height + 'px', 'important');
|
||||
}
|
||||
|
|
|
@ -392,8 +392,8 @@ Object.assign(document.body, {
|
|||
this.ondragend();
|
||||
if (event.dataTransfer.files.length) {
|
||||
event.preventDefault();
|
||||
if ($('#onlyUpdates input').checked) {
|
||||
$('#onlyUpdates input').click();
|
||||
if ($('#only-updates input').checked) {
|
||||
$('#only-updates input').click();
|
||||
}
|
||||
importFromFile({file: event.dataTransfer.files[0]});
|
||||
}
|
||||
|
|
|
@ -75,9 +75,9 @@ onDOMready().then(() => {
|
|||
event.target.matches('[type="text"], [type="search"]')) {
|
||||
return;
|
||||
}
|
||||
const k = event.which;
|
||||
const {which: k, key} = event;
|
||||
// focus search field on "/" key
|
||||
if (k === 191 && !event.shiftKey) {
|
||||
if (key === '/' || !key && k === 191 && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
$('#search').focus();
|
||||
return;
|
||||
|
|
|
@ -139,7 +139,7 @@ select {
|
|||
margin-left: .5ex;
|
||||
}
|
||||
|
||||
.svg-icon.configure {
|
||||
.svg-icon.config {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
@ -392,6 +392,13 @@ select {
|
|||
background-color: hsla(0, 0%, 50%, .2);
|
||||
}
|
||||
|
||||
#only-updates {
|
||||
position: relative;
|
||||
left: -5px;
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.checkmate {
|
||||
position: relative;
|
||||
height: 12px;
|
||||
|
|
|
@ -108,7 +108,7 @@ function reportUpdateState(state, style, details) {
|
|||
entry.classList.add('can-update');
|
||||
entry.updatedCode = style;
|
||||
$('.update-note', entry).textContent = '';
|
||||
$('#onlyUpdates').classList.remove('hidden');
|
||||
$('#only-updates').classList.remove('hidden');
|
||||
break;
|
||||
case BG.updater.SKIPPED: {
|
||||
if (entry.classList.contains('can-update')) {
|
||||
|
@ -151,12 +151,12 @@ function reportUpdateState(state, style, details) {
|
|||
function renderUpdatesOnlyFilter({show, check} = {}) {
|
||||
const numUpdatable = $$('.can-update').length;
|
||||
const mightUpdate = numUpdatable > 0 || $('.update-problem');
|
||||
const checkbox = $('#onlyUpdates input');
|
||||
const checkbox = $('#only-updates input');
|
||||
show = show !== undefined ? show : mightUpdate;
|
||||
check = check !== undefined ? show && check : checkbox.checked && mightUpdate;
|
||||
|
||||
$('#onlyUpdates').classList.toggle('hidden', !show);
|
||||
checkbox.checked = check;
|
||||
$('#only-updates').classList.toggle('hidden', !show);
|
||||
checkbox.checked = check && show;
|
||||
checkbox.dispatchEvent(new Event('change'));
|
||||
|
||||
const btnApply = $('#apply-all-updates');
|
||||
|
|
16
popup.html
16
popup.html
|
@ -33,9 +33,7 @@
|
|||
<a href="#" class="enable" i18n-text="enableStyleLabel"></a>
|
||||
<a href="#" class="disable" i18n-text="disableStyleLabel"></a>
|
||||
<a href="#" class="configure" i18n-title="configureStyle">
|
||||
<svg class="svg-icon config" viewBox="0 0 14 16">
|
||||
<path d="m6.2578 1.1191c-0.4526 0-0.81641 0.36381-0.81641 0.81641v0.69531a5.5932 5.5932 0 0 0-1.1328 0.47266l-0.49414-0.49414c-0.16002-0.16002-0.36907-0.24023-0.57812-0.24023-0.20905 0-0.41811 0.080216-0.57812 0.24023l-1.0488 1.0488c-0.32004 0.32004-0.32004 0.83621 0 1.1562l0.49023 0.49023a5.5932 5.5932 0 0 0-0.4668 1.1348h-0.69726c-0.4526 0-0.81641 0.36576-0.81641 0.81836v1.4844c0 0.4526 0.36381 0.81641 0.81641 0.81641h0.69726a5.5932 5.5932 0 0 0 0.4707 1.1328l-0.49414 0.49414c-0.32004 0.32004-0.32004 0.83426 0 1.1543l1.0488 1.0508c0.32004 0.32003 0.83621 0.32003 1.1562 0l0.49023-0.49024a5.5932 5.5932 0 0 0 1.1367 0.4668v0.69727c0 0.4526 0.36381 0.81641 0.81641 0.81641h1.4844c0.4526 0 0.81641-0.36381 0.81641-0.81641v-0.69727a5.5932 5.5932 0 0 0 1.1328-0.4707l0.49414 0.49414c0.32004 0.32003 0.83622 0.32003 1.1562 0l1.0488-1.0508c0.32004-0.32004 0.32004-0.83426 0-1.1543l-0.49023-0.49023a5.5932 5.5932 0 0 0 0.4668-1.1367h0.69726c0.4526 0 0.81641-0.36381 0.81641-0.81641v-1.4844c0-0.4526-0.36381-0.81836-0.81641-0.81836h-0.69726a5.5932 5.5932 0 0 0-0.4707-1.1309l0.49414-0.49414c0.32004-0.32004 0.32004-0.83621 0-1.1562l-1.0488-1.0488c-0.16002-0.16002-0.36907-0.24023-0.57812-0.24023s-0.41811 0.080216-0.57812 0.24023l-0.49023 0.49023a5.5932 5.5932 0 0 0-1.1367-0.4668v-0.69727c0-0.4526-0.36381-0.81641-0.81641-0.81641zm0.56836 0.7793h0.34766c0.22291 0 0.40234 0.17943 0.40234 0.40234v1.1621a4.5763 4.5763 0 0 1 2.2227 0.92383l0.82422-0.82422c0.15762-0.15762 0.41074-0.15762 0.56836 0l0.24609 0.24609c0.15762 0.15762 0.15762 0.41074 0 0.56836l-0.82226 0.82227a4.5763 4.5763 0 0 1 0.91797 2.2246h1.166c0.22291 0 0.40234 0.17943 0.40234 0.40234v0.34766c0 0.22291-0.17943 0.40234-0.40234 0.40234h-1.1641a4.5763 4.5763 0 0 1-0.92188 2.2227l0.82422 0.82422c0.15762 0.15762 0.15762 0.41074 0 0.56836l-0.24609 0.24609c-0.15762 0.15763-0.41074 0.15763-0.56836 0l-0.82227-0.82226a4.5763 4.5763 0 0 1-2.2246 0.91797v1.166c0 0.22291-0.17943 0.40234-0.40234 0.40234h-0.34766c-0.22291 0-0.40234-0.17943-0.40234-0.40234v-1.1641a4.5763 4.5763 0 0 1-2.2227-0.92188l-0.82422 0.82422c-0.15762 0.15763-0.41074 0.15763-0.56836 0l-0.24609-0.24609c-0.15762-0.15762-0.15762-0.41074 0-0.56836l0.82226-0.82226a4.5763 4.5763 0 0 1-0.91797-2.2246h-1.166c-0.22291 0-0.40234-0.17943-0.40234-0.40234v-0.34766c0-0.22291 0.17943-0.40234 0.40234-0.40234h1.1641a4.5763 4.5763 0 0 1 0.92188-2.2227l-0.82422-0.82422c-0.15762-0.15762-0.15762-0.41074 0-0.56836l0.24609-0.24609c0.15762-0.15762 0.41074-0.15762 0.56836 0l0.82227 0.82227a4.5763 4.5763 0 0 1 2.2246-0.91797v-1.166c0-0.22291 0.17943-0.40234 0.40234-0.40234zm0.17383 2.7109a3.3898 3.3898 0 0 0-3.3906 3.3906 3.3898 3.3898 0 0 0 3.3906 3.3887 3.3898 3.3898 0 0 0 3.3906-3.3887 3.3898 3.3898 0 0 0-3.3906-3.3906zm0 1.1875a2.2034 2.2034 0 0 1 2.2031 2.2031 2.2034 2.2034 0 0 1-2.2031 2.2031 2.2034 2.2034 0 0 1-2.2031-2.2031 2.2034 2.2034 0 0 1 2.2031-2.2031z"/>
|
||||
</svg>
|
||||
<svg class="svg-icon config"><use xlink:href="#svg-icon-config"></use></svg>
|
||||
</a>
|
||||
<a class="style-edit-link" href="edit.html?id=" i18n-title="editStyleLabel">
|
||||
<svg class="svg-icon edit" viewBox="0 0 14 16">
|
||||
|
@ -221,6 +219,18 @@
|
|||
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
|
||||
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,6.8L352.3,609.2L184.4,386.9c-3.2-4.2-8-7-13.2-7.8c-5.3-0.8-10.6,0.6-14.9,3.9L18,487.5c-8.8,6.7-10.6,19.3-3.9,28.1L325,927.2c3.6,4.8,9.3,7.7,15.3,8c0.2,0,0.5,0,0.7,0c5.8,0,11.3-2.5,15.1-6.8L985,212.6C992.3,204.3,991.5,191.6,983.2,184.3z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-icon-select-arrow" viewBox="0 0 1792 1792">
|
||||
<path fill-rule="evenodd" d="M1408 704q0 26-19 45l-448 448q-19 19-45 19t-45-19l-448-448q-19-19-19-45t19-45 45-19h896q26 0 45 19t19 45z"/>
|
||||
</symbol>
|
||||
|
||||
<symbol id="svg-icon-config" viewBox="0 0 14 14">
|
||||
<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 id="svg-icon-config-uso" viewBox="0 0 14 14">
|
||||
<path d="M2,3h4v2H4v6h6V9h2v4H2V3z M8,1h6v6l-2.2-2.2l-4,4L6.2,7.2l4-4L8,1z"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -34,23 +34,24 @@ var hotkeys = (() => {
|
|||
return;
|
||||
}
|
||||
let entry;
|
||||
const k = event.which;
|
||||
if (k >= 48 && k <= 57 || k >= 96 && k <= 105) {
|
||||
const {which: k, key} = event;
|
||||
if (key ? key >= '0' && key <= '9' : k >= 48 && k <= 57 || k >= 96 && k <= 105) {
|
||||
// 0-9, numpad 0-9
|
||||
entry = installed.children[k === 48 || k === 96 ? 9 : k - (k > 96 ? 97 : 49)];
|
||||
} else if (k >= 65 && k <= 90) {
|
||||
// a-z
|
||||
const letter = new RegExp('^\\x' + k.toString(16), 'i');
|
||||
entry = [...installed.children].find(entry => letter.test(entry.textContent));
|
||||
} else if (k === 192 || k === 106) {
|
||||
const i = key === '0' ? 9 : key ? Number(key) - 1 : k === 48 || k === 96 ? 9 : k - (k > 96 ? 97 : 49);
|
||||
entry = installed.children[i];
|
||||
} else if (key ? key === '`' || key === '*' && !event.shiftKey : k === 192 || k === 106) {
|
||||
// backtick ` and numpad *
|
||||
invertTogglables();
|
||||
} else if (k === 109) {
|
||||
} else if (key ? key === '-' : k === 109) {
|
||||
// numpad -
|
||||
toggleState(installed.children, 'enabled', false);
|
||||
} else if (k === 107) {
|
||||
} else if (key ? key === '+' : k === 107) {
|
||||
// numpad +
|
||||
toggleState(installed.children, 'disabled', true);
|
||||
} else if (key ? key.length === 1 : k >= 65 && k <= 90) {
|
||||
// any single character
|
||||
const letter = new RegExp(key ? '^' + key : '^\\x' + k.toString(16), 'i');
|
||||
entry = [...installed.children].find(entry => letter.test(entry.textContent));
|
||||
}
|
||||
if (!entry) {
|
||||
return;
|
||||
|
|
|
@ -274,6 +274,7 @@ function createStyleElement({
|
|||
if (!style.usercssData && style.updateUrl && style.updateUrl.includes('?') && style.url) {
|
||||
config.href = style.url;
|
||||
config.target = '_blank';
|
||||
$('use', config).attributes['xlink:href'].nodeValue = '#svg-icon-config-uso';
|
||||
} else if (!style.usercssData || !Object.keys(style.usercssData.vars || {}).length) {
|
||||
config.style.display = 'none';
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
1. Until https://github.com/CSSLint/parser-lib/issues/229 is fixed, manually replace:
|
||||
|
||||
while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN) {
|
||||
|
||||
in "_function: function()" with
|
||||
|
||||
while (lt !== Tokens.COMMA && lt !== Tokens.S && lt !== Tokens.RPAREN && lt !== Tokens.EOF) {
|
||||
|
||||
2. Apply our hacks unless supported natively
|
||||
(use git history for the file as this warning may be obsolete):
|
||||
|
||||
* 449a27cc Add CSSLint position sticky rule
|
||||
* d49e44dd CSS variables
|
||||
* 2e86c958 fire startdocument on {
|
||||
* bc63ecca support "i" in attribute selector
|
||||
* 2468784e fix crashing on unclosed calc() at eof
|
||||
* 3287b79f Support :any(), :-webkit-any(), :-moz-any()
|
||||
* 4684016a Support @supports inside @-moz-document
|
|
@ -2627,9 +2627,12 @@ Parser.prototype = function() {
|
|||
|
||||
if (value === null) {
|
||||
break;
|
||||
} else {
|
||||
values.push(value);
|
||||
}
|
||||
const last = values[values.length - 1];
|
||||
if (last && last.line === value.line && last.col === value.col && last.text === value.text) {
|
||||
break;
|
||||
}
|
||||
values.push(value);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
@ -2731,6 +2734,13 @@ Parser.prototype = function() {
|
|||
}
|
||||
}
|
||||
|
||||
if (value === null) {
|
||||
const usoVar = this._isUsoVar();
|
||||
if (usoVar) {
|
||||
([line, col, value] = usoVar);
|
||||
}
|
||||
}
|
||||
|
||||
/*if (value === null) {
|
||||
return null;
|
||||
//throw new Error("Expected identifier at line " + tokenStream.token().startLine + ", character " + tokenStream.token().startCol + ".");
|
||||
|
@ -3173,6 +3183,21 @@ Parser.prototype = function() {
|
|||
},
|
||||
|
||||
|
||||
_isUsoVar() {
|
||||
const tokenStream = this._tokenStream;
|
||||
for (let i = tokenStream._ltIndex - 1; i >= 0; i--) {
|
||||
const {type, value, startLine, startCol} = tokenStream._lt[i];
|
||||
if (type === tokenStream._tokenData.S) {
|
||||
// NOP
|
||||
} else if (type === tokenStream._tokenData.COMMENT &&
|
||||
value[2] === '[' && value[3] === '[' && value.endsWith(']]*/')) {
|
||||
return [startLine, startCol, value];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Throws an error when an unexpected token is found.
|
||||
* @param {Object} token The token that was found.
|
||||
|
@ -3181,17 +3206,6 @@ Parser.prototype = function() {
|
|||
* @private
|
||||
*/
|
||||
_unexpectedToken: function(token) {
|
||||
for (let i = tokenStream._ltIndex - 1; i >= 0; i--) {
|
||||
const {type, value} = tokenStream._lt[i];
|
||||
if (type === tokenStream._tokenData.S) {
|
||||
// NOP
|
||||
} else if (type === tokenStream._tokenData.COMMENT &&
|
||||
value[2] === '[' && value[3] === '[' && value.endsWith(']]*/')) {
|
||||
return;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new SyntaxError("Unexpected token '" + token.value + "' at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
|
||||
},
|
||||
|
||||
|
@ -7186,7 +7200,8 @@ TokenStreamBase.prototype = {
|
|||
|
||||
if (!this.match(tokenTypes)) {
|
||||
token = this.LT(1);
|
||||
throw new SyntaxError("Expected " + this._tokenData[tokenTypes[0]].name +
|
||||
const info = this._tokenData[tokenTypes[0]];
|
||||
throw new SyntaxError("Expected " + (info.text || info.name) +
|
||||
" at line " + token.startLine + ", col " + token.startCol + ".", token.startLine, token.startCol);
|
||||
}
|
||||
},
|
||||
|
@ -10978,6 +10993,8 @@ CSSLint.addFormatter({
|
|||
}
|
||||
});
|
||||
|
||||
parserlib.css.Tokens[parserlib.css.Tokens.COMMENT].hide = false;
|
||||
|
||||
self.onmessage = ({data: {action = 'run', code, config}}) => {
|
||||
switch (action) {
|
||||
|
||||
|
@ -10991,19 +11008,19 @@ self.onmessage = ({data: {action = 'run', code, config}}) => {
|
|||
self.postMessage(CSSLint.getRules().map(rule => JSON.parse(JSON.stringify(rule))));
|
||||
return;
|
||||
|
||||
case 'run':
|
||||
self.postMessage(CSSLint.verify(code, config).messages.map(m => {
|
||||
// the functions are non-tranferable and we need only an id
|
||||
m.rule = {id: m.rule.id};
|
||||
return m;
|
||||
}));
|
||||
case 'run': {
|
||||
const results = CSSLint.verify(code, config).messages
|
||||
.filter(m => !m.message.includes('/*[[') && !m.message.includes(']]*/'))
|
||||
.map(m => Object.assign(m, {rule: {id: m.rule.id}}));
|
||||
self.postMessage(results);
|
||||
return;
|
||||
|
||||
}
|
||||
case 'parse':
|
||||
if (!self.mozParser) {
|
||||
self.importScripts('/js/moz-parser.js');
|
||||
}
|
||||
mozParser.parse(code)
|
||||
.then(sections => self.postMessage(sections));
|
||||
.then(sections => self.postMessage(sections))
|
||||
.catch(info => self.postMessage({__ERROR__: info}));
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user