tui.editor

πŸžπŸ“ Markdown WYSIWYG Editor. GFM Standard + Chart & UML Extensible.

MIT License

Downloads
589.4K
Stars
16.7K
Committers
28

Bot releases are hidden (Show)

tui.editor - [email protected]

Published by js87zz over 3 years ago

Bugfixes

  • Fixed broken composition in squire selection.(#1668)
  • Fixed wrong converting bullet list item with the ordered number contents.(#1669)
tui.editor - [email protected]

Published by js87zz over 3 years ago

Bugfixes

  • Added type="button" to file upload button.(#1585)
  • Fixed that addImageBlobHook inserts image twice.(#1623)
  • Fixed wrong parsing of html attrs.(#1630)
  • Fixed that getHTML API triggers change event.(#1632)
  • Fixed that the custom toolbar item cannot be toggled with active, disabled state.(#1639)
  • Fixed wrong customHTMLRenderer option type definition.(#1640)
  • Fixed that encode link url unnecessarily.(#1641)
  • Fixed that editor cannot parse the br tag when calling setHTML API.(#1644)

Environment

  • added missing dev dependencies.(#1649)
  • change bundling format of the chart, uml, color-syntax plugins to umd for compatibility of the webpack4.(#1649)
tui.editor - [email protected]

Published by js87zz over 3 years ago

Bugfixes

  • change remove method to destroy method in vue wrapper.(#1583)
tui.editor - v3.0.0

Published by js87zz over 3 years ago

🎊 TOAST UI Editor 3.0 🎊

With the release of TOAST UI Editor 2.0, we were able to improve a lot of features including the Editor's markdown parsing accuracy, syntax highlighting feature, scroll sync accuracy, and more. All of these improvements were made possible due to the implementation of our own ToastMark markdown parser. However, because we focused mainly on the markdown editor for the 2.0, there were no further improvements on the UI like toolbars and switch tabs.

We worked on TOAST UI 3.0 with not only markdown on our mind but also improving the overall structure of the editor and the usage. We added ways for our users to extend our editor's functionalities including custom markdown syntax support, widget node insertion, and improved plugin system and we also overhauled the design to be more sleek and modern. πŸ™Œ

Let's take a look at the TOAST UI Editor 3.0's new changes.

🧐 What Changed With 3.0?

Core Module Replacement βž” Lighter Editor

The original markdown editor had both CodeMirror and ToastMark maintain text information and share changes between the two. However, for the WYSIWYG editor, we used squire to edit and manage the contents.

In other words, because the two editors edited and managed data differently, the controlling structures were also completely different. Therefore, there were issues with internal code consistency and feature extension.

  • When adding or editing certain text, despite the similarity in task, the editors have to use two different APIs and options.
  • While heading, list, tables, and more are maintained as nodes, internally, the editors manage the nodes as completely different objects, making the code difficult to read.

Granted markdown is a text-based editor and WYSIWYG editor is a DOM node-based editor, so the data model structures must be different. However, if two editors were to use a singular module to manage the nodes, classes and structures of operations that abstractify data or manage data can be used uniformly.

  • Customizing the editor using options and APIs as users is a painstaking task. If a user were to customize a certain node's rendered result, the user would have to make the changes for both the markdown editor as well as the WYSIWYG editor according to their structures.

In order to deal with this issue, we used the Prosemirror, a development tool used to build a WYSIWYG editor, for TOAST UI Editor 3.0, and we were able to unify the internal dependencies of the editors into one. The unified dependency allowed us to follow a single, internal structure, and we were able to remove the past dependencies including CodeMirror, squire, and to-mark.

// All nodes from the editor will take the following class structure. 
export class ListItem extends NodeSchema {
  get name() {
    return 'listItem';
  }

  get schema() {
    return {
      content: 'paragraph listGroup*',
      attrs: {
        task: { default: false },
        checked: { default: false },
        rawHTML: { default: null },
      },
      defining: true,
      parseDOM: [
        // ...
      ],
      toDOM({ attrs }: ProsemirrorNode): DOMOutputSpecArray {
        // ...
      },
    };
  }

  commands(): EditorCommand {
    // ...
  }

  keymaps() {
    return {
      Enter: this.commands()(),
    };
  }
}

Furthermore, we reduced the total file size of the bundle by about thirty percent from 602.1KB to 495.6KB.

images

Our decision to use Prosemirror will be discussed in a separate article.

Since v3.0 also provides a ESM bundle, if you do not need legacy browser support, you can use the ESM bundle to use the editor more efficiently.

Custom Markdown Syntax Support

TOAST UI Editor primarily follows the CommonMark while supporting GFM, additionally. However, what if you were to render elements like mathematical expressions or charts? TOAST UI Editor 3.0 options allow users to customize markdown syntax.

Using custom syntax, users can use KaTex syntax to represent mathematical expressions as shown in the following example.

Markdown
image

WYSIWYG
image

As you can see in the above images, you can enter any text to use custom syntax in the block surrounded by the $$ symbol. Using custom syntax, users can define their own parsing logic to render text that isn't supported by markdown.

Widget Node

TOAST UI Editor 3.0 now comes with newly added widgetRules option that allows users to display plain text as a designated widget node. With this option, you can display the linked text as mention nodes or as any form of DOM node you choose.

const reWidgetRule = /\[(@\S+)\]\((\S+)\)/;

const editor = new Editor({
  el: document.querySelector('#editor'),
  widgetRules: [
    {
      rule: reWidgetRule,
      toDOM(text) {
        const rule = reWidgetRule;
        const matched = text.match(rule);
        const span = document.createElement('span');
  
        span.innerHTML = `<a class="widget-anchor" href="${matched[2]}">${matched[1]}</a>`;
        return span;
      },
    },
  ],
});

As you can see in the example code, the widgetRules define the rules in an array, and each rule is attributed as rule and toDOM properties.

  • rule: Must be a RegExp value, and any text that fits the expression is substituted as widget node.
  • toDOM: Define the DOM node of the widget node that will be rendered.

image

You can also insert the widget node synced with a popup widget as shown below.

image

Plugin System

TOAST UI Editor offers five plugins out of the box.

Plugin Description
chart Plugin for rendering charts
code-syntax-highlight Plugin for syntax highlighting
color-syntax Plugin for color picker
table-merged-cell Plugin for table merged cells
uml Plugin for UML

Aside from the five default plugins, users can also define their own plugin functions. Previously in v2.0, there was no clear format for defining plugins, and users had to access the editor instance directly as shown below. The previous method of defining plugins made it difficult for users to understand the code by creating a strong coupling between the editor and the plugin.

v2.0

export default function colorSyntaxPlugin(editor, options = {}) {
  // ...
  editor.eventManager.listen('convertorAfterMarkdownToHtmlConverted', html => {
    // ...
  });

  editor.eventManager.listen('convertorAfterHtmlToMarkdownConverted', markdown => {
    // ...
  });

  if (!editor.isViewer() && editor.getUI().name === 'default') {
    editor.addCommand('markdown', {
      name: 'color',
      exec(mde, color) {
        // Access the CodeMirror instance
        const cm = mde.getEditor();
        const rangeFrom = cm.getCursor('from');
        // ...
      }
    });

    editor.addCommand('wysiwyg', {
      name: 'color',
      exec(wwe, color) {
        if (!color) {
          return;
        }

        // access the squire instance
        const sq = wwe.getEditor();
        const tableSelectionManager = wwe.componentManager.getManager('tableSelection');

        // ...
      }
    });
  }
});

The code above is a little snippet of the color-syntax plugin code from the v2.0. Without a predefined format, there was a lot of editor API dependent code, and there are even codes that have to access CodeMirror and squire directly to control the internal states.

TOAST UI Editor 3.0 has removed all of the previous foundational structures and has made it so that users can define the plugins in a predefined format. Furthermore, the plugin is now separated to function even with a minimal access to the editor.

v3.0

export default function colorSyntaxPlugin(context, options) {
  // ...
  return {
    markdownCommands: {
      color: ({ selectedColor }, { tr, selection, schema }, dispatch) => {
        if (selectedColor) {
          // ...
          return true;
        }
        return false;
      },
    },
    wysiwygCommands: {
      color: ({ selectedColor }, { tr, selection, schema }, dispatch) => {
        if (selectedColor) {
          // ...
          return true;
        }
        return false;
      },
    },
    toolbarItems: [
      {
        groupIndex: 0,
        itemIndex: 3,
        item: toolbarItem,
      },
    ],
    // ...
  };
}

Newly defined color-syntax plugin code is comparatively simpler and easier to read than the previous code. The object returned from the plugin function has properties (markdownCommands, wysiwygCommands, and toolbarItems) that clearly illustrate their responsibilities and controls. Moreover, the properties in this process are not dependent on the editor API or the editor's properties.

The improved plugin system makes it easier for the users to add the v3.0's new custom markdown syntax or to register commands. Currently, the editor ships with five default plugins, but we plan on adding more plugins that support summary and details tags as well as autocomplete popup plugins.

To apply the newly improved plugin system, check out the migration guide!

Design

TOAST UI Editor 3.0 has completely reworked the designs. We have increased the sizes of UI elements like toolbars and tabs in order to increase readability, and we have also rounded out the borders to give a smoother feel.

v2.0
image

v3.0
image

Furthermore, the Dark Theme has been added.

// ...
import '@toast-ui/editor/dist/toastui-editor.css';
import '@toast-ui/editor/dist/theme/toastui-editor-dark.css';

const editor = new Editor({
  // ...
  theme: 'dark'
});

image

πŸ“ Migration Guide

There are still more considerable changes to the TOAST UI Editor 3.0 than we have mentioned above. With the substantial changes a lot of usages were changed as well. To help you along the way, we have prepared a migration guide.

Migration Guide(πŸ‡ΊπŸ‡Έ): https://github.com/nhn/tui.editor/blob/master/docs/v3.0-migration-guide.md

The features mentioned above are explained in greater detail in the following guides.

✍ Additional Changes

Aside from the newly introduced features, there are additional, internal maintenance related changes.

  • Applying TypeScript
    We rewrote the entire codebase in TypeScript. This allowed us to prevent unidentified errors through static type checking and to write error proof code through type hinting.
  • Applying Virtual DOM
    We built our own virtual DOM and changed the original command based DOM manipulation code to be more declarative. This change was easy because we were already familiar with libraries like React and Vue.js, and through this, we were able to reduce the amount of UI component codes by nearly 40%.
  • Applying Modern Dev Tools
    We used dev tools with no-bundling philosophies like snowpack to increase productivity. Moreover, npm7's workspace allowed us to manage the dependencies among monorepo packages more efficiently.

πŸš€ What's Next?

The main characteristic of TOAST UI Editor is that it is a markdown based editor that support WYSIWYG editor simultaneously. For the development of TOAST UI Editor 3.0, we focused on highlighting this characteristic and strove to improve compatibility between the structures of the two editors as well as the editors themselves. As a result, we were able to remove a bunch of limiting conditions that existed previously during feature extension.

For now, we are planning on following updates in the future. πŸ’ͺ

  • Extending the Plugin Ecosystem
  • Server Side Rendering (SSR) Support
  • Synchronous Editing Feature

We are planning on researching and developing synchronous editing, which was not possible before, as well as extending default plugins and customizable options. Furthermore, the compatibility between two editors will be enhanced, and the performance dealing with large documents will be optimized.

The TOAST UI Editor's Github is always open! Look forward to our future updates! πŸ˜€

tui.editor - [email protected]

Published by js87zz over 3 years ago

Bug Fixes

Editor

  • c7450cf incorrect type definitions in customHTMLRenderer prop (#1460)
  • 11b40c3 fixed that cannot convert details, summary block using useDefaultHTMLSanitizer: false option (#1472)
tui.editor - [email protected]

Published by seonim-ryu almost 4 years ago

Bug Fixes

  • e202e59 Pasted table is broken when merged cells contain tags (#1313)
tui.editor - [email protected]

Published by seonim-ryu almost 4 years ago

Bug Fixes

Editor

  • 16203d1 The list is not created in a WYSIWYG table when the editor's container is a list (#1254)
  • 65e8ee1 Incorrect pasting if data copied from MS Office has styling (#1258)
tui.editor - [email protected]

Published by seonim-ryu almost 4 years ago

Bug Fixes

  • f0caaac Error occurs when pasting into a table (fix #1249)
tui.editor - [email protected]

Published by seonim-ryu almost 4 years ago

New Features

  • b129c66 Support Portuguese language (pt-BR) (#1220)

Bug Fixes

  • b129c66 Revised Norwegian for i18n (#1207)
tui.editor - [email protected]

Published by seonim-ryu almost 4 years ago

New Features

Editor

  • 929dc94 [WYSIWYG] Add and edit link to image (#1208)
  • b129c66 Support Portuguese language (pt-BR) (#1220)

Bug Fixes

Editor

  • 90143c4 Fix a problem that when copying a child list, it was pasted in an indented state (#1230)
  • b129c66 Revised Norwegian for i18n (#1207)
tui.editor - [email protected]

Published by seonim-ryu about 4 years ago

New Features

  • 855abe6 Support Croatian language (hr-HR) (#1162)
tui.editor - [email protected]

Published by seonim-ryu about 4 years ago

New Features

Editor

const editor = new Editor({
  frontMatter: true
});

frontmatter

  • 855abe6 Support Croatian language (hr-HR) (#1162)
  • 4df75a0 [Markdown] Add key action to table in markdown (#1126)

Case 1: tab (or shift + tab) key

Pressing the tab key in the markdown table moves the cursor cell by cell.

Case 2 : enter key

Pressing the enter key in the markdown table adds the syntax for the new row.

  • 151f98e [Viewer] Add an internal attribute to disable task markers when using the customHTMLRenderer option (#1163)

Bug Fixes

Editor

  • 60e747a Type inference is wrong when table-merged-cell plugin is set in the plugin option (#1160)
  • b312e15 [Markdown] Syntax highlighting is broken when wrapping text containing blank lines with fence code block syntax (#1167)
  • be8f7b3 [WYSIWYG] Format is broken when copying or pasting a list in MS Office (#1153)
tui.editor - [email protected]

Published by seonim-ryu about 4 years ago

Bug Fix

Editor

8ca00e8 [WYSIWYG] Wrong widget element position when scrolling (#1113)
e3cd805 [WYSIWYG] List in the table is broken after changing to markdown when using table-merged-cell plugin (#1119)

tui.editor - [email protected]

Published by seonim-ryu about 4 years ago

Bug Fix

  • e3cd805 [WYSIWYG] <span> tag in the table is broken when converted to markdown (#1059)
tui.editor - [email protected]

Published by seonim-ryu over 4 years ago

Bug Fix

  • 337e860 Add button type on confirm button for preventing to submit form (#1091)
tui.editor - [email protected]

Published by seonim-ryu over 4 years ago

New Features

Editor

  • d0b7501 [Markdown] Smart task's marker (#1080) : This is a function to change the state of the marker in the task list according to the user's action

Case 1 : When pressing the x or backspace key in square brackets corresponding to the task marker

change

Case 2 : When pressing the shift + ctrl + x shortcut in the task list

toggle

Bug Fix

Editor

  • 5a5ae7d [Markdown] Remove highlight from preview after blur (#1093)
  • f98ffc4 [WYSIWYG] Remove newlines in copied text when pasting to table (#1102)
  • 6be680c [WYSIWYG] Script error occurs in table when selecting or adding column (#1110)

etc.

  • 75e48c3 Update dev-dependency version with security vulnerability
  • 6bcec75 Change environment of to-mark library
tui.editor - v2.2.0

Published by seonim-ryu over 4 years ago

Enhancement

Editor

  • 5f62f5e Improve default HTML sanitizer module to solve XSS vulnerability (#734)
  • 75c7da5 Set contenteditable attribute on paragraph block type using custom renderer (#998)
  • 609e89d [Markdown] The code block's language is case-insensitive (#1004)
  • ec405e2 [Markdown] Add a margin to separate the code blocks when highlighting the code block syntax (#1032)
  • 739dfe4 [WYSIWYG] Remove span tag with default color when copying/pasting text in the Viewer (or the Preview) (#1036)

Bug Fixes

Editor

  • 5ec7db0 form is submitted when the mode switch button is clicked (#969)
  • dfe4382 Remove types of removed API (setValue, getValue) (#970)
  • 5ec7db0 Editor and viewer font styles are different (#1045)
  • a2f95ae [Markdown] Typing is slow when the list depth is long or there is a lot of content (#1012)
  • d9b9412 [Markdown] Shortcut for shift-tab in list does not work correctly (#1014)
  • ec405e2 [Markdown] Syntax highlighting of code blocks is broken under certain situations (#1032)
  • 22a1744 [WYSIWYG] Script error occurs when text corresponding to a block of code is pasted (#693, #939)
  • d03b508 [WYSIWYG] change event does not fire when list bullet is entered (#757)
  • 7c00b60 [WYSIWYG] Typed text disappears when changing style in heading (#878)
  • 964009c [WYSIWYG] Text in table context menu overflows in certain languages (#891)
  • 1f6a54d [WYSIWYG] Resizable box is created on the element with min-height applied in Internet Explorer (#984)
  • 6f983b4 [WYSIWYG] Enter the tag string related to XSS in the code block and move the cursor to execute the script (#1021)
tui.editor - v2.1.2

Published by seonim-ryu over 4 years ago

BugFix

Editor

  • c9295c7 Fix: pasting error in table when using custom sanitizer (fix #980) (#981)
tui.editor - v2.1.1

Published by seonim-ryu over 4 years ago

Bug Fixes

Editor

  • e81b843 Fix: list disappear when parent container is list (fix #972) (#973)
tui.editor - v2.1.0

Published by seonim-ryu over 4 years ago

Enhancement

Syntax Highlighting (#910)

The syntax highlighting of the Markdown Editor has been enhanced. Colors are clearly separated so that the actual content is more visible than the syntax used in the markdown, and the look and feel of the editing area and preview area are unified as much as possible to give a feeling similar to the actual content. If you look at the image below, you can see that the readability and unity are noticeably better than the previous version. You can now check for syntax errors in entered text accurately and quickly in the editing area.

  • Old Style

old

  • New Style

new

New Features

Preview Highlighting (#946)

In Markdown Editor, the function to display the position of the editing text in real time has been added. The preview area is displayed in block units according to the cursor position of the markdown editor, and the edit position can be quickly identified.

preview-highlighting

The previewHighlight option has also been added so that you can disable preview highlighting only if you wish.

const editor = new Editor({
  // ...
  previewHighlight: false // default: true
});

referenceDefinition Option (#887)

The option to use the link reference definitions has been added, and set the referenceDefinition: true to enable the link reference definitions. Links commonly used in the document can be defined as link reference definitions for convenient use.

const editor = new Editor({
  // ...
  referenceDefinition: true // default: false
});
[TOAST UI Editor]: https://ui.toast.com/tui-editor
[NHN]: https://github.com/nhn 

Thanks for loving [TOAST UI Editor] of [NHN].

customHTMLRenderer Option (#894)

The customHTMLRenderer option has been added to allow users to customize markdown data that is converted to HTML through the Markdown Renderer. The option value is an object that assigns a callback function to the markdown node type defined in ToastMark, and returns a token object for generating HTML in each callback function. You can find detailed usage in the tutorial documentation.

const editor = new Editor({
  // ...
  customHTMLRenderer: {
    paragraph(node, context) {
      const { entering, origin } = context;
      const result = origin();

      if (entering) {
        result.attributes = { 'data-my-attr': 'custom-attr' };
        result.classNames = ['custom-class1', 'custom-class2'];
      }

      return result;
    },

    heading(node, { entering }): {
      const tagName = `h${node.level}`;
      
      if (entering) {
        return {
          type: 'openTag',
          tagName,
          classNames: ['my-heading']
        }
      }
      
      return {
        type: 'closeTag',
        tagName
      }
    }
  }
});

customHTMLSanitizer Option (#945)

The customHTMLSanitizer option has been added so that you can use the desired sanitizer module, such as DOMPurify, instead of the built-in sanitizer.

import DOMPurify from 'dompurify';

const purifyOptions = { ... };
const editor = new Editor({
  // ...
  customHTMLSanitizer: html => {
    return DOMPurify.sanitize(html, purifyOptions) || ''
  }
});

Provide CSS File Excluding Viewer Style

If you want to customize and use only the Viewer style, you can minimize the use of duplicate styles using the toastui-editor-only.css file.

  • npm
- @toast-ui/editor/
   β”œβ”€ dist/
   β”‚     β”œβ”€ toastui-editor-only.css
   β”‚     β”œβ”€ ...
  • CDN
- uicdn.toast.com/editor/
   β”œβ”€ 2.1.0/
   β”‚     β”œβ”€ toastui-editor-only.css
   β”‚     β”œβ”€ toastui-editor-only.min.css
   β”‚     β”œβ”€ ...

Bug Fixes

  • Prevent to remove heading tag when press the enter key (fix #872) (#888)
  • Replace form tag to div tag to prevent script error (fix #837) (#890)
  • Wrong position of the tooltip on the toolbar item (#918)
  • Wrong position of table and code block gadgt (#947)
  • Press enter key inside code block makes autolinks (#911)
  • Sanitize empty figure element (#913)
  • Wrong ordered list regexp when extending list by pressing the enter key (#925)
  • Can't apply linkAttribute to wysiwyg editor (#931)
  • Not working shortcut of CodeMirror in markdown editor (#951)