Notes/src/footnote-ui.ts
2025-01-06 18:59:52 +02:00

114 lines
3.2 KiB
TypeScript

import { Plugin } from 'ckeditor5/src/core.js';
import { addListToDropdown, createDropdown, ViewModel, type ListDropdownItemDefinition } from '@ckeditor/ckeditor5-ui';
import { Collection } from 'ckeditor5/src/utils.js';
import {
ATTRIBUTES,
COMMANDS,
ELEMENTS,
TOOLBAR_COMPONENT_NAME
} from './constants.js';
import insertFootnoteIcon from '../theme/icons/insert-footnote.svg';
import { modelQueryElement, modelQueryElementsAll } from './utils.js';
export default class FootnoteUI extends Plugin {
public init(): void {
const editor = this.editor;
const translate = editor.t;
editor.ui.componentFactory.add( TOOLBAR_COMPONENT_NAME, locale => {
const dropdownView = createDropdown( locale );
// Populate the list in the dropdown with items.
// addListToDropdown( dropdownView, getDropdownItemsDefinitions( placeholderNames ) );
const command = editor.commands.get( COMMANDS.insertFootnote );
if ( !command ) {
throw new Error( 'Command not found.' );
}
dropdownView.buttonView.set( {
label: translate( 'Footnote' ),
icon: insertFootnoteIcon,
tooltip: true
} );
dropdownView.class = 'ck-code-block-dropdown';
dropdownView.bind( 'isEnabled' ).to( command );
dropdownView.on(
'change:isOpen',
( evt, propertyName, newValue ) => {
dropdownView?.listView?.items.clear();
if ( newValue ) {
addListToDropdown(
dropdownView,
this.getDropdownItemsDefinitions() as any
);
} else {
dropdownView?.listView?.items.clear();
const listElement = dropdownView?.listView?.element;
if ( listElement && listElement.parentNode ) {
listElement.parentNode.removeChild( listElement );
}
}
}
);
// Execute the command when the dropdown item is clicked (executed).
this.listenTo( dropdownView, 'execute', evt => {
editor.execute( COMMANDS.insertFootnote, {
footnoteIndex: ( evt.source as any ).commandParam
} );
editor.editing.view.focus();
} );
return dropdownView;
} );
}
public getDropdownItemsDefinitions(): Collection<ListDropdownItemDefinition> {
const itemDefinitions = new Collection<ListDropdownItemDefinition>();
const defaultDef: ListDropdownItemDefinition = {
type: 'button',
model: new ViewModel( {
commandParam: 0,
label: 'New footnote',
withText: true
} )
};
itemDefinitions.add( defaultDef );
const rootElement = this.editor.model.document.getRoot();
if ( !rootElement ) {
throw new Error( 'Document has no root element.' );
}
const footnoteSection = modelQueryElement(
this.editor,
rootElement,
element => element.is( 'element', ELEMENTS.footnoteSection )
);
if ( footnoteSection ) {
const footnoteItems = modelQueryElementsAll(
this.editor,
rootElement,
element => element.is( 'element', ELEMENTS.footnoteItem )
);
footnoteItems.forEach( footnote => {
const index = footnote.getAttribute( ATTRIBUTES.footnoteIndex );
const definition: ListDropdownItemDefinition = {
type: 'button',
model: new ViewModel( {
commandParam: index,
label: `Insert footnote ${ index }`,
withText: true
} )
};
itemDefinitions.add( definition );
} );
}
return itemDefinitions;
}
}