add upDownKeyJumps option, remove left/right

This commit is contained in:
tophf 2022-10-03 01:13:29 +03:00
parent b22bbaaec0
commit 79dff2775b
7 changed files with 70 additions and 58 deletions

View File

@ -186,6 +186,10 @@
"message": "Theme", "message": "Theme",
"description": "Label for the style editor's CSS theme." "description": "Label for the style editor's CSS theme."
}, },
"cm_arrowKeysTraverse": {
"message": "Arrow keys ↑↓ traverse sections",
"description": "Label for the option in the editor."
},
"colorpickerPaletteHint": { "colorpickerPaletteHint": {
"message": "Right-click a swatch to cycle through its source lines" "message": "Right-click a swatch to cycle through its source lines"
}, },

View File

@ -338,6 +338,12 @@
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg> <svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label> </label>
</div> </div>
<div class="option sectioned-only">
<label i18n="cm_arrowKeysTraverse">
<input id="editor.arrowKeysTraverse" type="checkbox">
<svg class="svg-icon checked"><use xlink:href="#svg-icon-checked"/></svg>
</label>
</div>
<div class="option"> <div class="option">
<label i18n="cm_colorpicker"> <label i18n="cm_colorpicker">
<input id="editor.colorpicker" type="checkbox"> <input id="editor.colorpicker" type="checkbox">

View File

@ -67,6 +67,7 @@
k.slice('editor.'.length); k.slice('editor.'.length);
const prefKeys = prefs.knownKeys.filter(k => const prefKeys = prefs.knownKeys.filter(k =>
k !== 'editor.colorpicker' && // handled in colorpicker-helper.js k !== 'editor.colorpicker' && // handled in colorpicker-helper.js
k !== 'editor.arrowKeysTraverse' && // handled in sections-editor.js
prefToCmOpt(k) in CodeMirror.defaults); prefToCmOpt(k) in CodeMirror.defaults);
const {insertTab, insertSoftTab} = CodeMirror.commands; const {insertTab, insertSoftTab} = CodeMirror.commands;

View File

@ -75,8 +75,8 @@ html:not(.is-new-style) #heading::before {
right: 24px; right: 24px;
} }
/************ checkbox & select************/ /************ checkbox & select************/
.options-column > div[class="option"] { .options-column > .option {
margin-bottom: 4px; margin-bottom: .25rem;
} }
.options-column > .usercss-only { .options-column > .usercss-only {
@ -107,6 +107,8 @@ label {
} }
#sections { #sections {
padding-left: var(--header-width); padding-left: var(--header-width);
}
.usercss #sections {
min-height: 0; min-height: 0;
height: 100%; height: 100%;
} }

View File

