mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
chore(ckeditor5-footnotes): integrate source code changes
This commit is contained in:
parent
9643bf310e
commit
d977866c44
@ -1,6 +0,0 @@
|
||||
import type { Footnotes } from './index.js';
|
||||
declare module '@ckeditor/ckeditor5-core' {
|
||||
interface PluginsMap {
|
||||
[Footnotes.pluginName]: Footnotes;
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export {};
|
||||
//# sourceMappingURL=augmentation.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"augmentation.js","sourceRoot":"","sources":["augmentation.ts"],"names":[],"mappings":""}
|
@ -1,7 +0,0 @@
|
||||
import type { Footnotes } from './index.js';
|
||||
|
||||
declare module '@ckeditor/ckeditor5-core' {
|
||||
interface PluginsMap {
|
||||
[ Footnotes.pluginName ]: Footnotes;
|
||||
}
|
||||
}
|
31
_regroup/ckeditor5-footnotes/src/constants.d.ts
vendored
31
_regroup/ckeditor5-footnotes/src/constants.d.ts
vendored
@ -1,31 +0,0 @@
|
||||
export declare const TOOLBAR_COMPONENT_NAME = "footnote";
|
||||
export declare const DATA_FOOTNOTE_ID = "data-footnote-id";
|
||||
export declare const ELEMENTS: {
|
||||
footnoteItem: string;
|
||||
footnoteReference: string;
|
||||
footnoteSection: string;
|
||||
footnoteContent: string;
|
||||
footnoteBackLink: string;
|
||||
};
|
||||
export declare const CLASSES: {
|
||||
footnoteContent: string;
|
||||
footnoteItem: string;
|
||||
footnoteReference: string;
|
||||
footnoteSection: string;
|
||||
footnoteBackLink: string;
|
||||
footnotes: string;
|
||||
hidden: string;
|
||||
};
|
||||
export declare const COMMANDS: {
|
||||
insertFootnote: string;
|
||||
};
|
||||
export declare const ATTRIBUTES: {
|
||||
footnoteContent: string;
|
||||
footnoteId: string;
|
||||
footnoteIndex: string;
|
||||
footnoteItem: string;
|
||||
footnoteReference: string;
|
||||
footnoteSection: string;
|
||||
footnoteBackLink: string;
|
||||
footnoteBackLinkHref: string;
|
||||
};
|
@ -1,32 +0,0 @@
|
||||
export const TOOLBAR_COMPONENT_NAME = 'footnote';
|
||||
export const DATA_FOOTNOTE_ID = 'data-footnote-id';
|
||||
export const ELEMENTS = {
|
||||
footnoteItem: 'footnoteItem',
|
||||
footnoteReference: 'footnoteReference',
|
||||
footnoteSection: 'footnoteSection',
|
||||
footnoteContent: 'footnoteContent',
|
||||
footnoteBackLink: 'footnoteBackLink'
|
||||
};
|
||||
export const CLASSES = {
|
||||
footnoteContent: 'footnote-content',
|
||||
footnoteItem: 'footnote-item',
|
||||
footnoteReference: 'footnote-reference',
|
||||
footnoteSection: 'footnote-section',
|
||||
footnoteBackLink: 'footnote-back-link',
|
||||
footnotes: 'footnotes',
|
||||
hidden: 'hidden'
|
||||
};
|
||||
export const COMMANDS = {
|
||||
insertFootnote: 'InsertFootnote'
|
||||
};
|
||||
export const ATTRIBUTES = {
|
||||
footnoteContent: 'data-footnote-content',
|
||||
footnoteId: 'data-footnote-id',
|
||||
footnoteIndex: 'data-footnote-index',
|
||||
footnoteItem: 'data-footnote-item',
|
||||
footnoteReference: 'data-footnote-reference',
|
||||
footnoteSection: 'data-footnote-section',
|
||||
footnoteBackLink: 'data-footnote-back-link',
|
||||
footnoteBackLinkHref: 'data-footnote-back-link-href'
|
||||
};
|
||||
//# sourceMappingURL=constants.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"constants.js","sourceRoot":"","sources":["constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,QAAQ,GAAG;IACvB,YAAY,EAAE,cAAc;IAC5B,iBAAiB,EAAE,mBAAmB;IACtC,eAAe,EAAE,iBAAiB;IAClC,eAAe,EAAE,iBAAiB;IAClC,gBAAgB,EAAE,kBAAkB;CACpC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG;IACtB,eAAe,EAAE,kBAAkB;IACnC,YAAY,EAAE,eAAe;IAC7B,iBAAiB,EAAE,oBAAoB;IACvC,eAAe,EAAE,kBAAkB;IACnC,gBAAgB,EAAE,oBAAoB;IACtC,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,QAAQ;CAChB,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACvB,cAAc,EAAE,gBAAgB;CAChC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,eAAe,EAAE,uBAAuB;IACxC,UAAU,EAAE,kBAAkB;IAC9B,aAAa,EAAE,qBAAqB;IACpC,YAAY,EAAE,oBAAoB;IAClC,iBAAiB,EAAE,yBAAyB;IAC5C,eAAe,EAAE,uBAAuB;IACxC,gBAAgB,EAAE,yBAAyB;IAC3C,oBAAoB,EAAE,8BAA8B;CACpD,CAAC"}
|
@ -1,6 +0,0 @@
|
||||
import { type Editor } from 'ckeditor5/src/core.js';
|
||||
import { type Element } from 'ckeditor5/src/engine.js';
|
||||
/**
|
||||
* Adds functionality to support creating footnotes using markdown syntax, e.g. `[^1]`.
|
||||
*/
|
||||
export declare const addFootnoteAutoformatting: (editor: Editor, rootElement: Element) => void;
|
@ -1,101 +0,0 @@
|
||||
import { Text, TextProxy } from 'ckeditor5/src/engine.js';
|
||||
import { inlineAutoformatEditing } from "@ckeditor/ckeditor5-autoformat";
|
||||
import { COMMANDS, ELEMENTS } from '../constants.js';
|
||||
import { modelQueryElement, modelQueryElementsAll } from '../utils.js';
|
||||
/**
|
||||
* CKEditor's autoformatting feature (basically find and replace) has two opinionated default modes:
|
||||
* block autoformatting, which replaces the entire line, and inline autoformatting,
|
||||
* which expects a section to be formatted (but, importantly, not removed) surrounded by
|
||||
* a pair of delimters which get removed.
|
||||
*
|
||||
* Neither of those are ideal for this case. We want to replace the matched text with a new element,
|
||||
* without deleting the entire line.
|
||||
*
|
||||
* However, inlineAutoformatEditing allows for passing in a custom callback to handle
|
||||
* regex matching, which also allows us to specify which sections to remove and
|
||||
* which sections pass on to the formatting callback. This method removes the entire
|
||||
* matched text, while passing the range of the numeric text on to the formatting callback.
|
||||
*
|
||||
* If 0 or more than 1 match is found, it returns empty ranges for both format and remove, which is a no-op.
|
||||
*/
|
||||
const regexMatchCallback = (editor, text) => {
|
||||
const selectionStart = editor.model.document.selection.anchor;
|
||||
// get the text node containing the cursor's position, or the one ending at `the cursor's position
|
||||
const surroundingText = selectionStart && (selectionStart.textNode || selectionStart.getShiftedBy(-1).textNode);
|
||||
if (!selectionStart || !surroundingText) {
|
||||
return {
|
||||
remove: [],
|
||||
format: []
|
||||
};
|
||||
}
|
||||
const results = text.matchAll(/\[\^([0-9]+)\]/g);
|
||||
for (const result of results || []) {
|
||||
const removeStartIndex = text.indexOf(result[0]);
|
||||
const removeEndIndex = removeStartIndex + result[0].length;
|
||||
const textNodeOffset = selectionStart.parent.getChildStartOffset(surroundingText);
|
||||
// if the cursor isn't at the end of the range to be replaced, do nothing
|
||||
if (textNodeOffset === null || selectionStart.offset !== textNodeOffset + removeEndIndex) {
|
||||
continue;
|
||||
}
|
||||
const formatStartIndex = removeStartIndex + 2;
|
||||
const formatEndIndex = formatStartIndex + result[1].length;
|
||||
return {
|
||||
remove: [[removeStartIndex, removeEndIndex]],
|
||||
format: [[formatStartIndex, formatEndIndex]]
|
||||
};
|
||||
}
|
||||
return {
|
||||
remove: [],
|
||||
format: []
|
||||
};
|
||||
};
|
||||
/**
|
||||
* This callback takes in a range of text passed on by regexMatchCallback,
|
||||
* and attempts to insert a corresponding footnote reference at the current location.
|
||||
*
|
||||
* Footnotes only get inserted if the matching range is an integer between 1
|
||||
* and the number of existing footnotes + 1.
|
||||
*/
|
||||
const formatCallback = (ranges, editor, rootElement) => {
|
||||
const command = editor.commands.get(COMMANDS.insertFootnote);
|
||||
if (!command || !command.isEnabled) {
|
||||
return;
|
||||
}
|
||||
const text = [...ranges[0].getItems()][0];
|
||||
if (!(text instanceof TextProxy || text instanceof Text)) {
|
||||
return false;
|
||||
}
|
||||
const match = text.data.match(/[0-9]+/);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
const footnoteIndex = parseInt(match[0]);
|
||||
const footnoteSection = modelQueryElement(editor, rootElement, element => element.is('element', ELEMENTS.footnoteSection));
|
||||
if (!footnoteSection) {
|
||||
if (footnoteIndex !== 1) {
|
||||
return false;
|
||||
}
|
||||
editor.execute(COMMANDS.insertFootnote);
|
||||
return;
|
||||
}
|
||||
const footnoteCount = modelQueryElementsAll(editor, footnoteSection, element => element.is('element', ELEMENTS.footnoteItem)).length;
|
||||
if (footnoteIndex === footnoteCount + 1) {
|
||||
editor.execute(COMMANDS.insertFootnote);
|
||||
return;
|
||||
}
|
||||
else if (footnoteIndex >= 1 && footnoteIndex <= footnoteCount) {
|
||||
editor.execute(COMMANDS.insertFootnote, { footnoteIndex });
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Adds functionality to support creating footnotes using markdown syntax, e.g. `[^1]`.
|
||||
*/
|
||||
export const addFootnoteAutoformatting = (editor, rootElement) => {
|
||||
if (editor.plugins.has('Autoformat')) {
|
||||
const autoformatPluginInstance = editor.plugins.get('Autoformat');
|
||||
inlineAutoformatEditing(editor, autoformatPluginInstance, text => regexMatchCallback(editor, text), (_, ranges) => formatCallback(ranges, editor, rootElement));
|
||||
}
|
||||
};
|
||||
//# sourceMappingURL=auto-formatting.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"auto-formatting.js","sourceRoot":"","sources":["auto-formatting.ts"],"names":[],"mappings":"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"}
|
@ -1,5 +0,0 @@
|
||||
import { type Editor } from 'ckeditor5/src/core.js';
|
||||
/**
|
||||
* Defines methods for converting between model, data view, and editing view representations of each element type.
|
||||
*/
|
||||
export declare const defineConverters: (editor: Editor) => void;
|
@ -1,296 +0,0 @@
|
||||
import { Element } from "ckeditor5/src/engine.js";
|
||||
import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget.js';
|
||||
import { ATTRIBUTES, CLASSES, ELEMENTS } from '../constants.js';
|
||||
import { viewQueryElement } from '../utils.js';
|
||||
/**
|
||||
* Defines methods for converting between model, data view, and editing view representations of each element type.
|
||||
*/
|
||||
export const defineConverters = (editor) => {
|
||||
const conversion = editor.conversion;
|
||||
/** *********************************Attribute Conversion************************************/
|
||||
conversion.for('downcast').attributeToAttribute({
|
||||
model: ATTRIBUTES.footnoteId,
|
||||
view: ATTRIBUTES.footnoteId
|
||||
});
|
||||
conversion.for('downcast').attributeToAttribute({
|
||||
model: ATTRIBUTES.footnoteIndex,
|
||||
view: ATTRIBUTES.footnoteIndex
|
||||
});
|
||||
/** *********************************Footnote Section Conversion************************************/
|
||||
// ((data) view → model)
|
||||
conversion.for('upcast').elementToElement({
|
||||
view: {
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteSection]: true
|
||||
}
|
||||
},
|
||||
model: ELEMENTS.footnoteSection,
|
||||
converterPriority: 'high'
|
||||
});
|
||||
// (model → data view)
|
||||
conversion.for('dataDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteSection,
|
||||
view: {
|
||||
name: 'ol',
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteSection]: '',
|
||||
role: 'doc-endnotes'
|
||||
},
|
||||
classes: [CLASSES.footnoteSection, CLASSES.footnotes]
|
||||
}
|
||||
});
|
||||
// (model → editing view)
|
||||
conversion.for('editingDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteSection,
|
||||
view: (_, conversionApi) => {
|
||||
const viewWriter = conversionApi.writer;
|
||||
// eslint-disable-next-line max-len
|
||||
/** The below is a div rather than an ol because using an ol here caused weird behavior, including randomly duplicating the footnotes section.
|
||||
* This is techincally invalid HTML, but it's valid in the data view (that is, the version shown in the post). I've added role='list'
|
||||
* as a next-best option, in accordance with ARIA recommendations.
|
||||
*/
|
||||
const section = viewWriter.createContainerElement('div', {
|
||||
[ATTRIBUTES.footnoteSection]: '',
|
||||
role: 'doc-endnotes list',
|
||||
class: CLASSES.footnoteSection
|
||||
});
|
||||
return toWidget(section, viewWriter, { label: 'footnote widget' });
|
||||
}
|
||||
});
|
||||
/** *********************************Footnote Content Conversion************************************/
|
||||
conversion.for('upcast').elementToElement({
|
||||
view: {
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteContent]: true
|
||||
}
|
||||
},
|
||||
model: (viewElement, conversionApi) => {
|
||||
const modelWriter = conversionApi.writer;
|
||||
return modelWriter.createElement(ELEMENTS.footnoteContent);
|
||||
}
|
||||
});
|
||||
conversion.for('dataDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteContent,
|
||||
view: {
|
||||
name: 'div',
|
||||
attributes: { [ATTRIBUTES.footnoteContent]: '' },
|
||||
classes: [CLASSES.footnoteContent]
|
||||
}
|
||||
});
|
||||
conversion.for('editingDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteContent,
|
||||
view: (_, conversionApi) => {
|
||||
const viewWriter = conversionApi.writer;
|
||||
// Note: You use a more specialized createEditableElement() method here.
|
||||
const section = viewWriter.createEditableElement('div', {
|
||||
[ATTRIBUTES.footnoteContent]: '',
|
||||
class: CLASSES.footnoteContent
|
||||
});
|
||||
return toWidgetEditable(section, viewWriter);
|
||||
}
|
||||
});
|
||||
/** *********************************Footnote Item Conversion************************************/
|
||||
conversion.for('upcast').elementToElement({
|
||||
view: {
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteItem]: true
|
||||
}
|
||||
},
|
||||
model: (viewElement, conversionApi) => {
|
||||
const modelWriter = conversionApi.writer;
|
||||
const id = viewElement.getAttribute(ATTRIBUTES.footnoteId);
|
||||
const index = viewElement.getAttribute(ATTRIBUTES.footnoteIndex);
|
||||
if (id === undefined || index === undefined) {
|
||||
return null;
|
||||
}
|
||||
return modelWriter.createElement(ELEMENTS.footnoteItem, {
|
||||
[ATTRIBUTES.footnoteIndex]: index,
|
||||
[ATTRIBUTES.footnoteId]: id
|
||||
});
|
||||
},
|
||||
/** converterPriority is needed to supersede the builtin upcastListItemStyle
|
||||
* which for unknown reasons causes a null reference error.
|
||||
*/
|
||||
converterPriority: 'high'
|
||||
});
|
||||
conversion.for('dataDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteItem,
|
||||
view: createFootnoteItemViewElement
|
||||
});
|
||||
conversion.for('editingDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteItem,
|
||||
view: createFootnoteItemViewElement
|
||||
});
|
||||
/** *********************************Footnote Reference Conversion************************************/
|
||||
conversion.for('upcast').elementToElement({
|
||||
view: {
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteReference]: true
|
||||
}
|
||||
},
|
||||
model: (viewElement, conversionApi) => {
|
||||
const modelWriter = conversionApi.writer;
|
||||
const index = viewElement.getAttribute(ATTRIBUTES.footnoteIndex);
|
||||
const id = viewElement.getAttribute(ATTRIBUTES.footnoteId);
|
||||
if (index === undefined || id === undefined) {
|
||||
return null;
|
||||
}
|
||||
return modelWriter.createElement(ELEMENTS.footnoteReference, {
|
||||
[ATTRIBUTES.footnoteIndex]: index,
|
||||
[ATTRIBUTES.footnoteId]: id
|
||||
});
|
||||
}
|
||||
});
|
||||
conversion.for('editingDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteReference,
|
||||
view: (modelElement, conversionApi) => {
|
||||
const viewWriter = conversionApi.writer;
|
||||
const footnoteReferenceViewElement = createFootnoteReferenceViewElement(modelElement, conversionApi);
|
||||
return toWidget(footnoteReferenceViewElement, viewWriter);
|
||||
}
|
||||
});
|
||||
conversion.for('dataDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteReference,
|
||||
view: createFootnoteReferenceViewElement
|
||||
});
|
||||
/** This is an event listener for changes to the `data-footnote-index` attribute on `footnoteReference` elements.
|
||||
* When that event fires, the callback function below updates the displayed view of the footnote reference in the
|
||||
* editor to match the new index.
|
||||
*/
|
||||
conversion.for('editingDowncast').add(dispatcher => {
|
||||
dispatcher.on(`attribute:${ATTRIBUTES.footnoteIndex}:${ELEMENTS.footnoteReference}`, (_, data, conversionApi) => updateFootnoteReferenceView(data, conversionApi, editor), { priority: 'high' });
|
||||
});
|
||||
/** *********************************Footnote Back Link Conversion************************************/
|
||||
conversion.for('upcast').elementToElement({
|
||||
view: {
|
||||
attributes: {
|
||||
[ATTRIBUTES.footnoteBackLink]: true
|
||||
}
|
||||
},
|
||||
model: (viewElement, conversionApi) => {
|
||||
const modelWriter = conversionApi.writer;
|
||||
const id = viewElement.getAttribute(ATTRIBUTES.footnoteId);
|
||||
if (id === undefined) {
|
||||
return null;
|
||||
}
|
||||
return modelWriter.createElement(ELEMENTS.footnoteBackLink, {
|
||||
[ATTRIBUTES.footnoteId]: id
|
||||
});
|
||||
}
|
||||
});
|
||||
conversion.for('dataDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteBackLink,
|
||||
view: createFootnoteBackLinkViewElement
|
||||
});
|
||||
conversion.for('editingDowncast').elementToElement({
|
||||
model: ELEMENTS.footnoteBackLink,
|
||||
view: createFootnoteBackLinkViewElement
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Creates and returns a view element for a footnote backlink,
|
||||
* which navigates back to the inline reference in the text. Used
|
||||
* for both data and editing downcasts.
|
||||
*/
|
||||
function createFootnoteBackLinkViewElement(modelElement, conversionApi) {
|
||||
const viewWriter = conversionApi.writer;
|
||||
const id = `${modelElement.getAttribute(ATTRIBUTES.footnoteId)}`;
|
||||
if (id === undefined) {
|
||||
throw new Error('Footnote return link has no provided Id.');
|
||||
}
|
||||
const footnoteBackLinkView = viewWriter.createContainerElement('span', {
|
||||
class: CLASSES.footnoteBackLink,
|
||||
[ATTRIBUTES.footnoteBackLink]: '',
|
||||
[ATTRIBUTES.footnoteId]: id
|
||||
});
|
||||
const sup = viewWriter.createContainerElement('sup');
|
||||
const strong = viewWriter.createContainerElement('strong');
|
||||
const anchor = viewWriter.createContainerElement('a', { href: `#fnref${id}` });
|
||||
const innerText = viewWriter.createText('^');
|
||||
viewWriter.insert(viewWriter.createPositionAt(anchor, 0), innerText);
|
||||
viewWriter.insert(viewWriter.createPositionAt(strong, 0), anchor);
|
||||
viewWriter.insert(viewWriter.createPositionAt(sup, 0), strong);
|
||||
viewWriter.insert(viewWriter.createPositionAt(footnoteBackLinkView, 0), sup);
|
||||
return footnoteBackLinkView;
|
||||
}
|
||||
/**
|
||||
* Creates and returns a view element for an inline footnote reference. Used for both
|
||||
* data downcast and editing downcast conversions.
|
||||
*/
|
||||
function createFootnoteReferenceViewElement(modelElement, conversionApi) {
|
||||
const viewWriter = conversionApi.writer;
|
||||
const index = `${modelElement.getAttribute(ATTRIBUTES.footnoteIndex)}`;
|
||||
const id = `${modelElement.getAttribute(ATTRIBUTES.footnoteId)}`;
|
||||
if (index === 'undefined') {
|
||||
throw new Error('Footnote reference has no provided index.');
|
||||
}
|
||||
if (id === 'undefined') {
|
||||
throw new Error('Footnote reference has no provided id.');
|
||||
}
|
||||
const footnoteReferenceView = viewWriter.createContainerElement('span', {
|
||||
class: CLASSES.footnoteReference,
|
||||
[ATTRIBUTES.footnoteReference]: '',
|
||||
[ATTRIBUTES.footnoteIndex]: index,
|
||||
[ATTRIBUTES.footnoteId]: id,
|
||||
role: 'doc-noteref',
|
||||
id: `fnref${id}`
|
||||
});
|
||||
const innerText = viewWriter.createText(`[${index}]`);
|
||||
const link = viewWriter.createContainerElement('a', { href: `#fn${id}` });
|
||||
const superscript = viewWriter.createContainerElement('sup');
|
||||
viewWriter.insert(viewWriter.createPositionAt(link, 0), innerText);
|
||||
viewWriter.insert(viewWriter.createPositionAt(superscript, 0), link);
|
||||
viewWriter.insert(viewWriter.createPositionAt(footnoteReferenceView, 0), superscript);
|
||||
return footnoteReferenceView;
|
||||
}
|
||||
/**
|
||||
* Creates and returns a view element for an inline footnote reference. Used for both
|
||||
* data downcast and editing downcast conversions.
|
||||
*/
|
||||
function createFootnoteItemViewElement(modelElement, conversionApi) {
|
||||
const viewWriter = conversionApi.writer;
|
||||
const index = modelElement.getAttribute(ATTRIBUTES.footnoteIndex);
|
||||
const id = modelElement.getAttribute(ATTRIBUTES.footnoteId);
|
||||
if (!index) {
|
||||
throw new Error('Footnote item has no provided index.');
|
||||
}
|
||||
if (!id) {
|
||||
throw new Error('Footnote item has no provided id.');
|
||||
}
|
||||
return viewWriter.createContainerElement('li', {
|
||||
class: CLASSES.footnoteItem,
|
||||
[ATTRIBUTES.footnoteItem]: '',
|
||||
[ATTRIBUTES.footnoteIndex]: `${index}`,
|
||||
[ATTRIBUTES.footnoteId]: `${id}`,
|
||||
role: 'doc-endnote',
|
||||
id: `fn${id}`
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Triggers when the index attribute of a footnote changes, and
|
||||
* updates the editor display of footnote references accordingly.
|
||||
*/
|
||||
function updateFootnoteReferenceView(data, conversionApi, editor) {
|
||||
const { item, attributeNewValue: newIndex } = data;
|
||||
if (!(item instanceof Element) ||
|
||||
!conversionApi.consumable.consume(item, `attribute:${ATTRIBUTES.footnoteIndex}:${ELEMENTS.footnoteReference}`)) {
|
||||
return;
|
||||
}
|
||||
const footnoteReferenceView = conversionApi.mapper.toViewElement(item);
|
||||
if (!footnoteReferenceView) {
|
||||
return;
|
||||
}
|
||||
const viewWriter = conversionApi.writer;
|
||||
const anchor = viewQueryElement(editor, footnoteReferenceView, element => element.name === 'a');
|
||||
const textNode = anchor === null || anchor === void 0 ? void 0 : anchor.getChild(0);
|
||||
if (!textNode || !anchor) {
|
||||
viewWriter.remove(footnoteReferenceView);
|
||||
return;
|
||||
}
|
||||
viewWriter.remove(textNode);
|
||||
const innerText = viewWriter.createText(`[${newIndex}]`);
|
||||
viewWriter.insert(viewWriter.createPositionAt(anchor, 0), innerText);
|
||||
viewWriter.setAttribute('href', `#fn${item.getAttribute(ATTRIBUTES.footnoteId)}`, anchor);
|
||||
viewWriter.setAttribute(ATTRIBUTES.footnoteIndex, newIndex, footnoteReferenceView);
|
||||
}
|
||||
//# sourceMappingURL=converters.js.map
|
File diff suppressed because one or more lines are too long
@ -1,59 +0,0 @@
|
||||
/**
|
||||
* CKEditor dataview nodes can be converted to a output view or an editor view via downcasting
|
||||
* * Upcasting is converting to the platonic ckeditor version.
|
||||
* * Downcasting is converting to the output version.
|
||||
*/
|
||||
import { type RootElement } from 'ckeditor5/src/engine.js';
|
||||
import { Autoformat } from "@ckeditor/ckeditor5-autoformat";
|
||||
import { Plugin } from "ckeditor5/src/core.js";
|
||||
import { Widget } from 'ckeditor5/src/widget.js';
|
||||
import '../footnote.css';
|
||||
export default class FootnoteEditing extends Plugin {
|
||||
static get requires(): readonly [typeof Widget, typeof Autoformat];
|
||||
/**
|
||||
* The root element of the document.
|
||||
*/
|
||||
get rootElement(): RootElement;
|
||||
init(): void;
|
||||
/**
|
||||
* This method broadly deals with deletion of text and elements, and updating the model
|
||||
* accordingly. In particular, the following cases are handled:
|
||||
* 1. If the footnote section gets deleted, all footnote references are removed.
|
||||
* 2. If a delete operation happens in an empty footnote, the footnote is deleted.
|
||||
*/
|
||||
private _handleDelete;
|
||||
/**
|
||||
* Clear the children of the provided footnoteContent element,
|
||||
* leaving an empty paragraph behind. This allows users to empty
|
||||
* a footnote without deleting it. modelWriter is passed in to
|
||||
* batch these changes with the ones that instantiated them,
|
||||
* such that the set can be undone with a single action.
|
||||
*/
|
||||
private _clearContents;
|
||||
/**
|
||||
* Removes a footnote and its references, and renumbers subsequent footnotes. When a footnote's
|
||||
* id attribute changes, it's references automatically update from a dispatcher event in converters.js,
|
||||
* which triggers the `updateReferenceIds` method. modelWriter is passed in to batch these changes with
|
||||
* the ones that instantiated them, such that the set can be undone with a single action.
|
||||
*/
|
||||
private _removeFootnote;
|
||||
/**
|
||||
* Deletes all references to the footnote with the given id. If no id is provided,
|
||||
* all references are deleted. modelWriter is passed in to batch these changes with
|
||||
* the ones that instantiated them, such that the set can be undone with a single action.
|
||||
*/
|
||||
private _removeReferences;
|
||||
/**
|
||||
* Updates all references for a single footnote. This function is called when
|
||||
* the index attribute of an existing footnote changes, which happens when a footnote
|
||||
* with a lower index is deleted. batch is passed in to group these changes with
|
||||
* the ones that instantiated them.
|
||||
*/
|
||||
private _updateReferenceIndices;
|
||||
/**
|
||||
* Reindexes footnotes such that footnote references occur in order, and reorders
|
||||
* footnote items in the footer section accordingly. batch is passed in to group changes with
|
||||
* the ones that instantiated them.
|
||||
*/
|
||||
private _orderFootnotes;
|
||||
}
|
@ -1,252 +0,0 @@
|
||||
/**
|
||||
* CKEditor dataview nodes can be converted to a output view or an editor view via downcasting
|
||||
* * Upcasting is converting to the platonic ckeditor version.
|
||||
* * Downcasting is converting to the output version.
|
||||
*/
|
||||
import { Element } from 'ckeditor5/src/engine.js';
|
||||
import { Autoformat } from "@ckeditor/ckeditor5-autoformat";
|
||||
import { Plugin } from "ckeditor5/src/core.js";
|
||||
import { Widget } from 'ckeditor5/src/widget.js';
|
||||
import { viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget';
|
||||
import '../footnote.css';
|
||||
import { addFootnoteAutoformatting } from './auto-formatting.js';
|
||||
import { defineConverters } from './converters.js';
|
||||
import { defineSchema } from './schema.js';
|
||||
import { ATTRIBUTES, COMMANDS, ELEMENTS } from '../constants.js';
|
||||
import InsertFootnoteCommand from '../insert-footnote-command.js';
|
||||
import { modelQueryElement, modelQueryElementsAll } from '../utils.js';
|
||||
export default class FootnoteEditing extends Plugin {
|
||||
static get requires() {
|
||||
return [Widget, Autoformat];
|
||||
}
|
||||
/**
|
||||
* The root element of the document.
|
||||
*/
|
||||
get rootElement() {
|
||||
const rootElement = this.editor.model.document.getRoot();
|
||||
if (!rootElement) {
|
||||
throw new Error('Document has no rootElement element.');
|
||||
}
|
||||
return rootElement;
|
||||
}
|
||||
init() {
|
||||
defineSchema(this.editor.model.schema);
|
||||
defineConverters(this.editor);
|
||||
this.editor.commands.add(COMMANDS.insertFootnote, new InsertFootnoteCommand(this.editor));
|
||||
addFootnoteAutoformatting(this.editor, this.rootElement);
|
||||
this.editor.model.document.on('change:data', (eventInfo, batch) => {
|
||||
const eventSource = eventInfo.source;
|
||||
const diffItems = [...eventSource.differ.getChanges()];
|
||||
// If a footnote reference is inserted, ensure that footnote references remain ordered.
|
||||
if (diffItems.some(diffItem => diffItem.type === 'insert' && diffItem.name === ELEMENTS.footnoteReference)) {
|
||||
this._orderFootnotes(batch);
|
||||
}
|
||||
// for each change to a footnote item's index attribute, update the corresponding references accordingly
|
||||
diffItems.forEach(diffItem => {
|
||||
if (diffItem.type === 'attribute' && diffItem.attributeKey === ATTRIBUTES.footnoteIndex) {
|
||||
const { attributeNewValue: newFootnoteIndex } = diffItem;
|
||||
const footnote = [...diffItem.range.getItems()].find(item => item.is('element', ELEMENTS.footnoteItem));
|
||||
const footnoteId = footnote instanceof Element && footnote.getAttribute(ATTRIBUTES.footnoteId);
|
||||
if (!footnoteId) {
|
||||
return;
|
||||
}
|
||||
this._updateReferenceIndices(batch, `${footnoteId}`, newFootnoteIndex);
|
||||
}
|
||||
});
|
||||
}, { priority: 'high' });
|
||||
this._handleDelete();
|
||||
// The following callbacks are needed to map nonempty view elements
|
||||
// to empty model elements.
|
||||
// See https://ckeditor.com/docs/ckeditor5/latest/api/module_widget_utils.html#function-viewToModelPositionOutsideModelElement
|
||||
this.editor.editing.mapper.on('viewToModelPosition', viewToModelPositionOutsideModelElement(this.editor.model, viewElement => viewElement.hasAttribute(ATTRIBUTES.footnoteReference)));
|
||||
}
|
||||
/**
|
||||
* This method broadly deals with deletion of text and elements, and updating the model
|
||||
* accordingly. In particular, the following cases are handled:
|
||||
* 1. If the footnote section gets deleted, all footnote references are removed.
|
||||
* 2. If a delete operation happens in an empty footnote, the footnote is deleted.
|
||||
*/
|
||||
_handleDelete() {
|
||||
const viewDocument = this.editor.editing.view.document;
|
||||
const editor = this.editor;
|
||||
this.listenTo(viewDocument, 'delete', (evt, data) => {
|
||||
const doc = editor.model.document;
|
||||
const deletedElement = doc.selection.getSelectedElement();
|
||||
const selectionEndPos = doc.selection.getLastPosition();
|
||||
const selectionStartPos = doc.selection.getFirstPosition();
|
||||
if (!selectionEndPos || !selectionStartPos) {
|
||||
throw new Error('Selection must have at least one range to perform delete operation.');
|
||||
}
|
||||
this.editor.model.change(modelWriter => {
|
||||
// delete all footnote references if footnote section gets deleted
|
||||
if (deletedElement && deletedElement.is('element', ELEMENTS.footnoteSection)) {
|
||||
this._removeReferences(modelWriter);
|
||||
}
|
||||
const deletingFootnote = deletedElement && deletedElement.is('element', ELEMENTS.footnoteItem);
|
||||
const currentFootnote = deletingFootnote ?
|
||||
deletedElement :
|
||||
selectionEndPos.findAncestor(ELEMENTS.footnoteItem);
|
||||
if (!currentFootnote) {
|
||||
return;
|
||||
}
|
||||
const endParagraph = selectionEndPos.findAncestor('paragraph');
|
||||
const startParagraph = selectionStartPos.findAncestor('paragraph');
|
||||
const currentFootnoteContent = selectionEndPos.findAncestor(ELEMENTS.footnoteContent);
|
||||
if (!currentFootnoteContent || !startParagraph || !endParagraph) {
|
||||
return;
|
||||
}
|
||||
const footnoteIsEmpty = startParagraph.maxOffset === 0 && currentFootnoteContent.childCount === 1;
|
||||
if (deletingFootnote || footnoteIsEmpty) {
|
||||
this._removeFootnote(modelWriter, currentFootnote);
|
||||
data.preventDefault();
|
||||
evt.stop();
|
||||
}
|
||||
});
|
||||
}, { priority: 'high' });
|
||||
}
|
||||
/**
|
||||
* Clear the children of the provided footnoteContent element,
|
||||
* leaving an empty paragraph behind. This allows users to empty
|
||||
* a footnote without deleting it. modelWriter is passed in to
|
||||
* batch these changes with the ones that instantiated them,
|
||||
* such that the set can be undone with a single action.
|
||||
*/
|
||||
_clearContents(modelWriter, footnoteContent) {
|
||||
const contents = modelWriter.createRangeIn(footnoteContent);
|
||||
modelWriter.appendElement('paragraph', footnoteContent);
|
||||
modelWriter.remove(contents);
|
||||
}
|
||||
/**
|
||||
* Removes a footnote and its references, and renumbers subsequent footnotes. When a footnote's
|
||||
* id attribute changes, it's references automatically update from a dispatcher event in converters.js,
|
||||
* which triggers the `updateReferenceIds` method. modelWriter is passed in to batch these changes with
|
||||
* the ones that instantiated them, such that the set can be undone with a single action.
|
||||
*/
|
||||
_removeFootnote(modelWriter, footnote) {
|
||||
// delete the current footnote and its references,
|
||||
// and renumber subsequent footnotes.
|
||||
if (!this.editor) {
|
||||
return;
|
||||
}
|
||||
const footnoteSection = footnote.findAncestor(ELEMENTS.footnoteSection);
|
||||
if (!footnoteSection) {
|
||||
modelWriter.remove(footnote);
|
||||
return;
|
||||
}
|
||||
const index = footnoteSection.getChildIndex(footnote);
|
||||
const id = footnote.getAttribute(ATTRIBUTES.footnoteId);
|
||||
this._removeReferences(modelWriter, `${id}`);
|
||||
modelWriter.remove(footnote);
|
||||
// if no footnotes remain, remove the footnote section
|
||||
if (footnoteSection.childCount === 0) {
|
||||
modelWriter.remove(footnoteSection);
|
||||
this._removeReferences(modelWriter);
|
||||
}
|
||||
else {
|
||||
if (index == null) {
|
||||
throw new Error('Index is nullish');
|
||||
}
|
||||
// after footnote deletion the selection winds up surrounding the previous footnote
|
||||
// (or the following footnote if no previous footnote exists). Typing in that state
|
||||
// immediately deletes the footnote. This deliberately sets the new selection position
|
||||
// to avoid that.
|
||||
const neighborFootnote = index === 0 ? footnoteSection.getChild(index) : footnoteSection.getChild((index !== null && index !== void 0 ? index : 0) - 1);
|
||||
if (!(neighborFootnote instanceof Element)) {
|
||||
return;
|
||||
}
|
||||
const neighborEndParagraph = modelQueryElementsAll(this.editor, neighborFootnote, element => element.is('element', 'paragraph')).pop();
|
||||
if (neighborEndParagraph) {
|
||||
modelWriter.setSelection(neighborEndParagraph, 'end');
|
||||
}
|
||||
}
|
||||
if (index == null) {
|
||||
throw new Error('Index is nullish');
|
||||
}
|
||||
// renumber subsequent footnotes
|
||||
const subsequentFootnotes = [...footnoteSection.getChildren()].slice(index !== null && index !== void 0 ? index : 0);
|
||||
for (const [i, child] of subsequentFootnotes.entries()) {
|
||||
modelWriter.setAttribute(ATTRIBUTES.footnoteIndex, `${index !== null && index !== void 0 ? index : 0 + i + 1}`, child);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deletes all references to the footnote with the given id. If no id is provided,
|
||||
* all references are deleted. modelWriter is passed in to batch these changes with
|
||||
* the ones that instantiated them, such that the set can be undone with a single action.
|
||||
*/
|
||||
_removeReferences(modelWriter, footnoteId = undefined) {
|
||||
const removeList = [];
|
||||
if (!this.rootElement) {
|
||||
throw new Error('Document has no root element.');
|
||||
}
|
||||
const footnoteReferences = modelQueryElementsAll(this.editor, this.rootElement, e => e.is('element', ELEMENTS.footnoteReference));
|
||||
footnoteReferences.forEach(footnoteReference => {
|
||||
const id = footnoteReference.getAttribute(ATTRIBUTES.footnoteId);
|
||||
if (!footnoteId || id === footnoteId) {
|
||||
removeList.push(footnoteReference);
|
||||
}
|
||||
});
|
||||
for (const item of removeList) {
|
||||
modelWriter.remove(item);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Updates all references for a single footnote. This function is called when
|
||||
* the index attribute of an existing footnote changes, which happens when a footnote
|
||||
* with a lower index is deleted. batch is passed in to group these changes with
|
||||
* the ones that instantiated them.
|
||||
*/
|
||||
_updateReferenceIndices(batch, footnoteId, newFootnoteIndex) {
|
||||
const footnoteReferences = modelQueryElementsAll(this.editor, this.rootElement, e => e.is('element', ELEMENTS.footnoteReference) && e.getAttribute(ATTRIBUTES.footnoteId) === footnoteId);
|
||||
this.editor.model.enqueueChange(batch, writer => {
|
||||
footnoteReferences.forEach(footnoteReference => {
|
||||
writer.setAttribute(ATTRIBUTES.footnoteIndex, newFootnoteIndex, footnoteReference);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Reindexes footnotes such that footnote references occur in order, and reorders
|
||||
* footnote items in the footer section accordingly. batch is passed in to group changes with
|
||||
* the ones that instantiated them.
|
||||
*/
|
||||
_orderFootnotes(batch) {
|
||||
const footnoteReferences = modelQueryElementsAll(this.editor, this.rootElement, e => e.is('element', ELEMENTS.footnoteReference));
|
||||
const uniqueIds = new Set(footnoteReferences.map(e => e.getAttribute(ATTRIBUTES.footnoteId)));
|
||||
const orderedFootnotes = [...uniqueIds].map(id => modelQueryElement(this.editor, this.rootElement, e => e.is('element', ELEMENTS.footnoteItem) && e.getAttribute(ATTRIBUTES.footnoteId) === id));
|
||||
this.editor.model.enqueueChange(batch, writer => {
|
||||
var _a;
|
||||
const footnoteSection = modelQueryElement(this.editor, this.rootElement, e => e.is('element', ELEMENTS.footnoteSection));
|
||||
if (!footnoteSection) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* In order to keep footnotes with no existing references at the end of the list,
|
||||
* the loop below reverses the list of footnotes with references and inserts them
|
||||
* each at the beginning.
|
||||
*/
|
||||
for (const footnote of orderedFootnotes.reverse()) {
|
||||
if (footnote) {
|
||||
writer.move(writer.createRangeOn(footnote), footnoteSection, 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* once the list is sorted, make one final pass to update footnote indices.
|
||||
*/
|
||||
for (const footnote of modelQueryElementsAll(this.editor, footnoteSection, e => e.is('element', ELEMENTS.footnoteItem))) {
|
||||
const index = `${((_a = footnoteSection === null || footnoteSection === void 0 ? void 0 : footnoteSection.getChildIndex(footnote)) !== null && _a !== void 0 ? _a : -1) + 1}`;
|
||||
if (footnote) {
|
||||
writer.setAttribute(ATTRIBUTES.footnoteIndex, index, footnote);
|
||||
}
|
||||
const id = footnote.getAttribute(ATTRIBUTES.footnoteId);
|
||||
// /**
|
||||
// * unfortunately the following line seems to be necessary, even though updateReferenceIndices
|
||||
// * should fire from the attribute change immediately above. It seems that events initiated by
|
||||
// * a `change:data` event do not themselves fire another `change:data` event.
|
||||
// */
|
||||
if (id) {
|
||||
this._updateReferenceIndices(batch, `${id}`, `${index}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=footnote-editing.js.map
|
File diff suppressed because one or more lines are too long
@ -1,7 +0,0 @@
|
||||
import type { Schema } from 'ckeditor5/src/engine.js';
|
||||
/**
|
||||
* Declares the custom element types used by the footnotes plugin.
|
||||
* See here for the meanings of each rule:
|
||||
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_schema-SchemaItemDefinition.html#member-isObject
|
||||
*/
|
||||
export declare const defineSchema: (schema: Schema) => void;
|
@ -1,63 +0,0 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { ATTRIBUTES, ELEMENTS } from '../constants.js';
|
||||
/**
|
||||
* Declares the custom element types used by the footnotes plugin.
|
||||
* See here for the meanings of each rule:
|
||||
* https://ckeditor.com/docs/ckeditor5/latest/api/module_engine_model_schema-SchemaItemDefinition.html#member-isObject
|
||||
*/
|
||||
export const defineSchema = (schema) => {
|
||||
/**
|
||||
* Footnote section at the footer of the document.
|
||||
*/
|
||||
schema.register(ELEMENTS.footnoteSection, {
|
||||
isObject: true,
|
||||
allowWhere: '$block',
|
||||
allowIn: '$root',
|
||||
allowChildren: ELEMENTS.footnoteItem,
|
||||
allowAttributes: [ATTRIBUTES.footnoteSection]
|
||||
});
|
||||
/**
|
||||
* Individual footnote item within the footnote section.
|
||||
*/
|
||||
schema.register(ELEMENTS.footnoteItem, {
|
||||
isBlock: true,
|
||||
isObject: true,
|
||||
allowContentOf: '$root',
|
||||
allowAttributes: [ATTRIBUTES.footnoteSection, ATTRIBUTES.footnoteId, ATTRIBUTES.footnoteIndex]
|
||||
});
|
||||
/**
|
||||
* Editable footnote item content container.
|
||||
*/
|
||||
schema.register(ELEMENTS.footnoteContent, {
|
||||
allowIn: ELEMENTS.footnoteItem,
|
||||
allowContentOf: '$root',
|
||||
allowAttributes: [ATTRIBUTES.footnoteSection]
|
||||
});
|
||||
/**
|
||||
* Inline footnote citation, placed within the main text.
|
||||
*/
|
||||
schema.register(ELEMENTS.footnoteReference, {
|
||||
allowWhere: '$text',
|
||||
isInline: true,
|
||||
isObject: true,
|
||||
allowAttributes: [ATTRIBUTES.footnoteReference, ATTRIBUTES.footnoteId, ATTRIBUTES.footnoteIndex]
|
||||
});
|
||||
/**
|
||||
* return link which takes you from the footnote to the inline reference.
|
||||
*/
|
||||
schema.register(ELEMENTS.footnoteBackLink, {
|
||||
allowIn: ELEMENTS.footnoteItem,
|
||||
isInline: true,
|
||||
isSelectable: false,
|
||||
allowAttributes: [ATTRIBUTES.footnoteBackLink, ATTRIBUTES.footnoteId]
|
||||
});
|
||||
schema.addChildCheck((context, childDefinition) => {
|
||||
if (context.endsWith(ELEMENTS.footnoteContent) && childDefinition.name === ELEMENTS.footnoteSection) {
|
||||
return false;
|
||||
}
|
||||
if (context.endsWith(ELEMENTS.footnoteContent) && childDefinition.name === 'listItem') {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
//# sourceMappingURL=schema.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"schema.js","sourceRoot":"","sources":["schema.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAE,MAAc,EAAS,EAAE;IACtD;;KAEI;IACJ,MAAM,CAAC,QAAQ,CAAE,QAAQ,CAAC,eAAe,EAAE;QAC1C,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,QAAQ;QACpB,OAAO,EAAE,OAAO;QAChB,aAAa,EAAE,QAAQ,CAAC,YAAY;QACpC,eAAe,EAAE,CAAE,UAAU,CAAC,eAAe,CAAE;KAC/C,CAAE,CAAC;IAEJ;;KAEI;IACJ,MAAM,CAAC,QAAQ,CAAE,QAAQ,CAAC,YAAY,EAAE;QACvC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,cAAc,EAAE,OAAO;QACvB,eAAe,EAAE,CAAE,UAAU,CAAC,eAAe,EAAE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,aAAa,CAAE;KAChG,CAAE,CAAC;IAEJ;;KAEI;IACJ,MAAM,CAAC,QAAQ,CAAE,QAAQ,CAAC,eAAe,EAAE;QAC1C,OAAO,EAAE,QAAQ,CAAC,YAAY;QAC9B,cAAc,EAAE,OAAO;QACvB,eAAe,EAAE,CAAE,UAAU,CAAC,eAAe,CAAE;KAC/C,CAAE,CAAC;IAEJ;;KAEI;IACJ,MAAM,CAAC,QAAQ,CAAE,QAAQ,CAAC,iBAAiB,EAAE;QAC5C,UAAU,EAAE,OAAO;QACnB,QAAQ,EAAE,IAAI;QACd,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,CAAE,UAAU,CAAC,iBAAiB,EAAE,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,aAAa,CAAE;KAClG,CAAE,CAAC;IAEJ;;KAEI;IACJ,MAAM,CAAC,QAAQ,CAAE,QAAQ,CAAC,gBAAgB,EAAE;QAC3C,OAAO,EAAE,QAAQ,CAAC,YAAY;QAC9B,QAAQ,EAAE,IAAI;QACd,YAAY,EAAE,KAAK;QACnB,eAAe,EAAE,CAAE,UAAU,CAAC,gBAAgB,EAAE,UAAU,CAAC,UAAU,CAAE;KACvE,CAAE,CAAC;IAEJ,MAAM,CAAC,aAAa,CAAE,CAAE,OAAO,EAAE,eAAe,EAAG,EAAE;QACpD,IAAK,OAAO,CAAC,QAAQ,CAAE,QAAQ,CAAC,eAAe,CAAE,IAAI,eAAe,CAAC,IAAI,KAAK,QAAQ,CAAC,eAAe,EAAG;YACxG,OAAO,KAAK,CAAC;SACb;QACD,IAAK,OAAO,CAAC,QAAQ,CAAE,QAAQ,CAAC,eAAe,CAAE,IAAI,eAAe,CAAC,IAAI,KAAK,UAAU,EAAG;YAC1F,OAAO,KAAK,CAAC;SACb;IACF,CAAC,CAAE,CAAC;AACL,CAAC,CAAC"}
|
@ -1,7 +0,0 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import { type ListDropdownItemDefinition } from '@ckeditor/ckeditor5-ui';
|
||||
import { Collection } from '@ckeditor/ckeditor5-utils';
|
||||
export default class FootnoteUI extends Plugin {
|
||||
init(): void;
|
||||
getDropdownItemsDefinitions(): Collection<ListDropdownItemDefinition>;
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import { addListToDropdown, createDropdown, SplitButtonView, ViewModel } from '@ckeditor/ckeditor5-ui';
|
||||
import { Collection } from '@ckeditor/ckeditor5-utils';
|
||||
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 {
|
||||
init() {
|
||||
const editor = this.editor;
|
||||
const translate = editor.t;
|
||||
editor.ui.componentFactory.add(TOOLBAR_COMPONENT_NAME, locale => {
|
||||
const dropdownView = createDropdown(locale, SplitButtonView);
|
||||
const splitButtonView = dropdownView.buttonView;
|
||||
// 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.');
|
||||
}
|
||||
splitButtonView.set({
|
||||
label: translate('Footnote'),
|
||||
icon: insertFootnoteIcon,
|
||||
tooltip: true,
|
||||
isToggleable: true
|
||||
});
|
||||
splitButtonView.bind('isOn').to(command, 'value', value => !!value);
|
||||
splitButtonView.on('execute', () => {
|
||||
editor.execute(COMMANDS.insertFootnote, {
|
||||
footnoteIndex: 0
|
||||
});
|
||||
editor.editing.view.focus();
|
||||
});
|
||||
dropdownView.class = 'ck-code-block-dropdown';
|
||||
dropdownView.bind('isEnabled').to(command);
|
||||
dropdownView.on('change:isOpen', (evt, propertyName, newValue) => {
|
||||
var _a, _b, _c;
|
||||
(_a = dropdownView === null || dropdownView === void 0 ? void 0 : dropdownView.listView) === null || _a === void 0 ? void 0 : _a.items.clear();
|
||||
if (newValue) {
|
||||
addListToDropdown(dropdownView, this.getDropdownItemsDefinitions());
|
||||
}
|
||||
else {
|
||||
(_b = dropdownView === null || dropdownView === void 0 ? void 0 : dropdownView.listView) === null || _b === void 0 ? void 0 : _b.items.clear();
|
||||
const listElement = (_c = dropdownView === null || dropdownView === void 0 ? void 0 : dropdownView.listView) === null || _c === void 0 ? void 0 : _c.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.commandParam
|
||||
});
|
||||
editor.editing.view.focus();
|
||||
});
|
||||
return dropdownView;
|
||||
});
|
||||
}
|
||||
getDropdownItemsDefinitions() {
|
||||
const itemDefinitions = new Collection();
|
||||
const defaultDef = {
|
||||
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 = {
|
||||
type: 'button',
|
||||
model: new ViewModel({
|
||||
commandParam: index,
|
||||
label: `Insert footnote ${index}`,
|
||||
withText: true
|
||||
})
|
||||
};
|
||||
itemDefinitions.add(definition);
|
||||
});
|
||||
}
|
||||
return itemDefinitions;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=footnote-ui.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"footnote-ui.js","sourceRoot":"","sources":["footnote-ui.ts"],"names":[],"mappings":"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"}
|
@ -1,7 +0,0 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import FootnoteEditing from './footnote-editing/footnote-editing.js';
|
||||
import FootnoteUI from './footnote-ui.js';
|
||||
export default class Footnotes extends Plugin {
|
||||
static get pluginName(): "Footnotes";
|
||||
static get requires(): readonly [typeof FootnoteEditing, typeof FootnoteUI];
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import FootnoteEditing from './footnote-editing/footnote-editing.js';
|
||||
import FootnoteUI from './footnote-ui.js';
|
||||
export default class Footnotes extends Plugin {
|
||||
static get pluginName() {
|
||||
return 'Footnotes';
|
||||
}
|
||||
static get requires() {
|
||||
return [FootnoteEditing, FootnoteUI];
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=footnotes.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"footnotes.js","sourceRoot":"","sources":["footnotes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE/C,OAAO,eAAe,MAAM,wCAAwC,CAAC;AACrE,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAE1C,MAAM,CAAC,OAAO,OAAO,SAAU,SAAQ,MAAM;IACrC,MAAM,KAAK,UAAU;QAC3B,OAAO,WAAoB,CAAC;IAC7B,CAAC;IAEM,MAAM,KAAK,QAAQ;QACzB,OAAO,CAAE,eAAe,EAAE,UAAU,CAAW,CAAC;IACjD,CAAC;CACD"}
|
@ -1,14 +0,0 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
|
||||
import FootnoteEditing from './footnote-editing/footnote-editing.js';
|
||||
import FootnoteUI from './footnote-ui.js';
|
||||
|
||||
export default class Footnotes extends Plugin {
|
||||
public static get pluginName() {
|
||||
return 'Footnotes' as const;
|
||||
}
|
||||
|
||||
public static get requires() {
|
||||
return [ FootnoteEditing, FootnoteUI ] as const;
|
||||
}
|
||||
}
|
5
_regroup/ckeditor5-footnotes/src/index.d.ts
vendored
5
_regroup/ckeditor5-footnotes/src/index.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
import './augmentation.js';
|
||||
export { default as Footnotes } from './footnotes.js';
|
||||
export declare const icons: {
|
||||
insertFootnoteIcon: string;
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
import insertFootnoteIcon from './../theme/icons/insert-footnote.svg';
|
||||
import './augmentation.js';
|
||||
export { default as Footnotes } from './footnotes.js';
|
||||
export const icons = {
|
||||
insertFootnoteIcon
|
||||
};
|
||||
//# sourceMappingURL=index.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,sCAAsC,CAAC;AACtE,OAAO,mBAAmB,CAAC;AAE3B,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,CAAC,MAAM,KAAK,GAAG;IACpB,kBAAkB;CAClB,CAAC"}
|
@ -1,8 +0,0 @@
|
||||
import insertFootnoteIcon from './../theme/icons/insert-footnote.svg';
|
||||
import './augmentation.js';
|
||||
|
||||
export { default as Footnotes } from './footnotes.js';
|
||||
|
||||
export const icons = {
|
||||
insertFootnoteIcon
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
export default class InsertFootnoteCommand extends Command {
|
||||
/**
|
||||
* Creates a footnote reference with the given index, and creates a matching
|
||||
* footnote if one doesn't already exist. Also creates the footnote section
|
||||
* if it doesn't exist. If `footnoteIndex` is 0 (or not provided), the added
|
||||
* footnote is given the next unused index--e.g. 7, if 6 footnotes exist so far.
|
||||
*/
|
||||
execute({ footnoteIndex }?: {
|
||||
footnoteIndex?: number;
|
||||
}): void;
|
||||
/**
|
||||
* Called automatically when changes are applied to the document. Sets `isEnabled`
|
||||
* to determine whether footnote creation is allowed at the current location.
|
||||
*/
|
||||
refresh(): void;
|
||||
/**
|
||||
* Returns the footnote section if it exists, or creates on if it doesn't.
|
||||
*/
|
||||
private _getFootnoteSection;
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
import { ATTRIBUTES, ELEMENTS } from './constants.js';
|
||||
import { modelQueryElement } from './utils.js';
|
||||
export default class InsertFootnoteCommand extends Command {
|
||||
/**
|
||||
* Creates a footnote reference with the given index, and creates a matching
|
||||
* footnote if one doesn't already exist. Also creates the footnote section
|
||||
* if it doesn't exist. If `footnoteIndex` is 0 (or not provided), the added
|
||||
* footnote is given the next unused index--e.g. 7, if 6 footnotes exist so far.
|
||||
*/
|
||||
execute({ footnoteIndex } = { footnoteIndex: 0 }) {
|
||||
this.editor.model.enqueueChange(modelWriter => {
|
||||
const doc = this.editor.model.document;
|
||||
const rootElement = doc.getRoot();
|
||||
if (!rootElement) {
|
||||
return;
|
||||
}
|
||||
const footnoteSection = this._getFootnoteSection(modelWriter, rootElement);
|
||||
let index = undefined;
|
||||
let id = undefined;
|
||||
if (footnoteIndex === 0) {
|
||||
index = `${footnoteSection.maxOffset + 1}`;
|
||||
id = Math.random().toString(36).slice(2);
|
||||
}
|
||||
else {
|
||||
index = `${footnoteIndex}`;
|
||||
const matchingFootnote = modelQueryElement(this.editor, footnoteSection, element => element.is('element', ELEMENTS.footnoteItem) && element.getAttribute(ATTRIBUTES.footnoteIndex) === index);
|
||||
if (matchingFootnote) {
|
||||
id = matchingFootnote.getAttribute(ATTRIBUTES.footnoteId);
|
||||
}
|
||||
}
|
||||
if (!id || !index) {
|
||||
return;
|
||||
}
|
||||
modelWriter.setSelection(doc.selection.getLastPosition());
|
||||
const footnoteReference = modelWriter.createElement(ELEMENTS.footnoteReference, {
|
||||
[ATTRIBUTES.footnoteId]: id,
|
||||
[ATTRIBUTES.footnoteIndex]: index
|
||||
});
|
||||
this.editor.model.insertContent(footnoteReference);
|
||||
modelWriter.setSelection(footnoteReference, 'after');
|
||||
// if referencing an existing footnote
|
||||
if (footnoteIndex !== 0) {
|
||||
return;
|
||||
}
|
||||
const footnoteContent = modelWriter.createElement(ELEMENTS.footnoteContent);
|
||||
const footnoteItem = modelWriter.createElement(ELEMENTS.footnoteItem, {
|
||||
[ATTRIBUTES.footnoteId]: id,
|
||||
[ATTRIBUTES.footnoteIndex]: index
|
||||
});
|
||||
const footnoteBackLink = modelWriter.createElement(ELEMENTS.footnoteBackLink, { [ATTRIBUTES.footnoteId]: id });
|
||||
const p = modelWriter.createElement('paragraph');
|
||||
modelWriter.append(p, footnoteContent);
|
||||
modelWriter.append(footnoteContent, footnoteItem);
|
||||
modelWriter.insert(footnoteBackLink, footnoteItem, 0);
|
||||
this.editor.model.insertContent(footnoteItem, modelWriter.createPositionAt(footnoteSection, footnoteSection.maxOffset));
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Called automatically when changes are applied to the document. Sets `isEnabled`
|
||||
* to determine whether footnote creation is allowed at the current location.
|
||||
*/
|
||||
refresh() {
|
||||
const model = this.editor.model;
|
||||
const lastPosition = model.document.selection.getLastPosition();
|
||||
const allowedIn = lastPosition && model.schema.findAllowedParent(lastPosition, ELEMENTS.footnoteReference);
|
||||
this.isEnabled = allowedIn !== null;
|
||||
}
|
||||
/**
|
||||
* Returns the footnote section if it exists, or creates on if it doesn't.
|
||||
*/
|
||||
_getFootnoteSection(writer, rootElement) {
|
||||
const footnoteSection = modelQueryElement(this.editor, rootElement, element => element.is('element', ELEMENTS.footnoteSection));
|
||||
if (footnoteSection) {
|
||||
return footnoteSection;
|
||||
}
|
||||
const newFootnoteSection = writer.createElement(ELEMENTS.footnoteSection);
|
||||
this.editor.model.insertContent(newFootnoteSection, writer.createPositionAt(rootElement, rootElement.maxOffset));
|
||||
return newFootnoteSection;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=insert-footnote-command.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"insert-footnote-command.js","sourceRoot":"","sources":["insert-footnote-command.ts"],"names":[],"mappings":"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"}
|
27
_regroup/ckeditor5-footnotes/src/utils.d.ts
vendored
27
_regroup/ckeditor5-footnotes/src/utils.d.ts
vendored
@ -1,27 +0,0 @@
|
||||
import { type Editor } from 'ckeditor5/src/core.js';
|
||||
import { Element, Text, TextProxy, ViewElement } from 'ckeditor5/src/engine.js';
|
||||
/**
|
||||
* Returns an array of all descendant elements of
|
||||
* the root for which the provided predicate returns true.
|
||||
*/
|
||||
export declare const modelQueryElementsAll: (editor: Editor, rootElement: Element, predicate?: (item: Element) => boolean) => Array<Element>;
|
||||
/**
|
||||
* Returns an array of all descendant text nodes and text proxies of
|
||||
* the root for which the provided predicate returns true.
|
||||
*/
|
||||
export declare const modelQueryTextAll: (editor: Editor, rootElement: Element, predicate?: (item: Text | TextProxy) => boolean) => Array<Text | TextProxy>;
|
||||
/**
|
||||
* Returns the first descendant element of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export declare const modelQueryElement: (editor: Editor, rootElement: Element, predicate?: (item: Element) => boolean) => Element | null;
|
||||
/**
|
||||
* Returns the first descendant text node or text proxy of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export declare const modelQueryText: (editor: Editor, rootElement: Element, predicate?: (item: Text | TextProxy) => boolean) => Text | TextProxy | null;
|
||||
/**
|
||||
* Returns the first descendant element of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export declare const viewQueryElement: (editor: Editor, rootElement: ViewElement, predicate?: (item: ViewElement) => boolean) => ViewElement | null;
|
@ -1,88 +0,0 @@
|
||||
import { Element, Text, TextProxy, ViewElement } from 'ckeditor5/src/engine.js';
|
||||
// There's ample DRY violation in this file; type checking
|
||||
// polymorphism without full typescript is just incredibly finicky.
|
||||
// I (Jonathan) suspect there's a more elegant solution for this,
|
||||
// but I tried a lot of things and none of them worked.
|
||||
/**
|
||||
* Returns an array of all descendant elements of
|
||||
* the root for which the provided predicate returns true.
|
||||
*/
|
||||
export const modelQueryElementsAll = (editor, rootElement, predicate = _ => true) => {
|
||||
const range = editor.model.createRangeIn(rootElement);
|
||||
const output = [];
|
||||
for (const item of range.getItems()) {
|
||||
if (!(item instanceof Element)) {
|
||||
continue;
|
||||
}
|
||||
if (predicate(item)) {
|
||||
output.push(item);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
/**
|
||||
* Returns an array of all descendant text nodes and text proxies of
|
||||
* the root for which the provided predicate returns true.
|
||||
*/
|
||||
export const modelQueryTextAll = (editor, rootElement, predicate = _ => true) => {
|
||||
const range = editor.model.createRangeIn(rootElement);
|
||||
const output = [];
|
||||
for (const item of range.getItems()) {
|
||||
if (!(item instanceof Text || item instanceof TextProxy)) {
|
||||
continue;
|
||||
}
|
||||
if (predicate(item)) {
|
||||
output.push(item);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
/**
|
||||
* Returns the first descendant element of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export const modelQueryElement = (editor, rootElement, predicate = _ => true) => {
|
||||
const range = editor.model.createRangeIn(rootElement);
|
||||
for (const item of range.getItems()) {
|
||||
if (!(item instanceof Element)) {
|
||||
continue;
|
||||
}
|
||||
if (predicate(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
/**
|
||||
* Returns the first descendant text node or text proxy of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export const modelQueryText = (editor, rootElement, predicate = _ => true) => {
|
||||
const range = editor.model.createRangeIn(rootElement);
|
||||
for (const item of range.getItems()) {
|
||||
if (!(item instanceof Text || item instanceof TextProxy)) {
|
||||
continue;
|
||||
}
|
||||
if (predicate(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
/**
|
||||
* Returns the first descendant element of the root for which the provided
|
||||
* predicate returns true, or null if no such element is found.
|
||||
*/
|
||||
export const viewQueryElement = (editor, rootElement, predicate = _ => true) => {
|
||||
const range = editor.editing.view.createRangeIn(rootElement);
|
||||
for (const item of range.getItems()) {
|
||||
if (!(item instanceof ViewElement)) {
|
||||
continue;
|
||||
}
|
||||
if (predicate(item)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
//# sourceMappingURL=utils.js.map
|
@ -1 +0,0 @@
|
||||
{"version":3,"file":"utils.js","sourceRoot":"","sources":["utils.ts"],"names":[],"mappings":"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"}
|
@ -1,7 +0,0 @@
|
||||
declare module '@ckeditor/ckeditor5-inspector' {
|
||||
const inspector: {
|
||||
attach( editor: any ): void;
|
||||
};
|
||||
|
||||
export default inspector;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
import { type Editor } from 'ckeditor5/src/core.js';
|
||||
import { Text, TextProxy, type Element, type Range } from 'ckeditor5/src/engine.js';
|
||||
import { type Autoformat, inlineAutoformatEditing } from "@ckeditor/ckeditor5-autoformat";
|
||||
import { type Editor, Text, TextProxy, type Element, type Range, type Autoformat, inlineAutoformatEditing } from 'ckeditor5';
|
||||
|
||||
import { COMMANDS, ELEMENTS } from '../constants.js';
|
||||
import { modelQueryElement, modelQueryElementsAll } from '../utils.js';
|
@ -1,6 +1,4 @@
|
||||
import { type Editor, } from 'ckeditor5/src/core.js';
|
||||
import { type DowncastConversionApi, type ViewContainerElement, Element } from "ckeditor5/src/engine.js";
|
||||
import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget.js';
|
||||
import { type Editor, type DowncastConversionApi, type ViewContainerElement, Element, toWidget, toWidgetEditable } from 'ckeditor5';
|
||||
|
||||
import { ATTRIBUTES, CLASSES, ELEMENTS } from '../constants.js';
|
||||
import { viewQueryElement } from '../utils.js';
|
@ -4,22 +4,6 @@
|
||||
* * Downcasting is converting to the output version.
|
||||
*/
|
||||
|
||||
import {
|
||||
Element,
|
||||
type Batch,
|
||||
type RootElement,
|
||||
type Writer
|
||||
} from 'ckeditor5/src/engine.js';
|
||||
|
||||
import { Autoformat } from "@ckeditor/ckeditor5-autoformat";
|
||||
import { Plugin } from "ckeditor5/src/core.js";
|
||||
import { Widget } from 'ckeditor5/src/widget.js';
|
||||
import { viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget';
|
||||
|
||||
import { type ViewElement } from "ckeditor5/src/engine.js";
|
||||
|
||||
import '../footnote.css';
|
||||
|
||||
import { addFootnoteAutoformatting } from './auto-formatting.js';
|
||||
import { defineConverters } from './converters.js';
|
||||
import { defineSchema } from './schema.js';
|
||||
@ -27,6 +11,7 @@ import { defineSchema } from './schema.js';
|
||||
import { ATTRIBUTES, COMMANDS, ELEMENTS } from '../constants.js';
|
||||
import InsertFootnoteCommand from '../insert-footnote-command.js';
|
||||
import { modelQueryElement, modelQueryElementsAll } from '../utils.js';
|
||||
import { Autoformat, Batch, Element, Plugin, RootElement, viewToModelPositionOutsideModelElement, Widget, Writer } from 'ckeditor5';
|
||||
|
||||
export default class FootnoteEditing extends Plugin {
|
||||
public static get requires() {
|
@ -1,6 +1,5 @@
|
||||
import type { Schema } from 'ckeditor5/src/engine.js';
|
||||
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { Schema } from 'ckeditor5';
|
||||
import { ATTRIBUTES, ELEMENTS } from '../constants.js';
|
||||
|
||||
/**
|
@ -1,6 +1,4 @@
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import { addListToDropdown, createDropdown, SplitButtonView, ViewModel, type ListDropdownItemDefinition } from '@ckeditor/ckeditor5-ui';
|
||||
import { Collection } from '@ckeditor/ckeditor5-utils';
|
||||
import { Plugin, addListToDropdown, createDropdown, SplitButtonView, ViewModel, type ListDropdownItemDefinition, Collection } from 'ckeditor5';
|
||||
|
||||
import {
|
||||
ATTRIBUTES,
|
@ -1,39 +1,13 @@
|
||||
import { Plugin, ButtonView } from 'ckeditor5';
|
||||
|
||||
import ckeditor5Icon from '../theme/icons/ckeditor.svg';
|
||||
import { Plugin } from 'ckeditor5';
|
||||
import FootnoteEditing from './footnote-editing/footnote-editing.js';
|
||||
import FootnoteUI from './footnote-ui.js';
|
||||
|
||||
export default class Footnotes extends Plugin {
|
||||
public static get pluginName() {
|
||||
return 'Footnotes' as const;
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
const editor = this.editor;
|
||||
const t = editor.t;
|
||||
const model = editor.model;
|
||||
|
||||
// Register the "footnotes" button, so it can be displayed in the toolbar.
|
||||
editor.ui.componentFactory.add( 'footnotes', locale => {
|
||||
const view = new ButtonView( locale );
|
||||
|
||||
view.set( {
|
||||
label: t( 'Footnotes' ),
|
||||
icon: ckeditor5Icon,
|
||||
tooltip: true
|
||||
} );
|
||||
|
||||
// Insert a text into the editor after clicking the button.
|
||||
this.listenTo( view, 'execute', () => {
|
||||
model.change( writer => {
|
||||
const textNode = writer.createText( 'Hello CKEditor 5!' );
|
||||
|
||||
model.insertContent( textNode );
|
||||
} );
|
||||
|
||||
editor.editing.view.focus();
|
||||
} );
|
||||
|
||||
return view;
|
||||
} );
|
||||
public static get requires() {
|
||||
return [ FootnoteEditing, FootnoteUI ] as const;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import ckeditor from './../theme/icons/ckeditor.svg';
|
||||
import insertFootnoteIcon from './../theme/icons/insert-footnote.svg';
|
||||
import './augmentation.js';
|
||||
import "../theme/footnote.css";
|
||||
|
||||
export { default as Footnotes } from './footnotes.js';
|
||||
|
||||
export const icons = {
|
||||
ckeditor
|
||||
insertFootnoteIcon
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
import { type Element, type RootElement, type Writer } from "ckeditor5/src/engine.js";
|
||||
import { Command, type Element, type RootElement, type Writer } from "ckeditor5";
|
||||
|
||||
import { ATTRIBUTES, ELEMENTS } from './constants.js';
|
||||
import { modelQueryElement } from './utils.js';
|
@ -1 +0,0 @@
|
||||
<svg width='68' height='64' viewBox='0 0 68 64' xmlns='http://www.w3.org/2000/svg'><g fill='none' fill-rule='evenodd'><path d='M43.71 11.025a11.508 11.508 0 0 0-1.213 5.159c0 6.42 5.244 11.625 11.713 11.625.083 0 .167 0 .25-.002v16.282a5.464 5.464 0 0 1-2.756 4.739L30.986 60.7a5.548 5.548 0 0 1-5.512 0L4.756 48.828A5.464 5.464 0 0 1 2 44.089V20.344c0-1.955 1.05-3.76 2.756-4.738L25.474 3.733a5.548 5.548 0 0 1 5.512 0l12.724 7.292z' fill='#FFF'/><path d='M45.684 8.79a12.604 12.604 0 0 0-1.329 5.65c0 7.032 5.744 12.733 12.829 12.733.091 0 .183-.001.274-.003v17.834a5.987 5.987 0 0 1-3.019 5.19L31.747 63.196a6.076 6.076 0 0 1-6.037 0L3.02 50.193A5.984 5.984 0 0 1 0 45.003V18.997c0-2.14 1.15-4.119 3.019-5.19L25.71.804a6.076 6.076 0 0 1 6.037 0L45.684 8.79zm-29.44 11.89c-.834 0-1.51.671-1.51 1.498v.715c0 .828.676 1.498 1.51 1.498h25.489c.833 0 1.51-.67 1.51-1.498v-.715c0-.827-.677-1.498-1.51-1.498h-25.49.001zm0 9.227c-.834 0-1.51.671-1.51 1.498v.715c0 .828.676 1.498 1.51 1.498h18.479c.833 0 1.509-.67 1.509-1.498v-.715c0-.827-.676-1.498-1.51-1.498H16.244zm0 9.227c-.834 0-1.51.671-1.51 1.498v.715c0 .828.676 1.498 1.51 1.498h25.489c.833 0 1.51-.67 1.51-1.498v-.715c0-.827-.677-1.498-1.51-1.498h-25.49.001zm41.191-14.459c-5.835 0-10.565-4.695-10.565-10.486 0-5.792 4.73-10.487 10.565-10.487C63.27 3.703 68 8.398 68 14.19c0 5.791-4.73 10.486-10.565 10.486v-.001z' fill='#1EBC61' fill-rule='nonzero'/><path d='M60.857 15.995c0-.467-.084-.875-.251-1.225a2.547 2.547 0 0 0-.686-.88 2.888 2.888 0 0 0-1.026-.531 4.418 4.418 0 0 0-1.259-.175c-.134 0-.283.006-.447.018-.15.01-.3.034-.446.07l.075-1.4h3.587v-1.8h-5.462l-.214 5.06c.319-.116.682-.21 1.089-.28.406-.071.77-.107 1.088-.107.218 0 .437.021.655.063.218.041.413.114.585.218s.313.244.422.419c.109.175.163.391.163.65 0 .424-.132.745-.396.961a1.434 1.434 0 0 1-.938.325c-.352 0-.656-.1-.912-.3-.256-.2-.43-.453-.523-.762l-1.925.588c.1.35.258.664.472.943.214.279.47.514.767.706.298.191.63.339.995.443.365.104.749.156 1.151.156.437 0 .86-.064 1.272-.193.41-.13.778-.323 1.1-.581a2.8 2.8 0 0 0 .775-.981c.193-.396.29-.864.29-1.405h-.001z' fill='#FFF' fill-rule='nonzero'/></g></svg>
|
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 384 B After Width: | Height: | Size: 384 B |
Loading…
x
Reference in New Issue
Block a user