Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/icons/mermaid-info.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/icons/mermaid-insert.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/icons/mermaid-preview-mode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/icons/mermaid-source-mode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/icons/mermaid-split-mode.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/op-ckeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ FullEditor.defaultConfig.toolbar = {
'todoList',
'imageUpload',
'blockQuote',
'mermaid',
'|',
'insertTable',
'macroList',
Expand Down Expand Up @@ -64,6 +65,7 @@ ConstrainedEditor.defaultConfig.toolbar = {
'todoList',
'imageUpload',
'blockQuote',
'mermaid',
'|',
'opContentRevisions',
'undo',
Expand Down
3 changes: 3 additions & 0 deletions src/op-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import OpMacroWikiPageLinkPlugin from "./plugins/op-macro-wiki-page-link/op-macr
import OpMacroWikiPageLinkAddExisting from "./plugins/op-macro-wiki-page-link/op-macro-wiki-page-link-add-existing";
import OpMacroWikiPageLinkCreateNew from "./plugins/op-macro-wiki-page-link/op-macro-wiki-page-link-create-new";
import OPResizerGuard from "./plugins/op-resizer-guard/op-resizer-guard-plugin";
import Mermaid from './plugins/mermaid/mermaid';

// We divide our plugins into separate concerns here
// in order to enable / disable each group by configuration
Expand Down Expand Up @@ -109,6 +110,8 @@ export const builtinPlugins = [

OPMacroListPlugin,

Mermaid,

OpCustomCssClassesPlugin,
].concat(
// OpenProject Macro plugin group
Expand Down
22 changes: 22 additions & 0 deletions src/plugins/mermaid/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Software License Agreement
==========================

**CKEditor 5 mermaid feature** (https://ckeditor.com/ckeditor-5/)<br>
Copyright (c) 2003-2022, [CKSource](http://cksource.com) Holding sp. z o.o. All rights reserved.

Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html).

Sources of Intellectual Property Included in CKEditor 5 mermaid feature
---------------------------------------------------------------------

Where not otherwise indicated, all CKEditor 5 mermaid feature content is authored by CKSource engineers and consists of CKSource-owned intellectual property.

The following libraries are included in CKEditor 5 mermaid feature under the [MIT license](https://opensource.org/licenses/MIT):

* Lo-Dash - Copyright (c) JS Foundation and other contributors https://js.foundation/. Based on Underscore.js, copyright Jeremy Ashkenas.
* mermaid - Copyright (c) 2014 - 2021 Knut Sveidqvist. (MIT License)

Trademarks
----------

**CKEditor** is a trademark of [CKSource](http://cksource.com) Holding sp. z o.o. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders.
53 changes: 53 additions & 0 deletions src/plugins/mermaid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Mermaid diagrams

A `mermaid` block widget holding diagram source, shown as a source textarea, a rendered preview, or
both side by side. Load the `Mermaid` glue plugin; it pulls in `MermaidEditing`, `MermaidToolbar`
and `MermaidUI`.

| File | Role |
|---|---|
| `mermaid.js` | Glue plugin |
| `mermaid_editing.js` | Schema, conversion, and the renderer (`renderMermaid`) |
| `mermaid_ui.js` | The insert button with its optional template dropdown, the mode buttons, the info button |
| `mermaid_toolbar.js` | Registers the balloon toolbar shown when a diagram is selected |
| `insert_mermaid_command.js` | Inserts a blank or pre-filled diagram |
| `mermaid_{preview,source_view,split_view}_command.js` | Switch the widget's `displayMode` |
| `utils.js` | `debounce` for the source textarea, `checkIsOn` for button state |

## The mermaid library is not a dependency

The plugin never imports mermaid - bundling it pulls in d3, cytoscape and katex, which pushed this
build's Terser stage past ten minutes. The host passes the library in through editor config:

```js
mermaid: {
lazyLoad: () => import( 'mermaid' ).then( m => m.default ),
config: { /* mermaid initialize() config */ },
samples: [ /* { name, content } diagram templates for the insert dropdown */ ],
openHelp: () => { /* opens https://mermaid.js.org/intro/ when not given */ }
}
```

`renderMermaid` calls `lazyLoad` once, memoises the promise, and calls `initialize()` on the
resolved instance. Without it the widget still edits and round-trips its source; only the preview
stays empty. Renders are generation-stamped so a slow render that has been superseded cannot
overwrite a newer one, and a failed render shows the error message in place.

## Round-trip

A diagram is content, not markup: it round-trips as a fenced `mermaid` code block, upcast from
`pre > code.language-mermaid` and downcast back to it. The upcast runs on `element:pre` at
`highest` priority because this build's own code block plugin claims every `<pre>` on `high` and
consumes the `<code>` inside it without dispatching it.

Upstream also persists the picked display mode on the `<code>` element. That is dropped here: the
data format is CommonMark, so an attribute on `<code>` never survives the round trip and every
diagram opens in split mode.

## Provenance

Vendored from [Trilium](https://github.com/TriliumNext/Trilium)'s
`packages/ckeditor5/src/plugins/mermaid`, itself derived from CKSource's
`@ckeditor/ckeditor5-mermaid`, copyright CKSource Holding sp. z o.o., used under the
GPL-2.0-or-later arm of its license - see `LICENSE.md` next to this file. Converted from TypeScript
to JavaScript and retargeted at this build's individual `@ckeditor/ckeditor5-*` packages.
39 changes: 39 additions & 0 deletions src/plugins/mermaid/insert_mermaid_command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Command } from '@ckeditor/ckeditor5-core';

/** The name under which {@link InsertMermaidCommand} is registered in the editor. */
export const INSERT_MERMAID_COMMAND = 'insertMermaidCommand';

const DEFAULT_MERMAID_MARKUP = `flowchart TB
A --> B
B --> C`;

/**
* The insert mermaid command.
*
* Allows to insert mermaid.
*/
export default class InsertMermaidCommand extends Command {

refresh() {
const documentSelection = this.editor.model.document.selection;
const selectedElement = documentSelection.getSelectedElement();

this.isEnabled = !( selectedElement && selectedElement.name === 'mermaid' );
}

execute( options = {} ) {
const model = this.editor.model;
let mermaidItem;

model.change( writer => {
mermaidItem = writer.createElement( 'mermaid', {
displayMode: options.displayMode ?? 'split',
source: options.source ?? DEFAULT_MERMAID_MARKUP
} );

model.insertContent( mermaidItem );
} );

return mermaidItem;
}
}
28 changes: 28 additions & 0 deletions src/plugins/mermaid/mermaid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Plugin } from '@ckeditor/ckeditor5-core';

import '../../theme/mermaid.css';
import MermaidEditing from './mermaid_editing';
import MermaidToolbar from './mermaid_toolbar';
import MermaidUI from './mermaid_ui';

/**
* The Mermaid diagram feature: a `<mermaid>` block widget with a source textarea and a rendered
* preview, switchable between source / split / preview modes.
*
* The mermaid library itself is not a dependency - the host supplies it through
* `config.mermaid.lazyLoad`, so the diagram renderer is only fetched when a diagram is shown.
*
* Derived from CKSource's `@ckeditor/ckeditor5-mermaid`; see `LICENSE.md` and `README.md` next to
* this file.
*/
export default class Mermaid extends Plugin {

static get requires() {
return [ MermaidEditing, MermaidToolbar, MermaidUI ];
}

static get pluginName() {
return 'Mermaid';
}

}
Loading
Loading