@ -31,6 +31,7 @@ function createSection(originalSection, genId, si) {
value: originalSection.code, value: originalSection.code,
}); });
el.CodeMirror = cm; // used by getAssociatedEditor el.CodeMirror = cm; // used by getAssociatedEditor
cm.el = el;
editor.applyScrollInfo(cm, si); editor.applyScrollInfo(cm, si);
const changeListeners = new Set(); const changeListeners = new Set();
@ -114,49 +115,10 @@ function createSection(originalSection, genId, si) {
changeGeneration = newGeneration; changeGeneration = newGeneration;
emitSectionChange('code'); emitSectionChange('code');
}); });
cm.display.wrapper.on('keydown', event => handleKeydown(cm, event), true);
$('.test-regexp', el).onclick = () => updateRegexpTester(true); $('.test-regexp', el).onclick = () => updateRegexpTester(true);
initBeautifyButton($('.beautify-section', el), [cm]); initBeautifyButton($('.beautify-section', el), [cm]);
} }
function handleKeydown(cm, event) {
if (event.shiftKey || event.altKey || event.metaKey) {
return;
}
const {key} = event;
const {line, ch} = cm.getCursor();
switch (key) {
case 'ArrowLeft':
if (line || ch) {
return;
}
// fallthrough
case 'ArrowUp':
cm = line === 0 && editor.prevEditor(cm, false);
if (!cm) {
return;
}
event.preventDefault();
event.stopPropagation();
cm.setCursor(cm.doc.size - 1, key === 'ArrowLeft' ? 1e20 : ch);
break;
case 'ArrowRight':
if (line < cm.doc.size - 1 || ch < cm.getLine(line).length - 1) {
return;
}
// fallthrough
case 'ArrowDown':
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, false);
if (!cm) {
return;
}
event.preventDefault();
event.stopPropagation();
cm.setCursor(0, 0);
break;
}
}
async function updateRegexpTester(toggle) { async function updateRegexpTester(toggle) {
const isLoaded = typeof regexpTester === 'object' || const isLoaded = typeof regexpTester === 'object' ||
toggle && await require(['/edit/regexp-tester']); /* global regexpTester */ toggle && await require(['/edit/regexp-tester']); /* global regexpTester */

View File

@ -6,6 +6,7 @@
/* global createSection */// sections-editor-section.js /* global createSection */// sections-editor-section.js
/* global editor */ /* global editor */
/* global linterMan */ /* global linterMan */
/* global prefs */
/* global styleSectionsEqual */ // sections-util.js /* global styleSectionsEqual */ // sections-util.js
/* global t */// localization.js /* global t */// localization.js
'use strict'; 'use strict';
@ -21,6 +22,7 @@ function SectionsEditor() {
let sectionOrder = ''; let sectionOrder = '';
let headerOffset; // in compact mode the header is at the top so it reduces the available height let headerOffset; // in compact mode the header is at the top so it reduces the available height
let cmExtrasHeight; // resize grip + borders let cmExtrasHeight; // resize grip + borders
let upDownJumps;
updateMeta(); updateMeta();
rerouteHotkeys.toggle(true); // enabled initially because we don't always focus a CodeMirror rerouteHotkeys.toggle(true); // enabled initially because we don't always focus a CodeMirror
@ -30,6 +32,10 @@ function SectionsEditor() {
$('#from-mozilla').on('click', () => showMozillaFormatImport()); $('#from-mozilla').on('click', () => showMozillaFormatImport());
document.on('wheel', scrollEntirePageOnCtrlShift, {passive: false}); document.on('wheel', scrollEntirePageOnCtrlShift, {passive: false});
CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow'; CodeMirror.defaults.extraKeys['Shift-Ctrl-Wheel'] = 'scrollWindow';
prefs.subscribe('editor.arrowKeysTraverse', (_, val) => {
for (const {cm} of sections) handleKeydownSetup(cm, val);
upDownJumps = val;
}, {runNow: true});
/** @namespace Editor */ /** @namespace Editor */
Object.assign(editor, { Object.assign(editor, {
@ -70,15 +76,15 @@ function SectionsEditor() {
} }
}, },
nextEditor(cm, cycle = true) { nextEditor(cm, upDown) {
return cycle || cm !== findLast(sections, s => !s.removed).cm return !upDown || cm !== findLast(sections, s => !s.removed).cm
? nextPrevEditor(cm, 1) ? nextPrevEditor(cm, 1, upDown)
: null; : null;
}, },
prevEditor(cm, cycle = true) { prevEditor(cm, upDown) {
return cycle || cm !== sections.find(s => !s.removed).cm return !upDown || cm !== sections.find(s => !s.removed).cm
? nextPrevEditor(cm, -1) ? nextPrevEditor(cm, -1, upDown)
: null; : null;
}, },
@ -112,14 +118,16 @@ function SectionsEditor() {
editor.useSavedStyle(newStyle); editor.useSavedStyle(newStyle);
}, },
scrollToEditor(cm) { scrollToEditor(cm, partial) {
const {el} = sections.find(s => s.cm === cm); const cc = partial && cm.cursorCoords(true, 'window');
const r = el.getBoundingClientRect(); const {top: y1, bottom: y2} = cm.el.getBoundingClientRect();
const h = window.innerHeight; const rc = container.getBoundingClientRect();
if (r.bottom > h && r.top > 0 || const rcY1 = Math.max(rc.top, 0);
r.bottom < h && r.top < 0) { const rcY2 = Math.min(rc.bottom, innerHeight);
window.scrollBy(0, (r.top + r.bottom - h) / 2 | 0); const bad = partial
} ? cc.top < rcY1 || cc.top > rcY2 - 30
: y1 >= rcY1 ^ y2 <= rcY2;
if (bad) window.scrollBy(0, (y1 + y2 - rcY2 + rcY1) / 2 | 0);
}, },
}); });
@ -291,10 +299,36 @@ function SectionsEditor() {
} }
} }
function nextPrevEditor(cm, direction) { function handleKeydown(event) {
if (event.shiftKey || event.altKey || event.metaKey ||
event.key !== 'ArrowUp' && event.key !== 'ArrowDown') {
return;
}
let pos;
let cm = this.CodeMirror;
const {line, ch} = cm.getCursor();
if (event.key === 'ArrowUp') {
cm = line === 0 && editor.prevEditor(cm, true);
pos = cm && [cm.doc.size - 1, ch];
} else {
cm = line === cm.doc.size - 1 && editor.nextEditor(cm, true);
pos = cm && [0, 0];
}
if (cm) {
cm.setCursor(...pos);
event.preventDefault();
event.stopPropagation();
}
}
function handleKeydownSetup(cm, state) {
cm.display.wrapper[state ? 'on' : 'off']('keydown', handleKeydown, true);
}
function nextPrevEditor(cm, direction, upDown) {
const editors = editor.getEditors(); const editors = editor.getEditors();
cm = editors[(editors.indexOf(cm) + direction + editors.length) % editors.length]; cm = editors[(editors.indexOf(cm) + direction + editors.length) % editors.length];
editor.scrollToEditor(cm); editor.scrollToEditor(cm, upDown);
cm.focus(); cm.focus();
return cm; return cm;
} }
@ -577,6 +611,9 @@ function SectionsEditor() {
cm.focus(); cm.focus();
editor.scrollToEditor(cm); editor.scrollToEditor(cm);
} }
if (upDownJumps) {
handleKeydownSetup(cm, true);
}
updateSectionOrder(); updateSectionOrder();
updateLivePreview(); updateLivePreview();
section.onChange(updateLivePreview); section.onChange(updateLivePreview);

View File

@ -99,7 +99,7 @@
// "Delete" item in context menu for browsers that don't have it // "Delete" item in context menu for browsers that don't have it
'editor.contextDelete': false, 'editor.contextDelete': false,
'editor.selectByTokens': true, 'editor.selectByTokens': true,
'editor.arrowKeysTraverse': true,
'editor.appliesToLineWidget': true, // show applies-to line widget on the editor 'editor.appliesToLineWidget': true, // show applies-to line widget on the editor
'editor.autosaveDraft': 10, // seconds 'editor.autosaveDraft': 10, // seconds
'editor.livePreview': true, 'editor.livePreview': true,