fix/deduplicate/simplify installer html/css/js (#1383)

This commit is contained in:
tophf 2022-01-18 16:39:33 +03:00 committed by GitHub
parent 936f5b40d2
commit 0705392fb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 248 additions and 294 deletions

View File

@ -230,44 +230,6 @@
</table> </table>
</template> </template>
<template data-id="styleSettings">
<div>
<fieldset class="style-settings can-close-on-esc">
<label i18n-text="styleUpdateUrlLabel">
<input id="ss-update-url" type="text">
</label>
<div>
<div i18n-text="installPreferSchemeLabel"></div>
<label i18n-text-append="installPreferSchemeNone">
<input name="ss-scheme" type="radio" value="none">
</label>
<label i18n-text-append="installPreferSchemeDark">
<input name="ss-scheme" type="radio" value="dark">
</label>
<label i18n-text-append="installPreferSchemeLight">
<input name="ss-scheme" type="radio" value="light">
</label>
</div>
<label i18n-text="styleIncludeLabel">
<textarea id="ss-inclusions" spellcheck="false"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label>
<label i18n-text="styleExcludeLabel">
<textarea id="ss-exclusions" spellcheck="false"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label>
</fieldset>
<div class="buttons">
<button id="ss-save" i18n-text="confirmSave" disabled></button>
<label i18n-title="configOnChangeTooltip" i18n-text-append="configOnChange">
<input id="config.autosave" type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label>
<button id="ss-close" i18n-text="confirmClose"></button>
</div>
</div>
</template>
<link href="vendor/codemirror/lib/codemirror.css" rel="stylesheet"> <link href="vendor/codemirror/lib/codemirror.css" rel="stylesheet">
<link href="vendor/codemirror/addon/dialog/dialog.css" rel="stylesheet"> <link href="vendor/codemirror/addon/dialog/dialog.css" rel="stylesheet">
<link href="vendor/codemirror/addon/fold/foldgutter.css" rel="stylesheet"> <link href="vendor/codemirror/addon/fold/foldgutter.css" rel="stylesheet">

35
edit/settings.html Normal file
View File

@ -0,0 +1,35 @@
<div>
<fieldset class="style-settings can-close-on-esc">
<label i18n-text="styleUpdateUrlLabel">
<input id="ss-update-url" type="text">
</label>
<div id="ss-scheme">
<div i18n-text="installPreferSchemeLabel"></div>
<label i18n-text-append="installPreferSchemeNone">
<input name="ss-scheme" type="radio" value="none">
</label>
<label i18n-text-append="installPreferSchemeDark">
<input name="ss-scheme" type="radio" value="dark">
</label>
<label i18n-text-append="installPreferSchemeLight">
<input name="ss-scheme" type="radio" value="light">
</label>
</div>
<label i18n-text="styleIncludeLabel">
<textarea id="ss-inclusions" spellcheck="false"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label>
<label i18n-text="styleExcludeLabel">
<textarea id="ss-exclusions" spellcheck="false"
placeholder="*://site1.com/*&#10;*://site2.com/*"></textarea>
</label>
</fieldset>
<div class="buttons">
<button id="ss-save" i18n-text="confirmSave" disabled></button>
<label i18n-title="configOnChangeTooltip" i18n-text-append="configOnChange">
<input id="config.autosave" type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label>
<button id="ss-close" i18n-text="confirmClose"></button>
</div>
</div>

View File

@ -7,9 +7,10 @@
/* exported StyleSettings */ /* exported StyleSettings */
'use strict'; 'use strict';
function StyleSettings() { async function StyleSettings() {
const AUTOSAVE_DELAY = 500; // same as config-dialog.js const AUTOSAVE_DELAY = 500; // same as config-dialog.js
const SS_ID = 'styleSettings'; const SS_ID = 'styleSettings';
await t.fetchTemplate('/edit/settings.html', SS_ID);
const {style} = editor; const {style} = editor;
const ui = t.template[SS_ID].cloneNode(true); const ui = t.template[SS_ID].cloneNode(true);
const elAuto = $('[id="config.autosave"]', ui); const elAuto = $('[id="config.autosave"]', ui);

View File

@ -11,13 +11,12 @@
<script src="js/polyfill.js"></script> <script src="js/polyfill.js"></script>
<script src="js/msg.js"></script> <script src="js/msg.js"></script>
<script src="js/toolbox.js"></script> <script src="js/toolbox.js"></script>
<script src="install-usercss/preinit.js"></script>
<script src="js/prefs.js"></script> <script src="js/prefs.js"></script>
<script src="js/dom.js"></script> <script src="js/dom.js"></script>
<script src="js/localization.js"></script> <script src="js/localization.js"></script>
<script src="install-usercss/preinit.js"></script>
<script src="content/style-injector.js"></script> <script src="content/style-injector.js"></script>
<script src="content/apply.js"></script> <script src="content/apply.js"></script>
@ -25,66 +24,59 @@
<link href="install-usercss/install-usercss.css" rel="stylesheet"> <link href="install-usercss/install-usercss.css" rel="stylesheet">
</head> </head>
<body id="stylus-install-usercss"> <body id="stylus-install-usercss">
<div class="container"> <div id="header">
<div id="header"> <div id="header-contents">
<div id="header-content-wrapper"> <h1 class="w100">
<h1> <span class="meta-name"></span>
<span class="meta-name"></span> <small class="meta-version"></small>
<small class="meta-version"></small> </h1>
</h1> <div id="install-wrapper">
<div class="actions"> <h2 class="install-show" i18n-text="installButtonInstalled"></h2>
<h2 hidden class="installed" i18n-text="installButtonInstalled"></h2> <button class="install install-hide" i18n-text="installButton"></button>
<button class="install" i18n-text="installButton"></button> <a class="configure-usercss" i18n-title="configureStyle" tabindex="0">
<a class="configure-usercss" i18n-title="configureStyle" tabindex="0"> <svg class="svg-icon config"><use xlink:href="#svg-icon-config"></use></svg>
<svg class="svg-icon config"><use xlink:href="#svg-icon-config"></use></svg> </a>
</a> <div class="install-show w100-full">
<p id="live-reload-install-hint" hidden></p> <a href="manage.html"><button i18n-text="openManage"></button></a>
<label class="set-update-url"> <a id="edit" href="edit.html?id="><button i18n-text="editStyleLabel"></button></a>
<input type="checkbox"> <a id="delete" tabindex="0"><button i18n-text="deleteStyleLabel"></button></a>
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
<span i18n-text="installUpdateFromLabel"></span>
<p></p>
</label>
<label class="live-reload">
<input type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
<span i18n-text="liveReloadLabel"></span>
</label>
<label class="set-prefer-scheme">
<span i18n-text="installPreferSchemeLabel"></span>
<select>
<option value="none" i18n-text="installPreferSchemeNone"></option>
<option value="dark" i18n-text="installPreferSchemeDark"></option>
<option value="light" i18n-text="installPreferSchemeLight"></option>
</select>
</label>
<p hidden class="installed-actions">
<a href="manage.html" tabindex="0"><button i18n-text="openManage"></button></a>
<a href="edit.html?id=" tabindex="0"><button i18n-text="editStyleLabel"></button></a>
<a id="delete" tabindex="0"><button i18n-text="deleteStyleLabel"></button></a>
</p>
</div>
<p class="meta-description"></p>
<div>
<h3 i18n-text="author"></h3>
<span class="meta-author"></span>
</div>
<div>
<h3 i18n-text="license"></h3>
<span class="meta-license"></span>
</div>
<div class="external-link"></div>
<div id="applies-to-wrapper">
<h3 i18n-text="appliesLabel"></h3>
<ul class="applies-to">
</ul>
</div> </div>
</div> </div>
<div id="header-resizer" i18n-title="headerResizerHint"></div> <div id="ss-scheme" class="install-dim"></div>
</div> <div class="set-update-url w100 checkbox-wrapper install-disable">
<div class="main"> <label>
<div class="warnings"></div> <input type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
<span i18n-text="installUpdateFromLabel"></span>
</label>
<p></p>
</div>
<label class="live-reload checkbox-wrapper">
<input type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
<span i18n-text="liveReloadLabel"></span>
</label>
<div id="live-reload-install-hint" class="w100" hidden></div>
<div class="meta-description w100 hide-empty"></div>
<div>
<h3 i18n-text="author"></h3>
<span class="meta-author"></span>
</div>
<div>
<h3 i18n-text="license"></h3>
<span class="meta-license"></span>
</div>
<div class="external-link hide-empty"></div>
<div class="w100">
<h3 i18n-text="appliesLabel"></h3>
<ul class="applies-to">
</ul>
</div>
</div> </div>
<div id="header-resizer" i18n-title="headerResizerHint"></div>
</div>
<div class="main">
<div class="warnings"></div>
</div> </div>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;"> <svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">

View File

@ -2,6 +2,8 @@ body {
overflow: hidden; overflow: hidden;
margin: 0; margin: 0;
background: white; background: white;
display: flex;
height: 100vh;
} }
a { a {
@ -22,25 +24,29 @@ input:disabled + span {
color: rgb(128, 128, 128); color: rgb(128, 128, 128);
} }
.container {
display: flex;
height: 100vh;
}
#header, #header,
.warnings { .warnings {
flex: 0 0 var(--header-width); flex: 0 0 var(--header-width);
box-sizing: border-box; box-sizing: border-box;
padding: 1rem; padding: 1rem;
box-shadow: 0 0 50px -18px black; box-shadow: 0 0 50px -18px black;
word-break: break-all;
overflow-wrap: break-word; overflow-wrap: break-word;
overflow-y: auto; overflow-y: auto;
z-index: 100; z-index: 100;
} }
#header {
--child-gap: 1rem;
}
#header-contents > :nth-last-child(n + 2) {
margin-bottom: var(--child-gap);
}
#header.meta-init-error { #header.meta-init-error {
display: none; display: none;
} }
#header-contents ul {
margin: 0;
}
.warnings { .warnings {
display: none; display: none;
@ -72,26 +78,44 @@ input:disabled + span {
h1 { h1 {
margin-top: 0; margin-top: 0;
display: flex;
align-items: baseline;
flex-wrap: wrap;
} }
.meta-name {
h1 small { margin-right: .5em;
}
.meta-version {
font-size: 0.6em; font-size: 0.6em;
white-space: nowrap;
} }
.meta-version::before { .meta-version::before {
content: " v"; content: "v";
} }
.checkbox-wrapper {
.actions { padding-left: 16px;
margin-bottom: 1em; position: relative;
box-sizing: border-box;
display: block;
} }
.set-update-url p {
.actions label { word-break: break-all;
max-width: -moz-fit-content; opacity: .5;
max-width: fit-content; margin: .25em 0 0;
}
#install-wrapper {
display: flex; display: flex;
align-items: center; align-items: center;
margin: 0.5em 0; flex-wrap: wrap;
}
#install-wrapper > :nth-last-child(n + 2) {
margin-right: .5rem;
}
#live-reload-install-hint {
color: darkcyan;
}
.w100 {
width: 100%;
} }
.install { .install {
@ -107,7 +131,6 @@ h1 small {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
border-style: none; border-style: none;
margin-bottom: 1ex;
cursor: pointer; cursor: pointer;
box-shadow: inset 0 -1px 0 0 hsl(0, 0%, 24%), inset 0 1px 0 0 hsl(0, 0%, 30%), inset 1px 0 0 0 hsl(0, 0%, 24%); box-shadow: inset 0 -1px 0 0 hsl(0, 0%, 24%), inset 0 1px 0 0 hsl(0, 0%, 30%), inset 1px 0 0 0 hsl(0, 0%, 24%);
transition: color .25s, background-color .25s; transition: color .25s, background-color .25s;
@ -212,44 +235,25 @@ h1 small {
filter: hue-rotate(-18deg) brightness(.7) contrast(2); filter: hue-rotate(-18deg) brightness(.7) contrast(2);
} }
.install.installed { h2 {
display: none;
}
h2.installed.active {
display: inline-block;
font-weight: bold; font-weight: bold;
margin-top: 0; margin: 0;
color: darkcyan; color: darkcyan;
} }
h2.installed.active ~ .configure-usercss svg { .installed .configure-usercss svg {
fill: hsl(180, 100%, 20%); fill: hsl(180, 100%, 20%);
} }
h2.installed.active ~ .configure-usercss:hover svg { .installed .configure-usercss:hover svg {
fill: hsl(180, 100%, 30%); fill: hsl(180, 100%, 30%);
} }
.actions label input { #header-contents > .hide-empty:empty,
margin: 0 0.5em 0 0; body:not(.installed) .install-show,
flex: 0 0 auto; .installed .install-hide {
display: none !important;
} }
.installed .install-dim {
.actions label span {
min-width: 0;
}
.set-update-url {
flex-wrap: wrap;
}
.set-update-url p {
word-break: break-all;
opacity: .5; opacity: .5;
width: 100%;
margin: .25em 0 .25em;
}
label.set-prefer-scheme:not(.unavailable) {
padding-left: 0;
} }
.external { .external {
@ -270,8 +274,8 @@ li {
.main, .main,
.main .CodeMirror { .main .CodeMirror {
height: 100% !important; height: 100%;
width: 100% !important; width: 100%;
border: none; border: none;
} }
@ -290,22 +294,13 @@ li {
} }
#header.meta-init > * { #header.meta-init > * {
opacity: 1;
transition: opacity .5s; transition: opacity .5s;
-moz-user-select: auto;
user-select: auto;
} }
#header.meta-init[data-arrived-fast="true"] > * { .meta-init[data-arrived-fast="true"] > * {
transition-duration: .1s; transition-duration: .1s;
} }
label {
/* FIXME: why do we want to give all labels a padding? */
padding-left: 16px;
position: relative;
}
.lds-spinner { .lds-spinner {
top: 50px; top: 50px;
opacity: .2; opacity: .2;
@ -316,7 +311,6 @@ label {
.configure-usercss .svg-icon.config { .configure-usercss .svg-icon.config {
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-top: -3px;
} }
#message-box.config-dialog { #message-box.config-dialog {
width: 0; width: 0;
@ -331,118 +325,74 @@ label {
@media (max-width: 850px) { @media (max-width: 850px) {
body { body {
overflow: hidden;
}
.container {
flex-direction: column; flex-direction: column;
} }
#header { #header {
flex: 0 1 auto;
border-right: none;
border-bottom: 1px dashed #AAA; border-bottom: 1px dashed #AAA;
overflow-x: auto; min-height: 6rem;
overflow-y: hidden; max-height: 40vh;
padding: 0; resize: vertical;
flex: 0 1 auto;
--child-gap: .75rem;
} }
#header:not(.meta-init) { #header:not(.meta-init) {
min-height: 300px; min-height: 300px;
} }
.main { #header-contents {
flex: 1;
}
#header-content-wrapper {
display: flex;
flex-wrap: wrap;
padding: .5rem 0 0 1rem;
box-sizing: border-box;
height: min-content;
}
#header-content-wrapper > * {
flex-grow: 1;
margin: 0;
padding: 0 1rem .5rem 0;
min-width: 0;
}
#header-content-wrapper > .meta-description + .flex-wrapper {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
padding: 0;
}
#header-content-wrapper > .meta-description + .flex-wrapper > * {
display: flex;
flex-direction: column;
flex: 1;
flex-wrap: wrap;
white-space: nowrap;
padding: 0 1rem .5rem 0;
box-sizing: border-box;
}
.flex-wrapper ul {
margin: 0;
}
#header-content-wrapper > .meta-description {
flex-basis: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.actions {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-content: flex-start;
align-items: flex-start; align-items: flex-start;
} }
.set-update-url p { #header-contents > :not(.w100) {
margin-right: 1rem;
}
.set-update-url {
display: flex;
white-space: nowrap; white-space: nowrap;
box-sizing: border-box;
}
.set-update-url p {
margin: 0 0 0 1rem;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.actions label {
min-width: 100px;
flex: 1;
}
.actions label span {
white-space: nowrap;
}
.has-warnings #header {
min-height: 4em;
max-height: 20%;
}
.warnings {
max-height: 20%;
}
.warning:not(:last-child) { .warning:not(:last-child) {
border-bottom: 1px dashed #b57c7c; border-bottom: 1px dashed #b57c7c;
padding-bottom: 1em; padding-bottom: 1em;
} }
ul.applies-to, #header-contents h3 {
.actions label {
margin: 0;
}
#header-content-wrapper > h1 {
font-size: 1.75em;
display: flex;
align-items: baseline;
}
#header-content-wrapper > h1 > .meta-version {
padding-left: 3px;
}
#header-content-wrapper > h1 > .meta-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#header-content-wrapper > * h3 {
margin: 0 0 .5rem; margin: 0 0 .5rem;
} }
.install {
flex-shrink: 0;
margin-right: 1em;
}
#message-box.config-dialog > div { #message-box.config-dialog > div {
top: auto; top: auto;
bottom: 3rem; bottom: 3rem;
} }
h1 {
flex-wrap: nowrap;
}
.meta-name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.main {
height: auto;
flex: 1;
}
}
@media (min-width: 850px) {
#header {
height: 100% !important; /* overrides user resize */
}
#ss-scheme > label {
display: block;
}
.w100-full {
width: 100%;
margin-top: var(--child-gap);
}
} }
/* Retina-specific stuff here */ /* Retina-specific stuff here */

