Add '_regroup/ckeditor5-build-trilium/' from commit '1a1cb3d60be4f042b523fd3dd2fc54c67afff1c9'

git-subtree-dir: _regroup/ckeditor5-build-trilium
git-subtree-mainline: b6f166f1d76a036d4877c046fb8ea4a7d6dbab42
git-subtree-split: 1a1cb3d60be4f042b523fd3dd2fc54c67afff1c9
This commit is contained in:
Elian Doran 2025-05-03 12:05:08 +03:00
commit 0e95149daa
36 changed files with 1710 additions and 0 deletions

View File

@ -0,0 +1,14 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* eslint-env node */
'use strict';
module.exports = {
rules: {
'ckeditor5-rules/ckeditor-imports': 'off'
}
};

View File

@ -0,0 +1,78 @@
{
"name": "@ckeditor/ckeditor5-build-trilium",
"version": "43.2.0",
"description": "The document editor build of CKEditor 5 the best browser-based rich text editor.",
"keywords": [
"ckeditor5-build",
"ckeditor",
"ckeditor5",
"ckeditor 5",
"wysiwyg",
"rich text",
"editor",
"html",
"contentEditable",
"editing",
"operational transformation",
"ot",
"collaboration",
"collaborative",
"real-time",
"framework"
],
"main": "./build/ckeditor.js",
"types": "./build/ckeditor.d.ts",
"files": [
"build",
"ckeditor5-metadata.json",
"CHANGELOG.md"
],
"dependencies": {
"@ckeditor/ckeditor5-adapter-ckfinder": "43.2.0",
"@ckeditor/ckeditor5-alignment": "43.2.0",
"@ckeditor/ckeditor5-autoformat": "43.2.0",
"@ckeditor/ckeditor5-basic-styles": "43.2.0",
"@ckeditor/ckeditor5-block-quote": "43.2.0",
"@ckeditor/ckeditor5-ckbox": "43.2.0",
"@ckeditor/ckeditor5-ckfinder": "43.2.0",
"@ckeditor/ckeditor5-cloud-services": "43.2.0",
"@ckeditor/ckeditor5-easy-image": "43.2.0",
"@ckeditor/ckeditor5-editor-decoupled": "43.2.0",
"@ckeditor/ckeditor5-essentials": "43.2.0",
"@ckeditor/ckeditor5-font": "43.2.0",
"@ckeditor/ckeditor5-heading": "43.2.0",
"@ckeditor/ckeditor5-image": "43.2.0",
"@ckeditor/ckeditor5-indent": "43.2.0",
"@ckeditor/ckeditor5-link": "43.2.0",
"@ckeditor/ckeditor5-list": "43.2.0",
"@ckeditor/ckeditor5-media-embed": "43.2.0",
"@ckeditor/ckeditor5-paragraph": "43.2.0",
"@ckeditor/ckeditor5-paste-from-office": "43.2.0",
"@ckeditor/ckeditor5-table": "43.2.0",
"@ckeditor/ckeditor5-typing": "43.2.0",
"@ckeditor/ckeditor5-utils": "43.2.0"
},
"devDependencies": {
"@ckeditor/ckeditor5-core": "43.2.0",
"@ckeditor/ckeditor5-dev-translations": "^43.0.0",
"@ckeditor/ckeditor5-dev-utils": "^43.0.0",
"@ckeditor/ckeditor5-theme-lark": "43.2.0",
"terser-webpack-plugin": "^4.2.3",
"typescript": "5.0.4",
"webpack": "^5.94.0",
"webpack-cli": "^5.1.4"
},
"author": "CKSource (http://cksource.com/)",
"license": "GPL-2.0-or-later",
"homepage": "https://ckeditor.com/ckeditor-5",
"bugs": "https://github.com/ckeditor/ckeditor5/issues",
"repository": {
"type": "git",
"url": "https://github.com/ckeditor/ckeditor5.git",
"directory": "packages/ckeditor5-build-decoupled-document"
},
"scripts": {
"build": "webpack --mode production",
"postbuild": "tsc -p ./tsconfig.types.json"
}
}

