mirror of
https://github.com/zadam/trilium.git
synced 2025-10-30 18:05:55 +01:00
feat(admonitions): allow selecting admonition type
This commit is contained in:
@@ -16,6 +16,10 @@ import type { DocumentFragment, Element, Position, Range, Schema, Writer } from
|
|||||||
*
|
*
|
||||||
* @extends module:core/command~Command
|
* @extends module:core/command~Command
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// TODO: Change me.
|
||||||
|
type AdmonitionType = string;
|
||||||
|
|
||||||
export default class AdmonitionCommand extends Command {
|
export default class AdmonitionCommand extends Command {
|
||||||
/**
|
/**
|
||||||
* Whether the selection starts in a block quote.
|
* Whether the selection starts in a block quote.
|
||||||
@@ -23,7 +27,7 @@ export default class AdmonitionCommand extends Command {
|
|||||||
* @observable
|
* @observable
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
declare public value: boolean;
|
declare public value: AdmonitionType | false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @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,
|
* @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.
|
* 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 model = this.editor.model;
|
||||||
const schema = model.schema;
|
const schema = model.schema;
|
||||||
const selection = model.document.selection;
|
const selection = model.document.selection;
|
||||||
@@ -51,6 +55,8 @@ export default class AdmonitionCommand extends Command {
|
|||||||
const blocks = Array.from( selection.getSelectedBlocks() );
|
const blocks = Array.from( selection.getSelectedBlocks() );
|
||||||
|
|
||||||
const value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;
|
const value = ( options.forceValue === undefined ) ? !this.value : options.forceValue;
|
||||||
|
// TODO: Fix me.
|
||||||
|
const valueString = (typeof value === "string" ? value : "note");
|
||||||
|
|
||||||
model.change( writer => {
|
model.change( writer => {
|
||||||
if ( !value ) {
|
if ( !value ) {
|
||||||
@@ -62,7 +68,7 @@ export default class AdmonitionCommand extends Command {
|
|||||||
return findQuote( block ) || checkCanBeQuoted( schema, block );
|
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}.
|
* Checks the command's {@link #value}.
|
||||||
*/
|
*/
|
||||||
private _getValue(): boolean {
|
private _getValue(): AdmonitionType | false {
|
||||||
const selection = this.editor.model.document.selection;
|
const selection = this.editor.model.document.selection;
|
||||||
|
|
||||||
const firstBlock = first( selection.getSelectedBlocks() );
|
const firstBlock = first( selection.getSelectedBlocks() );
|
||||||
|
|
||||||
// In the current implementation, the block quote must be an immediate parent of a block element.
|
// 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.
|
* Applies the quote to given blocks.
|
||||||
*/
|
*/
|
||||||
private _applyQuote( writer: Writer, blocks: Array<Element> ): void {
|
private _applyQuote( writer: Writer, blocks: Array<Element>, type?: AdmonitionType | false): void {
|
||||||
const quotesToMerge: Array<Element | DocumentFragment> = [];
|
const quotesToMerge: Array<Element | DocumentFragment> = [];
|
||||||
|
|
||||||
// Quote all groups of block. Iterate in the reverse order to not break following ranges.
|
// 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 );
|
let quote = findQuote( groupRange.start );
|
||||||
|
|
||||||
if ( !quote ) {
|
if ( !quote ) {
|
||||||
quote = writer.createElement( 'aside' );
|
quote = writer.createElement( 'aside', { type });
|
||||||
|
|
||||||
writer.wrap( groupRange, quote );
|
writer.wrap( groupRange, quote );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { Enter, type ViewDocumentEnterEvent } from 'ckeditor5/src/enter.js';
|
|||||||
import { Delete, type ViewDocumentDeleteEvent } from 'ckeditor5/src/typing.js';
|
import { Delete, type ViewDocumentDeleteEvent } from 'ckeditor5/src/typing.js';
|
||||||
|
|
||||||
import AdmonitionCommand from './admonitioncommand.js';
|
import AdmonitionCommand from './admonitioncommand.js';
|
||||||
|
import { ADMONITION_TYPES } from './admonitionui.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The block quote editing.
|
* The block quote editing.
|
||||||
@@ -45,14 +46,38 @@ export default class AdmonitionEditing extends Plugin {
|
|||||||
editor.commands.add( 'admonition', new AdmonitionCommand( editor ) );
|
editor.commands.add( 'admonition', new AdmonitionCommand( editor ) );
|
||||||
|
|
||||||
schema.register( 'aside', {
|
schema.register( 'aside', {
|
||||||
inheritAllFrom: '$container'
|
inheritAllFrom: '$container',
|
||||||
|
allowAttributes: "type"
|
||||||
} );
|
} );
|
||||||
|
|
||||||
editor.conversion.elementToElement( {
|
editor.conversion.for("upcast").elementToElement({
|
||||||
model: 'aside',
|
|
||||||
view: {
|
view: {
|
||||||
name: "aside",
|
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(" ")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ interface AdmonitionDefinition {
|
|||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ADMONITION_TYPES: Record<string, AdmonitionDefinition> = {
|
export const ADMONITION_TYPES: Record<string, AdmonitionDefinition> = {
|
||||||
"note": {
|
"note": {
|
||||||
title: "Note"
|
title: "Note"
|
||||||
},
|
},
|
||||||
@@ -71,28 +71,28 @@ export default class AdmonitionUI extends Plugin {
|
|||||||
const editor = this.editor;
|
const editor = this.editor;
|
||||||
const locale = editor.locale;
|
const locale = editor.locale;
|
||||||
const command = editor.commands.get( 'admonition' )!;
|
const command = editor.commands.get( 'admonition' )!;
|
||||||
const view = createDropdown(locale);
|
const dropdownView = createDropdown(locale);
|
||||||
const t = locale.t;
|
const t = locale.t;
|
||||||
|
|
||||||
addListToDropdown(view, this._getDropdownItems())
|
addListToDropdown(dropdownView, this._getDropdownItems())
|
||||||
|
|
||||||
view.buttonView.set( {
|
dropdownView.buttonView.set( {
|
||||||
label: t( 'Admonition' ),
|
label: t( 'Admonition' ),
|
||||||
icon: admonitionIcon,
|
icon: admonitionIcon,
|
||||||
isToggleable: true,
|
isToggleable: true,
|
||||||
tooltip: true
|
tooltip: true
|
||||||
} );
|
} );
|
||||||
|
|
||||||
view.bind( 'isEnabled' ).to( command, 'isEnabled' );
|
dropdownView.bind( 'isEnabled' ).to( command, 'isEnabled' );
|
||||||
// view.buttonView.bind( 'isOn' ).to( command, 'value' );
|
// view.buttonView.bind( 'isOn' ).to( command, 'value' );
|
||||||
|
|
||||||
// Execute the command.
|
// Execute the command.
|
||||||
this.listenTo( view, 'execute', () => {
|
this.listenTo(dropdownView, 'execute', evt => {
|
||||||
editor.execute( 'admonition' );
|
editor.execute("admonition", { forceValue: ( evt.source as any ).commandParam } );
|
||||||
editor.editing.view.focus();
|
editor.editing.view.focus();
|
||||||
} );
|
});
|
||||||
|
|
||||||
return view;
|
return dropdownView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getDropdownItems() {
|
private _getDropdownItems() {
|
||||||
|
|||||||
Reference in New Issue
Block a user