manage: collapsible #options block

This commit is contained in:
tophf 2017-11-29 19:05:47 +03:00
parent c0a227fa39
commit 189342472e
8 changed files with 77 additions and 33 deletions

View File

@ -166,7 +166,7 @@
<button id="to-mozilla" i18n-text="exportLabel"></button> <button id="to-mozilla" i18n-text="exportLabel"></button>
</div> </div>
</section> </section>
<details id="options"> <details id="options" data-pref="editor.options.expanded">
<summary><h2 id="options-heading" i18n-text="optionsHeading"></h2></summary> <summary><h2 id="options-heading" i18n-text="optionsHeading"></h2></summary>
<div class="option"> <div class="option">
<input id="editor.lineWrapping" type="checkbox"> <input id="editor.lineWrapping" type="checkbox">
@ -242,7 +242,7 @@
</span> </span>
</div> </div>
</details> </details>
<details id="lint" class="hidden"> <details id="lint" class="hidden" data-pref="editor.lint.expanded">
<summary> <summary>
<h2 i18n-text="linterIssues">: <span id="issue-count"></span><!-- EAT SPACE <h2 i18n-text="linterIssues">: <span id="issue-count"></span><!-- EAT SPACE
--><svg id="lint-help" class="svg-icon info intercepts-click"> --><svg id="lint-help" class="svg-icon info intercepts-click">

View File

@ -139,7 +139,7 @@ input:invalid {
} }
#header summary h2 { #header summary h2 {
display: inline-block; display: inline-block;
border-bottom: 2px dotted transparent; border-bottom: 1px dotted transparent;
} }
#header summary h2:hover { #header summary h2:hover {
border-color: #bbb; border-color: #bbb;

View File

