toggle narrow width mode tooltips via html+css; code cosmetics
This commit is contained in:
parent
1348eeb4e3
commit
e50ff316ba
17
edit.html
17
edit.html
|
@ -179,17 +179,26 @@
|
|||
class="CodeMirror-search-field" rows="1" required
|
||||
spellcheck="false"></textarea>
|
||||
</div>
|
||||
<button data-action="replace" i18n-text="replace" disabled>
|
||||
<button data-action="replace" i18n-text="replace" disabled></button>
|
||||
<button data-action="replaceAll" i18n-text="replaceAll" disabled></button>
|
||||
<button data-action="undo" i18n-text="undo" disabled></button>
|
||||
<!--
|
||||
Using a separate set of buttons because
|
||||
1. FF can display tooltips only when specified on the <button>, ignores the nested <title> in <svg>
|
||||
2. the icon doesn't fill the entire button area so tooltips aren't shown when the edges are hovered
|
||||
-->
|
||||
<button class="hidden" data-action="replace" i18n-title="replace" disabled>
|
||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
||||
<polygon points="15.83 4.75 8.76 11.82 5.2 8.26 3.51 9.95 8.76 15.19 17.52 6.43 15.83 4.75"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button data-action="replaceAll" i18n-text="replaceAll" disabled>
|
||||
<button class="hidden" data-action="replaceAll" i18n-title="replaceAll" disabled>
|
||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
||||
<polygon points="15.83 4.75 8.76 11.82 5.2 8.26 3.51 9.95 8.76 15.19 17.52 6.43 15.83 4.75"/>
|
||||
<polygon points="15.8,1.8 8.8,8.8 5.2,5.3 3.5,6.9 8.8,12.2 17.5,3.4 "/>
|
||||
<polygon points="15.8,7.8 8.8,14.8 5.2,11.3 3.5,12.9 8.8,18.2 17.5,9.4 "/>
|
||||
</svg>
|
||||
</button>
|
||||
<button data-action="undo" i18n-text="undo" disabled>
|
||||
<button class="hidden" data-action="undo" i18n-title="undo" disabled>
|
||||
<svg class="svg-icon" viewBox="0 0 20 20">
|
||||
<path d="M11.3,5.5H8.7V1.4L1.9,6.5l6.8,5.1V7.5h2.6c1.8,0,3.2,1.4,3.2,3.2s-1.4,3.2-3.2,3.2H7.8v2h3.5c2.9,0,5.2-2.3,5.2-5.2S14.2,5.5,11.3,5.5z"/>
|
||||
</svg>
|
||||
|
|
|
@ -209,10 +209,15 @@
|
|||
right: 0;
|
||||
max-width: none;
|
||||
}
|
||||
#search-replace-dialog[data-type="replace"] button {
|
||||
#search-replace-dialog[data-type="replace"] button:not(.hidden) {
|
||||
display: none !important;
|
||||
}
|
||||
#search-replace-dialog[data-type="replace"] button.hidden {
|
||||
display: block !important;
|
||||
font-size: 0;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
#search-replace-dialog[data-type="replace"] button svg {
|
||||
display: inline;
|
||||
|
@ -222,11 +227,4 @@
|
|||
max-width: calc(50vw - 120px);
|
||||
width: auto;
|
||||
}
|
||||
#search-replace-dialog[data-type="replace"] button[data-action="replaceAll"] svg {
|
||||
top: -3px;
|
||||
position: relative;
|
||||
/* unprefixed since Chrome 53 */
|
||||
-webkit-filter: drop-shadow(0 5px 0 currentColor);
|
||||
filter: drop-shadow(0 5px 0 currentColor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,16 +22,6 @@ onDOMready().then(() => {
|
|||
|
||||
const RX_MAYBE_REGEXP = /^\s*\/(.+?)\/([simguy]*)\s*$/;
|
||||
|
||||
const NARROW_WIDTH = [...document.styleSheets]
|
||||
.filter(({href}) => href && href.endsWith('global-search.css'))
|
||||
.map(sheet =>
|
||||
[...sheet.cssRules]
|
||||
.filter(r => r.media && r.conditionText.includes('max-width'))
|
||||
.map(r => r.conditionText.match(/\d+/) | 0)
|
||||
.sort((a, b) => a - b)
|
||||
.pop())
|
||||
.pop() || 800;
|
||||
|
||||
const state = {
|
||||
// used for case-sensitive matching directly
|
||||
find: '',
|
||||
|
@ -188,10 +178,12 @@ onDOMready().then(() => {
|
|||
state.replaceValue = state.replace.replace(/(\\r)?\\n/g, '\n').replace(/\\t/g, '\t');
|
||||
state.replaceHasRefs = /\$[$&`'\d]/.test(state.replaceValue);
|
||||
}
|
||||
const cmFocused = document.activeElement && document.activeElement.closest('.CodeMirror');
|
||||
state.activeAppliesTo = $(`.${APPLIES_VALUE_CLASS}:focus, .${APPLIES_VALUE_CLASS}.${TARGET_CLASS}`);
|
||||
state.cmStart = CodeMirror.closestVisible(
|
||||
document.activeElement && document.activeElement.closest('.CodeMirror') && document.activeElement ||
|
||||
state.activeAppliesTo || state.cm);
|
||||
cmFocused && document.activeElement ||
|
||||
state.activeAppliesTo ||
|
||||
state.cm);
|
||||
}
|
||||
|
||||
|
||||
|
@ -208,21 +200,19 @@ onDOMready().then(() => {
|
|||
return;
|
||||
}
|
||||
initState();
|
||||
if (!state.find) {
|
||||
clearMarker();
|
||||
makeTargetVisible(null);
|
||||
setupOverlay(editors.slice());
|
||||
showTally(0, 0);
|
||||
return;
|
||||
}
|
||||
const {cmStart} = state;
|
||||
const {index, found, foundInCode} = doSearchInEditors({cmStart, canAdvance, inApplies}) || {};
|
||||
const {index, found, foundInCode} = state.find && doSearchInEditors({cmStart, canAdvance, inApplies}) || {};
|
||||
if (!foundInCode) clearMarker();
|
||||
if (!found) makeTargetVisible(null);
|
||||
const radiateFrom = foundInCode ? index : editors.indexOf(cmStart);
|
||||
setupOverlay(radiateArray(editors, radiateFrom));
|
||||
enableReplaceButtons(foundInCode);
|
||||
debounce(showTally, 0, foundInCode && !state.numFound ? 1 : undefined);
|
||||
if (state.find) {
|
||||
const firstSuccessfulSearch = foundInCode && !state.numFound;
|
||||
debounce(showTally, 0, firstSuccessfulSearch ? 1 : undefined);
|
||||
} else {
|
||||
showTally(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -326,7 +316,7 @@ onDOMready().then(() => {
|
|||
|
||||
if (cursor) {
|
||||
state.undoHistory.push([cm]);
|
||||
state.undo.disabled = false;
|
||||
enableUndoButton(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +328,7 @@ onDOMready().then(() => {
|
|||
if (found.length) {
|
||||
state.lastFind = null;
|
||||
state.undoHistory.push(found);
|
||||
state.undo.disabled = false;
|
||||
enableUndoButton(true);
|
||||
doSearch({canAdvance: false});
|
||||
}
|
||||
}
|
||||
|
@ -388,8 +378,8 @@ onDOMready().then(() => {
|
|||
undoneSome = true;
|
||||
}
|
||||
}
|
||||
state.undo.disabled = !state.undoHistory.length;
|
||||
(state.undo.disabled ? state.input : state.undo).focus();
|
||||
enableUndoButton(state.undoHistory.length);
|
||||
(state.undoHistory.length ? state.undo : state.input).focus();
|
||||
if (undoneSome) {
|
||||
state.lastFind = null;
|
||||
restoreWindowScrollPos();
|
||||
|
@ -463,7 +453,6 @@ onDOMready().then(() => {
|
|||
cmState.annotateTimer = 0;
|
||||
}
|
||||
if (hasMatches) {
|
||||
if (cmState.annotateTimer) clearTimeout(cmState.annotateTimer);
|
||||
cmState.annotateTimer = setTimeout(annotateScrollbar, ANNOTATE_SCROLLBAR_DELAY,
|
||||
cm, query, state.icase);
|
||||
}
|
||||
|
@ -481,11 +470,10 @@ onDOMready().then(() => {
|
|||
const match = this.query.exec(stream.string);
|
||||
if (match && match.index === stream.pos) {
|
||||
this.numFound++;
|
||||
//state.numFound++;
|
||||
const t = performance.now();
|
||||
if (t - this.tallyShownTime > 10) {
|
||||
debounce(showTally);
|
||||
this.tallyShownTime = t;
|
||||
debounce(showTally);
|
||||
}
|
||||
stream.pos += match[0].length || 1;
|
||||
return MATCH_TOKEN_NAME;
|
||||
|
@ -573,6 +561,7 @@ onDOMready().then(() => {
|
|||
#search-replace-dialog [data-action="case"] {
|
||||
color: ${colors.icon.fill};
|
||||
}
|
||||
#search-replace-dialog[data-type="replace"] button:hover svg,
|
||||
#search-replace-dialog svg:hover {
|
||||
fill: inherit;
|
||||
}
|
||||
|
@ -587,20 +576,11 @@ onDOMready().then(() => {
|
|||
document.body.appendChild(dialog);
|
||||
dispatchEvent(new Event('showHotkeyInTooltip'));
|
||||
|
||||
measureInput(state.input);
|
||||
adjustTextareaSize(state.input);
|
||||
if (type === 'replace') {
|
||||
measureInput(state.input2);
|
||||
adjustTextareaSize(state.input2);
|
||||
enableReplaceButtons(state.find !== '');
|
||||
|
||||
addEventListener('resize', toggleReplaceButtonTooltips, {passive: true});
|
||||
toggleReplaceButtonTooltips(true);
|
||||
|
||||
state.undo = $('[data-action="undo"]');
|
||||
state.undo.disabled = !state.undoHistory.length;
|
||||
} else {
|
||||
removeEventListener('resize', toggleReplaceButtonTooltips, {passive: true});
|
||||
enableUndoButton(state.undoHistory.length);
|
||||
}
|
||||
|
||||
return dialog;
|
||||
|
@ -620,20 +600,11 @@ onDOMready().then(() => {
|
|||
}
|
||||
|
||||
|
||||
function measureInput(input) {
|
||||
const style = getComputedStyle(input);
|
||||
input._padding = parseFloat(style.paddingTop) + parseFloat(style.paddingBottom);
|
||||
input._maxWidth = parseFloat(style.maxWidth);
|
||||
input._rowHeight = input.clientHeight - input._padding;
|
||||
}
|
||||
|
||||
|
||||
function destroyDialog({restoreFocus = false} = {}) {
|
||||
state.input = null;
|
||||
$.remove(DIALOG_SELECTOR);
|
||||
debounce.unregister(doSearch);
|
||||
makeTargetVisible(null);
|
||||
removeEventListener('resize', toggleReplaceButtonTooltips, {passive: true});
|
||||
if (restoreFocus) setTimeout(focusNoScroll, 0, state.originalFocus);
|
||||
}
|
||||
|
||||
|
@ -675,20 +646,10 @@ onDOMready().then(() => {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function toggleReplaceButtonTooltips(debounced) {
|
||||
if (debounced !== true) {
|
||||
debounce(toggleReplaceButtonTooltips, 0, true);
|
||||
} else {
|
||||
const addTitle = window.innerWidth <= NARROW_WIDTH;
|
||||
for (const el of state.dialog.getElementsByTagName('button')) {
|
||||
if (addTitle && !el.title) {
|
||||
el.title = el.textContent;
|
||||
} else if (!addTitle && el.title) {
|
||||
el.title = '';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
function enableUndoButton(enabled) {
|
||||
if (state.dialog && state.dialog.dataset.type === 'replace') {
|
||||
for (const el of $$('[data-action="undo"]', state.dialog)) {
|
||||
el.disabled = !enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user