View File

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>CKEditor 5 document editor build development sample</title>
<style>
body {
max-width: 1000px;
margin: 20px auto;
}
</style>
</head>
<body>
<h1>CKEditor 5 document editor build development sample</h1>
<h2>The toolbar</h2>
<div class="toolbar-container"></div>
<h2>The editable</h2>
<div class="editable-container"></div>
<style>
.editable-container,
.toolbar-container {
position: relative;
border: 1px solid #ddd;
background: #eee;
}
.toolbar-container {
padding: 1em;
}
.editable-container {
padding: 3em;
overflow-y: scroll;
max-height: 500px;
}
.editable-container .ck-content {
min-height: 21cm;
padding: 2em;
border: 1px #D3D3D3 solid;
border-radius: var(--ck-border-radius);
background: white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
</style>
<script src="../build/ckeditor.js"></script>
<script>
const editorData = `<h2>Sample</h2>
<p>This is an instance of the <a href="https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/predefined-builds.html#document-editor">document editor build</a>.</p>
<figure class="image">
<img src="../tests/manual/sample.jpg" alt="Autumn fields" />
</figure>
<p>You can use this sample to validate whether your <a href="https://ckeditor.com/docs/ckeditor5/latest/installation/advanced/alternative-setups/custom-builds.html">custom build</a> works fine.</p>`;
DecoupledEditor.create( editorData )
.then( editor => {
window.editor = editor;
document.querySelector( '.toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
document.querySelector( '.editable-container' ).appendChild( editor.ui.view.editable.element );
} )
.catch( error => {
console.error( 'There was a problem initializing the editor.', error );
} );
</script>
</body>
</html>

View File

@ -0,0 +1,9 @@
import { EditorWatchdog } from "@ckeditor/ckeditor5-watchdog";
import BalloonEditor from "./ckeditor_balloon";
import DecoupledEditor from "./ckeditor_decoupled";
export default {
BalloonEditor,
DecoupledEditor,
EditorWatchdog
}

View File

@ -0,0 +1,18 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
// The editor creator to use.
import { BalloonEditor as BalloonEditorBase } from '@ckeditor/ckeditor5-editor-balloon';
import { BlockToolbar } from '@ckeditor/ckeditor5-ui';
import '../theme/theme.css';
import { COMMON_PLUGINS, COMMON_SETTINGS } from './config';
//@ts-ignore
export default class BalloonEditor extends BalloonEditorBase {
public static override builtinPlugins = [
...COMMON_PLUGINS,
BlockToolbar
];
}

View File

@ -0,0 +1,16 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
// The editor creator to use.
import { DecoupledEditor as DecoupledEditorBase } from '@ckeditor/ckeditor5-editor-decoupled';
import '../theme/theme.css';
import { COMMON_PLUGINS, COMMON_SETTINGS } from './config';
//@ts-ignore
export default class DecoupledEditor extends DecoupledEditorBase {
public static override builtinPlugins = [
...COMMON_PLUGINS,
];
}

View File

@ -0,0 +1,162 @@
import { FindAndReplace } from '@ckeditor/ckeditor5-find-and-replace';
import { CKFinderUploadAdapter } from '@ckeditor/ckeditor5-adapter-ckfinder';
import { Autoformat } from '@ckeditor/ckeditor5-autoformat';
import { Bold } from '@ckeditor/ckeditor5-basic-styles';
import { Italic } from '@ckeditor/ckeditor5-basic-styles';
import { Superscript } from '@ckeditor/ckeditor5-basic-styles';
import { Subscript } from '@ckeditor/ckeditor5-basic-styles';
import { Underline } from '@ckeditor/ckeditor5-basic-styles';
import { Strikethrough } from '@ckeditor/ckeditor5-basic-styles';
import { Code } from '@ckeditor/ckeditor5-basic-styles';
import { BlockQuote } from '@ckeditor/ckeditor5-block-quote';
import { Heading } from '@ckeditor/ckeditor5-heading';
import { Image, ImageInline } from '@ckeditor/ckeditor5-image';
import { ImageCaption } from '@ckeditor/ckeditor5-image';
import { ImageStyle } from '@ckeditor/ckeditor5-image';
import { ImageToolbar } from '@ckeditor/ckeditor5-image';
import { ImageUpload } from '@ckeditor/ckeditor5-image';
import { ImageResize } from '@ckeditor/ckeditor5-image';
import { Link } from '@ckeditor/ckeditor5-link';
import { AutoLink } from '@ckeditor/ckeditor5-link';
import { List } from '@ckeditor/ckeditor5-list';
import { ListProperties } from '@ckeditor/ckeditor5-list';
import { TodoList } from '@ckeditor/ckeditor5-list';
import { Paragraph } from '@ckeditor/ckeditor5-paragraph';
import { PasteFromOffice } from '@ckeditor/ckeditor5-paste-from-office';
import { PictureEditing } from '@ckeditor/ckeditor5-image';
import { Table } from '@ckeditor/ckeditor5-table';
import { TableToolbar } from '@ckeditor/ckeditor5-table';
import { TableProperties } from '@ckeditor/ckeditor5-table';
import { TableCellProperties } from '@ckeditor/ckeditor5-table';
import { TableCaption } from '@ckeditor/ckeditor5-table';
import { TableSelection } from '@ckeditor/ckeditor5-table';
import { TableColumnResize } from '@ckeditor/ckeditor5-table';
import { HeadingButtonsUI } from '@ckeditor/ckeditor5-heading';
import { ParagraphButtonUI } from '@ckeditor/ckeditor5-paragraph';
import { TextTransformation } from '@ckeditor/ckeditor5-typing';
import { Font } from '@ckeditor/ckeditor5-font';
import { FontColor } from '@ckeditor/ckeditor5-font';
import { FontBackgroundColor } from '@ckeditor/ckeditor5-font';
import { CodeBlock } from '@ckeditor/ckeditor5-code-block';
import { Mention } from '@ckeditor/ckeditor5-mention';
import { Indent } from '@ckeditor/ckeditor5-indent';
import { IndentBlock } from '@ckeditor/ckeditor5-indent';
import { SelectAll } from '@ckeditor/ckeditor5-select-all';
import { HorizontalLine } from '@ckeditor/ckeditor5-horizontal-line';
import { Clipboard } from '@ckeditor/ckeditor5-clipboard';
import { Enter } from '@ckeditor/ckeditor5-enter';
import { ShiftEnter } from '@ckeditor/ckeditor5-enter';
import { Typing } from '@ckeditor/ckeditor5-typing';
import { Undo } from '@ckeditor/ckeditor5-undo';
import { RemoveFormat } from '@ckeditor/ckeditor5-remove-format';
import { SpecialCharacters, SpecialCharactersEssentials } from '@ckeditor/ckeditor5-special-characters';
import { GeneralHtmlSupport } from "@ckeditor/ckeditor5-html-support";
import Uploadfileplugin from "../../ckeditor5-file-upload/uploadfileplugin";
import { PageBreak } from '@ckeditor/ckeditor5-page-break';
import { TextPartLanguage } from "@ckeditor/ckeditor5-language";
import { Style } from "../../ckeditor5-style";
import MentionCustomization from './mention_customization';
import UploadimagePlugin from './uploadimage';
import InternalLinkPlugin from './internallink';
import ItalicAsEmPlugin from './italic_as_em';
import MarkdownImportPlugin from './markdownimport';
import CuttonotePlugin from './cuttonote';
import IncludeNote from './includenote';
import ReferenceLink from './referencelink';
import indentBlockShortcutPlugin from './indent_block_shortcut';
import removeFormatLinksPlugin from './remove_format_links';
import {SpecialCharactersEmoji} from "./special_characters_emoji";
// External plugins
import { Math, AutoformatMath } from '../../ckeditor5-math/src/index';
import { Mermaid } from "../../ckeditor5-mermaid/src/index";
import '../../ckeditor5-footnotes/src/footnote.css';
import { Footnotes } from '../../ckeditor5-footnotes';
import Kbd from "../../ckeditor5-keyboard-marker/src/Kbd";
import { Admonition } from "../../ckeditor5-admonition";
import StrikethroughAsDel from './strikethrough_as_del';
export const COMMON_PLUGINS = [
// essentials package expanded to allow selectively disable Enter and ShiftEnter
Clipboard, Enter, SelectAll, ShiftEnter, Typing, Undo,
CKFinderUploadAdapter,
Autoformat,
Bold,
Italic,
Underline,
Strikethrough,
Code,
Superscript,
Subscript,
BlockQuote,
Heading,
Image,
ImageCaption,
ImageStyle,
ImageToolbar,
ImageUpload,
ImageResize,
ImageInline,
Link,
AutoLink,
List,
ListProperties,
TodoList,
Paragraph,
PasteFromOffice,
PictureEditing,
Table,
TableToolbar,
TableProperties,
TableCellProperties,
TableSelection,
TableCaption,
TableColumnResize,
Indent,
IndentBlock,
ParagraphButtonUI,
HeadingButtonsUI,
Uploadfileplugin,
UploadimagePlugin,
TextTransformation,
Font,
FontColor,
FontBackgroundColor,
CodeBlock,
SelectAll,
HorizontalLine,
RemoveFormat,
SpecialCharacters,
SpecialCharactersEssentials,
SpecialCharactersEmoji,
FindAndReplace,
Mention,
InternalLinkPlugin,
ItalicAsEmPlugin,
StrikethroughAsDel,
MarkdownImportPlugin,
CuttonotePlugin,
MentionCustomization,
IncludeNote,
ReferenceLink,
indentBlockShortcutPlugin,
removeFormatLinksPlugin,
PageBreak,
GeneralHtmlSupport,
TextPartLanguage,
Style,
// External plugins
Math,
AutoformatMath,
Footnotes,
Mermaid,
Kbd,
Admonition
];
export const COMMON_SETTINGS = { };

View File

@ -0,0 +1,59 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import scissorsIcon from './icons/scissors.svg';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
export default class CutToNotePlugin extends Plugin {
init() {
this.htmlDataProcessor = new HtmlDataProcessor();
this.editor.ui.componentFactory.add( 'cutToNote', locale => {
const view = new ButtonView( locale );
view.set( {
label: 'Cut & paste selection to sub-note',
icon: scissorsIcon,
tooltip: true
} );
// Callback executed once the image is clicked.
view.on('execute', () => {
const editorEl = this.editor.editing.view.getDomRoot();
const component = glob.getComponentByEl(editorEl);
component.triggerCommand('cutIntoNote');
});
return view;
} );
this.editor.getSelectedHtml = () => this.getSelectedHtml();
this.editor.removeSelection = () => this.removeSelection();
}
getSelectedHtml() {
const model = this.editor.model;
const document = model.document;
const content = this.editor.data.toView(model.getSelectedContent(document.selection));
return this.htmlDataProcessor.toData(content);
}
async removeSelection() {
const model = this.editor.model;
model.deleteContent(model.document.selection);
this.editor.execute("paragraph");
const component = this.getComponent();
await component.triggerCommand('saveNoteDetailNow');
}
getComponent() {
const editorEl = this.editor.editing.view.getDomRoot();
return glob.getComponentByEl( editorEl );
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="208" height="128" viewBox="0 0 208 128"><rect width="198" height="118" x="5" y="5" ry="10" stroke="#000" stroke-width="10" fill="none"/><path d="M30 98V30h20l20 25 20-25h20v68H90V59L70 84 50 59v39zm125 0l-30-33h20V30h20v35h20z"/></svg>

After

Width:  |  Height:  |  Size: 282 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M19,3H5C3.897,3,3,3.897,3,5v14c0,1.103,0.897,2,2,2h8c0.131,0,0.26-0.026,0.381-0.076s0.232-0.123,0.326-0.217l7-7 c0.086-0.086,0.147-0.187,0.196-0.293c0.014-0.03,0.022-0.061,0.033-0.093c0.028-0.084,0.046-0.17,0.051-0.259 C20.989,13.041,21,13.021,21,13V5C21,3.897,20.103,3,19,3z M5,5h14v7h-6c-0.553,0-1,0.448-1,1v6H5V5z M14,17.586V14h3.586 L14,17.586z"/></svg>

After

Width:  |  Height:  |  Size: 449 B

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><g><path d="M853.9,754.9c-26-45.4-66.5-76.2-109.1-87.8c-33.7-9.2-68.7-6.4-98.9,10.7l-90-157.3C611.6,409.5,736.5,160.5,759,121.2C788,70.4,736,10,736,10L500,422.8L264,10c0,0-52,60.4-22.9,111.2c22.5,39.3,147.5,288.3,203.1,399.3l-89.9,157.3c-30.2-17.1-65.3-19.9-98.9-10.7c-42.7,11.6-83.1,42.3-109.1,87.8c-46.8,81.7-28.9,179.7,39.7,219c30.4,17.5,65.7,20.3,99.6,11.1c42.6-11.6,83.1-42.4,109.1-87.7c11.4-20,18.9-41,22.8-61.8v0c0-0.2,0-0.3,0.2-0.5c0.2-1.7,0.5-3.5,0.7-5.4c19.3-129.5,55.8-195.7,81.6-227.8c25.9,32.1,62.4,98.3,81.7,227.8c0.2,1.9,0.5,3.6,0.7,5.4c0.1,0.2,0.1,0.3,0.2,0.5v0c3.9,20.8,11.4,41.8,22.7,61.8c26,45.3,66.5,76.1,109.2,87.7c34,9.2,69.2,6.4,99.7-11.1C882.8,934.5,900.6,836.5,853.9,754.9z M327.9,858.9c-14.8,25.8-38.1,45.2-62.5,51.8c-10.8,3-26.7,4.7-41.3-3.6c-31.1-17.8-36.2-70.1-11.1-114c15-26,37.8-45,62.5-51.8c10.7-2.9,26.7-4.7,41.3,3.6C347.9,762.7,353,814.9,327.9,858.9z M775.9,907.1c-14.6,8.4-30.4,6.6-41.3,3.6c-24.4-6.6-47.7-26-62.5-51.8c-25.1-44-20-96.2,11.1-114c14.7-8.3,30.6-6.5,41.3-3.6C749.3,748,772.1,767,787,793C812.1,837,807.1,889.3,775.9,907.1z"/><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 256 256" version="1.1" viewBox="0 0 256 256" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
<path d="m232.6 27.598c-17.706 0.092041-40.298 3.7127-58.258 10.104-1.7959 0.63909-3.5465 1.3043-5.2402 1.998-3.1 1.2-6.0988 2.6016-8.7988 4.1016-2.2 1.2-4.3016 2.4988-6.1016 3.7988-21.6 15.5-27.9 44.2-28.6 65.4l14.9-10.5 14.301-10 51.199-35.9-49.1 39.301-14.1 11.299-14.801 11.801c20.4 6.5 52.4 9.7992 74.9-6.3008 3.1886-2.319 6.4708-5.1162 9.7559-8.459 0.14708-0.08175 0.29689-0.1571 0.44336-0.24023 2.3386-2.3386 4.7705-4.8714 7.0215-7.5898 0.02928-0.033868 0.05864-0.065681 0.08789-0.099609 0.0964-0.038723 0.1948-0.072111 0.29102-0.11133 14.544-16.737 27.833-39.152 32.252-55.658 0.67979-2.5395 1.1487-4.9387 1.3809-7.1562 0.11607-1.1088 0.17422-2.173 0.16797-3.1855-1.0438-0.3625-2.1849-0.68557-3.4121-0.9707-1.2272-0.28513-2.542-0.53096-3.9336-0.74024s-2.8595-0.38069-4.3965-0.51562c-3.0739-0.26987-6.4198-0.39341-9.9609-0.375zm-202.79 20.252c-11.737-0.05-22.113 1.4004-28.312 4.6504 0.9 5.6625 4.3309 13.419 9.3125 21.77v0.001953c3.3209 5.5664 7.332 11.395 11.74 17.043v0.001953c6.6127 8.4716 14.122 16.534 21.547 22.684 2.3 1.9 4.5008 3.5996 6.8008 5.0996 0.048555 0.0124 0.097907 0.019 0.14648 0.03125 1.7845 1.2837 3.569 2.2777 5.3535 3.1699 20.8 10.4 45.5 3.7984 62.1-4.1016l-14.301-7.2988-13.6-6.9004-48.127-24.607 49.928 21.707 14.5 6.3008 15.199 6.5996c-3.4-18.3-14.099-44-35.799-54.9-3.3-1.6-6.9004-3.1004-10.9-4.4004-2.9-0.9-5.8996-1.7-9.0996-2.5-11.65-2.75-24.751-4.2996-36.488-4.3496zm97.488 73.85 3.6992 13.9 3.5996 13.201 12.801 47.6-15.9-47-4.5-13.4-4.8008-14.199c-10.3 13.4-21.3 36.199-15.5 57.199 0.8747 3.11 2.1333 6.3182 3.6719 9.709 0.01066 0.06374 0.01836 0.12769 0.0293 0.19141 1.1 2.5 2.3988 5.0992 3.7988 7.6992 10.4 18.8 27.701 38.501 39.701 42.801 0.00763-0.00936 0.01581-0.01991 0.02344-0.0293 0.02502 0.00909 0.05119 0.02035 0.07617 0.0293 8.8-10.8 16.8-42.601 15.9-65.701-0.1-2.7-0.30117-5.2992-0.70117-7.6992-0.3-1.9-0.69922-3.8-1.1992-5.5-5.6-20.2-25.199-32.601-40.699-38.801z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,176 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import {toWidget} from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import Command from '@ckeditor/ckeditor5-core/src/command';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import noteIcon from './icons/note.svg';
export default class IncludeNote extends Plugin {
static get requires() {
return [ IncludeNoteEditing, IncludeNoteUI ];
}
}
class IncludeNoteUI extends Plugin {
init() {
const editor = this.editor;
const t = editor.t;
// The "includeNote" button must be registered among the UI components of the editor
// to be displayed in the toolbar.
editor.ui.componentFactory.add( 'includeNote', locale => {
// The state of the button will be bound to the widget command.
const command = editor.commands.get( 'insertIncludeNote' );
// The button will be an instance of ButtonView.
const buttonView = new ButtonView( locale );
buttonView.set( {
// The t() function helps localize the editor. All strings enclosed in t() can be
// translated and change when the language of the editor changes.
label: t( 'Include note' ),
icon: noteIcon,
tooltip: true
} );
// Bind the state of the button to the command.
buttonView.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' );
// Execute the command when the button is clicked (executed).
this.listenTo( buttonView, 'execute', () => editor.execute( 'insertIncludeNote' ) );
return buttonView;
} );
}
}
class IncludeNoteEditing extends Plugin {
static get requires() {
return [ Widget ];
}
init() {
this._defineSchema();
this._defineConverters();
this.editor.commands.add( 'insertIncludeNote', new InsertIncludeNoteCommand( this.editor ) );
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( 'includeNote', {
// Behaves like a self-contained object (e.g. an image).
isObject: true,
allowAttributes: [ 'noteId', 'boxSize' ],
// Allow in places where other blocks are allowed (e.g. directly in the root).
allowWhere: '$block'
} );
}
_defineConverters() {
const editor = this.editor;
const conversion = editor.conversion;
// <includeNote> converters
conversion.for( 'upcast' ).elementToElement( {
model: ( viewElement, { writer: modelWriter } ) => {
return modelWriter.createElement( 'includeNote', {
noteId: viewElement.getAttribute( 'data-note-id' ),
boxSize: viewElement.getAttribute( 'data-box-size' ),
} );
},
view: {
name: 'section',
classes: 'include-note'
}
} );
conversion.for( 'dataDowncast' ).elementToElement( {
model: 'includeNote',
view: ( modelElement, { writer: viewWriter } ) => {
// it would make sense here to downcast to <iframe>, with this even HTML export can support note inclusion
return viewWriter.createContainerElement( 'section', {
class: 'include-note',
'data-note-id': modelElement.getAttribute( 'noteId' ),
'data-box-size': modelElement.getAttribute( 'boxSize' ),
} );
}
} );
conversion.for( 'editingDowncast' ).elementToElement( {
model: 'includeNote',
view: ( modelElement, { writer: viewWriter } ) => {
const noteId = modelElement.getAttribute( 'noteId' );
const boxSize = modelElement.getAttribute( 'boxSize' );
const section = viewWriter.createContainerElement( 'section', {
class: 'include-note box-size-' + boxSize,
'data-note-id': noteId,
'data-box-size': boxSize
} );
const includedNoteWrapper = viewWriter.createUIElement( 'div', {
class: 'include-note-wrapper',
"data-cke-ignore-events": true
}, function( domDocument ) {
const domElement = this.toDomElement( domDocument );
const editorEl = editor.editing.view.getDomRoot();
const component = glob.getComponentByEl( editorEl );
component.loadIncludedNote( noteId, $( domElement ) );
preventCKEditorHandling( domElement, editor );
return domElement;
} );
viewWriter.insert( viewWriter.createPositionAt( section, 0 ), includedNoteWrapper );
return toWidget( section, viewWriter, { label: 'include note widget' } );
}
} );
}
}
class InsertIncludeNoteCommand extends Command {
execute() {
const editorEl = this.editor.editing.view.getDomRoot();
const component = glob.getComponentByEl(editorEl);
component.triggerCommand('addIncludeNoteToText');
}
refresh() {
const model = this.editor.model;
const selection = model.document.selection;
const allowedIn = model.schema.findAllowedParent( selection.getFirstPosition(), 'includeNote' );
this.isEnabled = allowedIn !== null;
}
}
/**
* Hack coming from https://github.com/ckeditor/ckeditor5/issues/4465
* Source issue: https://github.com/zadam/trilium/issues/1117
*/
function preventCKEditorHandling( domElement, editor ) {
// Prevent the editor from listening on below events in order to stop rendering selection.
// commenting out click events to allow link click handler to still work
//domElement.addEventListener( 'click', stopEventPropagationAndHackRendererFocus, { capture: true } );
domElement.addEventListener( 'mousedown', stopEventPropagationAndHackRendererFocus, { capture: true } );
domElement.addEventListener( 'focus', stopEventPropagationAndHackRendererFocus, { capture: true } );
// Prevents TAB handling or other editor keys listeners which might be executed on editors selection.
domElement.addEventListener( 'keydown', stopEventPropagationAndHackRendererFocus, { capture: true } );
function stopEventPropagationAndHackRendererFocus( evt ) {
evt.stopPropagation();
// This prevents rendering changed view selection thus preventing to changing DOM selection while inside a widget.
editor.editing.view._renderer.isFocused = false;
}
}

View File

@ -0,0 +1,37 @@
/**
* https://github.com/zadam/trilium/issues/978
*/
export default function indentBlockShortcutPlugin(editor) {
editor.keystrokes.set( 'Tab', ( data, cancel ) => {
const command = editor.commands.get( 'indentBlock' );
if ( command.isEnabled && !isInTable() ) {
command.execute();
cancel();
}
} );
editor.keystrokes.set( 'Shift+Tab', ( data, cancel ) => {
const command = editor.commands.get( 'outdentBlock' );
if ( command.isEnabled && !isInTable() ) {
command.execute();
cancel();
}
} );
// in table TAB should switch cells
function isInTable() {
let el = editor.model.document.selection.getFirstPosition();
while (el) {
if (el.name === 'tableCell') {
return true;
}
el = el.parent;
}
return false;
}
}

View File

@ -0,0 +1,31 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import internalLinkIcon from './icons/trilium.svg';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
export default class InternalLinkPlugin extends Plugin {
init() {
const editor = this.editor;
editor.ui.componentFactory.add( 'internalLink', locale => {
const view = new ButtonView( locale );
view.set( {
label: 'Internal Trilium link (CTRL-L)',
icon: internalLinkIcon,
tooltip: true
} );
// enable internal link only if the editor is not read only
view.bind('isEnabled').to(editor, 'isReadOnly', isReadOnly => !isReadOnly);
view.on( 'execute', () => {
const editorEl = editor.editing.view.getDomRoot();
const component = glob.getComponentByEl(editorEl);
component.triggerCommand('addLinkToText');
} );
return view;
} );
}
}

View File

@ -0,0 +1,15 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
export default class ItalicAsEmPlugin extends Plugin {
init() {
this.editor.conversion
.for("downcast")
.attributeToElement({
model: "italic",
view: "em",
converterPriority: "high"
});
}
}

View File

@ -0,0 +1,26 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import markdownIcon from './icons/markdown-mark.svg';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
export default class MarkdownImportPlugin extends Plugin {
init() {
const editor = this.editor;
editor.ui.componentFactory.add( 'markdownImport', locale => {
const view = new ButtonView( locale );
view.set( {
label: 'Markdown import from clipboard',
icon: markdownIcon,
tooltip: true
} );
// Callback executed once the image is clicked.
view.on( 'execute', () => {
glob.importMarkdownInline();
} );
return view;
} );
}
}

View File

@ -0,0 +1,50 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import Command from '@ckeditor/ckeditor5-core/src/command';
export default class MentionCustomization extends Plugin {
afterInit() {
const editor = this.editor;
// override standard mention command (see https://github.com/ckeditor/ckeditor5/issues/6470)
editor.commands.add('mention', new CustomMentionCommand(editor));
}
}
class CustomMentionCommand extends Command {
execute(options) {
const {model} = this.editor;
const {document} = model;
const {selection} = document;
const {mention} = options;
const range = options.range || selection.getFirstRange();
if (mention.id.startsWith('#') || mention.id.startsWith('~')) {
model.change(writer => {
// Replace a range with the text with a mention.
model.insertContent( writer.createText( mention.id, {} ), range );
});
}
else if (mention.action === 'create-note') {
const editorEl = this.editor.editing.view.getDomRoot();
const component = glob.getComponentByEl(editorEl);
component.createNoteForReferenceLink(mention.noteTitle).then(notePath => {
this.insertReference(range, notePath);
});
}
else {
this.insertReference(range, options.mention.notePath);
}
}
insertReference(range, notePath) {
const {model} = this.editor;
model.change(writer => {
// override the selection or at least the beginning @ character
model.insertContent(writer.createText('', {}), range);
this.editor.execute('referenceLink', {href: '#' + notePath});
});
}
}

View File

@ -0,0 +1,142 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import { toWidget, viewToModelPositionOutsideModelElement } from '@ckeditor/ckeditor5-widget/src/utils';
import Widget from '@ckeditor/ckeditor5-widget/src/widget';
import Command from '@ckeditor/ckeditor5-core/src/command';
export default class ReferenceLink extends Plugin {
static get requires() {
return [ ReferenceLinkEditing ];
}
}
class ReferenceLinkCommand extends Command {
execute( { href } ) {
if (!href?.trim()) {
return;
}
const editor = this.editor;
// make sure the referenced note is in cache before adding the reference element
glob.getReferenceLinkTitle(href).then(() => {
editor.model.change(writer => {
const placeholder = writer.createElement('reference', {href});
// ... and insert it into the document.
editor.model.insertContent(placeholder);
// Put the selection on the inserted element.
writer.setSelection(placeholder, 'after');
});
});
}
refresh() {
const model = this.editor.model;
const selection = model.document.selection;
this.isEnabled = model.schema.checkChild(selection.focus.parent, 'reference');
}
}
class ReferenceLinkEditing extends Plugin {
static get requires() {
return [ Widget ];
}
init() {
this._defineSchema();
this._defineConverters();
this.editor.commands.add( 'referenceLink', new ReferenceLinkCommand( this.editor ) );
this.editor.editing.mapper.on(
'viewToModelPosition',
viewToModelPositionOutsideModelElement( this.editor.model,
viewElement => viewElement.hasClass( 'reference-link' ) )
);
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( 'reference', {
// Allow wherever a text is allowed:
allowWhere: '$text',
isInline: true,
// The inline widget is self-contained, so it cannot be split by the caret, and it can be selected:
isObject: true,
allowAttributes: [ 'href', 'uploadId', 'uploadStatus' ]
} );
}
_defineConverters() {
const editor = this.editor;
const conversion = editor.conversion;
conversion.for( 'upcast' ).elementToElement( {
view: {
name: 'a',
classes: [ 'reference-link' ]
},
model: ( viewElement, { writer: modelWriter } ) => {
const href = viewElement.getAttribute('href');
return modelWriter.createElement( 'reference', { href } );
}
} );
conversion.for( 'editingDowncast' ).elementToElement( {
model: 'reference',
view: ( modelItem, { writer: viewWriter } ) => {
const href = modelItem.getAttribute( 'href' );
const referenceLinkView = viewWriter.createContainerElement( 'a', {
href,
class: 'reference-link'
},
{
renderUnsafeAttributes: [ 'href' ]
} );
const noteTitleView = viewWriter.createUIElement('span', {}, function( domDocument ) {
const domElement = this.toDomElement( domDocument );
const editorEl = editor.editing.view.getDomRoot();
const component = glob.getComponentByEl(editorEl);
component.loadReferenceLinkTitle($(domElement), href);
return domElement;
});
viewWriter.insert( viewWriter.createPositionAt( referenceLinkView, 0 ), noteTitleView );
// Enable widget handling on a reference element inside the editing view.
return toWidget( referenceLinkView, viewWriter );
}
} );
conversion.for( 'dataDowncast' ).elementToElement( {
model: 'reference',
view: ( modelItem, { writer: viewWriter } ) => {
const href = modelItem.getAttribute( 'href' );
const referenceLinkView = viewWriter.createContainerElement( 'a', {
href: href,
class: 'reference-link'
} );
const title = glob.getReferenceLinkTitleSync(href);
const innerText = viewWriter.createText(title);
viewWriter.insert(viewWriter.createPositionAt(referenceLinkView, 0), innerText);
return referenceLinkView;
}
} );
}
}

View File

@ -0,0 +1,7 @@
// A simple plugin that extends the remove format feature to consider links.
export default function removeFormatLinksPlugin( editor ) {
// Extend the editor schema and mark the "linkHref" model attribute as formatting.
editor.model.schema.setAttributeProperties( 'linkHref', {
isFormatting: true
} );
}

View File

@ -0,0 +1,19 @@
export function SpecialCharactersEmoji( editor ) {
editor.plugins.get( 'SpecialCharacters' ).addItems( 'Emoji', [
{ title: 'smiley face', character: '😊' },
{ title: 'grinning face', character: '😄' },
{ title: 'grinning face with big eyes', character: '😃' },
{ title: 'grinning face with sweat', character: '😅' },
{ title: 'beaming face with smiling eyes', character: '😃' },
{ title: 'neutral face', character: '😐' },
{ title: 'rolling on the floor laughing', character: '🤣' },
{ title: 'face with tears of joy', character: '😂' },
{ title: 'heart', character: '❤️' },
{ title: 'hands pressed together', character: '🙏' },
{ title: 'thumbs up', character: '👍' },
{ title: 'rocket', character: '🚀' },
{ title: '100', character: '💯' },
{ title: 'wind blowing face', character: '🌬️' },
{ title: 'floppy disk', character: '💾' }
], { label: 'Emoji' } );
}

View File

@ -0,0 +1,15 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
export default class StrikethroughAsDel extends Plugin {
init() {
this.editor.conversion
.for("downcast")
.attributeToElement({
model: "strikethrough",
view: "del",
converterPriority: "high"
});
}
}

View File

@ -0,0 +1,139 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import FileRepository from '@ckeditor/ckeditor5-upload/src/filerepository';
export default class UploadimagePlugin extends Plugin {
/**
* @inheritDoc
*/
static get requires() {
return [ FileRepository ];
}
static get pluginName() {
return 'UploadimagePlugin';
}
init() {
this.editor.plugins.get('FileRepository').createUploadAdapter = loader => new Adapter(loader);
}
}
class Adapter {
/**
* Creates a new adapter instance.
*
* @param {module:upload/filerepository~FileLoader} loader
*/
constructor(loader) {
/**
* FileLoader instance to use during the upload.
*
* @member {module:upload/filerepository~FileLoader} #loader
*/
this.loader = loader;
}
/**
* Starts the upload process.
*
* @see module:upload/filerepository~Adapter#upload
* @returns {Promise}
*/
upload() {
return this.loader.file
.then( file => new Promise( ( resolve, reject ) => {
this._initRequest().then(() => {
this._initListeners( resolve, reject, file );
this._sendRequest( file );
});
} ) );
}
/**
* Aborts the upload process.
*
* @see module:upload/filerepository~Adapter#abort
* @returns {Promise}
*/
abort() {
if (this.xhr) {
this.xhr.abort();
}
}
/**
* Initializes the XMLHttpRequest object.
*
* @private
*/
_initRequest() {
return glob.getHeaders().then(headers => {
const xhr = this.xhr = new XMLHttpRequest();
const {noteId} = glob.getActiveContextNote();
// this must be a relative path
const url = `api/notes/${noteId}/attachments/upload`;
xhr.open('POST', url, true);
xhr.responseType = 'json';
for (const headerName in headers) {
xhr.setRequestHeader(headerName, headers[headerName]);
}
});
}
/**
* Initializes XMLHttpRequest listeners.
*
* @private
* @param {Function} resolve Callback function to be called when the request is successful.
* @param {Function} reject Callback function to be called when the request cannot be completed.
*/
async _initListeners(resolve, reject) {
const xhr = this.xhr;
const loader = this.loader;
const file = await loader.file;
const genericError = 'Cannot upload file:' + ` ${file.name}.`;
xhr.addEventListener('error', () => reject(genericError));
xhr.addEventListener('abort', () => reject());
xhr.addEventListener('load', () => {
const response = xhr.response;
if (!response || !response.uploaded) {
return reject(response && response.error && response.error.message ? response.error.message : genericError);
}
resolve({
default: response.url
});
});
// Upload progress when it's supported.
/* istanbul ignore else */
if (xhr.upload) {
xhr.upload.addEventListener('progress', evt => {
if (evt.lengthComputable) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
});
}
}
/**
* Prepares the data and sends the request.
*
* @private
*/
async _sendRequest() {
// Prepare form data.
const data = new FormData();
data.append('upload', await this.loader.file);
// Send request.
this.xhr.send(data);
}
}

View File

@ -0,0 +1,18 @@
const fs = require("fs");
const sourcePackageJson = JSON.parse(fs.readFileSync("../ckeditor5-build-decoupled-document/package.json"));
const destPackageJson = JSON.parse(fs.readFileSync("./package.json"));
function updateDependencies(sourceDeps, destDeps) {
for (const [ name, version ] of Object.entries(sourceDeps)) {
destDeps[name] = version;
}
}
updateDependencies(sourcePackageJson.dependencies, destPackageJson.dependencies);
updateDependencies(sourcePackageJson.devDependencies, destPackageJson.devDependencies);
const coreVersion = sourcePackageJson.devDependencies["@ckeditor/ckeditor5-core"];
destPackageJson.version = coreVersion;
fs.writeFileSync("./package.json", JSON.stringify(destPackageJson, null, 2));

View File

@ -0,0 +1,261 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* globals document */
import DecoupledEditor from '../src/ckeditor.js';
import BaseDecoupledEditor from '@ckeditor/ckeditor5-editor-decoupled/src/decouplededitor.js';
import { describeMemoryUsage, testMemoryUsage } from '@ckeditor/ckeditor5-core/tests/_utils/memory.js';
describe( 'DecoupledEditor build', () => {
let editor, editorData, editorElement;
beforeEach( () => {
editorData = '<p><strong>foo</strong> bar</p>';
editorElement = document.createElement( 'div' );
editorElement.innerHTML = editorData;
document.body.appendChild( editorElement );
} );
afterEach( () => {
editorElement.remove();
editor = null;
} );
describe( 'build', () => {
it( 'contains plugins', () => {
expect( DecoupledEditor.builtinPlugins ).to.not.be.empty;
} );
it( 'contains config', () => {
expect( DecoupledEditor.defaultConfig.toolbar ).to.not.be.empty;
} );
} );
describe( 'editor with data', () => {
test( () => editorData );
it( 'does not define the UI DOM structure', () => {
return DecoupledEditor.create( editorData )
.then( newEditor => {
expect( newEditor.ui.view.element ).to.be.null;
expect( newEditor.ui.view.toolbar.element.parentElement ).to.be.null;
expect( newEditor.ui.view.editable.element.parentElement ).to.be.null;
return newEditor.destroy();
} );
} );
} );
describe( 'editor with editable element', () => {
test( () => editorElement );
it( 'uses the provided editable element', () => {
return DecoupledEditor.create( editorElement )
.then( newEditor => {
expect( newEditor.ui.view.editable.element.parentElement ).to.equal( document.body );
return newEditor.destroy();
} );
} );
} );
describeMemoryUsage( () => {
testMemoryUsage(
'should not grow on multiple create/destroy',
() => DecoupledEditor.create( document.querySelector( '#mem-editor' ) ) );
} );
function test( getEditorDataOrElement ) {
describe( 'create()', () => {
beforeEach( () => {
return DecoupledEditor.create( getEditorDataOrElement() )
.then( newEditor => {
editor = newEditor;
} );
} );
afterEach( () => {
return editor.destroy();
} );
it( 'creates an instance which inherits from the DecoupledEditor', () => {
expect( editor ).to.be.instanceof( BaseDecoupledEditor );
expect( editor ).to.be.instanceof( BaseDecoupledEditor );
} );
it( 'loads passed data', () => {
expect( editor.getData() ).to.equal( '<p><strong>foo</strong> bar</p>' );
} );
} );
describe( 'destroy()', () => {
beforeEach( () => {
return DecoupledEditor.create( getEditorDataOrElement() )
.then( newEditor => {
editor = newEditor;
} );
} );
} );
describe( 'plugins', () => {
beforeEach( () => {
return DecoupledEditor.create( getEditorDataOrElement() )
.then( newEditor => {
editor = newEditor;
} );
} );
afterEach( () => {
return editor.destroy();
} );
it( 'paragraph works', () => {
const data = '<p>Some text inside a paragraph.</p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'basic-styles work', () => {
const data = [
'<p>',
'<strong>Test:strong</strong>',
'<i>Test:i</i>',
'<u>Test:u</u>',
'<s>Test:s</s>',
'</p>'
].join( '' );
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'block-quote works', () => {
const data = '<blockquote><p>Quote</p></blockquote>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'heading works', () => {
const data = [
'<h2>Heading 1.</h2>',
'<h3>Heading 1.1</h3>',
'<h4>Heading 1.1.1</h4>',
'<h4>Heading 1.1.2</h4>',
'<h3>Heading 1.2</h3>',
'<h4>Heading 1.2.1</h4>',
'<h2>Heading 2</h2>'
].join( '' );
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'image works', () => {
const data = '<figure class="image"><img src="/assets/sample.png"></figure>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'list works', () => {
const data = [
'<ul>',
'<li>Item 1.</li>',
'<li>Item 2.</li>',
'</ul>',
'<ol>',
'<li>Item 1.</li>',
'<li>Item 2.</li>',
'</ol>'
].join( '' );
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'list style works', () => {
const data = [
'<ol style="list-style-type:upper-roman;">' +
'<li>Item 1.</li>' +
'<li>Item 2.</li>' +
'</ol>'
].join( '' );
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'link works', () => {
const data = '<p><a href="//ckeditor.com">CKEditor.com</a></p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
it( 'font size works', () => {
const data = '<p><span class="text-big">foo</span></p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
expect( editor.model.document.selection.getAttribute( 'fontSize' ) ).to.equal( 'big' );
} );
it( 'font family works', () => {
const data = '<p><span style="font-family:Georgia, serif;">foo</span></p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
expect( editor.model.document.selection.getAttribute( 'fontFamily' ) ).to.equal( 'Georgia, serif' );
} );
it( 'font background color works', () => {
const data = '<p><span style="background-color:hsl(60,75%,60%);">foo</span></p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
expect( editor.model.document.selection.getAttribute( 'fontBackgroundColor' ) ).to.equal( 'hsl(60,75%,60%)' );
} );
it( 'font color works', () => {
const data = '<p><span style="color:hsl(0,75%,60%);">foo</span></p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
expect( editor.model.document.selection.getAttribute( 'fontColor' ) ).to.equal( 'hsl(0,75%,60%)' );
} );
it( 'alignment works', () => {
const data = '<p style="text-align:right;">foo</p>';
editor.setData( data );
expect( editor.getData() ).to.equal( data );
} );
} );
describe( 'config', () => {
afterEach( () => {
return editor.destroy();
} );
// https://github.com/ckeditor/ckeditor5/issues/572
it( 'allows configure toolbar items through config.toolbar', () => {
return DecoupledEditor
.create( getEditorDataOrElement(), {
toolbar: [ 'bold' ]
} )
.then( newEditor => {
editor = newEditor;
expect( editor.ui.view.toolbar.items.length ).to.equal( 1 );
} );
} );
} );
}
} );

View File

@ -0,0 +1,74 @@
<h2>The toolbar</h2>
<div class="toolbar-container"></div>
<h2>The editable</h2>
<div class="editable-container">
<div id="editor">
<h2>About CKEditor&nbsp;5</h2>
<p>This is <a href="https://ckeditor.com">CKEditor&nbsp;5</a>.</p>
<figure class="image">
<img src="./sample.jpg" alt="Autumn fields" />
</figure>
<p>After more than 2 years of building the next generation editor from scratch and closing over 980 tickets,
we created a highly <strong>extensible and flexible architecture</strong> which consists of an <strong>amazing
editing framework</strong> and <strong>editing solutions</strong> that will be built on top of it.</p>
<p>We explained this design choice in
<a href="https://medium.com/content-uneditable/ckeditor-5-the-future-of-rich-text-editing-2b9300f9df2c">&ldquo;CKEditor 5:
The future of rich text editing&ldquo;</a>:</p>
<blockquote><p>(…) we are changing our approach with CKEditor 5. We will no longer have only two solutions
available, instead CKEditor will be seen as a framework for editing solutions. At the same time, we will be
developing several out-of-the-box solutions based on it, which will be available to use in many different contexts.
It will be a real “one size fits all” approach, from little requirements, to super advanced full featured
applications.</p></blockquote>
<h3>Notes</h3>
<p><a href="https://ckeditor.com">CKEditor&nbsp;5</a> is <i>under heavy development</i> and this demo
is not production-ready software. For example:</p>
<ul>
<li><strong>Only Chrome, Opera and Safari are supported</strong>.</li>
<li>Firefox requires enabling the
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/onselectionchange">
&ldquo;dom.select_events.enabled&rdquo;</a> option.</li>
<li><a href="https://github.com/ckeditor/ckeditor5/issues/342">Support for pasting</a>
is under development (content filtering is unstable).</li>
</ul>
<p>It has <em>bugs</em> that we are aware of &mdash; and that we will be working on in the next few
iterations of the project. Stay tuned for some updates soon!</p>
</div>
</div>
<style>
.editable-container,
.toolbar-container {
position: relative;
border: 1px solid #ddd;
background: #eee;
}
.toolbar-container {
padding: 1em;
}
.editable-container {
padding: 3em;
overflow-y: scroll;
max-height: 500px;
}
.editable-container > .ck-editor__editable {
min-height: 21cm;
padding: 2em;
border: 1px #D3D3D3 solid;
border-radius: var(--ck-border-radius);
background: white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
</style>

View File

@ -0,0 +1,19 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* eslint-env commonjs */
/* globals window, document, console */
const DecoupledEditor = require( '../../build/ckeditor' );
DecoupledEditor.create( document.querySelector( '#editor' ) )
.then( editor => {
document.querySelector( '.toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
window.editor = editor;
} )
.catch( error => {
console.error( 'There was a problem initializing the editor.', error );
} );

View File

@ -0,0 +1,9 @@
# CKEditor&nbsp;5 document editor build standard version (CommonJS `require()`)
Just play with it.
**Note:** Remember to rebuild the bundles by running `npm run build` in build's package directory. You can also run webpack in the watch mode:
```
./node_modules/.bin/webpack -w
```

View File

@ -0,0 +1,97 @@
<h2>The toolbar</h2>
<div class="toolbar-container"></div>
<h2>The editable</h2>
<div class="editable-container">
<div id="editor">
<h2>About CKEditor&nbsp;5</h2>
<p>This is <a href="https://ckeditor.com">CKEditor&nbsp;5</a>.</p>
<figure class="image">
<img src="./sample.jpg" alt="Autumn fields" />
</figure>
<p>After more than 2 years of building the next generation editor from scratch and closing over 980 tickets,
we created a highly <strong>extensible and flexible architecture</strong> which consists of an <strong>amazing
editing framework</strong> and <strong>editing solutions</strong> that will be built on top of it.</p>
<p>We explained this design choice in
<a href="https://medium.com/content-uneditable/ckeditor-5-the-future-of-rich-text-editing-2b9300f9df2c">&ldquo;CKEditor 5:
The future of rich text editing&ldquo;</a>:</p>
<blockquote><p>(…) we are changing our approach with CKEditor 5. We will no longer have only two solutions
available, instead CKEditor will be seen as a framework for editing solutions. At the same time, we will be
developing several out-of-the-box solutions based on it, which will be available to use in many different contexts.
It will be a real “one size fits all” approach, from little requirements, to super advanced full featured
applications.</p></blockquote>
<h3>Notes</h3>
<p><a href="https://ckeditor.com">CKEditor&nbsp;5</a> is <i>under heavy development</i> and this demo
is not production-ready software. For example:</p>
<ol style="list-style-type:upper-roman;">
<li><strong>Only Chrome, Opera and Safari are supported</strong>.</li>
<li>Firefox requires enabling the
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/onselectionchange">
&ldquo;dom.select_events.enabled&rdquo;</a> option.</li>
<li><a href="https://github.com/ckeditor/ckeditor5/issues/342">Support for pasting</a>
is under development (content filtering is unstable).</li>
</ol>
<p>It has <em>bugs</em> that we are aware of &mdash; and that we will be working on in the next few
iterations of the project. Stay tuned for some updates soon!</p>
<table>
<thead>
<tr>
<th>Version</th>
<th>Release date</th>
</tr>
</thead>
<tbody>
<tr>
<td>10.0.1</td>
<td>May 22, 2018</td>
</tr>
<tr>
<td>10.0.0</td>
<td>April 25, 2018</td>
</tr>
<tr>
<td>10.0.0-beta.2</td>
<td>April 10, 2018</td>
</tr>
</tbody>
</table>
</div>
</div>
<style>
.editable-container,
.toolbar-container {
position: relative;
border: 1px solid #ddd;
background: #eee;
}
.toolbar-container {
padding: 1em;
}
.editable-container {
padding: 3em;
overflow-y: scroll;
max-height: 500px;
}
.editable-container > .ck-editor__editable {
min-height: 21cm;
padding: 2em;
border: 1px #D3D3D3 solid;
border-radius: var(--ck-border-radius);
background: white;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
}
</style>

View File

@ -0,0 +1,18 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* globals window, document, console */
import DecoupledEditor from '../../build/ckeditor.js';
DecoupledEditor.create( document.querySelector( '#editor' ) )
.then( editor => {
document.querySelector( '.toolbar-container' ).appendChild( editor.ui.view.toolbar.element );
window.editor = editor;
} )
.catch( error => {
console.error( 'There was a problem initializing the editor.', error );
} );

View File

@ -0,0 +1,9 @@
# CKEditor&nbsp;5 document editor build standard version
Just play with it.
**Note:** Remember to rebuild the bundles by running `npm run build` in build's package directory. You can also run webpack in the watch mode:
```
./node_modules/.bin/webpack -w
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@ -0,0 +1,9 @@
/*
* Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/* Give the block toolbar button some space, moving it a few pixels away from the editable area. */
.ck.ck-block-toolbar-button {
transform: translateX( calc(-1 * var(--ck-spacing-large)) );
}

View File

@ -0,0 +1,7 @@
{
"extends": "ckeditor5/tsconfig.json",
"include": [
"src",
"../../typings"
]
}

View File

@ -0,0 +1,13 @@
{
"extends": "ckeditor5/tsconfig.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"declarationDir": "build",
"stripInternal": true
},
"include": [
"src",
"../../typings"
]
}

View File

@ -0,0 +1,77 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
'use strict';
/* eslint-env node */
const path = require( 'path' );
const webpack = require( 'webpack' );
const { bundler, loaders } = require( '@ckeditor/ckeditor5-dev-utils' );
const { CKEditorTranslationsPlugin } = require( '@ckeditor/ckeditor5-dev-translations' );
const TerserPlugin = require( 'terser-webpack-plugin' );
module.exports = {
devtool: 'source-map',
performance: { hints: false },
entry: path.resolve( __dirname, 'src', 'ckeditor.ts' ),
output: {
// The name under which the editor will be exported.
library: 'CKEditor',
path: path.resolve( __dirname, 'build' ),
filename: 'ckeditor.js',
libraryTarget: 'umd',
libraryExport: 'default'
},
optimization: {
minimizer: [
new TerserPlugin( {
sourceMap: true,
terserOptions: {
output: {
// Preserve CKEditor 5 license comments.
comments: /^!/
}
},
extractComments: false
} )
]
},
plugins: [
new CKEditorTranslationsPlugin( {
// UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
// When changing the built-in language, remember to also change it in the editor's configuration (src/ckeditor.js).
language: 'en',
additionalLanguages: 'all'
} ),
new webpack.BannerPlugin( {
banner: bundler.getLicenseBanner(),
raw: true
} )
],
module: {
rules: [
loaders.getIconsLoader( { matchExtensionOnly: true } ),
loaders.getStylesLoader( {
themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ),
minify: true
} ),
loaders.getTypeScriptLoader()
]
},
resolve: {
extensions: [ '.ts', '.js', '.json' ],
extensionAlias: {
'.js': [ '.js', '.ts' ]
}
}
};