@ -6,6 +6,7 @@
/* global mozParser createSourceEditor */ /* global mozParser createSourceEditor */
/* global closeCurrentTab regExpTester messageBox */ /* global closeCurrentTab regExpTester messageBox */
/* global initColorpicker */ /* global initColorpicker */
/* global initCollapsibles */
'use strict'; 'use strict';
let styleId = null; let styleId = null;
@ -1430,28 +1431,6 @@ function addSections(sections, onAdded = () => {}) {
} }
} }
function initCollapsibles() {
function saveStateDelayed(event) {
if (event.target.closest('.intercepts-click')) {
event.preventDefault();
} else {
setTimeout(saveState, 0, event.target.closest('details'));
}
}
function saveState(el) {
prefs.set(`editor.${el.id}.expanded`, el.open);
}
function loadState(key, value) {
$('#' + key.split('.')[1]).open = value;
}
const collapsibles = $$('#header details');
for (const el of collapsibles) {
el.open = prefs.get(`editor.${el.id}.expanded`);
$('h2', el).addEventListener('click', saveStateDelayed);
}
prefs.subscribe(collapsibles.map(el => `editor.${el.id}.expanded`), loadState);
}
function initHooks() { function initHooks() {
if (initHooks.alreadyDone) { if (initHooks.alreadyDone) {
return; return;

View File

@ -211,3 +211,35 @@ function makeLink(href = '', content) {
} }
return $element(opt); return $element(opt);
} }
function initCollapsibles({bindClickOn = 'h2'} = {}) {
const prefMap = {};
const elements = $$('details[data-pref]');
for (const el of elements) {
const key = el.dataset.pref;
prefMap[key] = el;
el.open = prefs.get(key);
(bindClickOn && $(bindClickOn, el) || el).addEventListener('click', onClick);
}
prefs.subscribe(Object.keys(prefMap), (key, value) => {
const el = prefMap[key];
if (el.open !== value) {
el.open = value;
}
});
function onClick(event) {
if (event.target.closest('.intercepts-click')) {
event.preventDefault();
} else {
setTimeout(saveState, 0, event.target.closest('details'));
}
}
function saveState(el) {
prefs.set(el.dataset.pref, el.open);
}
}

View File

@ -23,6 +23,8 @@ var prefs = new function Prefs() {
'manage.onlyEnabled.invert': false, // display only disabled styles 'manage.onlyEnabled.invert': false, // display only disabled styles
'manage.onlyLocal.invert': false, // display only externally installed styles 'manage.onlyLocal.invert': false, // display only externally installed styles
'manage.onlyUsercss.invert': false, // display only non-usercss (standard) styles 'manage.onlyUsercss.invert': false, // display only non-usercss (standard) styles
// UI element state: expanded/collapsed
'manage.options.expanded': true,
// the new compact layout doesn't look good on Android yet // the new compact layout doesn't look good on Android yet
'manage.newUI': !navigator.appVersion.includes('Android'), 'manage.newUI': !navigator.appVersion.includes('Android'),
'manage.newUI.favicons': false, // show favicons for the sites in applies-to 'manage.newUI.favicons': false, // show favicons for the sites in applies-to

View File

@ -138,7 +138,7 @@
<template data-id="extraAppliesTo"> <template data-id="extraAppliesTo">
<details class="applies-to-extra"> <details class="applies-to-extra">
<summary i18n-text="appliesDisplayTruncatedSuffix"></summary> <summary class="applies-to-extra-expander" i18n-text="appliesDisplayTruncatedSuffix"></summary>
</details> </details>
</template> </template>
@ -229,8 +229,8 @@
</a> </a>
</label> </label>
</p> </p>
<div id="options"> <details id="options" data-pref="manage.options.expanded">
<h2 id="options-heading" i18n-text="optionsHeading"></h2> <summary><h2 id="options-heading" i18n-text="optionsHeading"></h2></summary>
<label><input id="manage.newUI" type="checkbox"><span i18n-text="manageNewUI"></span></label> <label><input id="manage.newUI" type="checkbox"><span i18n-text="manageNewUI"></span></label>
<div id="newUIoptions"> <div id="newUIoptions">
<div> <div>
@ -258,7 +258,7 @@
i18n-title="editorStylesButton" i18n-title="editorStylesButton"
target="_blank"><button i18n-text="cm_theme"></button></a> target="_blank"><button i18n-text="cm_theme"></button></a>
</p> </p>
</div> </details>
<div id="backup"> <div id="backup">
<h2 id="backup-title" i18n-text="backupButtons"></h2> <h2 id="backup-title" i18n-text="backupButtons"></h2>
<span id="backup-message" i18n-text="backupMessage"></span> <span id="backup-message" i18n-text="backupMessage"></span>

View File

@ -188,17 +188,17 @@ label.nobreak input {
margin-left: 1ex; margin-left: 1ex;
} }
summary { .applies-to-extra-expander {
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
outline: none; outline: none;
} }
.applies-to-extra summary { .applies-to-extra-expander {
list-style-type: none; /* for FF, allegedly */ list-style-type: none; /* for FF, allegedly */
} }
.applies-to-extra summary::-webkit-details-marker { .applies-to-extra-expander::-webkit-details-marker {
display: none; display: none;
} }
@ -239,6 +239,30 @@ summary {
display: none; display: none;
} }
/* collapsibles */
#header details:not([open]) h2 {
margin-bottom: -.25em;
}
#header summary {
align-items: center;
margin-left: -13px;
cursor: pointer;
outline: none;
}
#header summary h2 {
display: inline-block;
border-bottom: 1px dotted transparent;
margin-top: .2em;
margin-bottom: .4em;
}
#header summary h2:hover {
border-color: #bbb;
}
/* compact layout */ /* compact layout */
.newUI #installed { .newUI #installed {

View File

@ -3,6 +3,7 @@
/* global checkUpdate, handleUpdateInstalled */ /* global checkUpdate, handleUpdateInstalled */
/* global objectDiff */ /* global objectDiff */
/* global configDialog */ /* global configDialog */
/* global initCollapsibles */
'use strict'; 'use strict';
let installed; let installed;
@ -74,6 +75,9 @@ function initGlobalEvents() {
// N.B. triggers existing onchange listeners // N.B. triggers existing onchange listeners
setupLivePrefs(); setupLivePrefs();
// the options block
initCollapsibles();
$$('[id^="manage.newUI"]') $$('[id^="manage.newUI"]')
.forEach(el => (el.oninput = (el.onchange = switchUI))); .forEach(el => (el.oninput = (el.onchange = switchUI)));
@ -519,10 +523,13 @@ function usePrefsDuringPageLoad() {
for (const mutation of mutations) { for (const mutation of mutations) {
for (const node of mutation.addedNodes) { for (const node of mutation.addedNodes) {
// [naively] assuming each element of addedNodes is a childless element // [naively] assuming each element of addedNodes is a childless element
const prefValue = node.id ? prefs.readOnlyValues[node.id] : undefined; const key = node.dataset && node.dataset.pref || node.id;
const prefValue = key ? prefs.readOnlyValues[key] : undefined;
if (prefValue !== undefined) { if (prefValue !== undefined) {
if (node.type === 'checkbox') { if (node.type === 'checkbox') {
node.checked = prefValue; node.checked = prefValue;
} else if (node.localName === 'details') {
node.open = prefValue;
} else { } else {
node.value = prefValue; node.value = prefValue;
} }