diff --git a/packages/ckeditor5-admonition/src/admonitioncommand.ts b/packages/ckeditor5-admonition/src/admonitioncommand.ts index cf91e49f3..3ff85e0dc 100644 --- a/packages/ckeditor5-admonition/src/admonitioncommand.ts +++ b/packages/ckeditor5-admonition/src/admonitioncommand.ts @@ -16,6 +16,10 @@ import type { DocumentFragment, Element, Position, Range, Schema, Writer } from * * @extends module:core/command~Command */ + +// TODO: Change me. +type AdmonitionType = string; + export default class AdmonitionCommand extends Command { /** * Whether the selection starts in a block quote. @@ -23,7 +27,7 @@ export default class AdmonitionCommand extends Command { * @observable * @readonly */ - declare public value: boolean; + declare public value: AdmonitionType | false; /** * @inheritDoc @@ -43,7 +47,7 @@ export default class AdmonitionCommand extends Command { * @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?: boolean } = {} ): void { + public override execute( options: { forceValue?: AdmonitionType } = {} ): void { const model = this.editor.model; const schema = model.schema; const selection = model.document.selection; @@ -51,6 +55,8 @@ export default class AdmonitionCommand extends Command { 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"); model.change( writer => { if ( !value ) { @@ -62,7 +68,7 @@ export default class AdmonitionCommand extends Command { return findQuote( block ) || checkCanBeQuoted( schema, block ); } ); - this._applyQuote( writer, blocksToQuote ); + this._applyQuote( writer, blocksToQuote, valueString); } } ); } @@ -70,13 +76,15 @@ export default class AdmonitionCommand extends Command { /** * Checks the command's {@link #value}. */ - private _getValue(): boolean { + private _getValue(): AdmonitionType | false { const selection = this.editor.model.document.selection; const firstBlock = first( selection.getSelectedBlocks() ); // In the current implementation, the block quote must be an immediate parent of a block element. - return !!( firstBlock && findQuote( firstBlock ) ); + // TODO: Read correct quote. + const result = !!( firstBlock && findQuote( firstBlock ) ); + return result ? "note" : false; } /** @@ -143,7 +151,7 @@ export default class AdmonitionCommand extends Command { /** * Applies the quote to given blocks. */ - private _applyQuote( writer: Writer, blocks: Array ): void { + private _applyQuote( writer: Writer, blocks: Array, type?: AdmonitionType | false): void { const quotesToMerge: Array = []; // Quote all groups of block. Iterate in the reverse order to not break following ranges. @@ -151,7 +159,7 @@ export default class AdmonitionCommand extends Command { let quote = findQuote( groupRange.start ); if ( !quote ) { - quote = writer.createElement( 'aside' ); + quote = writer.createElement( 'aside', { type }); writer.wrap( groupRange, quote ); } diff --git a/packages/ckeditor5-admonition/src/admonitionediting.ts b/packages/ckeditor5-admonition/src/admonitionediting.ts index 9f16e4ae4..ce6ac6d8b 100644 --- a/packages/ckeditor5-admonition/src/admonitionediting.ts +++ b/packages/ckeditor5-admonition/src/admonitionediting.ts @@ -12,6 +12,7 @@ import { Enter, type ViewDocumentEnterEvent } from 'ckeditor5/src/enter.js'; import { Delete, type ViewDocumentDeleteEvent } from 'ckeditor5/src/typing.js'; import AdmonitionCommand from './admonitioncommand.js'; +import { ADMONITION_TYPES } from './admonitionui.js'; /** * The block quote editing. @@ -45,14 +46,38 @@ export default class AdmonitionEditing extends Plugin { editor.commands.add( 'admonition', new AdmonitionCommand( editor ) ); schema.register( 'aside', { - inheritAllFrom: '$container' + inheritAllFrom: '$container', + allowAttributes: "type" } ); - editor.conversion.elementToElement( { - model: 'aside', + editor.conversion.for("upcast").elementToElement({ view: { name: "aside", - classes: "admonition" + classes: "admonition", + }, + model: (viewElement, { writer }) => { + let type = "note"; + const allowedTypes = Object.keys(ADMONITION_TYPES); + for (const className of viewElement.getClassNames()) { + if (className !== "admonition" && allowedTypes.includes(className)) { + type = className; + } + } + + return writer.createElement("aside", { + type + }); + } + }); + + editor.conversion.for("downcast").elementToElement( { + model: 'aside', + view: (modelElement, { writer }) => { + return writer.createContainerElement( + "aside", { + class: [ "admonition", modelElement.getAttribute("type") ].join(" ") + } + ) } }); diff --git a/packages/ckeditor5-admonition/src/admonitionui.ts b/packages/ckeditor5-admonition/src/admonitionui.ts index 62a79c8e5..859ef44c3 100644 --- a/packages/ckeditor5-admonition/src/admonitionui.ts +++ b/packages/ckeditor5-admonition/src/admonitionui.ts @@ -18,7 +18,7 @@ interface AdmonitionDefinition { title: string; } -const ADMONITION_TYPES: Record = { +export const ADMONITION_TYPES: Record = { "note": { title: "Note" }, @@ -71,28 +71,28 @@ export default class AdmonitionUI extends Plugin { const editor = this.editor; const locale = editor.locale; const command = editor.commands.get( 'admonition' )!; - const view = createDropdown(locale); + const dropdownView = createDropdown(locale); const t = locale.t; - addListToDropdown(view, this._getDropdownItems()) + addListToDropdown(dropdownView, this._getDropdownItems()) - view.buttonView.set( { + dropdownView.buttonView.set( { label: t( 'Admonition' ), icon: admonitionIcon, isToggleable: true, tooltip: true } ); - view.bind( 'isEnabled' ).to( command, 'isEnabled' ); + dropdownView.bind( 'isEnabled' ).to( command, 'isEnabled' ); // view.buttonView.bind( 'isOn' ).to( command, 'value' ); // Execute the command. - this.listenTo( view, 'execute', () => { - editor.execute( 'admonition' ); + this.listenTo(dropdownView, 'execute', evt => { + editor.execute("admonition", { forceValue: ( evt.source as any ).commandParam } ); editor.editing.view.focus(); - } ); + }); - return view; + return dropdownView; } private _getDropdownItems() {