Merge pull request #6100 from BookStackApp/wysiwyg_minimal_inline_code

WYSIWYG: Added inline code support to minimal editor
This commit is contained in:
Dan Brown
2026-04-16 11:25:19 +01:00
committed by GitHub
5 changed files with 40 additions and 31 deletions

View File

@@ -27,6 +27,7 @@ class HtmlDescriptionFilter
'span' => [],
'em' => [],
'br' => [],
'code' => [],
];
public static function filterFromString(string $html): string

View File

@@ -59,7 +59,7 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
mergeRegister(
registerRichText(editor),
registerHistory(editor, createEmptyHistoryState(), 300),
registerShortcuts(context),
registerShortcuts(context, true),
registerKeyboardHandling(context),
registerMouseHandling(context),
registerSelectionHandling(context),
@@ -123,7 +123,7 @@ export function createBasicEditorInstance(container: HTMLElement, htmlContent: s
const editorTeardown = mergeRegister(
registerRichText(editor),
registerHistory(editor, createEmptyHistoryState(), 300),
registerShortcuts(context),
registerShortcuts(context, false),
registerAutoLinks(editor),
);
@@ -157,7 +157,7 @@ export function createCommentEditorInstance(container: HTMLElement, htmlContent:
const editorTeardown = mergeRegister(
registerRichText(editor),
registerHistory(editor, createEmptyHistoryState(), 300),
registerShortcuts(context),
registerShortcuts(context, false),
registerAutoLinks(editor),
registerMentions(context),
);

View File

@@ -38,29 +38,9 @@ type ShortcutAction = (editor: LexicalEditor, context: EditorUiContext) => boole
* List of action functions by their shortcut combo.
* We use "meta" as an abstraction for ctrl/cmd depending on platform.
*/
const actionsByKeys: Record<string, ShortcutAction> = {
'meta+s': () => {
window.$events.emit('editor-save-draft');
return true;
},
'meta+enter': () => {
window.$events.emit('editor-save-page');
return true;
},
'meta+1': (editor, context) => headerHandler(context, 'h2'),
'meta+2': (editor, context) => headerHandler(context, 'h3'),
'meta+3': (editor, context) => headerHandler(context, 'h4'),
'meta+4': (editor, context) => headerHandler(context, 'h5'),
'meta+5': wrapFormatAction(toggleSelectionAsParagraph),
'meta+d': wrapFormatAction(toggleSelectionAsParagraph),
'meta+6': wrapFormatAction(toggleSelectionAsBlockquote),
'meta+q': wrapFormatAction(toggleSelectionAsBlockquote),
'meta+7': wrapFormatAction(formatCodeBlock),
'meta+e': wrapFormatAction(formatCodeBlock),
const baseActionsByKeys: Record<string, ShortcutAction> = {
'meta+8': toggleInlineCode,
'meta+shift+e': toggleInlineCode,
'meta+9': wrapFormatAction(cycleSelectionCalloutFormats),
'meta+o': wrapFormatAction((e) => toggleSelectionAsList(e, 'number')),
'meta+p': wrapFormatAction((e) => toggleSelectionAsList(e, 'bullet')),
'meta+k': (editor, context) => {
@@ -87,12 +67,39 @@ const actionsByKeys: Record<string, ShortcutAction> = {
},
};
function createKeyDownListener(context: EditorUiContext): (e: KeyboardEvent) => void {
/**
* An extended set of the above, used for fuller-featured editors with heavier block-level formatting.
*/
const extendedActionsByKeys: Record<string, ShortcutAction> = {
...baseActionsByKeys,
'meta+s': () => {
window.$events.emit('editor-save-draft');
return true;
},
'meta+enter': () => {
window.$events.emit('editor-save-page');
return true;
},
'meta+1': (editor, context) => headerHandler(context, 'h2'),
'meta+2': (editor, context) => headerHandler(context, 'h3'),
'meta+3': (editor, context) => headerHandler(context, 'h4'),
'meta+4': (editor, context) => headerHandler(context, 'h5'),
'meta+5': wrapFormatAction(toggleSelectionAsParagraph),
'meta+d': wrapFormatAction(toggleSelectionAsParagraph),
'meta+6': wrapFormatAction(toggleSelectionAsBlockquote),
'meta+7': wrapFormatAction(formatCodeBlock),
'meta+e': wrapFormatAction(formatCodeBlock),
'meta+q': wrapFormatAction(toggleSelectionAsBlockquote),
'meta+9': wrapFormatAction(cycleSelectionCalloutFormats),
};
function createKeyDownListener(context: EditorUiContext, useExtended: boolean): (e: KeyboardEvent) => void {
const keySetToUse = useExtended ? extendedActionsByKeys : baseActionsByKeys;
return (event: KeyboardEvent) => {
const combo = keyboardEventToKeyComboString(event);
// console.log(`pressed: ${combo}`);
if (actionsByKeys[combo]) {
const handled = actionsByKeys[combo](context.editor, context);
if (keySetToUse[combo]) {
const handled = keySetToUse[combo](context.editor, context);
if (handled) {
event.stopPropagation();
event.preventDefault();
@@ -127,8 +134,8 @@ function overrideDefaultCommands(editor: LexicalEditor) {
}, COMMAND_PRIORITY_HIGH);
}
export function registerShortcuts(context: EditorUiContext) {
const listener = createKeyDownListener(context);
export function registerShortcuts(context: EditorUiContext, useExtended: boolean) {
const listener = createKeyDownListener(context, useExtended);
overrideDefaultCommands(context.editor);
return context.editor.registerRootListener((rootElement: null | HTMLElement, prevRootElement: null | HTMLElement) => {

View File

@@ -227,6 +227,7 @@ export function getBasicEditorToolbar(context: EditorUiContext): EditorContainer
new EditorButton(bold),
new EditorButton(italic),
new EditorButton(link),
new EditorButton(code),
new EditorButton(bulletList),
new EditorButton(numberList),
])

View File

@@ -256,8 +256,8 @@ class BookTest extends TestCase
{
$book = $this->entities->book();
$input = '<h1>Test</h1><p id="abc" href="beans">Content<a href="#cat" target="_blank" data-a="b">a</a><section>Hello</section></p>';
$expected = '<p>Content<a href="#cat" target="_blank">a</a></p>';
$input = '<h1>Test</h1><p id="abc" href="beans">Content<a href="#cat" target="_blank" data-a="b">a</a><section>Hello</section><code id="abc">code</code></p>';
$expected = '<p>Content<a href="#cat" target="_blank">a</a><code>code</code></p>';
$this->asEditor()->put($book->getUrl(), [
'name' => $book->name,