View File

@ -1,4 +1,4 @@
/* global $ $create $createLink $$remove showSpinner */// dom.js /* global $$ $ $create $createLink $$remove showSpinner */// dom.js
/* global API */// msg.js /* global API */// msg.js
/* global URLS closeCurrentTab deepEqual */// toolbox.js /* global URLS closeCurrentTab deepEqual */// toolbox.js
/* global messageBox */ /* global messageBox */
@ -7,6 +7,9 @@
/* global t */// localization.js /* global t */// localization.js
'use strict'; 'use strict';
const CFG_SEL = '#message-box.config-dialog';
let cfgShown = true;
let cm; let cm;
let initialUrl; let initialUrl;
let installed; let installed;
@ -44,6 +47,7 @@ setTimeout(() => !cm && showSpinner($('#header')), 200);
'/vendor/codemirror/keymap/emacs', '/vendor/codemirror/keymap/emacs',
'/vendor/codemirror/keymap/vim', // TODO: load conditionally '/vendor/codemirror/keymap/vim', // TODO: load conditionally
'/vendor/codemirror/mode/css/css', '/vendor/codemirror/mode/css/css',
'/vendor/codemirror/mode/stylus/stylus',
'/vendor/codemirror/addon/search/searchcursor', '/vendor/codemirror/addon/search/searchcursor',
'/vendor/codemirror/addon/fold/foldcode', '/vendor/codemirror/addon/fold/foldcode',
'/vendor/codemirror/addon/fold/foldgutter', '/vendor/codemirror/addon/fold/foldgutter',
@ -63,6 +67,7 @@ setTimeout(() => !cm && showSpinner($('#header')), 200);
({tabId, initialUrl} = preinit); ({tabId, initialUrl} = preinit);
liveReload = initLiveReload(); liveReload = initLiveReload();
preinit.tpl.then(el => $('#ss-scheme').append(...$('[id=ss-scheme]', el).children));
const [ const [
{dup, style, error, sourceCode}, {dup, style, error, sourceCode},
@ -97,12 +102,10 @@ setTimeout(() => !cm && showSpinner($('#header')), 200);
// update UI // update UI
if (versionTest < 0) { if (versionTest < 0) {
$('.actions').parentNode.insertBefore( $('h1').after($create('.warning', t('versionInvalidOlder')));
$create('.warning', t('versionInvalidOlder')),
$('.actions')
);
} }
$('button.install').onclick = () => { $('button.install').onclick = () => {
shouldShowConfig();
(!dup ? (!dup ?
Promise.resolve(true) : Promise.resolve(true) :
messageBox.confirm($create('span', t('styleInstallOverwrite', [ messageBox.confirm($create('span', t('styleInstallOverwrite', [
@ -136,11 +139,9 @@ setTimeout(() => !cm && showSpinner($('#header')), 200);
updateUrl.href.slice(0, 300) + '...'; updateUrl.href.slice(0, 300) + '...';
// set prefer scheme // set prefer scheme
const preferScheme = $('.set-prefer-scheme select'); $('#ss-scheme').onchange = e => {
preferScheme.onchange = () => { style.preferScheme = e.target.value;
style.preferScheme = preferScheme.value;
}; };
preferScheme.onchange();
if (URLS.isLocalhost(initialUrl)) { if (URLS.isLocalhost(initialUrl)) {
$('.live-reload input').onchange = liveReload.onToggled; $('.live-reload input').onchange = liveReload.onToggled;
@ -170,41 +171,28 @@ function updateMeta(style, dup = installedDup) {
!dup ? 'install' : !dup ? 'install' :
versionTest > 0 ? 'update' : versionTest > 0 ? 'update' :
'reinstall'); 'reinstall');
$('.set-update-url').title = dup && dup.updateUrl && t('installUpdateFrom', dup.updateUrl) || ''; $('.set-update-url').title = dup && dup.updateUrl &&
(t('installUpdateFrom', dup.updateUrl) || '').replace(/\S+$/, '\n$&');
$('.meta-name').textContent = data.name; $('.meta-name').textContent = data.name;
$('.meta-version').textContent = data.version; $('.meta-version').textContent = data.version;
$('.meta-description').textContent = data.description; $('.meta-description').textContent = data.description;
$('.set-prefer-scheme select').value = $$('#ss-scheme input').forEach(el => {
style.preferScheme === 'dark' ? 'dark' : el.checked = el.value === (style.preferScheme || 'none');
style.preferScheme === 'light' ? 'light' : 'none'; });
if (data.author) { replaceChildren($('.meta-author'), makeAuthor(data.author), true);
$('.meta-author').parentNode.style.display = ''; replaceChildren($('.meta-license'), data.license, true);
$('.meta-author').textContent = ''; replaceChildren($('.external-link'), makeExternalLink());
$('.meta-author').appendChild(makeAuthor(data.author));
} else {
$('.meta-author').parentNode.style.display = 'none';
}
$('.meta-license').parentNode.style.display = data.license ? '' : 'none';
$('.meta-license').textContent = data.license;
$('.applies-to').textContent = '';
getAppliesTo(style).then(list => getAppliesTo(style).then(list =>
$('.applies-to').append(...list.map(s => $create('li', s)))); replaceChildren($('.applies-to'), list.map(s => $create('li', s))));
$('.external-link').textContent = '';
const externalLink = makeExternalLink();
if (externalLink) {
$('.external-link').appendChild(externalLink);
}
Object.assign($('.configure-usercss'), { Object.assign($('.configure-usercss'), {
hidden: !data.vars, hidden: !data.vars,
onclick: openConfigDialog, onclick: openConfigDialog,
}); });
if (!data.vars) { if (!data.vars) {
$$remove('#message-box.config-dialog'); cfgShown = false;
$$remove(CFG_SEL);
} else if (!deepEqual(data.vars, vars)) { } else if (!deepEqual(data.vars, vars)) {
vars = data.vars; vars = data.vars;
// Use the user-customized vars from the installed style // Use the user-customized vars from the installed style
@ -214,6 +202,8 @@ function updateMeta(style, dup = installedDup) {
v.value = dv.value; v.value = dv.value;
} }
} }
}
if (shouldShowConfig()) {
openConfigDialog(); openConfigDialog();
} }
@ -227,26 +217,26 @@ function updateMeta(style, dup = installedDup) {
if (dup) enablePostActions(); if (dup) enablePostActions();
function makeAuthor(text) { function makeAuthor(text) {
const match = text.match(/^(.+?)(?:\s+<(.+?)>)?(?:\s+\((.+?)\))?$/); const match = text && text.match(/^(.+?)(?:\s+<(.+?)>)?(?:\s+\((.+?)\))?$/);
if (!match) { if (!match) {
return document.createTextNode(text); return text;
} }
const [, name, email, url] = match; const [, name, email, url] = match;
const frag = document.createDocumentFragment(); const elems = [];
if (email) { if (email) {
frag.appendChild($createLink(`mailto:${email}`, name)); elems.push($createLink(`mailto:${email}`, name));
} else { } else {
frag.appendChild($create('span', name)); elems.push($create('span', name));
} }
if (url) { if (url) {
frag.appendChild($createLink(url, elems.push($createLink(url,
$create('SVG:svg.svg-icon', {viewBox: '0 0 20 20'}, $create('SVG:svg.svg-icon', {viewBox: '0 0 20 20'},
$create('SVG:path', { $create('SVG:path', {
d: 'M4,4h5v2H6v8h8v-3h2v5H4V4z M11,3h6v6l-2-2l-4,4L9,9l4-4L11,3z', d: 'M4,4h5v2H6v8h8v-3h2v5H4V4z M11,3h6v6l-2-2l-4,4L9,9l4-4L11,3z',
})) }))
)); ));
} }
return frag; return elems;
} }
function makeExternalLink() { function makeExternalLink() {
@ -274,7 +264,7 @@ function updateMeta(style, dup = installedDup) {
function showError(err) { function showError(err) {
$('.warnings').textContent = ''; $('.warnings').textContent = '';
$('.warnings').classList.toggle('visible', Boolean(err)); $('.warnings').classList.toggle('visible', Boolean(err));
$('.container').classList.toggle('has-warnings', Boolean(err)); document.body.classList.toggle('has-warnings', Boolean(err));
err = Array.isArray(err) ? err : [err]; err = Array.isArray(err) ? err : [err];
if (err[0]) { if (err[0]) {
let i; let i;
@ -310,12 +300,11 @@ function install(style) {
$$remove('.warning'); $$remove('.warning');
$('button.install').disabled = true; $('button.install').disabled = true;
$('button.install').classList.add('installed'); $('button.install').classList.add('installed');
$('#live-reload-install-hint').classList.toggle('hidden', !liveReload.enabled); $('#live-reload-install-hint').hidden = !liveReload.enabled;
$('h2.installed').classList.add('active');
$('.set-update-url input[type=checkbox]').disabled = true;
$('.set-update-url').title = style.updateUrl ? $('.set-update-url').title = style.updateUrl ?
t('installUpdateFrom', style.updateUrl) : ''; t('installUpdateFrom', style.updateUrl) : '';
$('.set-prefer-scheme select').disabled = true; $$('.install-disable input').forEach(el => (el.disabled = true));
document.body.classList.add('installed');
enablePostActions(); enablePostActions();
updateMeta(style); updateMeta(style);
} }
@ -323,9 +312,7 @@ function install(style) {
function enablePostActions() { function enablePostActions() {
const {id} = installed || installedDup; const {id} = installed || installedDup;
sessionStorage.justEditedStyleId = id; sessionStorage.justEditedStyleId = id;
$('h2.installed').hidden = !installed; $('#edit').search = `?id=${id}`;
$('.installed-actions').hidden = false;
$('.installed-actions a[href*="edit.html"]').search = `?id=${id}`;
$('#delete').onclick = async () => { $('#delete').onclick = async () => {
if (await messageBox.confirm(t('deleteStyleConfirm'), 'danger center', t('confirmDelete'))) { if (await messageBox.confirm(t('deleteStyleConfirm'), 'danger center', t('confirmDelete'))) {
await API.styles.delete(id); await API.styles.delete(id);
@ -434,3 +421,16 @@ function initLiveReload() {
}); });
} }
} }
function shouldShowConfig() {
// TODO: rewrite message-box to support multiple instances or find an existing tiny library
const prev = cfgShown;
cfgShown = $(CFG_SEL) != null;
return prev && !cfgShown;
}
function replaceChildren(el, children, toggleParent) {
if (el.firstChild) el.textContent = '';
if (children) el.append(...Array.isArray(children) ? children : [children]);
if (toggleParent) el.parentNode.hidden = !el.firstChild;
}

View File

@ -1,5 +1,6 @@
/* global API */// msg.js /* global API */// msg.js
/* global closeCurrentTab download */// toolbox.js /* global closeCurrentTab download */// toolbox.js
/* global t */// localization.js
'use strict'; 'use strict';
/* exported preinit */ /* exported preinit */
@ -89,5 +90,7 @@ const preinit = (() => {
return {error, sourceCode}; return {error, sourceCode};
} }
})(), })(),
tpl: t.fetchTemplate('/edit/settings.html', 'styleSettings'),
}; };
})(); })();

View File

@ -1,3 +1,4 @@
/* global download */// toolbox.js
'use strict'; 'use strict';
//#region Exports //#region Exports
@ -118,6 +119,16 @@ Object.assign(t, {
return bin; return bin;
}, },
async fetchTemplate(url, name) {
let el = t.template[name];
if (!el) {
el = (await download(url, {responseType: 'document'})).body.firstElementChild;
t.NodeList(el.getElementsByTagName('*'));
t.template[name] = el;
}
return el;
},
sanitizeHtml(root) { sanitizeHtml(root) {
const toRemove = []; const toRemove = [];
const walker = document.createTreeWalker(root); const walker = document.createTreeWalker(root);

View File

@ -438,7 +438,7 @@ function download(url, {
const usoVars = []; const usoVars = [];
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
const u = new URL(collapseUsoVars(url)); const u = new URL(collapseUsoVars(url), location);
const onTimeout = () => { const onTimeout = () => {
xhr.abort(); xhr.abort();
reject(new Error('Timeout fetching ' + u.href)); reject(new Error('Timeout fetching ' + u.href));