scrollable details + sticky header (#1400)
* shorten section labels in lint report * `sectioned` class on html for sectioned editor * fix scrollElementIntoView
This commit is contained in:
parent
225a2cec31
commit
dd38856eda
|
@ -418,17 +418,15 @@
|
|||
<summary><h2 i18n-text="sections"></h2></summary>
|
||||
<ol id="toc"></ol>
|
||||
</details>
|
||||
<details id="lint" data-pref="editor.lint.expanded" class="hidden-unless-compact ignore-pref-if-compact">
|
||||
<details id="lint" data-pref="editor.lint.expanded" class="ignore-pref-if-compact" hidden>
|
||||
<summary>
|
||||
<h2 i18n-text="linterIssues">: <span id="issue-count"></span>
|
||||
<h2><span i18n-text="linterIssues"></span><span id="issue-count"></span>
|
||||
<a id="lint-help" class="svg-inline-wrapper intercepts-click" tabindex="0">
|
||||
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
|
||||
</a>
|
||||
</h2>
|
||||
</summary>
|
||||
<div class="lint-scroll-container">
|
||||
<div class="lint-report-container"></div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<div id="header-resizer" i18n-title="headerResizerHint"></div>
|
||||
|
|
57
edit/base.js
57
edit/base.js
|
@ -6,14 +6,7 @@
|
|||
/* global initBeautifyButton */// beautify.js
|
||||
/* global prefs */
|
||||
/* global t */// localization.js
|
||||
/* global
|
||||
FIREFOX
|
||||
debounce
|
||||
getOwnTab
|
||||
sessionStore
|
||||
tryJSONparse
|
||||
tryURL
|
||||
*/// toolbox.js
|
||||
/* global FIREFOX getOwnTab sessionStore tryJSONparse tryURL */// toolbox.js
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
|
@ -39,7 +32,7 @@ const editor = {
|
|||
cancel: () => location.assign('/manage.html'),
|
||||
|
||||
updateClass() {
|
||||
document.documentElement.classList.toggle('is-new-style', !editor.style.id);
|
||||
$.rootCL.toggle('is-new-style', !editor.style.id);
|
||||
},
|
||||
|
||||
updateTitle(isDirty = editor.dirty.isDirty()) {
|
||||
|
@ -56,9 +49,14 @@ const editor = {
|
|||
|
||||
const baseInit = (() => {
|
||||
const domReady = waitForSelector('#sections');
|
||||
const mqCompact = matchMedia('(max-width: 850px)');
|
||||
const toggleCompact = mq => $.rootCL.toggle('compact-layout', mq.matches);
|
||||
mqCompact.on('change', toggleCompact);
|
||||
toggleCompact(mqCompact);
|
||||
|
||||
return {
|
||||
domReady,
|
||||
mqCompact,
|
||||
ready: Promise.all([
|
||||
domReady,
|
||||
loadStyle(),
|
||||
|
@ -94,7 +92,7 @@ const baseInit = (() => {
|
|||
editor.style = style;
|
||||
editor.updateClass();
|
||||
editor.updateTitle(false);
|
||||
document.documentElement.classList.toggle('usercss', editor.isUsercss);
|
||||
$.rootCL.add(editor.isUsercss ? 'usercss' : 'sectioned');
|
||||
sessionStore.justEditedStyleId = style.id || '';
|
||||
// no such style so let's clear the invalid URL parameters
|
||||
if (!style.id) history.replaceState({}, '', location.pathname);
|
||||
|
@ -120,45 +118,6 @@ const baseInit = (() => {
|
|||
}
|
||||
})();
|
||||
|
||||
//#endregion
|
||||
//#region init layout/resize
|
||||
|
||||
baseInit.domReady.then(() => {
|
||||
let headerHeight;
|
||||
detectLayout(true);
|
||||
window.on('resize', () => detectLayout());
|
||||
|
||||
function detectLayout(now) {
|
||||
const compact = window.innerWidth <= 850;
|
||||
if (compact) {
|
||||
document.body.classList.add('compact-layout');
|
||||
if (!editor.isUsercss) {
|
||||
if (now) fixedHeader();
|
||||
else debounce(fixedHeader, 250);
|
||||
window.on('scroll', fixedHeader, {passive: true});
|
||||
}
|
||||
} else {
|
||||
document.body.classList.remove('compact-layout', 'fixed-header');
|
||||
window.off('scroll', fixedHeader);
|
||||
}
|
||||
for (const el of $$('details[data-pref]')) {
|
||||
el.open = compact ? false : prefs.get(el.dataset.pref);
|
||||
}
|
||||
}
|
||||
|
||||
function fixedHeader() {
|
||||
const headerFixed = $('.fixed-header');
|
||||
if (!headerFixed) headerHeight = $('#header').clientHeight;
|
||||
const scrollPoint = headerHeight - 43;
|
||||
if (window.scrollY >= scrollPoint && !headerFixed) {
|
||||
$('body').style.setProperty('--fixed-padding', ` ${headerHeight}px`);
|
||||
$('body').classList.add('fixed-header');
|
||||
} else if (window.scrollY < scrollPoint && headerFixed) {
|
||||
$('body').classList.remove('fixed-header');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//#endregion
|
||||
//#region init header
|
||||
|
||||
|
|
335
edit/edit.css
335
edit/edit.css
|
@ -1,5 +1,7 @@
|
|||
:root {
|
||||
--fixed-padding: unset;
|
||||
--pad: 1rem; /* Edge padding for modals/blocks/whatnot. TODO: reuse it in more places */
|
||||
--pad05: calc(0.5 * var(--pad));
|
||||
--popup-button-width: 16px;
|
||||
}
|
||||
|
||||
body {
|
||||
|
@ -70,7 +72,7 @@ html:not(.is-new-style) #heading::after {
|
|||
#popup-button:hover {
|
||||
filter: drop-shadow(0 0 3px hsl(180, 70%, 50%));
|
||||
}
|
||||
.usercss body:not(.compact-layout) #popup-button {
|
||||
.usercss:not(.compact-layout) #popup-button {
|
||||
right: 24px;
|
||||
}
|
||||
/************ checkbox & select************/
|
||||
|
@ -91,10 +93,10 @@ label {
|
|||
#header {
|
||||
width: var(--header-width);
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
padding: 1rem;
|
||||
padding-top: var(--pad);
|
||||
box-shadow: 0 0 3rem -1.2rem black;
|
||||
box-sizing: border-box;
|
||||
z-index: 10;
|
||||
|
@ -222,56 +224,61 @@ input:invalid {
|
|||
margin-left: 0;
|
||||
}
|
||||
/* collapsibles */
|
||||
#header details {
|
||||
margin-right: var(--header-resizer-width);
|
||||
}
|
||||
#header details[open] {
|
||||
overflow-y: auto;
|
||||
margin-top: calc(1.5*var(--pad));
|
||||
}
|
||||
#header details[open] summary {
|
||||
position: absolute;
|
||||
margin-top: calc(-1.5*var(--pad));
|
||||
}
|
||||
#header summary {
|
||||
align-items: center;
|
||||
margin-left: -13px;
|
||||
margin-left: .25em;
|
||||
cursor: pointer;
|
||||
}
|
||||
#header summary + * {
|
||||
padding: .5rem 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#header summary h2 {
|
||||
display: inline-block;
|
||||
border-bottom: 1px dotted transparent;
|
||||
margin-top: .1em;
|
||||
margin-bottom: .1em;
|
||||
margin-left: -13px;
|
||||
margin: 0 0 0 -13px;
|
||||
padding-left: 13px; /* clicking directly on details-marker doesn't set pref so we cover it with h2 */
|
||||
max-width: calc(var(--header-width) - 2*var(--pad));
|
||||
vertical-align: middle;
|
||||
}
|
||||
#header summary h2,
|
||||
#header summary h2 > :first-child {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#header summary:hover h2 {
|
||||
border-color: #bbb;
|
||||
}
|
||||
|
||||
#header summary svg {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
#header details > :not(summary) {
|
||||
margin: 0 0 0 var(--pad);
|
||||
padding: calc(var(--pad)/4) 0;
|
||||
}
|
||||
#details-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
margin-top: var(--pad05);
|
||||
}
|
||||
|
||||
#header details[open] + details[open] {
|
||||
margin-top: .5rem;
|
||||
}
|
||||
|
||||
#actions .buttons {
|
||||
display: inline-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#actions .buttons > * {
|
||||
margin: 0 .25rem .5rem 0;
|
||||
}
|
||||
|
||||
#options:not([open]) + #lint h2 {
|
||||
margin-top: 0;
|
||||
}
|
||||
#lint:not([open]) h2 {
|
||||
margin-bottom: 0;
|
||||
margin: 0 .25rem var(--pad05) 0;
|
||||
}
|
||||
|
||||
#publish > div > * {
|
||||
|
@ -373,11 +380,11 @@ input:invalid {
|
|||
box-shadow: none !important;
|
||||
pointer-events: auto !important; /* FF bug */
|
||||
}
|
||||
.section-editor .section {
|
||||
.sectioned .section {
|
||||
margin: 0 0.7rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
.section-editor .section:not(:first-child) {
|
||||
.sectioned .section:not(:first-child) {
|
||||
border-top: 2px solid hsl(0, 0%, 80%);
|
||||
}
|
||||
.add-section:after {
|
||||
|
@ -413,10 +420,10 @@ input:invalid {
|
|||
content: counter(codebox) ": " attr(data-text);
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
.single-editor .applies-to {
|
||||
.usercss .applies-to {
|
||||
border-width: 1px 0;
|
||||
}
|
||||
.single-editor .applies-to > label::before {
|
||||
.usercss .applies-to > label::before {
|
||||
content: attr(data-index) ":";
|
||||
margin-right: 0.25rem;
|
||||
font-size: 12px;
|
||||
|
@ -426,8 +433,6 @@ input:invalid {
|
|||
}
|
||||
#toc {
|
||||
counter-reset: codelabel;
|
||||
margin: 0;
|
||||
padding: .5rem 0;
|
||||
}
|
||||
#toc li {
|
||||
white-space: nowrap;
|
||||
|
@ -582,7 +587,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
padding: 0;
|
||||
line-height: var(--input-height);
|
||||
}
|
||||
.section-editor .applies-to label {
|
||||
.sectioned .applies-to label {
|
||||
margin-left: -24px;
|
||||
position: absolute;
|
||||
}
|
||||
|
@ -829,42 +834,17 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
|
||||
/************ lint ************/
|
||||
#lint {
|
||||
overflow: hidden;
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
#lint > summary {
|
||||
position: relative;
|
||||
margin-left: 0;
|
||||
padding-left: 4px;
|
||||
}
|
||||
#lint[open]:not(.hidden-unless-compact) {
|
||||
min-height: 102px;
|
||||
}
|
||||
#lint summary h2 {
|
||||
text-indent: -2px;
|
||||
}
|
||||
#lint > .lint-scroll-container {
|
||||
margin: 1rem 10px 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#lint summary h2 {
|
||||
display: inline-flex;
|
||||
}
|
||||
#lint table {
|
||||
font-size: 100%;
|
||||
border-spacing: 0;
|
||||
margin-bottom: 1rem;
|
||||
line-height: 1.0;
|
||||
width: 100%;
|
||||
font-size: 85%;
|
||||
cursor: pointer;
|
||||
}
|
||||
#lint tr td:last-child {
|
||||
width: 100%;
|
||||
|
@ -872,26 +852,28 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
#lint td[role="line"] {
|
||||
padding-left: 0.25rem;
|
||||
}
|
||||
#lint table:last-child {
|
||||
margin-bottom: 0;
|
||||
#lint .report {
|
||||
display: flex;
|
||||
}
|
||||
#lint table.empty {
|
||||
#lint .empty {
|
||||
display: none;
|
||||
}
|
||||
#lint caption {
|
||||
text-align: left;
|
||||
#lint .caption {
|
||||
vertical-align: top;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
#lint tbody {
|
||||
font-size: 85%;
|
||||
cursor: pointer;
|
||||
#lint .report:not(.empty) ~ :not(.empty) {
|
||||
border-top: 1px dotted rgba(128, 128, 128, .5);
|
||||
margin-top: .25em;
|
||||
padding-top: .25em;
|
||||
}
|
||||
#lint tr:hover {
|
||||
background-color: hsla(180, 50%, 36%, .2);
|
||||
}
|
||||
#lint td {
|
||||
padding: 0;
|
||||
line-height: 16px;
|
||||
}
|
||||
#lint td[role="severity"] {
|
||||
font-size: 0;
|
||||
|
@ -908,6 +890,9 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#issue-count::before {
|
||||
content: ':\A0';
|
||||
}
|
||||
#message-box.center.lint-config #message-box-contents {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -965,16 +950,11 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
html:not(.usercss) .usercss-only,
|
||||
.sectioned .usercss-only,
|
||||
.usercss .sectioned-only {
|
||||
display: none !important; /* hide during page init */
|
||||
}
|
||||
|
||||
body:not(.compact-layout) .hidden-unless-compact,
|
||||
body.linter-disabled .hidden-unless-compact {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#options:not([open]) + #lint {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
@ -1021,151 +1001,140 @@ body.linter-disabled .hidden-unless-compact {
|
|||
margin-left: 0.2rem;
|
||||
}
|
||||
|
||||
/************ full-width only ************/
|
||||
/* TODO: maybe move more rules here so we don't need to reset them in @media(max-width: 850px) */
|
||||
@media (min-width: 851px) {
|
||||
#header > :not(#details-wrapper):not(#header-resizer) {
|
||||
margin-left: var(--pad);
|
||||
margin-right: var(--pad);
|
||||
}
|
||||
#publish[open],
|
||||
#header details:not([open]) {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
#header details[open]:not(:last-child) {
|
||||
margin-bottom: var(--pad05);
|
||||
}
|
||||
#header details:last-child {
|
||||
padding-bottom: var(--pad);
|
||||
}
|
||||
}
|
||||
|
||||
/************ reponsive layouts ************/
|
||||
@media(max-width: 850px) {
|
||||
body {
|
||||
.sectioned body {
|
||||
height: 100%;
|
||||
}
|
||||
.usercss body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.usercss #header,
|
||||
#header:not(.sticky) {
|
||||
position: static;
|
||||
}
|
||||
#header:not(.sticky) {
|
||||
display: block;
|
||||
}
|
||||
#header {
|
||||
flex: 0 1 auto;
|
||||
flex: 0 0 auto;
|
||||
height: unset;
|
||||
width: unset;
|
||||
position: inherit;
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
background: #fff;
|
||||
border-right: none;
|
||||
border-bottom: 1px dashed #AAA;
|
||||
padding: .5rem 1rem .5rem .5rem;
|
||||
padding: var(--pad05) var(--pad05) 0;
|
||||
}
|
||||
.fixed-header {
|
||||
--fixed-height: 40px;
|
||||
padding-top: var(--fixed-padding);
|
||||
}
|
||||
.fixed-header #header {
|
||||
min-height: var(--fixed-height);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
.fixed-header #header > *:not(#details-wrapper),
|
||||
.fixed-header #options {
|
||||
display: none !important;
|
||||
}
|
||||
.fixed-header #details-wrapper {
|
||||
padding-top: calc((var(--fixed-height) - 1.2rem) / 2); /* 1.2 is the normal line height */
|
||||
}
|
||||
#header summary + *,
|
||||
#lint > .lint-scroll-container {
|
||||
margin-left: 1rem;
|
||||
padding: .25rem 0 .5rem;
|
||||
}
|
||||
#header input[type="checkbox"] {
|
||||
vertical-align: middle;
|
||||
}
|
||||
#header details {
|
||||
margin: 0;
|
||||
#header.sticky {
|
||||
flex-direction: row;
|
||||
box-shadow: 0 0 3rem -.75rem black;
|
||||
}
|
||||
#header.sticky #basic-info,
|
||||
#header.sticky #mozilla-format-buttons,
|
||||
#header.sticky .buttons > button,
|
||||
#header.sticky .split-btn-pedal,
|
||||
#heading,
|
||||
h2 {
|
||||
display: none;
|
||||
}
|
||||
.popup-window #details-wrapper {
|
||||
margin-right: var(--popup-button-width);
|
||||
}
|
||||
#basic-info {
|
||||
margin-bottom: .5rem;
|
||||
margin: 0 var(--popup-button-width) var(--pad05) 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
#basic-info #name,
|
||||
#basic-info > *:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#basic-info > *:not(:last-child) {
|
||||
margin-right: 0.8rem;
|
||||
}
|
||||
#basic-info #name {
|
||||
flex-grow: 1;
|
||||
#header details > :not(summary) {
|
||||
margin-left: var(--pad05);
|
||||
}
|
||||
#options-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
box-sizing: border-box;
|
||||
#header h2 {
|
||||
font-size: 14px;
|
||||
}
|
||||
#actions {
|
||||
display: inline-block;
|
||||
}
|
||||
#details-wrapper {
|
||||
display: inline-flex;
|
||||
vertical-align: top;
|
||||
max-width: 100%;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: .25em 0 var(--pad05);
|
||||
}
|
||||
#options[open] {
|
||||
width: 100%;
|
||||
}
|
||||
#sections-list[open] {
|
||||
max-height: 102px;
|
||||
}
|
||||
#sections-list[open] #toc {
|
||||
max-height: 60px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#header details:not(#options) {
|
||||
max-width: 50%;
|
||||
}
|
||||
.options-column {
|
||||
flex-grow: 1;
|
||||
padding-right: .5rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.options-column > .usercss-only {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
#options-wrapper .options-column:nth-child(2) {
|
||||
#details-wrapper details[open] {
|
||||
margin-top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
#options:not([open]),
|
||||
#lint:not([open]) {
|
||||
overflow: initial;
|
||||
#details-wrapper details[open]:hover,
|
||||
#details-wrapper details[open]:focus-within {
|
||||
z-index: 1001;
|
||||
}
|
||||
#options:not([open]) + #lint:not([open]) {
|
||||
margin-top: 0;
|
||||
}
|
||||
#lint summary {
|
||||
#details-wrapper details[open] > summary {
|
||||
position: static;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
#header summary {
|
||||
margin-left: 0;
|
||||
padding-left: 4px;
|
||||
#details-wrapper details[open] > summary + * {
|
||||
position: absolute;
|
||||
overflow: hidden auto;
|
||||
max-height: var(--max-height, 10vh);
|
||||
background: #fff;
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, .3);
|
||||
padding: var(--pad);
|
||||
margin-top: var(--pad05);
|
||||
}
|
||||
#header summary h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@media (max-height: 500px) {
|
||||
#details-wrapper {
|
||||
--max-height: 50px;
|
||||
}
|
||||
.option label {
|
||||
margin: 0;
|
||||
}
|
||||
#options [type="number"] {
|
||||
text-align: left; /* workaround the column flow bug in webkit */
|
||||
padding-left: 0.2rem;
|
||||
#sections-list[open] > #toc {
|
||||
left: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: min-content;
|
||||
}
|
||||
#options #tabSize-label {
|
||||
position: relative;
|
||||
top: 0.2rem;
|
||||
#sections-list[open] > #toc,
|
||||
#lint[open] > .lint-report-container {
|
||||
max-width: 50vw;
|
||||
right: 0;
|
||||
}
|
||||
#lint > .lint-scroll-container {
|
||||
padding-top: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
#lint {
|
||||
padding: 0;
|
||||
margin: .5rem 0 0;
|
||||
}
|
||||
#lint:not([open]) + #footer {
|
||||
margin: .25em 0 -1em .25em;
|
||||
#options[open],
|
||||
#publish[open],
|
||||
#lint:not([open]) {
|
||||
flex: 0 0 auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
#sections {
|
||||
height: unset !important;
|
||||
padding-left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
#sections > :not(.single-editor) {
|
||||
margin: 0 .5rem;
|
||||
|
@ -1175,10 +1144,6 @@ body.linter-disabled .hidden-unless-compact {
|
|||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
.usercss #options:not([open]) ~ #lint.hidden ~ #footer,
|
||||
.usercss #lint:not([open]) + #footer {
|
||||
margin-top: -.25em;
|
||||
}
|
||||
#help-popup.big[style="display: block;"],
|
||||
#help-popup[style="display: block;"] {
|
||||
width: max-content;
|
||||
|
|
44
edit/edit.js
44
edit/edit.js
|
@ -1,4 +1,4 @@
|
|||
/* global $ $create messageBoxProxy waitForSheet */// dom.js
|
||||
/* global $$ $ $create messageBoxProxy waitForSheet */// dom.js
|
||||
/* global API msg */// msg.js
|
||||
/* global CodeMirror */
|
||||
/* global SectionsEditor */
|
||||
|
@ -25,11 +25,7 @@ baseInit.ready.then(async () => {
|
|||
await editor.ready;
|
||||
editor.ready = true;
|
||||
editor.dirty.onChange(editor.updateDirty);
|
||||
|
||||
prefs.subscribe('editor.linter', (key, value) => {
|
||||
document.body.classList.toggle('linter-disabled', value === '');
|
||||
linterMan.run();
|
||||
});
|
||||
prefs.subscribe('editor.linter', () => linterMan.run());
|
||||
|
||||
// enabling after init to prevent flash of validation failure on an empty name
|
||||
$('#name').required = !editor.isUsercss;
|
||||
|
@ -61,6 +57,42 @@ baseInit.ready.then(async () => {
|
|||
'/edit/drafts',
|
||||
'/edit/global-search',
|
||||
]);
|
||||
}).then(() => {
|
||||
// Set up mini-header on scroll
|
||||
const {isUsercss} = editor;
|
||||
const el = $create({
|
||||
style: `
|
||||
top: 0;
|
||||
height: 1px;
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
`.replace(/;/g, '!important;'),
|
||||
});
|
||||
const scroller = isUsercss ? $('.CodeMirror-scroll') : document.body;
|
||||
const xoRoot = isUsercss ? scroller : undefined;
|
||||
const xo = new IntersectionObserver(onScrolled, {root: xoRoot});
|
||||
scroller.appendChild(el);
|
||||
onCompactToggled(baseInit.mqCompact);
|
||||
baseInit.mqCompact.on('change', onCompactToggled);
|
||||
|
||||
/** @param {MediaQueryList} mq */
|
||||
function onCompactToggled(mq) {
|
||||
for (const el of $$('details[data-pref]')) {
|
||||
el.open = mq.matches ? false : prefs.get(el.dataset.pref);
|
||||
}
|
||||
if (mq.matches) {
|
||||
xo.observe(el);
|
||||
} else {
|
||||
xo.disconnect();
|
||||
}
|
||||
}
|
||||
/** @param {IntersectionObserverEntry[]} entries */
|
||||
function onScrolled(entries) {
|
||||
const h = $('#header');
|
||||
const sticky = !entries.pop().isIntersecting;
|
||||
if (!isUsercss) scroller.style.paddingTop = sticky ? h.offsetHeight + 'px' : '';
|
||||
h.classList.toggle('sticky', sticky);
|
||||
}
|
||||
});
|
||||
|
||||
//#endregion
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
title: t('optionsCustomizePopup') + '\n' + POPUP_HOTKEY,
|
||||
onclick: embedPopup,
|
||||
});
|
||||
document.documentElement.appendChild(btn);
|
||||
$.root.appendChild(btn);
|
||||
$.rootCL.add('popup-window');
|
||||
baseInit.domReady.then(() => {
|
||||
document.body.appendChild(btn);
|
||||
// Adding a dummy command to show in keymap help popup
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
undoHistory: [],
|
||||
|
||||
searchInApplies: !document.documentElement.classList.contains('usercss'),
|
||||
searchInApplies: !editor.isUsercss,
|
||||
};
|
||||
|
||||
//endregion
|
||||
|
@ -588,7 +588,7 @@
|
|||
input: colorMimicry($('input:not(:disabled)'), {bg: 'backgroundColor'}),
|
||||
icon: colorMimicry($$('svg.info')[1], {fill: 'fill'}),
|
||||
};
|
||||
document.documentElement.appendChild(
|
||||
$.root.appendChild(
|
||||
$(DIALOG_STYLE_SELECTOR) ||
|
||||
$create('style' + DIALOG_STYLE_SELECTOR)
|
||||
).textContent = `
|
||||
|
|
|
@ -312,7 +312,7 @@ linterMan.DEFAULTS = {
|
|||
function updateCount() {
|
||||
const issueCount = Array.from(tables.values())
|
||||
.reduce((sum, table) => sum + table.trs.length, 0);
|
||||
$('#lint').classList.toggle('hidden-unless-compact', issueCount === 0);
|
||||
$('#lint').hidden = !issueCount;
|
||||
$('#issue-count').textContent = issueCount;
|
||||
}
|
||||
|
||||
|
@ -328,19 +328,20 @@ linterMan.DEFAULTS = {
|
|||
}
|
||||
|
||||
function createTable(cm) {
|
||||
const caption = $create('caption');
|
||||
const tbody = $create('tbody');
|
||||
const table = $create('table', [caption, tbody]);
|
||||
const caption = $create('.caption');
|
||||
const table = $create('table');
|
||||
const report = $create('.report', [caption, table]);
|
||||
const trs = [];
|
||||
return {
|
||||
element: table,
|
||||
element: report,
|
||||
trs,
|
||||
updateAnnotations,
|
||||
updateCaption,
|
||||
};
|
||||
|
||||
function updateCaption() {
|
||||
caption.textContent = editor.getEditorTitle(cm);
|
||||
const t = editor.getEditorTitle(cm);
|
||||
Object.assign(caption, typeof t == 'string' ? {textContent: t} : t);
|
||||
}
|
||||
|
||||
function updateAnnotations(lines) {
|
||||
|
@ -352,20 +353,20 @@ linterMan.DEFAULTS = {
|
|||
} else {
|
||||
tr = createTr();
|
||||
trs.push(tr);
|
||||
tbody.append(tr.element);
|
||||
table.appendChild(tr.element);
|
||||
}
|
||||
tr.update(anno);
|
||||
i++;
|
||||
}
|
||||
if (i === 0) {
|
||||
trs.length = 0;
|
||||
tbody.textContent = '';
|
||||
table.textContent = '';
|
||||
} else {
|
||||
while (trs.length > i) {
|
||||
trs.pop().element.remove();
|
||||
}
|
||||
}
|
||||
table.classList.toggle('empty', trs.length === 0);
|
||||
report.classList.toggle('empty', !trs.length);
|
||||
|
||||
function *getAnnotations() {
|
||||
for (const line of lines.filter(Boolean)) {
|
||||
|
|
|
@ -218,7 +218,7 @@ function MozSectionWidget(cm, finder = MozSectionFinder(cm)) {
|
|||
transition: none;
|
||||
}
|
||||
`;
|
||||
document.documentElement.appendChild(actualStyle);
|
||||
$.root.appendChild(actualStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,7 +25,6 @@ function SectionsEditor() {
|
|||
updateMeta();
|
||||
rerouteHotkeys.toggle(true); // enabled initially because we don't always focus a CodeMirror
|
||||
editor.livePreview.init();
|
||||
container.classList.add('section-editor');
|
||||
$('#to-mozilla').on('click', showMozillaFormat);
|
||||
$('#to-mozilla-help').on('click', showToMozillaHelp);
|
||||
$('#from-mozilla').on('click', () => showMozillaFormatImport());
|
||||
|
@ -46,8 +45,11 @@ function SectionsEditor() {
|
|||
},
|
||||
|
||||
getEditorTitle(cm) {
|
||||
const index = editor.getEditors().indexOf(cm);
|
||||
return `${t('sectionCode')} ${index + 1}`;
|
||||
const index = editor.getEditors().indexOf(cm) + 1;
|
||||
return {
|
||||
textContent: `#${index}`,
|
||||
title: `${t('sectionCode')} ${index}`,
|
||||
};
|
||||
},
|
||||
|
||||
getValue(asObject) {
|
||||
|
@ -394,7 +396,7 @@ function SectionsEditor() {
|
|||
}
|
||||
|
||||
function lockPageUI(locked) {
|
||||
document.documentElement.style.pointerEvents = locked ? 'none' : '';
|
||||
$.root.style.pointerEvents = locked ? 'none' : '';
|
||||
if (popup.codebox) {
|
||||
popup.classList.toggle('ready', locked ? false : !popup.codebox.isBlank());
|
||||
popup.codebox.options.readOnly = locked;
|
||||
|
|
|
@ -195,7 +195,7 @@ function showCodeMirrorPopup(title, html, options) {
|
|||
}, options));
|
||||
cm.focus();
|
||||
|
||||
document.documentElement.style.pointerEvents = 'none';
|
||||
$.root.style.pointerEvents = 'none';
|
||||
popup.style.pointerEvents = 'auto';
|
||||
|
||||
const onKeyDown = event => {
|
||||
|
@ -210,7 +210,7 @@ function showCodeMirrorPopup(title, html, options) {
|
|||
|
||||
window.on('closeHelp', () => {
|
||||
window.off('keydown', onKeyDown, true);
|
||||
document.documentElement.style.removeProperty('pointer-events');
|
||||
$.root.style.removeProperty('pointer-events');
|
||||
cm = popup.codebox = null;
|
||||
}, {once: true});
|
||||
|
||||
|
|
|
@ -277,13 +277,15 @@ input[type="number"][data-focused-via-click]:focus {
|
|||
/* header resizer */
|
||||
:root {
|
||||
--header-width: 280px;
|
||||
--header-resizer-width: 8px;
|
||||
}
|
||||
#header-resizer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 6px;
|
||||
width: var(--header-resizer-width);
|
||||
box-sizing: border-box;
|
||||
cursor: e-resize;
|
||||
border-width: 0 1px;
|
||||
border-style: solid;
|
||||
|
@ -318,6 +320,7 @@ body.resizing-v > * {
|
|||
|
||||
.split-btn {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.split-btn-pedal {
|
||||
margin-left: -1px !important;
|
||||
|
|
14
js/dom.js
14
js/dom.js
|
@ -27,6 +27,9 @@ Object.assign(EventTarget.prototype, {
|
|||
|
||||
//#region Exports
|
||||
|
||||
$.root = document.documentElement;
|
||||
$.rootCL = $.root.classList;
|
||||
|
||||
// Makes the focus outline appear on keyboard tabbing, but not on mouse clicks.
|
||||
const focusAccessibility = {
|
||||
// last event's focusedViaClick
|
||||
|
@ -292,8 +295,8 @@ function scrollElementIntoView(element, {invalidMarginRatio = 0} = {}) {
|
|||
const windowHeight = window.innerHeight;
|
||||
if (top < Math.max(parentTop, windowHeight * invalidMarginRatio) ||
|
||||
top > Math.min(parentBottom, windowHeight) - height - windowHeight * invalidMarginRatio) {
|
||||
const scroller = element.closest('.scroller');
|
||||
scroller.scrollBy(0, top - (scroller ? scroller.clientHeight : windowHeight) / 2 + height);
|
||||
const scroller = element.closest('.scroller') || window;
|
||||
scroller.scrollBy(0, top - (scroller.clientHeight || windowHeight) / 2 + height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,10 +477,9 @@ const dom = {};
|
|||
const lazyScripts = [
|
||||
'/js/dom-on-load',
|
||||
];
|
||||
const elHtml = document.documentElement;
|
||||
if (!UA.windows) elHtml.classList.add('non-windows');
|
||||
if (!UA.windows) $.rootCL.add('non-windows');
|
||||
// set language for a) CSS :lang pseudo and b) hyphenation
|
||||
elHtml.setAttribute('lang', chrome.i18n.getUILanguage());
|
||||
$.root.setAttribute('lang', chrome.i18n.getUILanguage());
|
||||
// set up header width resizer
|
||||
const HW = 'headerWidth.';
|
||||
const HWprefId = HW + location.pathname.match(/^.(\w*)/)[1];
|
||||
|
@ -489,7 +491,7 @@ const dom = {};
|
|||
// If this is a small window on a big monitor the user can maximize it later
|
||||
const max = (innerWidth < 850 ? screen.availWidth : innerWidth) / 3;
|
||||
width = Math.round(Math.max(200, Math.min(max, Number(width) || 0)));
|
||||
elHtml.style.setProperty('--header-width', width + 'px');
|
||||
$.root.style.setProperty('--header-width', width + 'px');
|
||||
return width;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -36,9 +36,8 @@ Object.assign(newUI, {
|
|||
ids: Object.keys(newUI),
|
||||
prefKeyForId: id => `manage.newUI.${id}`.replace(/\.enabled$/, ''),
|
||||
renderClass: () => {
|
||||
const cl = document.documentElement.classList;
|
||||
cl.toggle('newUI', newUI.enabled);
|
||||
cl.toggle('oldUI', !newUI.enabled);
|
||||
$.rootCL.toggle('newUI', newUI.enabled);
|
||||
$.rootCL.toggle('oldUI', !newUI.enabled);
|
||||
},
|
||||
});
|
||||
// ...read the actual values
|
||||
|
@ -128,7 +127,7 @@ function onRuntimeMessage(msg) {
|
|||
|
||||
async function toggleEmbeddedOptions(state) {
|
||||
const el = $('#stylus-embedded-options') ||
|
||||
state && document.documentElement.appendChild($create('iframe', {
|
||||
state && $.root.appendChild($create('iframe', {
|
||||
id: 'stylus-embedded-options',
|
||||
src: '/options.html',
|
||||
}));
|
||||
|
|
|
@ -172,11 +172,11 @@ const sorter = (() => {
|
|||
|
||||
function updateColumnCount() {
|
||||
let newValue = 1;
|
||||
for (let el = document.documentElement.lastElementChild;
|
||||
for (let el = $.root.lastElementChild;
|
||||
el.localName === 'style';
|
||||
el = el.previousElementSibling) {
|
||||
if (el.textContent.includes('--columns:')) {
|
||||
newValue = Math.max(1, getComputedStyle(document.documentElement).getPropertyValue('--columns') | 0);
|
||||
newValue = Math.max(1, getComputedStyle($.root).getPropertyValue('--columns') | 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ preinit.then(({frames, styles, url}) => {
|
|||
msg.onExtension(onRuntimeMessage);
|
||||
|
||||
prefs.subscribe('popup.stylesFirst', (key, stylesFirst) => {
|
||||
document.documentElement.classList.toggle('styles-last', !stylesFirst);
|
||||
$.rootCL.toggle('styles-last', !stylesFirst);
|
||||
}, {runNow: true});
|
||||
if (CHROME_POPUP_BORDER_BUG) {
|
||||
prefs.subscribe('popup.borders', toggleSideBorders, {runNow: true});
|
||||
|
@ -70,7 +70,7 @@ function setPopupWidth(_key, width) {
|
|||
|
||||
function toggleSideBorders(_key, state) {
|
||||
// runs before <body> is parsed
|
||||
const style = document.documentElement.style;
|
||||
const style = $.root.style;
|
||||
if (state) {
|
||||
style.cssText +=
|
||||
'border-left: 2px solid white !important;' +
|
||||
|
|
Loading…
Reference in New Issue
Block a user