chore(ckeditor5-mermaid): port source code
@ -30,8 +30,7 @@
|
||||
"ckeditor5-metadata.json"
|
||||
],
|
||||
"dependencies": {
|
||||
"ckeditor5": "43.2.0",
|
||||
"lodash-es": "^4.17.15"
|
||||
"ckeditor5": "43.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ckeditor/ckeditor5-dev-build-tools": "^42.0.0",
|
||||
|
@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @module mermaid
|
||||
*/
|
||||
|
||||
import infoIcon from './../theme/icons/info.svg';
|
||||
import insertMermaidIcon from './../theme/icons/insert.svg';
|
||||
import previewModeIcon from './../theme/icons/preview-mode.svg';
|
||||
import splitModeIcon from './../theme/icons/split-mode.svg';
|
||||
import sourceModeIcon from './../theme/icons/source-mode.svg';
|
||||
|
||||
export { default as Mermaid } from './mermaid.js';
|
||||
|
||||
export const icons = {
|
||||
infoIcon,
|
||||
insertMermaidIcon,
|
||||
previewModeIcon,
|
||||
splitModeIcon,
|
||||
sourceModeIcon
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* @module mermaid/mermaid
|
||||
*/
|
||||
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
|
||||
import MermaidEditing from './mermaidediting.js';
|
||||
import MermaidToolbar from './mermaidtoolbar.js';
|
||||
import MermaidUI from './mermaidui.js';
|
||||
|
||||
import '../theme/mermaid.css';
|
||||
|
||||
export default class Mermaid extends Plugin {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static get requires() {
|
||||
return [ MermaidEditing, MermaidToolbar, MermaidUI ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static get pluginName() {
|
||||
return 'Mermaid';
|
||||
}
|
||||
}
|
@ -85,5 +85,9 @@
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"lodash-es": "^4.17.21"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,25 @@
|
||||
import type { Mermaid } from './index.js';
|
||||
import MermaidEditing from './mermaidediting.js';
|
||||
import MermaidToolbar from './mermaidtoolbar.js';
|
||||
import MermaidUI from './mermaidui.js';
|
||||
|
||||
declare module 'ckeditor5' {
|
||||
interface PluginsMap {
|
||||
[ Mermaid.pluginName ]: Mermaid;
|
||||
[ MermaidEditing.pluginName ]: MermaidEditing;
|
||||
[ MermaidToolbar.pluginName ]: MermaidToolbar;
|
||||
[ MermaidUI.pluginName]: MermaidUI;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Mermaid {
|
||||
init(config: MermaidConfig, element: HTMLElement): void;
|
||||
}
|
||||
|
||||
interface MermaidConfig {
|
||||
|
||||
}
|
||||
|
||||
var mermaid: Mermaid | null | undefined;
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
/**
|
||||
* @module mermaid/insertmermaidcommand
|
||||
*/
|
||||
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
import { Command } from "ckeditor5";
|
||||
|
||||
const MOCK_MERMAID_MARKUP = `flowchart TB
|
||||
A --> B
|
||||
@ -12,14 +8,10 @@ B --> C`;
|
||||
* The insert mermaid command.
|
||||
*
|
||||
* Allows to insert mermaid.
|
||||
*
|
||||
* @extends module:core/command~Command
|
||||
*/
|
||||
export default class InsertMermaidCommand extends Command {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
refresh() {
|
||||
|
||||
override refresh() {
|
||||
const documentSelection = this.editor.model.document.selection;
|
||||
const selectedElement = documentSelection.getSelectedElement();
|
||||
|
||||
@ -30,10 +22,7 @@ export default class InsertMermaidCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
execute() {
|
||||
override execute() {
|
||||
const editor = this.editor;
|
||||
const model = editor.model;
|
||||
let mermaidItem;
|
@ -1,29 +1,22 @@
|
||||
/**
|
||||
* @module mermaid/mermaidpreviewcommand
|
||||
*/
|
||||
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
|
||||
import { checkIsOn } from '../utils.js';
|
||||
import { Element } from 'ckeditor5';
|
||||
|
||||
/**
|
||||
* The mermaid preview command.
|
||||
*
|
||||
* Allows to switch to a preview mode.
|
||||
*
|
||||
* @extends module:core/command~Command
|
||||
*/
|
||||
export default class MermaidPreviewCommand extends Command {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
refresh() {
|
||||
|
||||
override refresh() {
|
||||
const editor = this.editor;
|
||||
const documentSelection = editor.model.document.selection;
|
||||
const selectedElement = documentSelection.getSelectedElement();
|
||||
const isSelectedElementMermaid = selectedElement && selectedElement.name === 'mermaid';
|
||||
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition().findAncestor( 'mermaid' ) ) {
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition()?.findAncestor( 'mermaid' ) ) {
|
||||
this.isEnabled = !!selectedElement;
|
||||
} else {
|
||||
this.isEnabled = false;
|
||||
@ -32,19 +25,18 @@ export default class MermaidPreviewCommand extends Command {
|
||||
this.value = checkIsOn( editor, 'preview' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
execute() {
|
||||
override execute() {
|
||||
const editor = this.editor;
|
||||
const model = editor.model;
|
||||
const documentSelection = this.editor.model.document.selection;
|
||||
const mermaidItem = documentSelection.getSelectedElement() || documentSelection.getLastPosition().parent;
|
||||
const mermaidItem = (documentSelection.getSelectedElement() || documentSelection.getLastPosition()?.parent) as Element;
|
||||
|
||||
model.change( writer => {
|
||||
if ( mermaidItem.getAttribute( 'displayMode' ) !== 'preview' ) {
|
||||
writer.setAttribute( 'displayMode', 'preview', mermaidItem );
|
||||
}
|
||||
} );
|
||||
if (mermaidItem) {
|
||||
model.change( writer => {
|
||||
if ( mermaidItem.getAttribute( 'displayMode' ) !== 'preview' ) {
|
||||
writer.setAttribute( 'displayMode', 'preview', mermaidItem );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,7 @@
|
||||
/**
|
||||
* @module mermaid/mermaidsourceviewcommand
|
||||
*/
|
||||
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
|
||||
import { checkIsOn } from '../utils.js';
|
||||
import { Element } from 'ckeditor5';
|
||||
|
||||
/**
|
||||
* The mermaid source view command.
|
||||
@ -14,16 +11,14 @@ import { checkIsOn } from '../utils.js';
|
||||
* @extends module:core/command~Command
|
||||
*/
|
||||
export default class MermaidSourceViewCommand extends Command {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
refresh() {
|
||||
|
||||
override refresh() {
|
||||
const editor = this.editor;
|
||||
const documentSelection = editor.model.document.selection;
|
||||
const selectedElement = documentSelection.getSelectedElement();
|
||||
const isSelectedElementMermaid = selectedElement && selectedElement.name === 'mermaid';
|
||||
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition().findAncestor( 'mermaid' ) ) {
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition()?.findAncestor( 'mermaid' ) ) {
|
||||
this.isEnabled = !!selectedElement;
|
||||
} else {
|
||||
this.isEnabled = false;
|
||||
@ -32,14 +27,11 @@ export default class MermaidSourceViewCommand extends Command {
|
||||
this.value = checkIsOn( editor, 'source' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
execute() {
|
||||
override execute() {
|
||||
const editor = this.editor;
|
||||
const model = editor.model;
|
||||
const documentSelection = this.editor.model.document.selection;
|
||||
const mermaidItem = documentSelection.getSelectedElement() || documentSelection.getLastPosition().parent;
|
||||
const mermaidItem = (documentSelection.getSelectedElement() || documentSelection.getLastPosition()?.parent) as Element;
|
||||
|
||||
model.change( writer => {
|
||||
if ( mermaidItem.getAttribute( 'displayMode' ) !== 'source' ) {
|
@ -5,25 +5,22 @@
|
||||
import { Command } from 'ckeditor5/src/core.js';
|
||||
|
||||
import { checkIsOn } from '../utils.js';
|
||||
import { Element } from 'ckeditor5';
|
||||
|
||||
/**
|
||||
* The mermaid split view command.
|
||||
*
|
||||
* Allows to switch to a split view mode.
|
||||
*
|
||||
* @extends module:core/command~Command
|
||||
*/
|
||||
export default class MermaidSplitViewCommand extends Command {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
refresh() {
|
||||
|
||||
override refresh() {
|
||||
const editor = this.editor;
|
||||
const documentSelection = editor.model.document.selection;
|
||||
const selectedElement = documentSelection.getSelectedElement();
|
||||
const isSelectedElementMermaid = selectedElement && selectedElement.name === 'mermaid';
|
||||
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition().findAncestor( 'mermaid' ) ) {
|
||||
if ( isSelectedElementMermaid || documentSelection.getLastPosition()?.findAncestor( 'mermaid' ) ) {
|
||||
this.isEnabled = !!selectedElement;
|
||||
} else {
|
||||
this.isEnabled = false;
|
||||
@ -32,14 +29,11 @@ export default class MermaidSplitViewCommand extends Command {
|
||||
this.value = checkIsOn( editor, 'split' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
execute() {
|
||||
override execute() {
|
||||
const editor = this.editor;
|
||||
const model = editor.model;
|
||||
const documentSelection = this.editor.model.document.selection;
|
||||
const mermaidItem = documentSelection.getSelectedElement() || documentSelection.getLastPosition().parent;
|
||||
const mermaidItem = (documentSelection.getSelectedElement() || documentSelection.getLastPosition()?.parent) as Element;
|
||||
|
||||
model.change( writer => {
|
||||
if ( mermaidItem.getAttribute( 'displayMode' ) !== 'split' ) {
|
@ -1,8 +1,16 @@
|
||||
import ckeditor from './../theme/icons/ckeditor.svg';
|
||||
import './augmentation.js';
|
||||
|
||||
export { default as Mermaid } from './mermaid.js';
|
||||
import infoIcon from './../theme/icons/info.svg';
|
||||
import insertMermaidIcon from './../theme/icons/insert.svg';
|
||||
import previewModeIcon from './../theme/icons/preview-mode.svg';
|
||||
import splitModeIcon from './../theme/icons/split-mode.svg';
|
||||
import sourceModeIcon from './../theme/icons/source-mode.svg';
|
||||
|
||||
export const icons = {
|
||||
ckeditor
|
||||
infoIcon,
|
||||
insertMermaidIcon,
|
||||
previewModeIcon,
|
||||
splitModeIcon,
|
||||
sourceModeIcon
|
||||
};
|
||||
|
@ -1,39 +1,17 @@
|
||||
import { Plugin, ButtonView } from 'ckeditor5';
|
||||
|
||||
import ckeditor5Icon from '../theme/icons/ckeditor.svg';
|
||||
import MermaidEditing from './mermaidediting.js';
|
||||
import MermaidToolbar from './mermaidtoolbar.js';
|
||||
import MermaidUI from './mermaidui.js';
|
||||
|
||||
export default class Mermaid extends Plugin {
|
||||
|
||||
static get requires() {
|
||||
return [ MermaidEditing, MermaidToolbar, MermaidUI ];
|
||||
}
|
||||
|
||||
public static get pluginName() {
|
||||
return 'Mermaid' as const;
|
||||
}
|
||||
|
||||
public init(): void {
|
||||
const editor = this.editor;
|
||||
const t = editor.t;
|
||||
const model = editor.model;
|
||||
|
||||
// Register the "mermaid" button, so it can be displayed in the toolbar.
|
||||
editor.ui.componentFactory.add( 'mermaid', locale => {
|
||||
const view = new ButtonView( locale );
|
||||
|
||||
view.set( {
|
||||
label: t( 'Mermaid' ),
|
||||
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;
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
@ -11,18 +11,30 @@ import MermaidPreviewCommand from './commands/mermaidPreviewCommand.js';
|
||||
import MermaidSourceViewCommand from './commands/mermaidSourceViewCommand.js';
|
||||
import MermaidSplitViewCommand from './commands/mermaidSplitViewCommand.js';
|
||||
import InsertMermaidCommand from './commands/insertMermaidCommand.js';
|
||||
import { DowncastAttributeEvent, DowncastConversionApi, Element, EventInfo, Item, Node, UpcastConversionApi, UpcastConversionData, ViewElement, ViewNode, ViewText, ViewUIElement } from 'ckeditor5';
|
||||
|
||||
// Time in milliseconds.
|
||||
const DEBOUNCE_TIME = 300;
|
||||
|
||||
/* global window */
|
||||
|
||||
interface MermaidConfig {
|
||||
lazyLoad?: () => Promise<Mermaid> | Mermaid;
|
||||
config: MermaidConfig;
|
||||
}
|
||||
|
||||
type DowncastConversionData = DowncastAttributeEvent["args"][0];
|
||||
|
||||
export default class MermaidEditing extends Plugin {
|
||||
|
||||
private _config!: MermaidConfig;
|
||||
private mermaid?: Mermaid;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static get pluginName() {
|
||||
return 'MermaidEditing';
|
||||
return 'MermaidEditing' as const;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -31,7 +43,7 @@ export default class MermaidEditing extends Plugin {
|
||||
init() {
|
||||
this._registerCommands();
|
||||
this._defineConverters();
|
||||
this._config = this.editor.config.get("mermaid");
|
||||
this._config = this.editor.config.get("mermaid") as MermaidConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,14 +95,7 @@ export default class MermaidEditing extends Plugin {
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* @param {*} evt
|
||||
* @param {*} data
|
||||
* @param {*} conversionApi
|
||||
*/
|
||||
_mermaidDataDowncast( evt, data, conversionApi ) {
|
||||
_mermaidDataDowncast( evt: EventInfo, data: DowncastConversionData, conversionApi: DowncastConversionApi ) {
|
||||
const model = this.editor.model;
|
||||
const { writer, mapper } = conversionApi;
|
||||
|
||||
@ -98,31 +103,24 @@ export default class MermaidEditing extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetViewPosition = mapper.toViewPosition( model.createPositionBefore( data.item ) );
|
||||
const targetViewPosition = mapper.toViewPosition( model.createPositionBefore( data.item as Item ) );
|
||||
// For downcast we're using only language-mermaid class. We don't set class to `mermaid language-mermaid` as
|
||||
// multiple markdown converters that we have seen are using only `language-mermaid` class and not `mermaid` alone.
|
||||
const code = writer.createContainerElement( 'code', {
|
||||
class: 'language-mermaid'
|
||||
} );
|
||||
} ) as unknown as ViewNode;
|
||||
const pre = writer.createContainerElement( 'pre', {
|
||||
spellcheck: 'false'
|
||||
} );
|
||||
const sourceTextNode = writer.createText( data.item.getAttribute( 'source' ) );
|
||||
} ) as unknown as ViewNode;
|
||||
const sourceTextNode = writer.createText( data.item.getAttribute( 'source' ) as string);
|
||||
|
||||
writer.insert( model.createPositionAt( code, 'end' ), sourceTextNode );
|
||||
writer.insert( model.createPositionAt( pre, 'end' ), code );
|
||||
writer.insert( mapper.toViewPosition(model.createPositionAt( code as unknown as Node, 'end' )), sourceTextNode );
|
||||
writer.insert( mapper.toViewPosition(model.createPositionAt( pre as unknown as Node, 'end' )), code );
|
||||
writer.insert( targetViewPosition, pre );
|
||||
mapper.bindElements( data.item, code );
|
||||
mapper.bindElements( data.item as Element, code as ViewElement );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* @param {*} evt
|
||||
* @param {*} data
|
||||
* @param {*} conversionApi
|
||||
*/
|
||||
_mermaidDowncast( evt, data, conversionApi ) {
|
||||
_mermaidDowncast( evt: EventInfo, data: DowncastConversionData, conversionApi: DowncastConversionApi ) {
|
||||
const { writer, mapper, consumable } = conversionApi;
|
||||
const { editor } = this;
|
||||
const { model, t } = editor;
|
||||
@ -132,7 +130,7 @@ export default class MermaidEditing extends Plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetViewPosition = mapper.toViewPosition( model.createPositionBefore( data.item ) );
|
||||
const targetViewPosition = mapper.toViewPosition( model.createPositionBefore( data.item as Item ) );
|
||||
|
||||
const wrapperAttributes = {
|
||||
class: [ 'ck-mermaid__wrapper' ]
|
||||
@ -147,26 +145,26 @@ export default class MermaidEditing extends Plugin {
|
||||
const editingContainer = writer.createUIElement( 'textarea', textareaAttributes, createEditingTextarea );
|
||||
const previewContainer = writer.createUIElement( 'div', { class: [ 'ck-mermaid__preview' ] }, createMermaidPreview );
|
||||
|
||||
writer.insert( writer.createPositionAt( wrapper, 'start' ), previewContainer );
|
||||
writer.insert( writer.createPositionAt( wrapper, 'start' ), editingContainer );
|
||||
writer.insert( writer.createPositionAt( wrapper, 'before' ), previewContainer );
|
||||
writer.insert( writer.createPositionAt( wrapper, 'before' ), editingContainer );
|
||||
|
||||
writer.insert( targetViewPosition, wrapper );
|
||||
|
||||
mapper.bindElements( data.item, wrapper );
|
||||
mapper.bindElements( data.item as Element, wrapper );
|
||||
|
||||
return toWidget( wrapper, writer, {
|
||||
widgetLabel: t( 'Mermaid widget' ),
|
||||
label: t( 'Mermaid widget' ),
|
||||
hasSelectionHandle: true
|
||||
} );
|
||||
|
||||
function createEditingTextarea( domDocument ) {
|
||||
const domElement = this.toDomElement( domDocument );
|
||||
function createEditingTextarea(this: ViewUIElement, domDocument: Document ) {
|
||||
const domElement = this.toDomElement( domDocument ) as HTMLElement as HTMLInputElement;
|
||||
|
||||
domElement.value = data.item.getAttribute( 'source' );
|
||||
domElement.value = data.item.getAttribute( 'source' ) as string;
|
||||
|
||||
const debouncedListener = debounce( event => {
|
||||
editor.model.change( writer => {
|
||||
writer.setAttribute( 'source', event.target.value, data.item );
|
||||
writer.setAttribute( 'source', event.target.value, data.item as Node );
|
||||
} );
|
||||
}, DEBOUNCE_TIME );
|
||||
|
||||
@ -179,16 +177,16 @@ export default class MermaidEditing extends Plugin {
|
||||
|
||||
// Move the selection onto the mermaid widget if it's currently not selected.
|
||||
if ( selectedElement !== data.item ) {
|
||||
model.change( writer => writer.setSelection( data.item, 'on' ) );
|
||||
model.change( writer => writer.setSelection( data.item as Node, 'on' ) );
|
||||
}
|
||||
}, true );
|
||||
|
||||
return domElement;
|
||||
}
|
||||
|
||||
function createMermaidPreview( domDocument ) {
|
||||
function createMermaidPreview(this: ViewUIElement, domDocument: Document ) {
|
||||
// Taking the text from the wrapper container element for now
|
||||
const mermaidSource = data.item.getAttribute( 'source' );
|
||||
const mermaidSource = data.item.getAttribute( 'source' ) as string;
|
||||
const domElement = this.toDomElement( domDocument );
|
||||
|
||||
domElement.innerHTML = mermaidSource;
|
||||
@ -202,31 +200,29 @@ export default class MermaidEditing extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} evt
|
||||
* @param {*} data
|
||||
* @param {*} conversionApi
|
||||
* @returns
|
||||
*/
|
||||
_sourceAttributeDowncast( evt, data, conversionApi ) {
|
||||
_sourceAttributeDowncast( evt: EventInfo, data: DowncastConversionData, conversionApi: DowncastConversionApi ) {
|
||||
// @todo: test whether the attribute was consumed.
|
||||
const newSource = data.attributeNewValue;
|
||||
const newSource = data.attributeNewValue as string;
|
||||
const domConverter = this.editor.editing.view.domConverter;
|
||||
|
||||
if ( newSource ) {
|
||||
const mermaidView = conversionApi.mapper.toViewElement( data.item );
|
||||
const mermaidView = conversionApi.mapper.toViewElement( data.item as Element );
|
||||
if (!mermaidView) {
|
||||
return;
|
||||
}
|
||||
|
||||
for ( const child of mermaidView.getChildren() ) {
|
||||
for ( const _child of mermaidView.getChildren() ) {
|
||||
const child = _child as ViewElement;
|
||||
if ( child.name === 'textarea' && child.hasClass( 'ck-mermaid__editing-view' ) ) {
|
||||
const domEditingTextarea = domConverter.viewToDom( child, window.document );
|
||||
// Text & HTMLElement & Node & DocumentFragment
|
||||
const domEditingTextarea = domConverter.viewToDom(child) as HTMLElement as HTMLInputElement;
|
||||
|
||||
if ( domEditingTextarea.value != newSource ) {
|
||||
domEditingTextarea.value = newSource;
|
||||
}
|
||||
} else if ( child.name === 'div' && child.hasClass( 'ck-mermaid__preview' ) ) {
|
||||
// @todo: we could optimize this and not refresh mermaid if widget is in source mode.
|
||||
const domPreviewWrapper = domConverter.viewToDom( child, window.document );
|
||||
const domPreviewWrapper = domConverter.viewToDom(child);
|
||||
|
||||
if ( domPreviewWrapper ) {
|
||||
domPreviewWrapper.innerHTML = newSource;
|
||||
@ -239,15 +235,8 @@ export default class MermaidEditing extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @private
|
||||
* @param {*} evt
|
||||
* @param {*} data
|
||||
* @param {*} conversionApi
|
||||
*/
|
||||
_mermaidUpcast( evt, data, conversionApi ) {
|
||||
const viewCodeElement = data.viewItem;
|
||||
_mermaidUpcast( evt: EventInfo, data: UpcastConversionData, conversionApi: UpcastConversionApi ) {
|
||||
const viewCodeElement = data.viewItem as ViewElement;
|
||||
const hasPreElementParent = !viewCodeElement.parent || !viewCodeElement.parent.is( 'element', 'pre' );
|
||||
const hasCodeAncestors = data.modelCursor.findAncestor( 'code' );
|
||||
const { consumable, writer } = conversionApi;
|
||||
@ -261,7 +250,7 @@ export default class MermaidEditing extends Plugin {
|
||||
}
|
||||
const mermaidSource = Array.from( viewCodeElement.getChildren() )
|
||||
.filter( item => item.is( '$text' ) )
|
||||
.map( item => item.data )
|
||||
.map( item => (item as ViewText).data )
|
||||
.join( '' );
|
||||
|
||||
const mermaidElement = writer.createElement( 'mermaid', {
|
||||
@ -282,14 +271,12 @@ export default class MermaidEditing extends Plugin {
|
||||
/**
|
||||
* Renders Mermaid in a given `domElement`. Expect this domElement to have mermaid
|
||||
* source set as text content.
|
||||
*
|
||||
* @param {HTMLElement} domElement
|
||||
*/
|
||||
async _renderMermaid( domElement ) {
|
||||
async _renderMermaid( domElement: HTMLElement ) {
|
||||
if (!window.mermaid && typeof this._config?.lazyLoad === "function") {
|
||||
this.mermaid = await this._config.lazyLoad();
|
||||
}
|
||||
|
||||
this.mermaid.init( this._config.config, domElement );
|
||||
this.mermaid?.init( this._config.config, domElement );
|
||||
}
|
||||
}
|
@ -2,27 +2,19 @@
|
||||
* @module mermaid/mermaidtoolbar
|
||||
*/
|
||||
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import { WidgetToolbarRepository } from 'ckeditor5/src/widget.js';
|
||||
import { Plugin, ViewDocumentSelection, ViewElement, WidgetToolbarRepository } from "ckeditor5";
|
||||
|
||||
|
||||
export default class MermaidToolbar extends Plugin {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
static get requires() {
|
||||
return [ WidgetToolbarRepository ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static get pluginName() {
|
||||
return 'MermaidToolbar';
|
||||
return 'MermaidToolbar' as const;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
afterInit() {
|
||||
const editor = this.editor;
|
||||
const t = editor.t;
|
||||
@ -40,8 +32,8 @@ export default class MermaidToolbar extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
function getSelectedElement( selection ) {
|
||||
const viewElement = selection.getSelectedElement();
|
||||
function getSelectedElement( selection: ViewDocumentSelection ) {
|
||||
const viewElement = selection.getSelectedElement() as unknown as ViewElement;
|
||||
|
||||
if ( viewElement && viewElement.hasClass( 'ck-mermaid__wrapper' ) ) {
|
||||
return viewElement;
|
@ -2,14 +2,13 @@
|
||||
* @module mermaid/mermaidui
|
||||
*/
|
||||
|
||||
import { Plugin } from 'ckeditor5/src/core.js';
|
||||
import { ButtonView } from 'ckeditor5/src/ui.js';
|
||||
|
||||
import insertMermaidIcon from '../theme/icons/insert.svg';
|
||||
import previewModeIcon from '../theme/icons/preview-mode.svg';
|
||||
import splitModeIcon from '../theme/icons/split-mode.svg';
|
||||
import sourceModeIcon from '../theme/icons/source-mode.svg';
|
||||
import infoIcon from '../theme/icons/info.svg';
|
||||
import { ButtonView, Editor, Element, Locale, Observable, Plugin } from 'ckeditor5';
|
||||
import InsertMermaidCommand from './commands/insertMermaidCommand.js';
|
||||
|
||||
/* global window, document */
|
||||
|
||||
@ -18,7 +17,7 @@ export default class MermaidUI extends Plugin {
|
||||
* @inheritDoc
|
||||
*/
|
||||
static get pluginName() {
|
||||
return 'MermaidUI';
|
||||
return 'MermaidUI' as const;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -53,9 +52,12 @@ export default class MermaidUI extends Plugin {
|
||||
const t = editor.t;
|
||||
const view = editor.editing.view;
|
||||
|
||||
editor.ui.componentFactory.add( 'mermaid', locale => {
|
||||
editor.ui.componentFactory.add( 'mermaid', (locale: Locale) => {
|
||||
const buttonView = new ButtonView( locale );
|
||||
const command = editor.commands.get( 'insertMermaidCommand' );
|
||||
const command = editor.commands.get( 'insertMermaidCommand' ) as InsertMermaidCommand;
|
||||
if (!command) {
|
||||
throw new Error("Missing command.");
|
||||
}
|
||||
|
||||
buttonView.set( {
|
||||
label: t( 'Insert Mermaid diagram' ),
|
||||
@ -63,21 +65,21 @@ export default class MermaidUI extends Plugin {
|
||||
tooltip: true
|
||||
} );
|
||||
|
||||
buttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );
|
||||
buttonView.bind( 'isOn', 'isEnabled' ).to( command as (Observable & { value: boolean; } & { isEnabled: boolean; }), 'value', 'isEnabled' );
|
||||
|
||||
// Execute the command when the button is clicked.
|
||||
command.listenTo( buttonView, 'execute', () => {
|
||||
const mermaidItem = editor.execute( 'insertMermaidCommand' );
|
||||
const mermaidItem = editor.execute( 'insertMermaidCommand' ) as Element;
|
||||
const mermaidItemViewElement = editor.editing.mapper.toViewElement( mermaidItem );
|
||||
|
||||
view.scrollToTheSelection();
|
||||
view.focus();
|
||||
|
||||
if ( mermaidItemViewElement ) {
|
||||
const mermaidItemDomElement = view.domConverter.viewToDom( mermaidItemViewElement, document );
|
||||
const mermaidItemDomElement = view.domConverter.viewToDom( mermaidItemViewElement );
|
||||
|
||||
if ( mermaidItemDomElement ) {
|
||||
mermaidItemDomElement.querySelector( '.ck-mermaid__editing-view' ).focus();
|
||||
(mermaidItemDomElement.querySelector( '.ck-mermaid__editing-view' ) as HTMLElement)?.focus();
|
||||
}
|
||||
}
|
||||
} );
|
||||
@ -117,17 +119,16 @@ export default class MermaidUI extends Plugin {
|
||||
* Adds the mermaid balloon toolbar button.
|
||||
*
|
||||
* @private
|
||||
* @param {module:core/editor/editor~Editor} editor
|
||||
* @param {String} name Name of the button.
|
||||
* @param {String} label Label for the button.
|
||||
* @param {String} icon The button icon.
|
||||
*/
|
||||
_createToolbarButton( editor, name, label, icon ) {
|
||||
_createToolbarButton( editor: Editor, name: string, label: string, icon: string ) {
|
||||
const t = editor.t;
|
||||
|
||||
editor.ui.componentFactory.add( name, locale => {
|
||||
const buttonView = new ButtonView( locale );
|
||||
const command = editor.commands.get( `${ name }Command` );
|
||||
if (!command) {
|
||||
throw new Error("Missing command.");
|
||||
}
|
||||
|
||||
buttonView.set( {
|
||||
label: t( label ),
|
||||
@ -135,7 +136,7 @@ export default class MermaidUI extends Plugin {
|
||||
tooltip: true
|
||||
} );
|
||||
|
||||
buttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );
|
||||
buttonView.bind( 'isOn', 'isEnabled' ).to( command as (Observable & { value: boolean; } & { isEnabled: boolean; }), 'value', 'isEnabled' );
|
||||
|
||||
// Execute the command when the button is clicked.
|
||||
command.listenTo( buttonView, 'execute', () => {
|
@ -3,21 +3,17 @@
|
||||
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module mermaid/utils
|
||||
*/
|
||||
import { Editor } from "ckeditor5";
|
||||
|
||||
/**
|
||||
* Helper function for setting the `isOn` state of buttons.
|
||||
*
|
||||
* @private
|
||||
* @param {module:core/editor/editor~Editor} editor
|
||||
* @param {String} commandName Short name of the command.
|
||||
* @returns {Boolean}
|
||||
* @param commandName Short name of the command.
|
||||
*/
|
||||
export function checkIsOn( editor, commandName ) {
|
||||
export function checkIsOn( editor: Editor, commandName: string ) {
|
||||
const selection = editor.model.document.selection;
|
||||
const mermaidItem = selection.getSelectedElement() || selection.getLastPosition().parent;
|
||||
const mermaidItem = selection.getSelectedElement() || selection.getLastPosition()?.parent;
|
||||
|
||||
if ( mermaidItem && mermaidItem.is( 'element', 'mermaid' ) && mermaidItem.getAttribute( 'displayMode' ) === commandName ) {
|
||||
return true;
|
@ -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: 712 B After Width: | Height: | Size: 712 B |
Before Width: | Height: | Size: 590 B After Width: | Height: | Size: 590 B |
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 897 B |
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 348 B |
19
pnpm-lock.yaml
generated
@ -882,6 +882,13 @@ importers:
|
||||
version: 9.12.7(bufferutil@4.0.9)(utf-8-validate@6.0.5)
|
||||
|
||||
packages/ckeditor5-mermaid:
|
||||
dependencies:
|
||||
'@types/lodash-es':
|
||||
specifier: 4.17.12
|
||||
version: 4.17.12
|
||||
lodash-es:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
devDependencies:
|
||||
'@ckeditor/ckeditor5-dev-build-tools':
|
||||
specifier: 43.0.1
|
||||
@ -4302,6 +4309,12 @@ packages:
|
||||
'@types/leaflet@1.9.17':
|
||||
resolution: {integrity: sha512-IJ4K6t7I3Fh5qXbQ1uwL3CFVbCi6haW9+53oLWgdKlLP7EaS21byWFJxxqOx9y8I0AP0actXSJLVMbyvxhkUTA==}
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==}
|
||||
|
||||
'@types/lodash@4.17.16':
|
||||
resolution: {integrity: sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==}
|
||||
|
||||
'@types/mdast@3.0.15':
|
||||
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==}
|
||||
|
||||
@ -18246,6 +18259,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/geojson': 7946.0.16
|
||||
|
||||
'@types/lodash-es@4.17.12':
|
||||
dependencies:
|
||||
'@types/lodash': 4.17.16
|
||||
|
||||
'@types/lodash@4.17.16': {}
|
||||
|
||||
'@types/mdast@3.0.15':
|
||||
dependencies:
|
||||
'@types/unist': 2.0.11
|
||||
|