From 878743500f6c8a855781b950469677694df936a8 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 13 Mar 2025 23:20:58 +0200 Subject: [PATCH] feat(admonitions): convert to split and get last type --- .../src/admonitioncommand.ts | 49 ++++++++++++++++--- .../ckeditor5-admonition/src/admonitionui.ts | 19 ++++--- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/packages/ckeditor5-admonition/src/admonitioncommand.ts b/packages/ckeditor5-admonition/src/admonitioncommand.ts index 42e713d27..798aef5ba 100644 --- a/packages/ckeditor5-admonition/src/admonitioncommand.ts +++ b/packages/ckeditor5-admonition/src/admonitioncommand.ts @@ -20,6 +20,18 @@ import type { DocumentFragment, Element, Position, Range, Schema, Writer } from // TODO: Change me. type AdmonitionType = string; +interface ExecuteOpts { + /** + * If set, it will force the command behavior. If `true`, the command will apply a block quote, + * otherwise the command will remove the block quote. If not set, the command will act basing on its current value. + */ + forceValue?: AdmonitionType; + /** + * If set to true and `forceValue` is not specified, the command will apply the previous admonition type (if the command was already executed). + */ + usePreviousChoice?: boolean +} + export default class AdmonitionCommand extends Command { /** * Whether the selection starts in a block quote. @@ -29,6 +41,8 @@ export default class AdmonitionCommand extends Command { */ declare public value: AdmonitionType | false; + private _lastType?: AdmonitionType; + /** * @inheritDoc */ @@ -44,19 +58,15 @@ export default class AdmonitionCommand extends Command { * * @fires execute * @param options Command options. - * @param options.forceValue If set, it will force the command behavior. If `true`, the command will apply a block quote, - * otherwise the command will remove the block quote. If not set, the command will act basing on its current value. */ - public override execute( options: { forceValue?: AdmonitionType } = {} ): void { + public override execute( options: ExecuteOpts = {} ): void { const model = this.editor.model; const schema = model.schema; const selection = model.document.selection; const blocks = Array.from( selection.getSelectedBlocks() ); - const value = ( options.forceValue === undefined ) ? !this.value : options.forceValue; - // TODO: Fix me. - const valueString = (typeof value === "string" ? value : "note"); + const value = this._getType(options); model.change( writer => { if ( !value ) { @@ -68,11 +78,33 @@ export default class AdmonitionCommand extends Command { return findQuote( block ) || checkCanBeQuoted( schema, block ); } ); - this._applyQuote( writer, blocksToQuote, valueString); + this._applyQuote( writer, blocksToQuote, value); } } ); } + private _getType(options: ExecuteOpts): AdmonitionType | false { + const value = (options.forceValue === undefined) ? !this.value : options.forceValue; + + // Allow removing the admonition. + if (!value) { + return false; + } + + // Prefer the type from the command, if any. + if (typeof value === "string") { + return value; + } + + // See if we can restore the previous language. + if (options.usePreviousChoice && this._lastType) { + return this._lastType; + } + + // Otherwise return a default. + return "note"; + } + /** * Checks the command's {@link #value}. */ @@ -156,7 +188,8 @@ export default class AdmonitionCommand extends Command { /** * Applies the quote to given blocks. */ - private _applyQuote( writer: Writer, blocks: Array, type?: AdmonitionType | false): void { + private _applyQuote( writer: Writer, blocks: Array, type?: AdmonitionType): void { + this._lastType = type; const quotesToMerge: Array = []; // Quote all groups of block. Iterate in the reverse order to not break following ranges. diff --git a/packages/ckeditor5-admonition/src/admonitionui.ts b/packages/ckeditor5-admonition/src/admonitionui.ts index 397912320..c81a37a28 100644 --- a/packages/ckeditor5-admonition/src/admonitionui.ts +++ b/packages/ckeditor5-admonition/src/admonitionui.ts @@ -8,7 +8,7 @@ */ import { Plugin, } from 'ckeditor5/src/core.js'; -import { addListToDropdown, createDropdown, ListDropdownButtonDefinition, ViewModel } from 'ckeditor5/src/ui.js'; +import { addListToDropdown, createDropdown, ListDropdownButtonDefinition, SplitButtonView, ViewModel } from 'ckeditor5/src/ui.js'; import '../theme/blockquote.css'; import admonitionIcon from '../theme/icons/admonition.svg'; @@ -72,23 +72,28 @@ export default class AdmonitionUI extends Plugin { const editor = this.editor; const locale = editor.locale; const command = editor.commands.get( 'admonition' )!; - const dropdownView = createDropdown(locale); + const dropdownView = createDropdown(locale, SplitButtonView); + const splitButtonView = dropdownView.buttonView; const t = locale.t; addListToDropdown(dropdownView, this._getDropdownItems()) - dropdownView.buttonView.set( { + // Button configuration. + splitButtonView.set( { label: t( 'Admonition' ), icon: admonitionIcon, isToggleable: true, tooltip: true } ); + splitButtonView.on("execute", () => { + editor.execute("admonition", { usePreviousChoice: true }); + editor.editing.view.focus(); + }); + splitButtonView.bind( 'isOn' ).to( command, 'value', value => (!!value) as boolean); + // Dropdown configuration dropdownView.bind( 'isEnabled' ).to( command, 'isEnabled' ); - // view.buttonView.bind( 'isOn' ).to( command, 'value' ); - - // Execute the command. - this.listenTo(dropdownView, 'execute', evt => { + dropdownView.on("execute", evt => { editor.execute("admonition", { forceValue: ( evt.source as any ).commandParam } ); editor.editing.view.focus(); });