Showing preview only (1,976K chars total). Download the full file or copy to clipboard to get everything.
Repository: nhn/tui.editor
Branch: master
Commit: 0c5c11bac0b9
Files: 498
Total size: 1.8 MB
Directory structure:
gitextract_h8buw_ig/
├── .eslintrc.js
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ └── question.md
│ ├── dependabot.yml
│ ├── stale.yml
│ └── workflows/
│ ├── check-types.yml
│ ├── examplePageTest.yml
│ ├── linter.yml
│ ├── plugin-test.yml
│ ├── publish-cdn.yml
│ ├── publish-doc.yml
│ ├── publish-npm-wrapper.yml
│ ├── publish-npm.yml
│ └── test.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── __mocks__/
│ └── cssMock.js
├── apps/
│ ├── editor/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ └── esm/
│ │ │ └── index.html
│ │ ├── examples/
│ │ │ ├── css/
│ │ │ │ └── tuidoc-example-style.css
│ │ │ ├── data/
│ │ │ │ ├── md-default.js
│ │ │ │ └── md-plugins.js
│ │ │ ├── example01-editor-basic.html
│ │ │ ├── example02-editor-with-horizontal-preview.html
│ │ │ ├── example03-editor-with-wysiwyg-mode.html
│ │ │ ├── example04-viewer.html
│ │ │ ├── example05-viewer-using-editor-factory.html
│ │ │ ├── example06-dark-theme.html
│ │ │ ├── example07-editor-with-chart-plugin.html
│ │ │ ├── example08-editor-with-code-syntax-highlight-plugin.html
│ │ │ ├── example09-editor-with-color-syntax-plugin.html
│ │ │ ├── example10-editor-with-table-merged-cell-plugin.html
│ │ │ ├── example11-editor-with-uml-plugin.html
│ │ │ ├── example12-editor-with-all-plugins.html
│ │ │ ├── example13-creating-plugin.html
│ │ │ ├── example14-using-command.html
│ │ │ ├── example15-customizing-toolbar-buttons.html
│ │ │ ├── example16-i18n.html
│ │ │ └── example17-placeholder.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── scripts/
│ │ │ ├── createConfigVariable.js
│ │ │ ├── createIndexPage.js
│ │ │ └── webpack.config.i18n.js
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ ├── integration/
│ │ │ │ │ ├── ui/
│ │ │ │ │ │ ├── layout.spec.ts
│ │ │ │ │ │ └── toolbar.spec.ts
│ │ │ │ │ ├── vdom/
│ │ │ │ │ │ └── render.spec.ts
│ │ │ │ │ └── widget/
│ │ │ │ │ └── widgetNode.spec.ts
│ │ │ │ └── unit/
│ │ │ │ ├── convertor.spec.ts
│ │ │ │ ├── dom.spec.ts
│ │ │ │ ├── editor.spec.ts
│ │ │ │ ├── eventEmitter.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ ├── common.spec.ts
│ │ │ │ │ └── image.spec.ts
│ │ │ │ ├── markdown/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── syntaxHighlight.spec.ts.snap
│ │ │ │ │ ├── keymap.spec.ts
│ │ │ │ │ ├── mdCommand.spec.ts
│ │ │ │ │ ├── mdEditor.spec.ts
│ │ │ │ │ ├── mdPreview.spec.ts
│ │ │ │ │ ├── smartTask.spec.ts
│ │ │ │ │ ├── syntaxHighlight.spec.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── sanitizer.spec.ts
│ │ │ │ ├── vdom/
│ │ │ │ │ └── template.spec.ts
│ │ │ │ ├── viewer.spec.ts
│ │ │ │ └── wysiwyg/
│ │ │ │ ├── customBlock.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ └── pasteMsoList.spec.ts
│ │ │ │ ├── keymap.spec.ts
│ │ │ │ ├── wwCommand.spec.ts
│ │ │ │ ├── wwEditor.spec.ts
│ │ │ │ ├── wwTableCommand.spec.ts
│ │ │ │ └── wwToDOMAdaptor.spec.ts
│ │ │ ├── base.ts
│ │ │ ├── commands/
│ │ │ │ ├── commandManager.ts
│ │ │ │ ├── defaultCommands.ts
│ │ │ │ └── wwCommands.ts
│ │ │ ├── convertors/
│ │ │ │ ├── convertor.ts
│ │ │ │ ├── toMarkdown/
│ │ │ │ │ ├── toMdConvertorState.ts
│ │ │ │ │ ├── toMdConvertors.ts
│ │ │ │ │ └── toMdNodeTypeWriters.ts
│ │ │ │ └── toWysiwyg/
│ │ │ │ ├── htmlToWwConvertors.ts
│ │ │ │ ├── toWwConvertorState.ts
│ │ │ │ └── toWwConvertors.ts
│ │ │ ├── css/
│ │ │ │ ├── contents.css
│ │ │ │ ├── editor.css
│ │ │ │ ├── md-syntax-highlighting.css
│ │ │ │ ├── preview-highlighting.css
│ │ │ │ └── theme/
│ │ │ │ └── dark.css
│ │ │ ├── editor.ts
│ │ │ ├── editorCore.ts
│ │ │ ├── esm/
│ │ │ │ ├── index.ts
│ │ │ │ └── indexViewer.ts
│ │ │ ├── event/
│ │ │ │ └── eventEmitter.ts
│ │ │ ├── helper/
│ │ │ │ ├── image.ts
│ │ │ │ ├── manipulation.ts
│ │ │ │ └── plugin.ts
│ │ │ ├── i18n/
│ │ │ │ ├── ar.ts
│ │ │ │ ├── cs-cz.ts
│ │ │ │ ├── de-de.ts
│ │ │ │ ├── en-us.ts
│ │ │ │ ├── es-es.ts
│ │ │ │ ├── fi-fi.ts
│ │ │ │ ├── fr-fr.ts
│ │ │ │ ├── gl-es.ts
│ │ │ │ ├── hr-hr.ts
│ │ │ │ ├── i18n.ts
│ │ │ │ ├── it-it.ts
│ │ │ │ ├── ja-jp.ts
│ │ │ │ ├── ko-kr.ts
│ │ │ │ ├── nb-no.ts
│ │ │ │ ├── nl-nl.ts
│ │ │ │ ├── pl-pl.ts
│ │ │ │ ├── pt-br.ts
│ │ │ │ ├── ru-ru.ts
│ │ │ │ ├── sv-se.ts
│ │ │ │ ├── tr-tr.ts
│ │ │ │ ├── uk-ua.ts
│ │ │ │ ├── zh-cn.ts
│ │ │ │ └── zh-tw.ts
│ │ │ ├── index.ts
│ │ │ ├── indexEditorOnlyStyle.ts
│ │ │ ├── indexViewer.ts
│ │ │ ├── markdown/
│ │ │ │ ├── helper/
│ │ │ │ │ ├── list.ts
│ │ │ │ │ ├── mdCommand.ts
│ │ │ │ │ ├── pos.ts
│ │ │ │ │ └── query.ts
│ │ │ │ ├── htmlRenderConvertors.ts
│ │ │ │ ├── marks/
│ │ │ │ │ ├── blockQuote.ts
│ │ │ │ │ ├── code.ts
│ │ │ │ │ ├── codeBlock.ts
│ │ │ │ │ ├── customBlock.ts
│ │ │ │ │ ├── emph.ts
│ │ │ │ │ ├── heading.ts
│ │ │ │ │ ├── html.ts
│ │ │ │ │ ├── link.ts
│ │ │ │ │ ├── listItem.ts
│ │ │ │ │ ├── simpleMark.ts
│ │ │ │ │ ├── strike.ts
│ │ │ │ │ ├── strong.ts
│ │ │ │ │ ├── table.ts
│ │ │ │ │ └── thematicBreak.ts
│ │ │ │ ├── mdEditor.ts
│ │ │ │ ├── mdPreview.ts
│ │ │ │ ├── nodes/
│ │ │ │ │ ├── doc.ts
│ │ │ │ │ ├── paragraph.ts
│ │ │ │ │ └── text.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ ├── helper/
│ │ │ │ │ │ └── markInfo.ts
│ │ │ │ │ ├── previewHighlight.ts
│ │ │ │ │ ├── smartTask.ts
│ │ │ │ │ └── syntaxHighlight.ts
│ │ │ │ └── scroll/
│ │ │ │ ├── animation.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── offset.ts
│ │ │ │ └── scrollSync.ts
│ │ │ ├── plugins/
│ │ │ │ ├── dropImage.ts
│ │ │ │ ├── placeholder.ts
│ │ │ │ └── popupWidget.ts
│ │ │ ├── queries/
│ │ │ │ └── queryManager.ts
│ │ │ ├── sanitizer/
│ │ │ │ └── htmlSanitizer.ts
│ │ │ ├── spec/
│ │ │ │ ├── mark.ts
│ │ │ │ ├── node.ts
│ │ │ │ └── specManager.ts
│ │ │ ├── ui/
│ │ │ │ ├── components/
│ │ │ │ │ ├── contextMenu.ts
│ │ │ │ │ ├── layout.ts
│ │ │ │ │ ├── popup.ts
│ │ │ │ │ ├── switch.ts
│ │ │ │ │ ├── tabs.ts
│ │ │ │ │ └── toolbar/
│ │ │ │ │ ├── buttonHoc.ts
│ │ │ │ │ ├── customPopupBody.ts
│ │ │ │ │ ├── customToolbarItem.ts
│ │ │ │ │ ├── dropdownToolbarButton.ts
│ │ │ │ │ ├── headingPopupBody.ts
│ │ │ │ │ ├── imagePopupBody.ts
│ │ │ │ │ ├── linkPopupBody.ts
│ │ │ │ │ ├── tablePopupBody.ts
│ │ │ │ │ ├── toolbar.ts
│ │ │ │ │ ├── toolbarButton.ts
│ │ │ │ │ └── toolbarGroup.ts
│ │ │ │ ├── toolbarItemFactory.ts
│ │ │ │ └── vdom/
│ │ │ │ ├── commit.ts
│ │ │ │ ├── component.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── htm.js
│ │ │ │ ├── render.ts
│ │ │ │ ├── renderer.ts
│ │ │ │ ├── template.ts
│ │ │ │ └── vnode.ts
│ │ │ ├── utils/
│ │ │ │ ├── common.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── map.ts
│ │ │ │ └── markdown.ts
│ │ │ ├── viewer.ts
│ │ │ ├── widget/
│ │ │ │ ├── rules.ts
│ │ │ │ └── widgetNode.ts
│ │ │ └── wysiwyg/
│ │ │ ├── adaptor/
│ │ │ │ ├── mdLikeNode.ts
│ │ │ │ └── wwToDOMAdaptor.ts
│ │ │ ├── clipboard/
│ │ │ │ ├── paste.ts
│ │ │ │ ├── pasteMsoList.ts
│ │ │ │ └── pasteToTable.ts
│ │ │ ├── command/
│ │ │ │ ├── list.ts
│ │ │ │ └── table.ts
│ │ │ ├── helper/
│ │ │ │ ├── node.ts
│ │ │ │ ├── table.ts
│ │ │ │ └── tableOffsetMap.ts
│ │ │ ├── marks/
│ │ │ │ ├── code.ts
│ │ │ │ ├── emph.ts
│ │ │ │ ├── link.ts
│ │ │ │ ├── strike.ts
│ │ │ │ └── strong.ts
│ │ │ ├── nodes/
│ │ │ │ ├── blockQuote.ts
│ │ │ │ ├── bulletList.ts
│ │ │ │ ├── codeBlock.ts
│ │ │ │ ├── customBlock.ts
│ │ │ │ ├── doc.ts
│ │ │ │ ├── frontMatter.ts
│ │ │ │ ├── heading.ts
│ │ │ │ ├── html.ts
│ │ │ │ ├── htmlComment.ts
│ │ │ │ ├── image.ts
│ │ │ │ ├── listItem.ts
│ │ │ │ ├── orderedList.ts
│ │ │ │ ├── paragraph.ts
│ │ │ │ ├── table.ts
│ │ │ │ ├── tableBody.ts
│ │ │ │ ├── tableBodyCell.ts
│ │ │ │ ├── tableHead.ts
│ │ │ │ ├── tableHeadCell.ts
│ │ │ │ ├── tableRow.ts
│ │ │ │ ├── text.ts
│ │ │ │ └── thematicBreak.ts
│ │ │ ├── nodeview/
│ │ │ │ ├── codeBlockView.ts
│ │ │ │ ├── customBlockView.ts
│ │ │ │ └── imageView.ts
│ │ │ ├── plugins/
│ │ │ │ ├── selection/
│ │ │ │ │ ├── cellSelection.ts
│ │ │ │ │ ├── tableSelection.ts
│ │ │ │ │ └── tableSelectionView.ts
│ │ │ │ ├── tableContextMenu.ts
│ │ │ │ ├── task.ts
│ │ │ │ └── toolbarState.ts
│ │ │ ├── specCreator.ts
│ │ │ └── wwEditor.ts
│ │ ├── tsBannerGenerator.js
│ │ ├── tsconfig.json
│ │ ├── tuidoc.config.json
│ │ ├── types/
│ │ │ ├── convertor.d.ts
│ │ │ ├── editor.d.ts
│ │ │ ├── event.d.ts
│ │ │ ├── index.d.ts
│ │ │ ├── map.d.ts
│ │ │ ├── markdown.d.ts
│ │ │ ├── plugin.d.ts
│ │ │ ├── prosemirror-commands.d.ts
│ │ │ ├── prosemirror-model.d.ts
│ │ │ ├── prosemirror-transform.d.ts
│ │ │ ├── spec.d.ts
│ │ │ ├── toastmark.d.ts
│ │ │ ├── toastui-editor-viewer.d.ts
│ │ │ ├── ui.d.ts
│ │ │ └── wysiwyg.d.ts
│ │ └── webpack.config.js
│ ├── react-editor/
│ │ ├── .eslintrc.js
│ │ ├── README.md
│ │ ├── demo/
│ │ │ └── esm/
│ │ │ ├── index.html
│ │ │ └── index.jsx
│ │ ├── index.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── editor.tsx
│ │ │ ├── index.ts
│ │ │ └── viewer.tsx
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ └── vue-editor/
│ ├── .eslintrc.js
│ ├── README.md
│ ├── demo/
│ │ └── esm/
│ │ ├── index.html
│ │ └── index.js
│ ├── index.d.ts
│ ├── package.json
│ ├── rollup.config.js
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── Editor.vue
│ │ ├── Viewer.vue
│ │ ├── index.js
│ │ └── mixin/
│ │ └── option.js
│ └── webpack.config.js
├── docs/
│ ├── COMMIT_MESSAGE_CONVENTION.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── README.md
│ ├── en/
│ │ ├── custom-block.md
│ │ ├── custom-html-renderer.md
│ │ ├── extended-autolinks.md
│ │ ├── getting-started.md
│ │ ├── i18n.md
│ │ ├── plugin.md
│ │ ├── toolbar.md
│ │ ├── viewer.md
│ │ └── widget.md
│ ├── ko/
│ │ ├── README.md
│ │ ├── custom-block.md
│ │ ├── custom-html-renderer.md
│ │ ├── extended-autolinks.md
│ │ ├── getting-started.md
│ │ ├── i18n.md
│ │ ├── plugin.md
│ │ ├── toolbar.md
│ │ ├── viewer.md
│ │ └── widget.md
│ ├── v3.0-migration-guide-ko.md
│ └── v3.0-migration-guide.md
├── jest-setup.js
├── jest.base.config.js
├── jest.config.js
├── lerna.json
├── libs/
│ └── toastmark/
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.md
│ ├── demo/
│ │ └── index.html
│ ├── jest.config.js
│ ├── package.json
│ ├── rollup.config.js
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── __sample__/
│ │ │ ├── index.css
│ │ │ └── index.ts
│ │ ├── __test__/
│ │ │ └── toastmark.spec.ts
│ │ ├── commonmark/
│ │ │ ├── __test__/
│ │ │ │ ├── base-examples.json
│ │ │ │ ├── base-examples.spec.ts
│ │ │ │ ├── helper.spec.ts
│ │ │ │ ├── options.spec.ts
│ │ │ │ ├── sourcepos.spec.ts
│ │ │ │ └── syntax-info.spec.ts
│ │ │ ├── blockHandlers.ts
│ │ │ ├── blockHelper.ts
│ │ │ ├── blockStarts.ts
│ │ │ ├── blocks.ts
│ │ │ ├── common.ts
│ │ │ ├── custom/
│ │ │ │ ├── __test__/
│ │ │ │ │ ├── customBlock.spec.ts
│ │ │ │ │ └── customInline.spec.ts
│ │ │ │ ├── customBlockHandler.ts
│ │ │ │ └── customBlockStart.ts
│ │ │ ├── from-code-point.ts
│ │ │ ├── frontMatter/
│ │ │ │ ├── __test__/
│ │ │ │ │ └── frontMatter.spec.ts
│ │ │ │ ├── frontMatterHandler.ts
│ │ │ │ └── frontMatterStart.ts
│ │ │ ├── gfm/
│ │ │ │ ├── __test__/
│ │ │ │ │ ├── autolinks.spec.ts
│ │ │ │ │ ├── strikethrough.spec.ts
│ │ │ │ │ ├── table.spec.ts
│ │ │ │ │ ├── tagfilter.spec.ts
│ │ │ │ │ └── taskListItem.spec.ts
│ │ │ │ ├── autoLinks.ts
│ │ │ │ ├── tableBlockHandler.ts
│ │ │ │ ├── tableBlockStart.ts
│ │ │ │ └── taskListItem.ts
│ │ │ ├── inlines.ts
│ │ │ ├── node.ts
│ │ │ ├── nodeWalker.ts
│ │ │ └── rawHtml.ts
│ │ ├── helper.ts
│ │ ├── html/
│ │ │ ├── __test__/
│ │ │ │ └── render.spec.ts
│ │ │ ├── baseConvertors.ts
│ │ │ ├── gfmConvertors.ts
│ │ │ ├── renderer.ts
│ │ │ └── tagFilter.ts
│ │ ├── index.ts
│ │ ├── nodeHelper.ts
│ │ └── toastmark.ts
│ ├── tsconfig.json
│ ├── types/
│ │ ├── index.d.ts
│ │ ├── node.d.ts
│ │ ├── parser.d.ts
│ │ ├── renderer.d.ts
│ │ └── toastMark.d.ts
│ └── webpack.config.js
├── package.json
├── plugins/
│ ├── chart/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── unit/
│ │ │ │ └── chartPlugin.spec.ts
│ │ │ ├── csv.js
│ │ │ ├── index.ts
│ │ │ └── util.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ └── index.d.ts
│ │ └── webpack.config.js
│ ├── code-syntax-highlight/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor-all-langs.html
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ ├── integration/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── codeHighlightPlugin.spec.ts.snap
│ │ │ │ │ │ └── codeHighlightPluginWithAllLangs.spec.ts.snap
│ │ │ │ │ ├── codeHighlightPlugin.spec.ts
│ │ │ │ │ └── codeHighlightPluginWithAllLangs.spec.ts
│ │ │ │ └── unit/
│ │ │ │ └── languageSelectBox.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── index.ts
│ │ │ ├── indexAll.ts
│ │ │ ├── nodeViews/
│ │ │ │ ├── codeSyntaxHighlightView.ts
│ │ │ │ └── languageSelectBox.ts
│ │ │ ├── plugin.ts
│ │ │ ├── plugins/
│ │ │ │ └── codeSyntaxHighlighting.ts
│ │ │ ├── prismjs-langs.ts
│ │ │ ├── renderers/
│ │ │ │ └── toHTMLRenderers.ts
│ │ │ └── utils/
│ │ │ ├── common.ts
│ │ │ └── dom.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ └── prosemirror-transform.d.ts
│ │ └── webpack.config.js
│ ├── color-syntax/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor.html
│ │ │ └── esm/
│ │ │ └── index.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── integration/
│ │ │ │ └── colorSyntaxPlugin.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── i18n/
│ │ │ │ └── langs.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ └── dom.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ ├── prosemirror-model.d.ts
│ │ │ └── tui-color-picker.d.ts
│ │ └── webpack.config.js
│ ├── table-merged-cell/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── data.js
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── integration/
│ │ │ │ ├── convertor.spec.ts
│ │ │ │ ├── markdown/
│ │ │ │ │ └── mergedTablePreview.spec.ts
│ │ │ │ └── wysiwyg/
│ │ │ │ ├── addColumn.spec.ts
│ │ │ │ ├── addRow.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ ├── cellSelection.ts
│ │ │ │ │ ├── tableOffsetMap.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── mergeCells.spec.ts
│ │ │ │ ├── removeColumn.spec.ts
│ │ │ │ ├── removeRow.spec.ts
│ │ │ │ └── splitCells.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── i18n/
│ │ │ │ └── langs.ts
│ │ │ ├── index.ts
│ │ │ ├── markdown/
│ │ │ │ ├── parser.ts
│ │ │ │ └── renderer.ts
│ │ │ └── wysiwyg/
│ │ │ ├── command/
│ │ │ │ ├── addColumn.ts
│ │ │ │ ├── addRow.ts
│ │ │ │ ├── direction.ts
│ │ │ │ ├── mergeCells.ts
│ │ │ │ ├── removeColumn.ts
│ │ │ │ ├── removeRow.ts
│ │ │ │ └── splitCells.ts
│ │ │ ├── commandFactory.ts
│ │ │ ├── contextMenu.ts
│ │ │ ├── renderer.ts
│ │ │ ├── tableOffsetMapMixin.ts
│ │ │ └── util.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ └── prosemirror-transform.d.ts
│ │ └── webpack.config.js
│ └── uml/
│ ├── README.md
│ ├── demo/
│ │ ├── editor.html
│ │ ├── esm/
│ │ │ └── index.html
│ │ └── viewer.html
│ ├── index.d.ts
│ ├── jest.config.js
│ ├── package.json
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── __test__/
│ │ │ └── integration/
│ │ │ └── umlPlugin.spec.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ └── webpack.config.js
├── scripts/
│ ├── pkg-script.js
│ └── publish-cdn.js
├── tsconfig.json
└── types/
└── tui-code-snippet.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.js
================================================
module.exports = {
root: true,
plugins: ['prettier', '@typescript-eslint'],
extends: ['tui/es6', 'plugin:prettier/recommended', 'plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
parserOptions: {
parser: 'typescript-eslint-parser',
},
env: {
browser: true,
node: true,
jest: true,
},
globals: {
jest: true,
},
ignorePatterns: ['node_modules/*', 'dist'],
rules: {
'@typescript-eslint/no-non-null-assertion': 0,
'@typescript-eslint/explicit-function-return-type': 0,
'@typescript-eslint/explicit-module-boundary-types': 0,
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/ban-ts-comment': 0,
'@typescript-eslint/no-useless-constructor': 2,
'lines-around-directive': 0,
'newline-before-return': 0,
'no-use-before-define': 0,
'no-useless-constructor': 0,
'padding-line-between-statements': [
2,
{ blankLine: 'always', prev: ['const', 'let', 'var'], next: '*' },
{ blankLine: 'any', prev: ['const', 'let', 'var'], next: ['const', 'let', 'var'] },
],
'no-useless-rename': 'error',
'no-duplicate-imports': ['error', { includeExports: true }],
'dot-notation': ['error', { allowKeywords: true }],
'prefer-destructuring': [
'error',
{
VariableDeclarator: {
array: true,
object: true,
},
AssignmentExpression: {
array: false,
object: false,
},
},
{
enforceForRenamedProperties: false,
},
],
'arrow-body-style': ['error', 'as-needed', { requireReturnForObjectLiteral: true }],
'object-property-newline': ['error', { allowMultiplePropertiesPerLine: true }],
'no-sync': 0,
complexity: 0,
'max-nested-callbacks': ['error', 4],
'no-cond-assign': 0,
'max-depth': ['error', 4],
'no-return-assign': 0,
},
};
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: Bug
assignees: ''
---
## Describe the bug
A clear and concise description of what the bug is.
## To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Desktop (please complete the following information):
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
## Smartphone (please complete the following information):
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
## Additional context
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: Enhancement, Need Discussion
assignees: ''
---
<!--
Thank you for your contribution.
When it comes to write an issue, please, use the template below.
To use the template is mandatory for submit new issue and we won't reply the issue that without the template.
And you can write template's contents in Korean also.
-->
## Version
Write the version that you are currently using.
## Development Environment
Write the browser type, OS and so on.
## Current Behavior
Write a description of the current operation. You can add sample code, 'CodePen' or 'jsfiddle' links.
```js
// Write example code
```
## Expected Behavior
Write a description of the future action.
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
---
name: Question
about: Create a question about the Editor
title: ''
labels: Question
assignees: ''
---
<!--
To make it easier for us to help you, please include as much useful information as possible.
Useful Links:
- tutorial: https://github.com/nhn/tui.editor/tree/master/docs
- API/Example: https://nhn.github.io/tui.editor/latest/
Before opening a new issue, please search existing issues https://github.com/nhn/tui.editor/issues
-->
## Summary
A clear and concise description of what the question is.
## Screenshots
If applicable, add screenshots to help explain your question.
## Version
Write the version of the Editor you are currently using.
## Additional context
Add any other context about the problem here.
================================================
FILE: .github/dependabot.yml
================================================
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: npm
open-pull-requests-limit: 30
directory: /
schedule:
interval: weekly
================================================
FILE: .github/stale.yml
================================================
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 30
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- Feature
- Enhancement
- Bug
- NHN Cloud
# Label to use when marking as stale
staleLabel: inactive
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as inactive because there hasn’t been much going on it lately.
It is going to be closed after 7 days. Thanks!
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
This issue will be closed due to inactivity. Thanks for your contribution!
================================================
FILE: .github/workflows/check-types.yml
================================================
name: Editor Check Types
on: pull_request
jobs:
check-types:
name: Check Types
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: check types
run: |
npm run test:types:all
================================================
FILE: .github/workflows/examplePageTest.yml
================================================
name: detect runtime error
on:
schedule:
- cron: '0 22 * * *'
jobs:
makeUrl:
runs-on: ubuntu-latest
env:
WORKING_DIRECTORY: ./apps/editor
steps:
- name: checkout repository
uses: actions/checkout@v2
- name: create config variable
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
node scripts/createConfigVariable.js
- name: set global error variable
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
echo ::set-env name=ERROR_VARIABLE::$(head -n 1 ./errorVariable.txt)
- name: set url
working-directory: ${{ env.WORKING_DIRECTORY }}
run: |
echo ::set-env name=URLS::$(head -n 1 ./url.txt)
- name: detect runtime error
uses: nhn/toast-ui.detect-runtime-error-actions@master
with:
global-error-log-variable: ${{ env.ERROR_VARIABLE }}
urls: ${{ env.URLS }}
browserlist: ie11, safari, edge, firefox, chrome
env:
BROWSERSTACK_USERNAME: ${{secrets.BROWSERSTACK_USERNAME}}
BROWSERSTACK_ACCESS_KEY: ${{secrets.BROWSERSTACK_ACCESS_KEY}}
================================================
FILE: .github/workflows/linter.yml
================================================
name: Editor Lint Code Base
on: pull_request
jobs:
lint:
name: Lint Code Base
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: eslint
run: |
npm run lint:all
================================================
FILE: .github/workflows/plugin-test.yml
================================================
name: Plugin Unit, Integration Test
on: pull_request
jobs:
plugin-test:
name: Unit, Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm install
- name: build toastmark
run: |
npm run build toastmark
- name: build editor
run: |
npm run build editor
- name: chart plugin unit, integration test
run: |
npm run test:ci chart
- name: color syntax plugin unit, integration test
run: |
npm run test:ci color
- name: code syntax highlighting plugin unit, integration test
run: |
npm run test:ci code
- name: table merged cell plugin unit, integration test
run: |
npm run test:ci table
- name: uml plugin unit, integration test
run: |
npm run test:ci uml
================================================
FILE: .github/workflows/publish-cdn.yml
================================================
name: Cdn Publish
on: [workflow_dispatch]
jobs:
pre-check:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Eslint
run: |
npm run lint:all
- name: Check types
run: |
npm run test:types:all
test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
- name: Toastmark unit, integration test
run: |
npm run test:ci toastmark
- name: Editor unit, integration test
run: |
npm run test:ci editor
plugin-test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: chart plugin unit, integration test
run: |
npm run test:ci chart
- name: color syntax plugin unit, integration test
run: |
npm run test:ci color
- name: code syntax highlighting plugin unit, integration test
run: |
npm run test:ci code
- name: table merged cell plugin unit, integration test
run: |
npm run test:ci table
- name: uml plugin unit, integration test
run: |
npm run test:ci uml
publish-cdn:
runs-on: ubuntu-latest
needs: [pre-check, test, plugin-test]
steps:
- uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: Publish CDN
run: |
npm run publish:cdn
env:
TOAST_CLOUD_TENENTID: ${{ secrets.TOAST_CLOUD_TENENTID }}
TOAST_CLOUD_STORAGEID: ${{ secrets.TOAST_CLOUD_STORAGEID }}
TOAST_CLOUD_USERNAME: ${{ secrets.TOAST_CLOUD_USERNAME }}
TOAST_CLOUD_PASSWORD: ${{ secrets.TOAST_CLOUD_PASSWORD }}
================================================
FILE: .github/workflows/publish-doc.yml
================================================
name: Doc Publish
on: [workflow_dispatch]
jobs:
pre-check:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Eslint
run: |
npm run lint:all
- name: Check types
run: |
npm run test:types:all
test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
- name: Toastmark unit, integration test
run: |
npm run test:ci toastmark
- name: Editor unit, integration test
run: |
npm run test:ci editor
plugin-test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: chart plugin unit, integration test
run: |
npm run test:ci chart
- name: color syntax plugin unit, integration test
run: |
npm run test:ci color
- name: code syntax highlighting plugin unit, integration test
run: |
npm run test:ci code
- name: table merged cell plugin unit, integration test
run: |
npm run test:ci table
- name: uml plugin unit, integration test
run: |
npm run test:ci uml
doc:
runs-on: ubuntu-latest
needs: [pre-check, test, plugin-test]
steps:
- uses: actions/checkout@v2
- name: Check the package version
id: check
uses: PostHog/check-package-version@v2
with:
path: ./apps/editor/
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm install
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: Use Node.js 10.x
uses: actions/setup-node@v2.5.1
with:
node-version: '10.x'
- name: Install @toast-ui/doc
run: |
npm i -g @toast-ui/doc
- name: Run doc
run: |
npm run doc
mv apps/editor/_${{ steps.check.outputs.committed-version }} ${{ steps.check.outputs.committed-version }}
mv apps/editor/_latest latest
rm -rf apps/editor/tmpdoc
git checkout -- apps/editor/types/index.d.ts package-lock.json
git add ${{ steps.check.outputs.committed-version }}/dist -f
git add latest/dist -f
git stash --include-untracked
- name: Checkout gh-pages
uses: actions/checkout@v2
with:
ref: gh-pages
- name: Commit files
run: |
git config --local user.email 'jw.lee@nhn.com'
git config --local user.name 'jwlee1108'
rm -rf ${{ steps.check.outputs.committed-version }}
rm -rf latest
git add .
git stash pop
git add .
git commit -m '${{ steps.check.outputs.committed-version }}'
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: gh-pages
================================================
FILE: .github/workflows/publish-npm-wrapper.yml
================================================
name: Wrapper Npm Publish
on: [workflow_dispatch]
jobs:
pre-check:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Eslint
run: |
npm run lint:all
- name: Check types
run: |
npm run test:types:all
test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
- name: Toastmark unit, integration test
run: |
npm run test:ci toastmark
- name: Editor unit, integration test
run: |
npm run test:ci editor
plugin-test:
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: chart plugin unit, integration test
run: |
npm run test:ci chart
- name: color syntax plugin unit, integration test
run: |
npm run test:ci color
- name: code syntax highlighting plugin unit, integration test
run: |
npm run test:ci code
- name: table merged cell plugin unit, integration test
run: |
npm run test:ci table
- name: uml plugin unit, integration test
run: |
npm run test:ci uml
publish:
runs-on: ubuntu-latest
needs: [pre-check, test, plugin-test]
steps:
- uses: actions/checkout@v2
- name: Check the package version
id: check
uses: PostHog/check-package-version@v2
with:
path: ./apps/editor/
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
registry-url: https://registry.npmjs.org/
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
npm run build react
npm run build vue
- name: Npm Publish(react)
working-directory: ./apps/react-editor
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}
- name: Npm Publish(vue)
working-directory: ./apps/vue-editor
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}
================================================
FILE: .github/workflows/publish-npm.yml
================================================
name: Npm Publish
on: [workflow_dispatch]
jobs:
checkVersion:
name: Check package version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Check package version
id: check
uses: PostHog/check-package-version@v2
with:
path: ./apps/editor/
- name: Cancel when unchanged
uses: andymckay/cancel-action@0.2
if: steps.check.outputs.is-new-version == 'false'
pre-check:
needs: [checkVersion]
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Eslint
run: |
npm run lint:all
- name: Check types
run: |
npm run test:types:all
test:
needs: [checkVersion]
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
- name: Toastmark unit, integration test
run: |
npm run test:ci toastmark
- name: Editor unit, integration test
run: |
npm run test:ci editor
plugin-test:
needs: [checkVersion]
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: chart plugin unit, integration test
run: |
npm run test:ci chart
- name: color syntax plugin unit, integration test
run: |
npm run test:ci color
- name: code syntax highlighting plugin unit, integration test
run: |
npm run test:ci code
- name: table merged cell plugin unit, integration test
run: |
npm run test:ci table
- name: uml plugin unit, integration test
run: |
npm run test:ci uml
publish:
runs-on: ubuntu-latest
needs: [pre-check, test, plugin-test]
steps:
- uses: actions/checkout@v2
- name: Check the package version
id: check
uses: PostHog/check-package-version@v2
with:
path: ./apps/editor/
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
registry-url: https://registry.npmjs.org/
- name: Install
run: |
npm ci
- name: Build
run: |
npm run build toastmark
npm run build editor
- name: Create Tag
run: |
git config --local user.email 'jw.lee@nhn.com'
git config --local user.name 'jwlee1108'
git tag editor@${{ steps.check.outputs.committed-version }}
- name: Push Tag
run: |
git push origin editor@${{ steps.check.outputs.committed-version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Npm Publish(editor)
working-directory: ./apps/editor
run: |
npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_AUTH_TOKEN}}
================================================
FILE: .github/workflows/test.yml
================================================
name: Editor Unit, Integration Test
on: pull_request
jobs:
test:
name: Unit, Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout branch
uses: actions/checkout@v2
- name: Use Node.js 15.x
uses: actions/setup-node@v2.5.1
with:
node-version: '15.x'
- name: Install
run: |
npm install
- name: build toastmark
run: |
npm run build toastmark
- name: toastmark unit, integration test
run: |
npm run test:ci toastmark
- name: editor unit, integration test
run: |
npm run test:ci editor
================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
screenshots
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
node_modules
# Bower Components
bower_components
lib
# IDEA
.idea
*.iml
# Window
Thumbs.db
Desktop.ini
# MAC
.DS_Store
# SVN
.svn
# eclipse
.project
.metadata
# build
build
# etc
*.swp
etc
temp
api
doc
report
karma.conf.local.js
.tern-project
.tern-port
*.vim
.\#*
.vscode/
dist/
================================================
FILE: .prettierignore
================================================
*.md
*.html
================================================
FILE: .prettierrc.js
================================================
module.exports = {
printWidth: 100,
singleQuote: true
};
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
education, socio-economic status, nationality, personal appearance, race,
religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at dl_javascript@nhn.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to TOAST UI
First off, thanks for taking the time to contribute! 🎉 😘 ✨
The following is a set of guidelines for contributing to TOAST UI. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
## Reporting Bugs
Bugs are tracked as GitHub issues. Search the list and try reproduce on [demo][demo] before you create an issue. When you create an issue, please provide the following information by filling in the template.
Explain the problem and include additional details to help maintainers reproduce the problem:
* **Use a clear and descriptive title** for the issue to identify the problem.
* **Describe the exact steps which reproduce the problem** in as many details as possible. Don't just say what you did, but explain how you did it. For example, if you moved the cursor to the end of a line, explain if you used a mouse or a keyboard.
* **Provide specific examples to demonstrate the steps.** Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets on the issue, use Markdown code blocks.
* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior.
* **Explain which behavior you expected to see instead and why.**
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
## Suggesting Enhancements
In case you want to suggest for TOAST UI Editor, please follow this guideline to help maintainers and the community understand your suggestion.
Before creating suggestions, please check [issue list](https://github.com/nhn/tui.editor/labels/feature) if there's already a request.
Create an issue and provide the following information:
* **Use a clear and descriptive title** for the issue to identify the suggestion.
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
* **Provide specific examples to demonstrate the steps.** Include copy/pasteable snippets which you use in those examples, as Markdown code blocks.
* **Include screenshots and animated GIFs** which helps demonstrate the steps or point out the part of TOAST UI Editor which the suggestion is related to.
* **Explain why this enhancement would be useful** to most TOAST UI users.
* **List some other text editors or applications where this enhancement exists.**
## First Code Contribution
Unsure where to begin contributing to TOAST UI? You can start by looking through these `document`, `good first issue` and `help wanted` issues:
* **document issues**: issues which should be reviewed or improved.
* **good first issues**: issues which should only require a few lines of code, and a test or two.
* **help wanted issues**: issues which should be a bit more involved than beginner issues.
## Pull Requests
### Development WorkFlow
- Set up your development environment
- Make change from a right branch
- Be sure the code passes `npm run lint:all`, `npm run test:types:all`, `npm run test:all`
- Make a pull request
### Development environment
- Prepare your machine node and it's packages installed.
- Checkout our repository
- Install dependencies by `npm install`
- Build toastmark by `npm run build toastmark`
- Start snowpack-dev-server by `npm run serve`
### Make changes
#### Checkout a branch
- **master**: PR Base branch.
- **production**: lastest release branch with distribution files. never make a PR on this
- **gh-pages**: API docs, examples and demo
#### Check Code Style
Run `npm run eslint` and make sure all the tests pass.
#### Test
Run `npm run test:all` and verify all the tests pass.
If you are adding new commands or features, they must include tests.
If you are changing functionality, update the tests if you need to.
#### Commit
Follow our [commit message conventions](./docs/COMMIT_MESSAGE_CONVENTION.md).
### Yes! Pull request
Make your pull request, then describe your changes.
#### Title
Follow other PR title format on below.
```
<Type>: Short Description (fix #111)
<Type>: Short Description (fix #123, #111, #122)
<Type>: Short Description (ref #111)
```
* capitalize first letter of Type
* use present tense: 'change' not 'changed' or 'changes'
#### Description
If it has related to issues, add links to the issues(like `#123`) in the description.
Fill in the [Pull Request Template](./docs/PULL_REQUEST_TEMPLATE.md) by check your case.
## Code of Conduct
This project and everyone participating in it is governed by the [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to dl_javascript@nhn.com.
> This Guide is base on [atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md), [CocoaPods](http://guides.cocoapods.org/contributing/contribute-to-cocoapods.html) and [ESLint](http://eslint.org/docs/developer-guide/contributing/pull-requests)
[demo]:https://nhn.github.io/tui.editor/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 NHN Cloud Corp.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# 
> GFM Markdown and WYSIWYG Editor - Productive and Extensible
[](https://github.com/nhn/tui.editor/releases/latest) [](https://www.npmjs.com/package/@toast-ui/editor) [](https://github.com/nhn/tui.editor/blob/master/LICENSE) [](https://github.com/nhn/tui.editor/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) [](https://github.com/nhn)
<img src="https://user-images.githubusercontent.com/37766175/121809054-446bac80-cc96-11eb-9139-08c6d9ad2d88.png" />
## 🚩 Table of Contents
- [Packages](#-packages)
- [Why TOAST UI Editor?](#-why-toast-ui-editor)
- [Features](#-features)
- [Examples](#-examples)
- [Browser Support](#-browser-support)
- [Pull Request Steps](#-pull-request-steps)
- [Contributing](#-contributing)
- [TOAST UI Family](#-toast-ui-family)
- [Used By](#-used-by)
- [License](#-license)
## 📦 Packages
### TOAST UI Editor
| Name | Description |
| --- | --- |
| [`@toast-ui/editor`](https://github.com/nhn/tui.editor/tree/master/apps/editor) | Plain JavaScript component |
### TOAST UI Editor's Wrappers
| Name | Description |
| --- | --- |
| [`@toast-ui/react-editor`](https://github.com/nhn/tui.editor/tree/master/apps/react-editor) | [React](https://reactjs.org/) wrapper component |
| [`@toast-ui/vue-editor`](https://github.com/nhn/tui.editor/tree/master/apps/vue-editor) | [Vue](https://vuejs.org/) wrapper component |
### TOAST UI Editor's Plugins
| Name | Description |
| --- | --- |
| [`@toast-ui/editor-plugin-chart`](https://github.com/nhn/tui.editor/tree/master/plugins/chart) | Plugin to render chart |
| [`@toast-ui/editor-plugin-code-syntax-highlight`](https://github.com/nhn/tui.editor/tree/master/plugins/code-syntax-highlight) | Plugin to highlight code syntax |
| [`@toast-ui/editor-plugin-color-syntax`](https://github.com/nhn/tui.editor/tree/master/plugins/color-syntax) | Plugin to color editing text |
| [`@toast-ui/editor-plugin-table-merged-cell`](https://github.com/nhn/tui.editor/tree/master/plugins/table-merged-cell) | Plugin to merge table columns |
| [`@toast-ui/editor-plugin-uml`](https://github.com/nhn/tui.editor/tree/master/plugins/uml) | Plugin to render UML |
## 🤖 Why TOAST UI Editor?
TOAST UI Editor provides **Markdown mode** and **WYSIWYG mode**. Depending on the type of use you want like production of *Markdown* or maybe to just edit the *Markdown*. The TOAST UI Editor can be helpful for both the usage. It offers **Markdown mode** and **WYSIWYG mode**, which can be switched any point in time.
### Productive Markdown Mode

**CommonMark + GFM Specifications**
Today *CommonMark* is the de-facto *Markdown* standard. *GFM (GitHub Flavored Markdown)* is another popular specification based on *CommonMark* - maintained by *GitHub*, which is the *Markdown* mostly used. TOAST UI Editor follows both [*CommonMark*](http://commonmark.org/) and [*GFM*](https://github.github.com/gfm/) specifications. Write documents with ease using productive tools provided by TOAST UI Editor and you can easily open the produced document wherever the specifications are supported.
* **Live Preview** : Edit Markdown while keeping an eye on the rendered HTML. Your edits will be applied immediately.
* **Scroll Sync** : Synchronous scrolling between Markdown and Preview. You don't need to scroll through each one separately.
* **Syntax Highlight** : You can check broken Markdown syntax immediately.
### Easy WYSIWYG Mode

* **Table** : Through the context menu of the table, you can add or delete columns or rows of the table, and you can also arrange text in cells.
* **Custom Block Editor** : The custom block area can be edited through the internal editor.
* **Copy and Paste** : Paste anything from browser, screenshot, excel, powerpoint, etc.
### UI
* **Toolbar** : Through the toolbar, you can style or add elements to the document you are editing.

* **Dark Theme** : You can use the dark theme.

### Use of Various Extended Functions - Plugins

CommonMark and GFM are great, but we often need more abstraction. The TOAST UI Editor comes with powerful **Plugins** in compliance with the Markdown syntax.
**Five basic plugins** are provided as follows, and can be downloaded and used with npm.
* [**`chart`**](https://github.com/nhn/tui.editor/tree/master/plugins/chart) : A code block marked as a 'chart' will render [TOAST UI Chart](https://github.com/nhn/tui.chart).
* [**`code-syntax-highlight`**](https://github.com/nhn/tui.editor/tree/master/plugins/code-syntax-highlight) : Highlight the code block area corresponding to the language provided by [Prism.js](https://prismjs.com/).
* [**`color-syntax`**](https://github.com/nhn/tui.editor/tree/master/plugins/color-syntax) :
Using [TOAST UI ColorPicker](https://github.com/nhn/tui.color-picker), you can change the color of the editing text with the GUI.
* [**`table-merged-cell`**](https://github.com/nhn/tui.editor/tree/master/plugins/table-merged-cell) :
You can merge columns of the table header and body area.
* [**`uml`**](https://github.com/nhn/tui.editor/tree/master/plugins/uml) : A code block marked as an 'uml' will render [UML diagrams](http://plantuml.com/screenshot).
## 🎨 Features
* [Viewer](https://github.com/nhn/tui.editor/tree/master/docs/en/viewer.md) : Supports a mode to display only markdown data without an editing area.
* [Internationalization (i18n)](https://github.com/nhn/tui.editor/tree/master/docs/en/i18n.md) : Supports English, Dutch, Korean, Japanese, Chinese, Spanish, German, Russian, French, Ukrainian, Turkish, Finnish, Czech, Arabic, Polish, Galician, Swedish, Italian, Norwegian, Croatian + language and you can extend.
* [Widget](https://github.com/nhn/tui.editor/tree/master/docs/en/widget.md) : This feature allows you to configure the rules that replaces the string matching to a specific `RegExp` with the widget node.
* [Custom Block](https://github.com/nhn/tui.editor/tree/master/docs/en/custom-block.md) : Nodes not supported by Markdown can be defined through custom block. You can display the node what you want through writing the parsing logic with custom block.
## 🐾 Examples
* [Basic](https://nhn.github.io/tui.editor/latest/tutorial-example01-editor-basic)
* [Viewer](https://nhn.github.io/tui.editor/latest/tutorial-example04-viewer)
* [Using All Plugins](https://nhn.github.io/tui.editor/latest/tutorial-example12-editor-with-all-plugins)
* [Creating the User's Plugin](https://nhn.github.io/tui.editor/latest/tutorial-example13-creating-plugin)
* [Customizing the Toobar Buttons](https://nhn.github.io/tui.editor/latest/tutorial-example15-customizing-toolbar-buttons)
* [Internationalization (i18n)](https://nhn.github.io/tui.editor/latest/tutorial-example16-i18n)
Here are more [examples](https://nhn.github.io/tui.editor/latest/tutorial-example01-editor-basic) and play with TOAST UI Editor!
## 🌏 Browser Support
| <img src="https://user-images.githubusercontent.com/1215767/34348387-a2e64588-ea4d-11e7-8267-a43365103afe.png" alt="Chrome" width="16px" height="16px" /> Chrome | <img src="https://user-images.githubusercontent.com/1215767/34348590-250b3ca2-ea4f-11e7-9efb-da953359321f.png" alt="IE" width="16px" height="16px" /> Internet Explorer | <img src="https://user-images.githubusercontent.com/1215767/34348380-93e77ae8-ea4d-11e7-8696-9a989ddbbbf5.png" alt="Edge" width="16px" height="16px" /> Edge | <img src="https://user-images.githubusercontent.com/1215767/34348394-a981f892-ea4d-11e7-9156-d128d58386b9.png" alt="Safari" width="16px" height="16px" /> Safari | <img src="https://user-images.githubusercontent.com/1215767/34348383-9e7ed492-ea4d-11e7-910c-03b39d52f496.png" alt="Firefox" width="16px" height="16px" /> Firefox |
| :---------: | :---------: | :---------: | :---------: | :---------: |
| Yes | 11+ | Yes | Yes | Yes |
## 🔧 Pull Request Steps
TOAST UI products are open source, so you can create a pull request(PR) after you fix issues. Run npm scripts and develop yourself with the following process.
### Setup
Fork `main` branch into your personal repository. Clone it to local computer. Install node modules. Before starting development, you should check if there are any errors.
```sh
$ git clone https://github.com/{your-personal-repo}/tui.editor.git
$ npm install
$ npm run build toastmark
$ npm run test editor
```
> TOAST UI Editor uses [npm workspace](https://docs.npmjs.com/cli/v7/using-npm/workspaces/), so you need to set the environment based on [npm7](https://github.blog/2021-02-02-npm-7-is-now-generally-available/). If subversion is used, dependencies must be installed by moving direct paths per package.
### Develop
You can see your code reflected as soon as you save the code by running a server. Don't miss adding test cases and then make green rights.
#### Run snowpack-dev-server
[snowpack](https://www.snowpack.dev/) allows you to run a development server without bundling.
``` sh
$ npm run serve editor
```
#### Run webpack-dev-server
If testing of legacy browsers is required, the development server can still be run using a [webpack](https://webpack.js.org/).
``` sh
$ npm run serve:ie editor
```
#### Run test
``` sh
$ npm test editor
```
### Pull Request
Before uploading your PR, run test one last time to check if there are any errors. If it has no errors, commit and then push it!
For more information on PR's steps, please see links in the Contributing section.
## 💬 Contributing
* [Code of Conduct](https://github.com/nhn/tui.editor/blob/master/CODE_OF_CONDUCT.md)
* [Contributing Guideline](https://github.com/nhn/tui.editor/blob/master/CONTRIBUTING.md)
* [Commit Convention](https://github.com/nhn/tui.editor/blob/master/docs/COMMIT_MESSAGE_CONVENTION.md)
* [Issue Guidelines](https://github.com/nhn/tui.editor/tree/master/.github/ISSUE_TEMPLATE)
## 🍞 TOAST UI Family
- [TOAST UI Calendar](https://github.com/nhn/tui.calendar)
- [TOAST UI Chart](https://github.com/nhn/tui.chart)
- [TOAST UI Grid](https://github.com/nhn/tui.grid)
- [TOAST UI Image Editor](https://github.com/nhn/tui.image-editor)
- [TOAST UI Components](https://github.com/nhn)
## 🚀 Used By
* [NHN Dooray! - Collaboration Service (Project, Messenger, Mail, Calendar, Drive, Wiki, Contacts)](https://dooray.com)
* [UNOTES - Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=ryanmcalister.Unotes)
## 📜 License
This software is licensed under the [MIT](https://github.com/nhn/tui.editor/blob/master/LICENSE) © [NHN Cloud](https://github.com/nhn).
================================================
FILE: __mocks__/cssMock.js
================================================
module.exports = {
process() {
return 'module.exports = {};';
},
};
================================================
FILE: apps/editor/README.md
================================================
# 
[](https://www.npmjs.com/package/@toast-ui/editor)
## 🚩 Table of Contents
- [Collect Statistics on the Use of Open Source](#Collect-statistics-on-the-use-of-open-source)
- [Documents](#-documents)
- [Install](#-install)
- [Usage](#-usage)
- [Tutorials](#-tutorials)
## Collect Statistics on the Use of Open Source
TOAST UI products apply Google Analytics (GA) to collect statistics on the use of open source, in order to identify how widely TOAST UI Editor is used throughout the world. It also serves as important index to determine the future course of projects. `location.hostname` (e.g. ui.toast.com) is to be collected and the sole purpose is nothing but to measure statistics on the usage.
To disable GA, use the following `usageStatistics` option when creating the instance.
```js
const options = {
// ...
usageStatistics: false
};
const editor = new Editor(options);
```
## 📙 Documents
- [Getting Started](https://github.com/nhn/tui.editor/blob/master/docs/en/getting-started.md)
- [APIs](https://nhn.github.io/tui.editor/latest/)
- v3.0 Migration Guide
- [English](https://github.com/nhn/tui.editor/blob/master/docs/v3.0-migration-guide.md)
- [한국어](https://github.com/nhn/tui.editor/blob/master/docs/v3.0-migration-guide-ko.md)
You can also see the older versions of API page on the [releases page](https://github.com/nhn/tui.editor/releases).
## 💾 Install
TOAST UI products can be used by using the package manager or downloading the source directly. However, we highly recommend using the package manager.
### Via Package Manager
TOAST UI products are registered in two package managers, [npm](https://www.npmjs.com/). You can conveniently install it using the commands provided by the package manager. When using npm, be sure to use it in the environment [Node.js](https://nodejs.org/en/) is installed.
#### npm
```sh
$ npm install --save @toast-ui/editor # Latest Version
$ npm install --save @toast-ui/editor@<version> # Specific Version
```
### Via Contents Delivery Network (CDN)
TOAST UI products are available over the CDN powered by [NHN Cloud](https://www.toast.com).
You can use the CDN as below.
```html
...
<body>
...
<script src="https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js"></script>
</body>
...
```
If you want to use a specific version, use the tag name instead of `latest` in the url's path.
The CDN directory has the following structure:
```
- uicdn.toast.com/
├─ editor/
│ ├─ latest/
│ │ ├─ toastui-editor-all.js
│ │ ├─ toastui-editor-all.min.js
│ │ ├─ toastui-editor-viewer.js
│ │ ├─ toastui-editor-viewer.min.js
│ │ ├─ toastui-editor.css
│ │ ├─ toastui-editor.min.css
│ │ ├─ toastui-editor-viewer.css
│ │ ├─ toastui-editor-viewer.min.css
│ │ ├─ toastui-editor-only.css
│ │ ├─ toastui-editor-only.min.css
│ │ └─ theme/
│ │ ├─ toastui-editor-dark.css
│ │ └─ toastui-editor-dark.min.css
│ │ └─ i18n/
│ │ └─ ...
│ ├─ 2.0.0/
│ │ └─ ...
```
## 🔨 Usage
First, you need to add the container element where TOAST UI Editor (henceforth referred to as 'Editor') will be created.
```html
...
<body>
<div id="editor"></div>
</body>
...
```
The editor can be used by creating an instance with the constructor function. To get the constructor function, you should import the module using one of the following ways depending on your environment.
### Using Module Format in Node Environment
- ES6 Modules
```javascript
import Editor from '@toast-ui/editor';
```
- CommonJS
```javascript
const Editor = require('@toast-ui/editor');
```
### Using Namespace in Browser Environment
```javascript
const Editor = toastui.Editor;
```
Then, you need to add the CSS files needed for the Editor. Import CSS files in node environment, and add it to html file when using CDN.
### Using in Node Environment
```javascript
import '@toast-ui/editor/dist/toastui-editor.css'; // Editor's Style
```
### Using in Browser Environment by CDN
```html
...
<head>
...
<!-- Editor's Style -->
<link rel="stylesheet" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
</head>
...
```
Finally you can create an instance with options and call various API after creating an instance.
```javascript
const editor = new Editor({
el: document.querySelector('#editor'),
height: '500px',
initialEditType: 'markdown',
previewStyle: 'vertical'
});
editor.getMarkdown();
```
### Default Options
- `height`: Height in string or auto ex) `300px` | `auto`
- `initialEditType`: Initial type to show `markdown` | `wysiwyg`
- `initialValue`: Initial value. Set Markdown string
- `previewStyle`: Preview style of Markdown mode `tab` | `vertical`
- `usageStatistics`: Let us know the _hostname_. We want to learn from you how you are using the Editor. You are free to disable it. `true` | `false`
Find out more options [here](https://nhn.github.io/tui.editor/latest/ToastUIEditor).
## 🦄 Tutorials
- [Viewer](https://github.com/nhn/tui.editor/blob/master/docs/en/viewer.md)
- [Plugins](https://github.com/nhn/tui.editor/blob/master/docs/en/plugin.md)
- [Internationalization (i18n)](https://github.com/nhn/tui.editor/blob/master/docs/en/i18n.md)
================================================
FILE: apps/editor/demo/esm/index.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>Demo</title>
</head>
<body>
<div id="editor"></div>
<!-- Editor -->
<script type="module">
import { Editor } from '/dist/index.js';
const content = [
'',
'',
'# Awesome Editor!',
'',
'It has been _released as opensource in 2018_ and has ~~continually~~ evolved to **receive 10k GitHub ⭐️ Stars**.',
'',
'## Create Instance',
'',
'You can create an instance with the following code and use `getHtml()` and `getMarkdown()` of the [Editor](https://github.com/nhn/tui.editor).',
'',
'```js',
'const editor = new Editor(options);',
'```',
'',
'> See the table below for default options',
'> > More API information can be found in the document',
'',
'| name | type | description |',
'| --- | --- | --- |',
'| el | `HTMLElement` | container element |',
'',
'## Features',
'',
'* CommonMark + GFM Specifications',
' * Live Preview',
' * Scroll Sync',
' * Auto Indent',
' * Syntax Highlight',
' 1. Markdown',
' 2. Preview',
'',
'## Support Wrappers',
'',
'> * Wrappers',
'> 1. [x] React',
'> 2. [x] Vue',
'> 3. [ ] Ember',
].join('\n');
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
useCommandShortcut: true,
extendedAutolinks: true,
frontMatter: true,
initialValue: content,
});
window.editor = editor;
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/css/tuidoc-example-style.css
================================================
body {
margin: 0;
padding: 0;
}
.tui-doc-description {
padding: 22px 52px;
background-color: rgba(81, 92, 230, 0.1);
line-height: 1.4em;
}
.tui-doc-description,
.tui-doc-description a {
font-family: Arial;
font-size: 14px;
color: #515ce6;
}
.tui-doc-contents {
padding: 20px 52px;
}
.tui-doc-contents .btn {
display: inline-block;
margin-bottom: 10px;
padding: 0 14px 0 15px;
height: 28px;
font-size: 12px;
font-weight: bold;
color: #fff;
border: 0;
vertical-align: top;
line-height: 22px;
background: #777;
cursor: pointer;
border-radius: 5px;
outline: 0;
}
================================================
FILE: apps/editor/examples/data/md-default.js
================================================
/* eslint-disable no-unused-vars */
/* eslint-disable no-var */
var content = [
'',
'',
'# Awesome Editor!',
'',
'It has been _released as opensource in 2018_ and has ~~continually~~ evolved to **receive 10k GitHub ⭐️ Stars**.',
'',
'## Create Instance',
'',
'You can create an instance with the following code and use `getHtml()` and `getMarkdown()` of the [Editor](https://github.com/nhn/tui.editor).',
'',
'```js',
'const editor = new Editor(options);',
'```',
'',
'> See the table below for default options',
'> > More API information can be found in the document',
'',
'| name | type | description |',
'| --- | --- | --- |',
'| el | `HTMLElement` | container element |',
'',
'## Features',
'',
'* CommonMark + GFM Specifications',
' * Live Preview',
' * Scroll Sync',
' * Auto Indent',
' * Syntax Highlight',
' 1. Markdown',
' 2. Preview',
'',
'## Support Wrappers',
'',
'> * Wrappers',
'> 1. [x] React',
'> 2. [x] Vue',
'> 3. [ ] Ember',
].join('\n');
================================================
FILE: apps/editor/examples/data/md-plugins.js
================================================
/* eslint-disable no-unused-vars */
/* eslint-disable no-var */
var chartContent = [
'$$chart',
',category1,category2',
'Jan,21,23',
'Feb,31,17',
'',
'type: column',
'title: Monthly Revenue',
'x.title: Amount',
'y.title: Month',
'y.min: 1',
'y.max: 40',
'y.suffix: $',
'$$',
].join('\n');
var codeContent = [
'```js',
"console.log('foo')",
'```',
'```javascript',
"console.log('bar')",
'```',
'```html',
'<div id="editor"><span>baz</span></div>',
'```',
'```wrong',
'[1 2 3]',
'```',
'```clojure',
'[1 2 3]',
'```',
].join('\n');
var tableContent = ['| @cols=2:merged |', '| --- | --- |', '| table | table2 |'].join('\n');
var umlContent = [
'$$uml',
'partition Conductor {',
' (*) --> "Climbs on Platform"',
' --> === S1 ===',
' --> Bows',
'}',
'',
'partition Audience #LightSkyBlue {',
' === S1 === --> Applauds',
'}',
'',
'partition Conductor {',
' Bows --> === S2 ===',
' --> WavesArmes',
' Applauds --> === S2 ===',
'}',
'',
'partition Orchestra #CCCCEE {',
' WavesArmes --> Introduction',
' --> "Play music"',
'}',
'$$',
].join('\n');
var allPluginsContent = [chartContent, codeContent, tableContent, umlContent].join('\n');
================================================
FILE: apps/editor/examples/example01-editor-basic.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>1. Editor</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/getting-started.md"
rel="noopener noreferrer" target="_blank"
>here</a>
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: content
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example02-editor-with-horizontal-preview.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>2. Editor With Horizontal Preview</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/getting-started.md"
rel="noopener noreferrer" target="_blank"
>here</a>
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'tab',
height: '500px',
initialValue: content
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example03-editor-with-wysiwyg-mode.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>3. Editor With WYSIWYG Mode</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/getting-started.md"
rel="noopener noreferrer" target="_blank"
>here</a>.
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
height: '500px',
initialValue: content,
initialEditType: 'wysiwyg'
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example04-viewer.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>4. Viewer</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Viewer -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor-viewer.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/viewer.md"
rel="noopener noreferrer" target="_blank"
>here</a>.
</div>
<div class="code-html tui-doc-contents">
<div id="viewer">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Viewer -->
<script src="../dist/cdn/toastui-editor-viewer.js"></script>
<script type="text/babel" class="code-js">
const viewer = new toastui.Editor({
el: document.querySelector('#viewer'),
initialValue: content
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example05-viewer-using-editor-factory.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>5. Viewer Using Editor's Factory</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Viewer -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor-viewer.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/viewer.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<div id="viewer">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const viewer = toastui.Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
initialValue: content
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example06-dark-theme.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>6. Editor with Dark Theme</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Dark theme -->
<link rel="stylesheet" href="../dist/cdn/theme/toastui-editor-dark.css" />
</head>
<body style="background: #111">
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2 style="color: #fff">Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2 style="color: #fff">Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: content,
theme: 'dark'
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: content,
theme: 'dark'
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example07-editor-with-chart-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>7. Editor with Chart Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Chart -->
<link rel="stylesheet" href="https://uicdn.toast.com/chart/v4.3.4/toastui-chart.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2>Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2>Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Chart -->
<script src="https://uicdn.toast.com/chart/v4.3.4/toastui-chart.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/editor-plugin-chart/3.0.0/toastui-editor-plugin-chart.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { chart } = Editor.plugin;
const chartOptions = {
minWidth: 100,
maxWidth: 600,
minHeight: 100,
maxHeight: 300
};
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: chartContent,
plugins: [[chart, chartOptions]]
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: chartContent,
plugins: [[chart, chartOptions]]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example08-editor-with-code-syntax-highlight-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>8. Editor with Code Syntax Highlight Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor's Dependencies -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/themes/prism.min.css"
/>
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Editor's Plugin -->
<link
rel="stylesheet"
href="https://uicdn.toast.com/editor-plugin-code-syntax-highlight/3.0.0/toastui-editor-plugin-code-syntax-highlight.min.css"
/>
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2>Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2>Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/editor-plugin-code-syntax-highlight/3.0.0/toastui-editor-plugin-code-syntax-highlight-all.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { codeSyntaxHighlight } = Editor.plugin;
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: codeContent,
plugins: [[codeSyntaxHighlight, { highlighter: Prism }]]
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: codeContent,
plugins: [[codeSyntaxHighlight, { highlighter: Prism }]]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example09-editor-with-color-syntax-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>9. Editor with Color Syntax Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Editor's Plugin -->
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.css"
/>
<link
rel="stylesheet"
href="https://uicdn.toast.com/editor-plugin-color-syntax/3.0.0/toastui-editor-plugin-color-syntax.min.css"
/>
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer"
target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.min.js"></script>
<script src="https://uicdn.toast.com/editor-plugin-color-syntax/3.0.0/toastui-editor-plugin-color-syntax.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { colorSyntax } = Editor.plugin;
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialEditType: 'wysiwyg',
initialValue: 'Select some text and choose a color from the toolbar.',
plugins: [colorSyntax]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example10-editor-with-table-merged-cell-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>10. Editor with Table Merged Cell Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<link rel="stylesheet" href="https://uicdn.toast.com/editor-plugin-table-merged-cell/3.0.0/toastui-editor-plugin-table-merged-cell.min.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer"
target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2>Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2>Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/editor-plugin-table-merged-cell/3.0.0/toastui-editor-plugin-table-merged-cell.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { tableMergedCell } = Editor.plugin;
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: tableContent,
plugins: [tableMergedCell]
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: tableContent,
plugins: [tableMergedCell]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example11-editor-with-uml-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>11. Editor with UML Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2>Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2>Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/editor-plugin-uml/3.0.0/toastui-editor-plugin-uml.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { uml } = Editor.plugin;
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: umlContent,
plugins: [uml]
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: umlContent,
plugins: [uml]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example12-editor-with-all-plugins.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>12. Editor with All Plugins</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Chart -->
<link rel="stylesheet" href="https://uicdn.toast.com/chart/v4.3.4/toastui-chart.css" />
<!-- Code Highlight -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.23.0/themes/prism.min.css"
/>
<link
rel="stylesheet"
href="https://uicdn.toast.com/editor-plugin-code-syntax-highlight/3.0.0/toastui-editor-plugin-code-syntax-highlight.min.css"
/>
<!-- Color syntax -->
<link
rel="stylesheet"
href="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.css"
/>
<link
rel="stylesheet"
href="https://uicdn.toast.com/editor-plugin-color-syntax/3.0.0/toastui-editor-plugin-color-syntax.min.css"
/>
<!-- Merged Table -->
<link rel="stylesheet" href="https://uicdn.toast.com/editor-plugin-table-merged-cell/3.0.0/toastui-editor-plugin-table-merged-cell.min.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer"
target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<!-- Editor -->
<h2>Editor</h2>
<div id="editor"></div>
<!-- Viewer Using Editor -->
<h2>Viewer</h2>
<div id="viewer"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-plugins.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<!-- Chart -->
<script src="https://uicdn.toast.com/chart/v4.3.4/toastui-chart.js"></script>
<!-- Color Picker -->
<script src="https://uicdn.toast.com/tui-color-picker/v2.2.6/tui-color-picker.min.js"></script>
<!-- Editor's Plugin -->
<script src="https://uicdn.toast.com/editor-plugin-chart/3.0.0/toastui-editor-plugin-chart.min.js"></script>
<script src="https://uicdn.toast.com/editor-plugin-code-syntax-highlight/3.0.0/toastui-editor-plugin-code-syntax-highlight-all.min.js"></script>
<script src="https://uicdn.toast.com/editor-plugin-color-syntax/3.0.0/toastui-editor-plugin-color-syntax.min.js"></script>
<script src="https://uicdn.toast.com/editor-plugin-table-merged-cell/3.0.0/toastui-editor-plugin-table-merged-cell.min.js"></script>
<script src="https://uicdn.toast.com/editor-plugin-uml/3.0.0/toastui-editor-plugin-uml.min.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
const { chart, codeSyntaxHighlight, colorSyntax, tableMergedCell, uml } = Editor.plugin;
const chartOptions = {
minWidth: 100,
maxWidth: 600,
minHeight: 100,
maxHeight: 300
};
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: allPluginsContent,
plugins: [[chart, chartOptions], [codeSyntaxHighlight, { highlighter: Prism }], colorSyntax, tableMergedCell, uml]
});
const viewer = Editor.factory({
el: document.querySelector('#viewer'),
viewer: true,
height: '500px',
initialValue: allPluginsContent,
plugins: [[chart, chartOptions], [codeSyntaxHighlight, { highlighter: Prism }], tableMergedCell, uml]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example13-creating-plugin.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>13. Creating Plugin</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css"
integrity="sha384-AfEj0r4/OFrOo5t7NnNe46zW/tFgW6x/bCJG8FqQCEo3+Aro6EYUG4+cU+KJWu/X"
crossorigin="anonymous"
/>
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/plugins.md"
rel="noopener noreferrer" target="_blank"
>here</a
> and
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/custom-block.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<p>Note: LaText doesn't support the ie11. Please check this example in Chrome.</p>
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/latex.js/dist/latex.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const { Editor } = toastui;
// Step 1: Define the user plugin function
function latexPlugin() {
const toHTMLRenderers = {
latex(node) {
const generator = new latexjs.HtmlGenerator({ hyphenate: false });
const { body } = latexjs.parse(node.literal, { generator }).htmlDocument();
return [
{ type: 'openTag', tagName: 'div', outerNewLine: true },
{ type: 'html', content: body.innerHTML },
{ type: 'closeTag', tagName: 'div', outerNewLine: true }
];
},
}
return { toHTMLRenderers }
}
const content = [
'$$latex',
'\\documentclass{article}',
'\\begin{document}',
'',
'$',
'f(x) = \\int_{-\\infty}^\\infty \\hat f(\\xi)\,e^{2 \\pi i \\xi x} \, d\\xi',
'$',
'\\end{document}',
'$$'
].join('\n');
const editor = new Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: content,
// Step 2: Set the defined plugin function as an option value
plugins: [latexPlugin]
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example14-using-command.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>14. Using Command</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
<div class="code-html tui-doc-contents">
<button id="btn" class="btn">Execute the "Bold" command</button>
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: 'Select this line and click the button above.'
});
document.getElementById('btn').addEventListener('click', () => {
editor.exec('bold');
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example15-customizing-toolbar-buttons.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>15. Customizing Toolbar Buttons</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
<!-- Customizing Button's Style in Example -->
<style type="text/css">
.toastui-editor-defaultUI button.first {
color: red;
}
.toastui-editor-defaultUI button.last {
color: orange;
}
</style>
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
function createLastButton() {
const button = document.createElement('button');
button.className = 'toastui-editor-toolbar-icons last';
button.style.backgroundImage = 'none';
button.style.margin = '0';
button.innerHTML = `<i>B</i>`;
button.addEventListener('click', () => {
editor.exec('bold');
});
return button;
}
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: 'The first and last buttons are customized.',
toolbarItems: [
['heading', 'bold', 'italic', 'strike'],
['hr', 'quote'],
['ul', 'ol', 'task', 'indent', 'outdent'],
['table', 'image', 'link'],
['code', 'codeblock'],
// Using Option: Customize the last button
[{
el: createLastButton(),
command: 'bold',
tooltip: 'Custom Bold'
}]
]
});
editor.insertToolbarItem({ groupIndex: 0, itemIndex: 0 }, {
name: 'myItem',
tooltip: 'Custom Button',
command: 'bold',
text: '@',
className: 'toastui-editor-toolbar-icons first',
style: { backgroundImage: 'none' }
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example16-i18n.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>16. Internationalization (i18n)</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
<br />
You can see the tutorial
<a
href="https://github.com/nhn/tui.editor/blob/master/docs/en/i18n.md"
rel="noopener noreferrer" target="_blank"
>here</a
>.
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script src="../dist/cdn/i18n/ko-kr.js"></script>
<script type="text/babel" class="code-js">
// In order to set the desired multilingual in ESM environment, you should import our language module as below.
// import '@toast-ui/editor/dist/i18n/ko-kr';
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
initialValue: 'Hover on item above show different language tooltips.',
language: 'ko'
});
</script>
</body>
</html>
================================================
FILE: apps/editor/examples/example17-placeholder.html
================================================
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8" />
<title>17. Placeholder</title>
<link rel="stylesheet" href="./css/tuidoc-example-style.css" />
<!-- Editor's Dependencies -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.48.4/codemirror.css"
/>
<!-- Editor -->
<link rel="stylesheet" href="../dist/cdn/toastui-editor.css" />
</head>
<body>
<div class="tui-doc-description">
<strong
>The example code can be slower than your environment because the code is transpiled by
babel-standalone in runtime.</strong
>
</div>
<div class="code-html tui-doc-contents">
<div id="editor"></div>
</div>
<!-- Added to check demo page in Internet Explorer -->
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="./data/md-default.js"></script>
<!-- Editor -->
<script src="../dist/cdn/toastui-editor-all.js"></script>
<script type="text/babel" class="code-js">
const editor = new toastui.Editor({
el: document.querySelector('#editor'),
previewStyle: 'vertical',
height: '500px',
placeholder: 'Please enter text.'
});
</script>
</body>
</html>
================================================
FILE: apps/editor/jest.config.js
================================================
// eslint-disable-next-line @typescript-eslint/no-var-requires
const base = require('../../jest.base.config');
module.exports = {
...base,
testEnvironment: 'jsdom',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1',
},
};
================================================
FILE: apps/editor/package.json
================================================
{
"name": "@toast-ui/editor",
"version": "3.2.2",
"description": "GFM Markdown Wysiwyg Editor - Productive and Extensible",
"keywords": [
"nhn",
"nhn cloud",
"toast",
"toastui",
"toast-ui",
"markdown",
"wysiwyg",
"editor",
"preview",
"gfm"
],
"main": "dist/toastui-editor.js",
"module": "dist/esm/",
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/toastui-editor.js"
},
"./viewer": {
"import": "./dist/esm/indexViewer.js",
"require": "./dist/toastui-editor-viewer.js"
},
"./dist/i18n/*": {
"import": "./dist/esm/i18n/*.js",
"require": "./dist/i18n/*.js"
},
"./dist/toastui-editor-viewer": "./dist/toastui-editor-viewer.js",
"./dist/toastui-editor.css": "./dist/toastui-editor.css",
"./dist/toastui-editor-viewer.css": "./dist/toastui-editor-viewer.css",
"./dist/toastui-editor-only.css": "./dist/toastui-editor-only.css",
"./dist/theme/toastui-editor-dark.css": "./dist/theme/toastui-editor-dark.css",
"./toastui-editor.css": "./dist/toastui-editor.css",
"./toastui-editor-viewer.css": "./dist/toastui-editor-viewer.css",
"./toastui-editor-only.css": "./dist/toastui-editor-only.css",
"./toastui-editor-dark.css": "./dist/theme/toastui-editor-dark.css"
},
"types": "types/index.d.ts",
"files": [
"dist/*.js",
"dist/*.css",
"dist/theme",
"dist/esm",
"dist/i18n",
"types"
],
"author": "NHN Cloud FE Development Lab <dl_javascript@nhn.com>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/nhn/tui.editor.git",
"directory": "apps/editor"
},
"bugs": {
"url": "https://github.com/nhn/tui.editor/issues"
},
"homepage": "https://ui.toast.com",
"browserslist": "last 2 versions, not ie <= 10",
"scripts": {
"lint": "eslint .",
"test:types": "tsc",
"test": "jest --watch",
"test:ci": "jest",
"serve": "snowpack dev",
"serve:ie": "webpack serve",
"build:i18n": "cross-env webpack --config scripts/webpack.config.i18n.js && webpack --config scripts/webpack.config.i18n.js --env minify",
"build:prod": "cross-env webpack build && webpack build --env minify && node tsBannerGenerator.js",
"build": "npm run build:esm && npm run build:i18n && npm run build:prod",
"build:esm": "rollup -c",
"note": "tui-note --tag=$(git describe --tags)",
"ts2js": "tsc --outDir tmpdoc --sourceMap false --target ES2015 --noEmit false",
"doc:dev": "npm run ts2js && tuidoc --serv",
"doc": "npm run ts2js && tuidoc"
},
"devDependencies": {
"@toast-ui/release-notes": "^2.0.1",
"@types/dompurify": "2.3.3",
"cross-env": "^6.0.3"
},
"dependencies": {
"dompurify": "^2.3.3",
"prosemirror-commands": "^1.1.9",
"prosemirror-history": "^1.1.3",
"prosemirror-inputrules": "^1.1.3",
"prosemirror-keymap": "^1.1.4",
"prosemirror-model": "^1.14.1",
"prosemirror-state": "^1.3.4",
"prosemirror-view": "^1.18.7"
}
}
================================================
FILE: apps/editor/rollup.config.js
================================================
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import fs from 'fs';
import banner from 'rollup-plugin-banner';
import { version, author, license } from './package.json';
function i18nEditorImportPath() {
return {
name: 'i18nEditorImportPath',
transform(code) {
return code.replace('../editorCore', '@toast-ui/editor');
},
};
}
const fileNames = fs.readdirSync('./src/i18n');
function createBannerPlugin(type) {
return banner(
[
`@toast-ui/editor${type ? ` : ${type}` : ''}`,
`@version ${version} | ${new Date().toDateString()}`,
`@author ${author}`,
`@license ${license}`,
].join('\n')
);
}
export default [
// editor
{
input: 'src/esm/index.ts',
output: {
dir: 'dist/esm',
format: 'es',
sourcemap: false,
},
plugins: [typescript(), commonjs(), nodeResolve(), createBannerPlugin()],
external: [/^prosemirror/],
},
// viewer
{
input: 'src/esm/indexViewer.ts',
output: {
dir: 'dist/esm',
format: 'es',
sourcemap: false,
},
plugins: [typescript(), commonjs(), nodeResolve(), createBannerPlugin('viewer')],
external: [/^prosemirror/],
},
// i18n
{
input: fileNames.map((fileName) => `src/i18n/${fileName}`),
output: {
dir: 'dist/esm/i18n',
format: 'es',
sourcemap: false,
},
external: ['@toast-ui/editor'],
plugins: [
typescript(),
commonjs(),
nodeResolve(),
i18nEditorImportPath(),
createBannerPlugin('i18n'),
],
},
];
================================================
FILE: apps/editor/scripts/createConfigVariable.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const config = require(path.resolve(__dirname, '../tuidoc.config.json'));
const examples = config.examples || {};
const { filePath, globalErrorLogVariable } = examples;
/**
* Get Examples Url
*/
function getTestUrls() {
if (!filePath) {
throw Error('not exist examples path at tuidoc.config.json');
}
const urlPrefix = 'http://nhn.github.io/tui.editor/latest';
const testUrls = fs.readdirSync(filePath).reduce((urls, fileName) => {
if (/html$/.test(fileName)) {
urls.push(`${urlPrefix}/${filePath}/${fileName}`);
}
return urls;
}, []);
fs.writeFileSync('url.txt', testUrls.join(', '));
}
function getGlobalVariable() {
if (!globalErrorLogVariable) {
throw Error('not exist examples path at tuidoc.config.json');
}
fs.writeFileSync('errorVariable.txt', String(globalErrorLogVariable));
}
getTestUrls();
getGlobalVariable();
================================================
FILE: apps/editor/scripts/createIndexPage.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const directory = path.resolve(__dirname, '../examples');
const fileName = 'index.html';
const style = `
<style>
.wrapper {
padding: 60px 50px;
font-size: 15px;
}
ul {
padding: 0;
list-style: none;
overflow: hidden;
}
li {
display: inline-block;
width: 30%;
overflow: hidden;
line-height: 2;
}
a {
color: #555;
text-decoration: none;
}
</style>
`;
function writeData(dir) {
let data = `
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"/>${style}</head>
<body>
<div class="wrapper">
<h1>Examples</h1>
`;
data += '<ul>';
const files = fs.readdirSync(dir);
files.forEach((item) => {
const p = `${directory}/${item}`;
if (fs.statSync(p).isFile()) {
data += `<li><a href="./${item}">${item}</a></li>`;
}
});
data += '</ul></div></body></html>';
return data;
}
const data = writeData(directory);
fs.writeFile(`snowpack/examples/${fileName}`, data, 'utf8', (err) => {
if (err) {
console.error(err);
} else {
console.log('index.html is created successfully');
}
});
================================================
FILE: apps/editor/scripts/webpack.config.i18n.js
================================================
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const webpack = require('webpack');
const entry = require('webpack-glob-entry');
const pkg = require('../package.json');
const TerserPlugin = require('terser-webpack-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
function getOptimizationConfig(minify) {
const minimizer = [];
if (minify) {
minimizer.push(
new TerserPlugin({
parallel: true,
extractComments: false,
})
);
}
return { minimizer };
}
function getEntries() {
const entries = entry('./src/i18n/*.ts');
delete entries['en-us'];
delete entries.i18n;
return entries;
}
module.exports = (env) => {
const { minify = false } = env;
return {
mode: 'production',
entry: getEntries(),
output: {
library: {
type: 'umd',
},
path: path.resolve(__dirname, minify ? '../dist/cdn/i18n' : '../dist/i18n'),
filename: `[name]${minify ? '.min' : ''}.js`,
},
externals: [
{
'../editorCore': {
commonjs: '@toast-ui/editor',
commonjs2: '@toast-ui/editor',
amd: '@toast-ui/editor',
root: ['toastui', 'Editor'],
},
},
],
module: {
rules: [
{
test: /\.ts$|\.js$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
},
},
],
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.BannerPlugin(
[
'TOAST UI Editor : i18n',
`@version ${pkg.version}`,
`@author ${pkg.author}`,
`@license ${pkg.license}`,
].join('\n')
),
new FileManagerPlugin({
events: {
onEnd: {
copy: [{ source: './dist/i18n/*.js', destination: './dist/cdn/i18n' }],
},
},
}),
new ESLintPlugin({
extensions: ['js', 'ts'],
exclude: ['node_modules', 'dist'],
failOnError: true,
}),
],
optimization: getOptimizationConfig(minify),
};
};
================================================
FILE: apps/editor/snowpack.config.js
================================================
/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
'demo/esm': '/',
'src/img': '/img',
src: '/dist',
},
devOptions: {
port: 8080,
},
alias: {
'@': './src',
'@t': './types',
},
workspaceRoot: '../../',
};
================================================
FILE: apps/editor/src/__test__/integration/ui/layout.spec.ts
================================================
import { cls } from '@/utils/dom';
import '@/i18n/en-us';
import { Editor } from '@/index';
import { Emitter } from '@t/event';
import { screen } from '@testing-library/dom';
const EDITOR_CLASS = 'toastui-editor';
function getElement(selector: string) {
return document.querySelector<HTMLElement>(selector)!;
}
function getElements(selector: string) {
return document.querySelectorAll<HTMLElement>(selector)!;
}
function getEditorMain() {
return getElement(`.${cls('main')}`)!;
}
function getMdEditor() {
return getElement(`.${cls('md-container')} .${EDITOR_CLASS}`)!;
}
function getMdPreview() {
return getElement(`.${cls('md-container')} .${cls('md-preview')}`)!;
}
function getWwEditor() {
return getElement(`.${cls('ww-container')} .${EDITOR_CLASS}`)!;
}
function getMdSwitch() {
return screen.getByText('Markdown')!;
}
function getWwSwitch() {
return screen.getByText('WYSIWYG')!;
}
function clickMdSwitch() {
return getMdSwitch().click();
}
function clickWwSwitch() {
return getWwSwitch().click();
}
function getMdWriteTab() {
return getElement(`.${cls('md-tab-container')} .tab-item`)!;
}
function getMdPreviewTab() {
return document.querySelectorAll<HTMLElement>(`.${cls('md-tab-container')} .tab-item`)[1];
}
function getScrollSyncWrapper() {
const scrollSync = getElement('.scroll-sync');
return scrollSync ? scrollSync.parentElement : null;
}
function clickMdWriteTab() {
return getMdWriteTab().click();
}
function clickMdPreviewTab() {
return getMdPreviewTab().click();
}
function assertToContainElement(el: HTMLElement) {
expect(document.body).toContainElement(el);
}
describe('layout component', () => {
let container: HTMLElement;
let editor: Editor;
let em: Emitter;
beforeEach(() => {
container = document.createElement('div');
editor = new Editor({
el: container,
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
});
em = editor.eventEmitter;
document.body.appendChild(container);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(container);
});
it('render default ui properly', () => {
assertToContainElement(getEditorMain());
assertToContainElement(getMdEditor());
assertToContainElement(getMdPreview());
assertToContainElement(getWwEditor());
assertToContainElement(getMdSwitch());
assertToContainElement(getWwSwitch());
});
it('show/hide editor', () => {
const layout = getElement(`.${cls('defaultUI')}`);
editor.hide();
expect(layout).toHaveClass('hidden');
editor.show();
expect(layout).not.toHaveClass('hidden');
});
describe('changing editor mode', () => {
it('should trigger needChangeMode when clicking the switch button', () => {
const spy = jest.fn();
em.listen('needChangeMode', spy);
clickWwSwitch();
expect(spy).toHaveBeenCalledWith('wysiwyg');
clickMdSwitch();
expect(spy).toHaveBeenCalledWith('markdown');
});
it('should switch the editor in layout when changeMode is triggered', () => {
const editorArea = getEditorMain();
const mdSwitch = getMdSwitch();
const wwSwitch = getWwSwitch();
em.emit('changeMode', 'wysiwyg');
expect(editorArea).toHaveClass(cls('ww-mode'));
expect(wwSwitch).toHaveClass('active');
expect(mdSwitch).not.toHaveClass('active');
em.emit('changeMode', 'markdown');
expect(editorArea).toHaveClass(cls('md-mode'));
expect(mdSwitch).toHaveClass('active');
expect(wwSwitch).not.toHaveClass('active');
});
it('should change layout when clicking the switch button', () => {
const editorArea = getEditorMain();
const mdSwitch = getMdSwitch();
const wwSwitch = getWwSwitch();
clickWwSwitch();
expect(editorArea).toHaveClass(cls('ww-mode'));
expect(wwSwitch).toHaveClass('active');
expect(mdSwitch).not.toHaveClass('active');
clickMdSwitch();
expect(editorArea).toHaveClass(cls('md-mode'));
expect(mdSwitch).toHaveClass('active');
expect(wwSwitch).not.toHaveClass('active');
});
it('should not render scrollSync when previewStyle is tab regardless of changing editor mode', () => {
editor = new Editor({
el: container,
previewStyle: 'tab',
});
const scrollSyncWrapper = getScrollSyncWrapper();
expect(scrollSyncWrapper).toBeNull();
em.emit('changeMode', 'wysiwyg');
expect(scrollSyncWrapper).toBeNull();
});
// @todo It needs to break test by each event (changePreviewStyle, changeMode)
it('should show scrollSync when previewStyle is vertical on only markdown mode', () => {
const scrollSyncWrapper = getScrollSyncWrapper();
em.emit('changePreviewStyle', 'vertical');
expect(scrollSyncWrapper).toHaveStyle({ display: 'inline-block' });
em.emit('changeMode', 'wysiwyg');
expect(getElement('.scroll-sync')).toBeNull();
});
it('should show scrollSync when previewStyle is changed on only markdown mode', () => {
const scrollSyncWrapper = getScrollSyncWrapper();
em.emit('changeMode', 'wysiwyg');
em.emit('changePreviewStyle', 'vertical');
expect(getElement('.scroll-sync')).toBeNull();
em.emit('changeMode', 'markdown');
expect(scrollSyncWrapper).toHaveStyle({ display: 'inline-block' });
});
});
describe('changing preview style', () => {
it('should hide markdown tab when changePreviewStyle is triggered', () => {
const tabSection = getElement(`.${cls('md-tab-container')}`)!;
expect(tabSection).toHaveStyle({ display: 'none' });
em.emit('changePreviewStyle', 'tab');
expect(tabSection).toHaveStyle({ display: 'block' });
});
it('should hide markdown tab when changeMode is triggered', () => {
editor = new Editor({
el: container,
previewStyle: 'tab',
initialEditType: 'markdown',
});
em = editor.eventEmitter;
const tabSection = getElement(`.${cls('md-tab-container')}`)!;
expect(tabSection).toHaveStyle({ display: 'block' });
em.emit('changeMode', 'wysiwyg');
expect(tabSection).toHaveStyle({ display: 'none' });
});
it('should display the markdown editor or preview by clicking markdown tab', () => {
expect(getMdWriteTab()).toHaveClass('active');
expect(getMdPreviewTab()).not.toHaveClass('active');
clickMdPreviewTab();
expect(getMdWriteTab()).not.toHaveClass('active');
expect(getMdPreviewTab()).toHaveClass('active');
});
it('should emit changePreviewTabWrite, changePreviewTabPreview events by clicking markdown tab', () => {
const spy1 = jest.fn();
const spy2 = jest.fn();
em.listen('changePreviewTabWrite', spy1);
em.listen('changePreviewTabPreview', spy2);
clickMdPreviewTab();
expect(spy2).toHaveBeenCalledTimes(1);
clickMdWriteTab();
expect(spy1).toHaveBeenCalledTimes(1);
});
it('should enable/disable the toolbar items by clicking markdown tab', () => {
editor = new Editor({
el: container,
previewStyle: 'tab',
initialEditType: 'markdown',
});
const scrollSyncWrapper = getScrollSyncWrapper();
clickMdPreviewTab();
expect(scrollSyncWrapper).toBeNull();
expect(getElement(`.${cls('toolbar-icons')}`)).toBeDisabled();
clickMdWriteTab();
expect(scrollSyncWrapper).toBeNull();
expect(getElement(`.${cls('toolbar-icons')}`)).not.toBeDisabled();
});
it('should enable the toolbar items when changeMode is triggered', () => {
editor = new Editor({
el: container,
previewStyle: 'tab',
initialEditType: 'markdown',
});
em = editor.eventEmitter;
clickMdPreviewTab();
em.emit('changeMode', 'wysiwyg');
expect(getElement(`.${cls('toolbar-icons')}`)).not.toBeDisabled();
em.emit('changeMode', 'markdown');
expect(getElement(`.${cls('toolbar-icons')}`)).not.toBeDisabled();
expect(getMdWriteTab()).toHaveClass('active');
});
it('should enable the toolbar items when changePreviewStyle is triggered', () => {
clickMdPreviewTab();
em.emit('changePreviewStyle', 'vertical');
expect(getElement(`.${cls('toolbar-icons')}`)).not.toBeDisabled();
});
});
describe('context menu', () => {
it('should be displayed when contextmenu event is triggered', () => {
const contextMenu = getElement(`.${cls('context-menu')}`);
expect(contextMenu).toHaveStyle({ display: 'none' });
em.emit('contextmenu', { pos: { left: 10, top: 10 }, menuGroups: [[{ label: 'test' }]] });
expect(contextMenu).toHaveStyle({ display: 'block' });
});
});
});
================================================
FILE: apps/editor/src/__test__/integration/ui/toolbar.spec.ts
================================================
import { cls } from '@/utils/dom';
import { fireEvent, getByLabelText, getByText, screen } from '@testing-library/dom';
import { Editor } from '@/index';
import '@/i18n/en-us';
function getElement(selector: string) {
return document.querySelector<HTMLElement>(selector)!;
}
function getPopUpElement() {
return getElement(`.${cls('popup')}`);
}
function fireMousemoveEvent(el: HTMLElement, x: number, y: number) {
const event = new MouseEvent('mousemove', {
bubbles: true,
cancelable: true,
});
// @ts-ignore
event.pageX = x;
// @ts-ignore
event.pageY = y;
fireEvent(el, event);
}
function fireMouseoverEvent(el: HTMLElement) {
const mouseover = new MouseEvent('mouseover', {
bubbles: true,
cancelable: true,
});
fireEvent(el, mouseover);
}
describe('Default toolbar', () => {
let el: HTMLDivElement, editor: Editor;
beforeEach(() => {
el = document.createElement('div');
editor = new Editor({
el,
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
});
document.body.appendChild(el);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(el);
});
it('should be rendered properly', () => {
[
'Headings',
'Bold',
'Italic',
'Italic',
'Line',
'Blockquote',
'Unordered list',
'Ordered list',
'Task',
'Indent',
'Outdent',
'Insert table',
'Insert image',
'Insert link',
'Inline code',
'Insert codeBlock',
].forEach((label) => {
expect(screen.queryByLabelText(label)).not.toBeNull();
});
expect(document.body).toContainElement(getElement('.scroll-sync'));
});
it('should trigger command event when clicking toolbar button', () => {
const spy = jest.fn();
editor.eventEmitter.listen('command', spy);
screen.getByLabelText('Bold').click();
// eslint-disable-next-line no-undefined
expect(spy).toHaveBeenCalledWith('bold', undefined);
});
it('should show tooltip when mouseover on toolbar button', () => {
fireMouseoverEvent(screen.getByLabelText('Headings'));
const tooltip = screen.getByText('Headings').parentElement;
expect(tooltip).toHaveStyle({ display: 'block' });
expect(tooltip).toHaveClass(cls('tooltip'));
});
describe('scroll sync button', () => {
it('should toggle active state when clicking scroll sync button', () => {
const scrollSyncSwitch = getElement('.scroll-sync');
expect(scrollSyncSwitch).toHaveClass('active');
scrollSyncSwitch.click();
expect(scrollSyncSwitch).not.toHaveClass('active');
});
it('should trigger command event with state', () => {
const spy = jest.fn();
editor.eventEmitter.listen('command', spy);
getElement('.scroll-sync').click();
expect(spy).toHaveBeenCalledWith('toggleScrollSync', { active: false });
getElement('.scroll-sync').click();
expect(spy).toHaveBeenCalledWith('toggleScrollSync', { active: true });
});
});
describe('Headings button', () => {
let headingPopup: HTMLElement;
let hedingButton: HTMLElement;
beforeEach(() => {
headingPopup = getPopUpElement();
hedingButton = screen.getByLabelText('Headings');
hedingButton.click();
});
it('should show the popup when clicking Headings button', () => {
expect(headingPopup).toHaveClass(cls('popup-add-heading'));
expect(headingPopup).toHaveStyle({ display: 'block' });
});
['1', '2', '3', '4', '5', '6'].forEach((level) => {
const mdHeadingOfLevel = '#'.repeat(parseInt(level, 10));
it(`should active heading button when click heading level ${level}`, () => {
getByText(headingPopup, `Heading ${level}`).click();
expect(hedingButton).toHaveClass('active');
});
it(`should add heading to document when click heading level ${level}`, () => {
getByText(headingPopup, `Heading ${level}`).click();
expect(editor.getMarkdown()).toBe(`${mdHeadingOfLevel} `);
});
});
});
describe('link button', () => {
let linkPopup: HTMLElement;
let linkButton: HTMLElement;
beforeEach(() => {
linkPopup = getPopUpElement();
linkButton = screen.getByLabelText('Insert link');
linkButton.click();
});
it('should show the popup when clicking link button', () => {
expect(linkPopup).toHaveClass(cls('popup-add-link'));
expect(linkPopup).toHaveStyle({ display: 'block' });
});
it('should hide popup when clicking Cancel button', () => {
const closeBtn = getByText(linkPopup, 'Cancel');
closeBtn.click();
expect(linkPopup).toHaveStyle({ display: 'none' });
});
it('should add link to document when clicking OK button', () => {
const urlText = getByText(linkPopup, 'URL').nextElementSibling as HTMLInputElement;
const linkText = getByText(linkPopup, 'Link text').nextElementSibling as HTMLInputElement;
const OkBtn = getByText(linkPopup, 'OK');
urlText.value = 'https://ui.toast.com';
linkText.value = 'toastui';
OkBtn.click();
expect(editor.getMarkdown()).toBe('[toastui](https://ui.toast.com)');
});
it('should add wrong class when url or text are not filled out', () => {
const urlText = getByText(linkPopup, 'URL').nextElementSibling as HTMLInputElement;
const linkText = getByText(linkPopup, 'Link text').nextElementSibling as HTMLInputElement;
const OkBtn = getByText(linkPopup, 'OK');
OkBtn.click();
expect(urlText).toHaveClass('wrong');
urlText.value = 'https://ui.toast.com';
OkBtn.click();
expect(linkText).toHaveClass('wrong');
});
});
describe('image button', () => {
let imagePopup: HTMLElement;
let imageButton: HTMLElement;
beforeEach(() => {
imagePopup = getPopUpElement();
imageButton = screen.getByLabelText('Insert image');
imageButton.click();
});
it('should show the popup when clicking image button', () => {
expect(imagePopup).toHaveClass(cls('popup-add-image'));
expect(imagePopup).toHaveStyle({ display: 'block' });
});
it('should hide popup when clicking Cancel button', () => {
const closeBtn = getByText(imagePopup, 'Cancel');
closeBtn.click();
expect(imagePopup).toHaveStyle({ display: 'none' });
});
it('should toggle tab when clicking the file or url tab', () => {
const fileTabBtn = getByLabelText(imagePopup, 'File');
const urlTabBtn = getByLabelText(imagePopup, 'URL');
urlTabBtn.click();
expect(fileTabBtn).not.toHaveClass('active');
expect(urlTabBtn).toHaveClass('active');
fileTabBtn.click();
expect(fileTabBtn).toHaveClass('active');
expect(urlTabBtn).not.toHaveClass('active');
});
it('should add image to document when clicking OK button', () => {
getByLabelText(imagePopup, 'URL').click();
const urlText = getByText(imagePopup, 'Image URL').nextElementSibling as HTMLInputElement;
const descriptionText = getByText(imagePopup, 'Description')
.nextElementSibling as HTMLInputElement;
const OkBtn = getByText(imagePopup, 'OK');
urlText.value = 'myImageUrl';
descriptionText.value = 'image';
OkBtn.click();
expect(editor.getMarkdown()).toBe('');
});
it('should add wrong class when url or text are not filled out', () => {
const fileText = getByText(imagePopup, 'Select image file')
.nextElementSibling as HTMLInputElement;
const urlText = getByText(imagePopup, 'Image URL').nextElementSibling as HTMLInputElement;
const OkBtn = getByText(imagePopup, 'OK');
OkBtn.click();
expect(fileText).toHaveClass('wrong');
getByLabelText(imagePopup, 'URL').click();
OkBtn.click();
expect(urlText).toHaveClass('wrong');
});
});
describe('table button', () => {
let tablePopup: HTMLElement;
let tableButton: HTMLElement;
beforeEach(() => {
tablePopup = getPopUpElement();
tableButton = screen.getByLabelText('Insert table');
tableButton.click();
});
it('should show the popup when clicking table button', () => {
expect(tablePopup).toHaveClass(cls('popup-add-table'));
expect(tablePopup).toHaveStyle({ display: 'block' });
});
it('should add table to document when selecting the area and clicking it', () => {
const tableSelection = tablePopup.querySelector(`.${cls('table-selection')}`)! as HTMLElement;
fireMousemoveEvent(tableSelection, 100, 60);
tableSelection.click();
expect(editor.getMarkdown()).toBe(
'\n| | | | | | |\n| --- | --- | --- | --- | --- | --- |\n| | | | | | |\n| | | | | | |\n| | | | | | |'
);
});
});
it('should active indent/outdent button when only ordered or bullet list actived', () => {
const bulletListBtn = screen.getByLabelText('Unordered list');
const orderedListBtn = screen.getByLabelText('Ordered list');
const indentBtn = screen.getByLabelText('Indent');
const outdentBtn = screen.getByLabelText('Outdent');
bulletListBtn.click();
expect(indentBtn).not.toBeDisabled();
expect(outdentBtn).not.toBeDisabled();
orderedListBtn.click();
expect(indentBtn).not.toBeDisabled();
expect(outdentBtn).not.toBeDisabled();
editor.reset();
expect(indentBtn).toBeDisabled();
expect(outdentBtn).toBeDisabled();
});
it('should change tab mode when changing markdown tab mode', () => {
editor.changePreviewStyle('tab');
const writeTab = screen.getByLabelText('Write');
const previewTab = screen.getByLabelText('Preview');
previewTab.click();
expect(writeTab).not.toHaveClass('active');
expect(previewTab).toHaveClass('active');
writeTab.click();
expect(writeTab).toHaveClass('active');
expect(previewTab).not.toHaveClass('active');
});
});
describe('Custom toobar button', () => {
let el: HTMLDivElement, editor: Editor;
function createCustomButtonWithPopup() {
const body = document.createElement('select');
body.innerHTML = `
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
`;
body.addEventListener('change', (ev) => {
editor.eventEmitter.emit('command', 'heading', {
level: Number((ev.target as HTMLSelectElement).value),
});
editor.eventEmitter.emit('closePopup');
(ev.target as HTMLSelectElement).value = '1';
});
return {
name: 'myToolbarWithPopup',
tooltip: 'L!',
className: 'my-toolbar-with-popup',
text: 'L!',
style: { color: '#fff', width: 30 },
popup: {
body,
className: 'my-popup',
style: { width: 'auto' },
},
};
}
const customButton = {
name: 'myToolbar',
tooltip: 'B!',
className: 'my-toolbar',
command: 'bold',
text: 'B!',
style: { color: '#222', width: 40 },
};
const customButtonWithPopup = createCustomButtonWithPopup();
beforeEach(() => {
el = document.createElement('div');
editor = new Editor({
el,
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
toolbarItems: [[customButton, customButtonWithPopup]],
});
document.body.appendChild(el);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(el);
});
it('should be rendered properly', () => {
const customToolbar1 = screen.getByLabelText('B!');
const customToolbar2 = screen.getByLabelText('L!');
expect(customToolbar1).toHaveTextContent('B!');
expect(customToolbar1).toHaveStyle({ color: '#222', width: '40px' });
expect(customToolbar2).toHaveTextContent('L!');
expect(customToolbar2).toHaveStyle({ color: '#fff', width: '30px' });
});
it('should show tooltip when mouseover on toolbar button', () => {
fireMouseoverEvent(screen.getByLabelText('B!'));
const tooltip = getElement(`.${cls('tooltip')}`);
expect(tooltip).toHaveStyle({ display: 'block' });
expect(tooltip).toHaveTextContent('B!');
});
it('should add text that matched command to document event when clicking button', () => {
screen.getByLabelText('B!').click();
expect(editor.getMarkdown()).toBe('****');
});
it('should show the popup when clicking button with popup option', () => {
screen.getByLabelText('L!').click();
const customPopup = getElement('.my-popup');
expect(customPopup).toHaveStyle({ display: 'block', width: 'auto' });
expect(customPopup).toHaveClass('my-popup');
});
it('should operate properly when event is triggered in popup', () => {
screen.getByLabelText('L!').click();
const customPopup = getElement('.my-popup');
const select = customPopup.querySelector('select')!;
select.value = '3';
fireEvent(select, new Event('change'));
expect(editor.getMarkdown()).toBe('### ');
});
});
describe('API', () => {
function getToolbarItems() {
return getElement(`.${cls('defaultUI-toolbar')}`).querySelectorAll('button:not(.more)');
}
let el: HTMLDivElement, editor: Editor;
beforeEach(() => {
const toolbarItems = [['heading', 'bold', 'italic', 'strike']];
el = document.createElement('div');
editor = new Editor({
el,
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
toolbarItems,
});
document.body.appendChild(el);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(el);
});
it('should insert item on calling insertToolbarItem', () => {
editor.insertToolbarItem({ groupIndex: 0, itemIndex: 1 }, 'ol');
const toolbarItems = getToolbarItems();
expect(toolbarItems[0]).toHaveClass('heading');
expect(toolbarItems[1]).toHaveClass('ordered-list');
expect(toolbarItems[2]).toHaveClass('bold');
expect(toolbarItems[3]).toHaveClass('italic');
expect(toolbarItems[4]).toHaveClass('strike');
// should have same parent because the toolbar is added to same group
expect(toolbarItems[1].parentElement).toEqual(toolbarItems[2].parentElement);
});
it('should add item on calling insertToolbarItem', () => {
editor.insertToolbarItem({ groupIndex: 1, itemIndex: 1 }, 'ol');
const toolbarItems = getToolbarItems();
expect(toolbarItems[0]).toHaveClass('heading');
expect(toolbarItems[1]).toHaveClass('bold');
expect(toolbarItems[2]).toHaveClass('italic');
expect(toolbarItems[3]).toHaveClass('strike');
expect(toolbarItems[4]).toHaveClass('ordered-list');
// should have different parent because the toolbar is added to another group
expect(toolbarItems[3].parentElement).not.toEqual(toolbarItems[4].parentElement);
});
it('should insert custom toolbar item on calling insertToolbarItem', () => {
const customButton = {
name: 'myToolbar',
tooltip: 'B!',
className: 'my-toolbar',
command: 'bold',
text: 'B!',
style: { color: '#222', width: 40 },
};
editor.insertToolbarItem({ groupIndex: 0, itemIndex: 1 }, customButton);
const toolbarItems = getToolbarItems();
expect(toolbarItems[0]).toHaveClass('heading');
expect(toolbarItems[1]).toHaveClass('my-toolbar');
expect(toolbarItems[1]).toHaveTextContent('B!');
expect(toolbarItems[1]).toHaveStyle({ color: '#222', width: '40px' });
expect(toolbarItems[2]).toHaveClass('bold');
expect(toolbarItems[3]).toHaveClass('italic');
expect(toolbarItems[4]).toHaveClass('strike');
});
it('should remove item on calling removeToolbarItem', () => {
editor.removeToolbarItem('bold');
expect(screen.queryByLabelText('Bold')).toBeNull();
});
});
describe('Event', () => {
let el: HTMLDivElement, editor: Editor;
beforeEach(() => {
el = document.createElement('div');
editor = new Editor({
el,
previewStyle: 'vertical',
height: '400px',
initialEditType: 'markdown',
});
document.body.appendChild(el);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(el);
});
describe('openPopup, closePopup', () => {
it('should open and close popup corresponding to name', () => {
editor.eventEmitter.emit('openPopup', 'image');
const imagePopup = getElement(`.${cls('popup-add-image')}`);
expect(imagePopup).toHaveStyle({ display: 'block' });
editor.eventEmitter.emit('closePopup');
expect(imagePopup).toHaveStyle({ display: 'none' });
});
it('should render popup with initial values', () => {
const initialValues = { linkUrl: 'http://test.com', linkText: 'foo' };
editor.eventEmitter.emit('openPopup', 'link', initialValues);
const urlText = screen.getByText('URL').nextElementSibling as HTMLInputElement;
const linkText = screen.getByText('Link text').nextElementSibling as HTMLInputElement;
expect(urlText).toHaveValue('http://test.com');
expect(linkText).toHaveValue('foo');
});
});
});
================================================
FILE: apps/editor/src/__test__/integration/vdom/render.spec.ts
================================================
import { oneLineTrim } from 'common-tags';
import { render } from '@/ui/vdom/renderer';
import { Component } from '@/ui/vdom/component';
import { VNode } from '@/ui/vdom/vnode';
import html from '@/ui/vdom/template';
interface Props {
mounted?: jest.Mock;
updated?: jest.Mock;
beforeDestroy?: jest.Mock;
refDOM?: jest.Mock<any, [HTMLElement]>;
}
interface State {
hide: boolean;
conditional: boolean;
}
class TestComponent extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
hide: false,
conditional: true,
};
}
show() {
this.setState({ hide: false });
}
hide() {
this.setState({ hide: true });
}
conditionalRender() {
this.setState({ conditional: false });
}
mounted() {
if (this.props.mounted) {
this.props.mounted();
}
}
updated() {
if (this.props.updated) {
this.props.updated();
}
}
beforeDestroy() {
if (this.props.beforeDestroy) {
this.props.beforeDestroy();
}
}
render() {
const style = {
display: this.state.hide ? 'none' : 'block',
};
return html`
<div
class="my-comp"
ref=${(el: HTMLElement) => {
if (this.props.refDOM) {
this.props.refDOM(el);
}
}}
>
<div style=${style}>child</div>
<div>
${this.state.conditional ? [1, 2, 3].map((num) => html`<span>${num}</span>`) : null}
</div>
${this.state.conditional ? [1, 2, 3].map((num) => html`<span>${num}</span>`) : null}
<button onClick=${() => this.show()}>show</button>
<button onClick=${() => this.hide()}>hide</button>
<button onClick=${() => this.conditionalRender()}>conditional</button>
</div>
`;
}
}
let container: HTMLElement, destroy: () => void;
describe('html', () => {
it('should be rendered properly', () => {
const wrapper = document.createElement('div');
render(wrapper, html`<div class="my-comp" data-id="my-comp">test</div>` as VNode);
expect(wrapper).toContainHTML('<div class="my-comp" data-id="my-comp">test</div>');
});
it('list children should be rendered properly', () => {
const wrapper = document.createElement('div');
const expected = oneLineTrim`
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>
`;
render(
wrapper,
html`<div>${[1, 2, 3].map((text) => html`<span>${text}</span>`)}</div>` as VNode
);
expect(wrapper).toContainHTML(expected);
});
it('nested vnode should be rendered properly', () => {
const wrapper = document.createElement('div');
const expected = oneLineTrim`
<div class="my-comp" data-id="my-comp">
<nav>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</nav>
</div>
`;
render(
wrapper,
html`
<div class="my-comp" data-id="my-comp">
<nav>
<ul>
${['1', '2', '3'].map((text) => html`<li>${text}</li>`)}
</ul>
</nav>
</div>
` as VNode
);
expect(wrapper).toContainHTML(expected);
});
it('should be rendered with style object properly', () => {
const wrapper = document.createElement('div');
const style = { display: 'inline-block', backgroundColor: '#ccc' };
const expected = oneLineTrim`
<div class="my-comp" style="display: inline-block; background-color: rgb(204, 204, 204);">test</div>
`;
render(wrapper, html`<div class="my-comp" style=${style}>test</div>` as VNode);
expect(wrapper).toContainHTML(expected);
});
it('should be rendered with pixel added automatically', () => {
const wrapper = document.createElement('div');
const style = { position: 'absolute', top: 10, left: 10 };
const expected = oneLineTrim`
<div class="my-comp" style="position: absolute; top: 10px; left: 10px;">test</div>
`;
render(wrapper, html`<div class="my-comp" style=${style}>test</div>` as VNode);
expect(wrapper).toContainHTML(expected);
});
});
describe('Class Component', () => {
function clickShowBtn() {
container.querySelector('button')!.click();
}
function clickHideBtn() {
container.querySelectorAll('button')[1].click();
}
function clickConditionalBtn() {
container.querySelectorAll('button')[2].click();
}
function renderComponent(spies?: Record<string, jest.Mock>) {
container = document.createElement('div');
destroy = render(container, html`<${TestComponent} ...${spies} />` as VNode);
}
it('should be rendered properly', () => {
renderComponent();
const expected = oneLineTrim`
<div class="my-comp">
<div style="display: block;">child</div>
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<span>1</span>
<span>2</span>
<span>3</span>
<button>show</button>
<button>hide</button>
<button>conditional</button>
</div>
`;
expect(container).toContainHTML(expected);
});
it('should be updated by event', () => {
renderComponent();
clickHideBtn();
let expected = oneLineTrim`
<div class="my-comp">
<div style="display: none;">child</div>
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<span>1</span>
<span>2</span>
<span>3</span>
<button>show</button>
<button>hide</button>
<button>conditional</button>
</div>
`;
expect(container).toContainHTML(expected);
clickShowBtn();
expected = oneLineTrim`
<div class="my-comp">
<div style="display: block;">child</div>
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<span>1</span>
<span>2</span>
<span>3</span>
<button>show</button>
<button>hide</button>
<button>conditional</button>
</div>
`;
expect(container).toContainHTML(expected);
});
it('should call ref function with DOM after rendering the component', () => {
const spy = jest.fn();
renderComponent({ refDOM: spy });
expect(spy).toHaveBeenCalledWith(container.querySelector('.my-comp'));
});
it('should call ref function with component after rendering the component', () => {
const spy = jest.fn();
renderComponent({ ref: spy });
expect(spy).toHaveBeenCalledTimes(1);
});
it('should call mounted life cycle method ', () => {
const spy = jest.fn();
renderComponent({ mounted: spy });
expect(spy).toHaveBeenCalledTimes(1);
});
it('should call mounted life cycle method once', () => {
const spy = jest.fn();
renderComponent({ mounted: spy });
clickHideBtn();
expect(spy).toHaveBeenCalledTimes(1);
});
it('should call updated life cycle method after component is updated', () => {
const spy = jest.fn();
renderComponent({ updated: spy });
clickHideBtn();
expect(spy).toHaveBeenCalledTimes(1);
});
it('should call beforeDestroy life cycle method after component is destroyed', () => {
const spy = jest.fn();
renderComponent({ beforeDestroy: spy });
destroy();
expect(spy).toHaveBeenCalledTimes(1);
expect(container).toContainHTML('');
});
it('should render conditional children components', () => {
renderComponent();
let expected = oneLineTrim`
<div class="my-comp">
<div style="display: block;">child</div>
<div>
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<span>1</span>
<span>2</span>
<span>3</span>
<button>show</button>
<button>hide</button>
<button>conditional</button>
</div>
`;
expect(container).toContainHTML(expected);
clickConditionalBtn();
expected = oneLineTrim`
<div class="my-comp">
<div style="display: block;">child</div>
<div></div>
<button>show</button>
<button>hide</button>
<button>conditional</button>
</div>
`;
expect(container).toContainHTML(expected);
});
});
================================================
FILE: apps/editor/src/__test__/integration/widget/widgetNode.spec.ts
================================================
import { oneLineTrim } from 'common-tags';
import Editor from '@/editorCore';
import { cls } from '@/utils/dom';
import { removeDataAttr } from '@/__test__/unit/markdown/util';
describe('widgetNode', () => {
let container: HTMLElement,
mdEditor: HTMLElement,
mdPreview: HTMLElement,
wwEditor: HTMLElement,
editor: Editor;
function getPreviewHTML() {
return removeDataAttr(mdPreview.querySelector(`.${cls('contents')}`)!.innerHTML);
}
beforeEach(() => {
container = document.createElement('div');
editor = new Editor({
el: container,
widgetRules: [
{
rule: /@\S+/,
toDOM(text) {
const span = document.createElement('span');
span.innerHTML = `<a href="www.google.com">${text}</a>`;
return span;
},
},
{
rule: /\[(#\S+)\]\((\S+)\)/,
toDOM: (text) => {
const rule = /\[(#\S+)\]\((\S+)\)/;
const matched = text.match(rule)!;
const span = document.createElement('span');
span.innerHTML = `<a href="${matched[2]}">${matched[1]}</a>`;
return span;
},
},
],
previewStyle: 'vertical',
});
const elements = editor.getEditorElements();
mdEditor = elements.mdEditor;
mdPreview = elements.mdPreview!;
wwEditor = elements.wwEditor!;
container.append(mdEditor);
container.append(mdPreview!);
container.append(wwEditor!);
document.body.appendChild(container);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(container);
});
describe('in markdown', () => {
it('should render widget node in the editor and preview using replaceWithWidget API', () => {
editor.setMarkdown('abc');
editor.replaceWithWidget([1, 1], [1, 3], '@test');
const expectedEditor = oneLineTrim`
<div>
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
c
</div>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
c
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node in the editor and preview using setMarkdown API', () => {
editor.setMarkdown('@test1 @test2');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span><a href="www.google.com">@test2</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node in the editor and preview using insertText API', () => {
editor.insertText('@test1 @test2');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span><a href="www.google.com">@test2</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node with markdown text', () => {
editor.replaceWithWidget([1, 1], [1, 1], '[#toast](ui.toast.com)');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="ui.toast.com">#toast</a></span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span><a href="ui.toast.com">#toast</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node using all widget rules', () => {
editor.insertText('@test1 [#toast](ui.toast.com) @test2');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span><a href="ui.toast.com">#toast</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span><a href="ui.toast.com">#toast</a></span>
</span>
<span class="tui-widget">
<span><a href="www.google.com">@test2</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should convert to wysiwyg properly', () => {
editor.setMarkdown('@test1 @test2');
editor.changeMode('wysiwyg');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
expect(wwEditor).toContainHTML(expectedEditor);
});
it('should keep "$" character in case of plain text other than widget node', () => {
editor.setMarkdown('@test1 $$myText @test2');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
$$myText
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
$$myText
<span class="tui-widget">
<span><a href="www.google.com">@test2</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node in the editor and preview using replaceSelection API', () => {
editor.setMarkdown('widgetNode: ');
editor.replaceSelection('@test1 @test2', [1, 1], [1, 13]);
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should return the markdown text without widget syntax through calling getMarkdown() API', () => {
const markdownText = oneLineTrim`
Brand site: [#toast](https://ui.toast.com), editor: [#toastui-editor](https://github.com/nhn/tui.editor)\n
The Toastui-editor...
`;
editor.setMarkdown(markdownText);
expect(editor.getMarkdown()).toBe(markdownText);
});
});
describe('in wysiwyg', () => {
it('should render widget node in the editor using replaceWithWidget API', () => {
editor.changeMode('wysiwyg');
editor.replaceWithWidget(1, 1, '@test');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
`;
expect(wwEditor).toContainHTML(expectedEditor);
});
it('should render widget node with markdown text', () => {
editor.changeMode('wysiwyg');
editor.replaceWithWidget(1, 1, '[#toast](ui.toast.com)');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="ui.toast.com">#toast</a></span>
</span>
`;
expect(wwEditor).toContainHTML(expectedEditor);
});
it('should convert to markdown properly', () => {
editor.changeMode('wysiwyg');
editor.replaceWithWidget(1, 1, '@test1 @test2');
editor.changeMode('markdown');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span><a href="www.google.com">@test2</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('should render widget node in the editor using replaceSelection API', () => {
editor.setMarkdown('widgetNode:');
editor.changeMode('wysiwyg');
editor.replaceSelection('@test1 @test2', 1, 12);
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span>
<a href="www.google.com">@test1</a>
</span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
expect(wwEditor).toContainHTML(expectedEditor);
});
it('should render widget node in the editor using insertText API', () => {
editor.changeMode('wysiwyg');
editor.insertText('@test1 @test2');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test1</a></span>
</span>
<span class="tui-widget">
<span>
<a href="www.google.com">@test2</a>
</span>
</span>
`;
expect(wwEditor).toContainHTML(expectedEditor);
});
});
});
================================================
FILE: apps/editor/src/__test__/unit/convertor.spec.ts
================================================
import { source, oneLineTrim } from 'common-tags';
import { Context, MdNode, Parser, HTMLConvertorMap } from '@toast-ui/toastmark';
import { Node, Schema } from 'prosemirror-model';
import { createSpecs } from '@/wysiwyg/specCreator';
import Convertor from '@/convertors/convertor';
import { WwToDOMAdaptor } from '@/wysiwyg/adaptor/wwToDOMAdaptor';
import EventEmitter from '@/event/eventEmitter';
import { ToMdConvertorMap, ToMdConvertorContext, NodeInfo, MarkInfo } from '@t/convertor';
import { createHTMLSchemaMap } from '@/wysiwyg/nodes/html';
import { sanitizeHTML } from '@/sanitizer/htmlSanitizer';
import { createHTMLrenderer } from './markdown/util';
function createSchema() {
const specs = createSpecs({});
return new Schema({
nodes: specs.nodes,
marks: specs.marks,
});
}
describe('Convertor', () => {
let convertor: Convertor;
let schema: Schema;
const parser = new Parser({
disallowedHtmlBlockTags: ['br', 'img'],
});
function assertConverting(markdown: string, expected: string) {
const mdNode = parser.parse(markdown);
const wwNode = convertor.toWysiwygModel(mdNode);
const result = convertor.toMarkdownText(wwNode!);
expect(result).toBe(expected);
}
beforeEach(() => {
schema = createSchema();
convertor = new Convertor(schema, {}, {}, new EventEmitter());
});
describe('should convert between markdown and wysiwyg node to', () => {
it('empty content', () => {
assertConverting('', '');
});
it('paragraph', () => {
const markdown = 'foo';
assertConverting(markdown, markdown);
});
it('headings', () => {
const markdown = source`
# heading1
## heading2
### heading3
#### heading4
##### heading5
###### heading6
`;
const expected = source`
# heading1
## heading2
### heading3
#### heading4
##### heading5
###### heading6
`;
assertConverting(markdown, expected);
});
it('codeBlock', () => {
const markdown = source`
\`\`\`
foo
\`\`\`
`;
assertConverting(markdown, markdown);
});
it('bullet list', () => {
const markdown = source`
* foo
* bar
* qux
* baz
`;
assertConverting(markdown, markdown);
});
it('ordered list', () => {
const markdown = source`
1. foo
2. bar
3. baz
`;
assertConverting(markdown, markdown);
});
it('blockQuote', () => {
const markdown = source`
> foo
> bar
>> baz
> > qux
> >> quxx
`;
const expected = source`
> foo
> bar
> > baz
> > qux
> > > quxx
`;
assertConverting(markdown, expected);
});
it('thematicBreak', () => {
const markdown = source`
---
***
- - -
* * * *
`;
const expected = source`
***
***
***
***
`;
assertConverting(markdown, expected);
});
it('image', () => {
const markdown = source`




`;
const expected = source`




`;
assertConverting(markdown, expected);
});
it('link', () => {
const markdown = source`
[](url)foo
[text](url)
[text](ur*l)
[Editor](https://github.com/nhn_test/tui.editor)
[this.is_a_test_link.com](this.is_a_test_link.com)
[text](url?key=abc&attribute=abc)
`;
const expected = source`
foo
[text](url)
[text](ur*l)
[Editor](https://github.com/nhn_test/tui.editor)
[this.is_a_test_link.com](this.is_a_test_link.com)
[text](url?key=abc&attribute=abc)
`;
assertConverting(markdown, expected);
});
it('code', () => {
const markdown = '`foo bar baz`';
assertConverting(markdown, markdown);
});
it('emphasis (strong, italic) syntax', () => {
const markdown = source`
**foo**
__bar__
*baz*
_qux_
`;
const expected = source`
**foo**
**bar**
*baz*
*qux*
`;
assertConverting(markdown, expected);
});
it('strike', () => {
const markdown = '~~strike~~';
assertConverting(markdown, markdown);
});
it('table', () => {
const markdown = source`
| thead | thead |
| --- | --- |
| tbody | tbody |
| thead |thead |
| -- | ----- |
| tbody|tbody|
| tbody|tbody|
|||
|-|-|
|||
`;
const expected = source`
| thead | thead |
| ----- | ----- |
| tbody | tbody |
| thead | thead |
| ----- | ----- |
| tbody | tbody |
| tbody | tbody |
| | |
| --- | --- |
| | |
`;
assertConverting(markdown, `${expected}\n`);
});
it('table with column align syntax', () => {
const markdown = source`
| default | left | right | center |
| --- | :--- | ---: | :---: |
| tbody | tbody | tbody | tbody |
| | | | |
| --- | :--- | ---: | :---: |
| default | left | right | center |
`;
const expected = source`
| default | left | right | center |
| ------- | :--- | ----: | :----: |
| tbody | tbody | tbody | tbody |
| | | | |
| --- | :--- | ---: | :---: |
| default | left | right | center |
`;
assertConverting(markdown, `${expected}\n`);
});
it('table with inline syntax', () => {
const markdown = source`
|  | foo  baz |
| ---- | ---- |
| [linkText](linkUrl) | foo [linkText](linkUrl) baz |
| **foo** _bar_ ~~baz~~ | **foo** *bar* ~~baz~~ [linkText](linkUrl) |
`;
const expected = source`
|  | foo  baz |
| --- | -------- |
| [linkText](linkUrl) | foo [linkText](linkUrl) baz |
| **foo** *bar* ~~baz~~ | **foo** *bar* ~~baz~~ [linkText](linkUrl) |
`;
assertConverting(markdown, `${expected}\n`);
});
// @TODO: should normalize table cell
// it('should normalize wrong table syntax when converting', () => {
// const markdown = source`
// | col1 | col2 | col3 |
// | --- | --- |
// | cell1 | cell2 | cell3 |
// `;
// const expected = source`
// | col1 | col2 | col3 |
// | ---- | ---- | ---- |
// | cell1 | cell2 | |
// `;
// assertConverting(markdown, `${expected}\n`);
// });
it('task', () => {
const markdown = source`
* [ ] foo
* [x] baz
* [x] bar
1. [x] foo
2. [ ] bar
`;
assertConverting(markdown, markdown);
});
it('list in blockQuote', () => {
const markdown = source`
> * foo
> * baz
> * bar
>> 1. qux
> > 2. quxx
`;
const expected = source`
> * foo
> * baz
> * bar
> > 1. qux
> > 2. quxx
`;
assertConverting(markdown, expected);
});
it('block nodes in list', () => {
const markdown = source`
1. foo
\`\`\`
bar
\`\`\`
> bam
`;
const expected = source`
1. foo
\`\`\`
bar
\`\`\`
> bam
`;
assertConverting(markdown, expected);
});
it('soft break', () => {
const markdown = source`
foo
bar
baz
qux
`;
const expected = source`
foo
bar
baz
qux
`;
assertConverting(markdown, expected);
});
it('<br>', () => {
const markdown = source`
foo
<br>
bar
<br>
<br>
baz
<br>
<br>
<br>
qux
`;
const expected = source`
foo
bar
<br>
baz
<br>
<br>
qux
`;
assertConverting(markdown, expected);
});
it('<br> with soft break', () => {
const markdown = source`
foo
<br>
bar
<br>
<br>
baz
<br>
qux
<br>
quux
<br>
quuz
`;
const expected = source`
foo
<br>
bar
<br>
<br>
baz
<br>
qux
<br>
quux
<br>
<br>
quuz
`;
assertConverting(markdown, expected);
});
it('<br> with html inline node', () => {
const markdown = source`
foo
bar
Para <b>Word</b><br>
`;
const expected = source`
foo
bar
Para <b>Word</b>
`;
assertConverting(markdown, expected);
});
it('<br> with following <br>', () => {
const markdown = source`
text1
<br>
text2<br>
<br>
text3
`;
const expected = source`
text1
text2
text3
`;
assertConverting(markdown, expected);
});
it('<br> in the middle of the paragraph', () => {
const markdown = source`
text1
<br>
te<br>xt2<br>
<br>
text3
`;
const expected = source`
text1
te
xt2
text3
`;
assertConverting(markdown, expected);
});
it('should convert html comment', () => {
const markdown = source`
<!--
foo
bar
baz
-->
`;
assertConverting(markdown, markdown);
});
});
describe('convert inline html', () => {
it('emphasis type', () => {
const markdown = source`
<b>foo</b>
<strong>foo</strong>
<i>foo</i>
<em>foo</em>
<s>foo</s>
<del>foo</del>
<code>foo</code>
`;
assertConverting(markdown, markdown);
});
it('link type', () => {
const markdown = source`
<a href="#">foo</a>
<img src="#">
<img src="#" alt="test">
`;
assertConverting(markdown, markdown);
});
it('table with <br>', () => {
const markdown = source`
| thead<br>thead | thead |
| ----- | ----- |
| tbody<br>tbody | tbody |
| tbody | tbody<br>tbody<br>tbody |
| tbody | **tbody**<br>_tbody_<br>~~tbody~~<br>\`tbody\` |
| tbody | <br>[link](linkUrl) |
`;
const expected = source`
| thead<br>thead | thead |
| ---------- | ----- |
| tbody<br>tbody | tbody |
| tbody | tbody<br>tbody<br>tbody |
| tbody | **tbody**<br>*tbody*<br>~~tbody~~<br>\`tbody\` |
| tbody | <br>[link](linkUrl) |
`;
assertConverting(markdown, `${expected}\n`);
});
it('table with list', () => {
const markdown = source`
| thead |
| ----- |
| <ul><li>bullet</li></ul> |
| <ol><li>ordered</li></ol> |
| <ul><li>nested<ul><li>nested</li></ul></li></ul> |
| <ul><li>nested<ul><li>nested</li><li>nested</li></ul></li></ul> |
| <ol><li>mix**ed**<ul><li>**mix**ed</li></ul></li></ol> |
| <ol><li>mix<i>ed</i><ul><li><strong>mix</strong>ed</li></ul></li></ol> |
| foo<ul><li>bar</li></ul>baz |
|  **mixed**<ul><li>[linkText](linkUrl) mixed</li></ul> |
`;
assertConverting(markdown, `${markdown}\n`);
});
it('table with unmatched html list', () => {
const markdown = source`
| thead |
| ----- |
| <ul><li>bullet</li><ul> |
| <ol><li>ordered</li><ol> |
| <ul><li>nested<ul><li>nested</li><ul><li><ul> |
`;
const expected = source`
| thead |
| ----- |
| <ul><li>bullet</li></ul> |
| <ol><li>ordered</li></ol> |
| <ul><li>nested<ul><li>nested</li></ul></li></ul> |
`;
assertConverting(markdown, `${expected}\n`);
});
});
describe('convert block html', () => {
it('paragraph and division are not converted to html block', () => {
const markdown = source`
<p>paragraph</p>
<div>division</div>
`;
const expected = source`
paragraph
division
`;
assertConverting(markdown, expected);
});
it('heading', () => {
const markdown = source`
<h1>heading1</h1>
<h2>heading2</h2>
<h3>heading3</h3>
<h4>heading4</h4>
<h5>heading4</h5>
<h6>heading4</h6>
`;
const expected = oneLineTrim`
<h1>heading1</h1>
<h2>heading2</h2>
<h3>heading3</h3>
<h4>heading4</h4>
<h5>heading4</h5>
<h6>heading4</h6>
`;
assertConverting(markdown, expected);
});
it('pre', () => {
const markdown = source`
<pre>code</pre>
`;
assertConverting(markdown, markdown);
});
it('blockquote', () => {
const markdown = source`
<blockquote>foo</blockquote>
<blockquote>foo<blockquote>foo</blockquote></blockquote>
`;
const expected = oneLineTrim`
<blockquote>foo</blockquote>
<blockquote>foo<blockquote>foo</blockquote></blockquote>
`;
assertConverting(markdown, expected);
});
it('bullet list', () => {
const markdown = source`
<ul><li>foo</li></ul>
<ul><li>foo<ul><li>foo</li></ul></li></ul>
`;
const expected = oneLineTrim`
<ul><li>foo</li></ul>
<ul><li>foo<ul><li>foo</li></ul></li></ul>
`;
assertConverting(markdown, expected);
});
it('ordered list', () => {
const markdown = source`
<ol><li>foo</li></ol>
<ol><li>foo<ol><li>foo</li></ol></li></ol>
`;
const expected = oneLineTrim`
<ol><li>foo</li></ol>
<ol><li>foo<ol><li>foo</li></ol></li></ol>
`;
assertConverting(markdown, expected);
});
it('task', () => {
const markdown = source`
<ul><li class="task-list-item" data-task>bullet task</li></ul>
<ul><li class="task-list-item checked" data-task data-task-checked>ordered task</li></ul>
`;
const expected = oneLineTrim`
<ul><li class="task-list-item" data-task>bullet task</li></ul>
<ul><li class="task-list-item checked" data-task data-task-checked>ordered task</li></ul>
`;
assertConverting(markdown, expected);
});
it('table', () => {
const markdown = source`
<table><thead><tr><th>foo</th></tr></thead><tbody><tr><td>bar</td></tr></tbody></table>
`;
assertConverting(markdown, markdown);
});
it('with html inline', () => {
const markdown = source`
<h1><b>foo</b></h1>
<ul><li>foo <i>bar</i></li></ul>
<blockquote><s>foo</s> bar</blockquote>
`;
const expected = oneLineTrim`
<h1><b>foo</b></h1>
<ul><li>foo <i>bar</i></li></ul>
<blockquote><s>foo</s> bar</blockquote>
`;
assertConverting(markdown, expected);
});
});
describe('convert custom inline', () => {
it('with info only', () => {
const markdown = source`$$custom$$`;
const expected = oneLineTrim`$$custom$$`;
assertConverting(markdown, expected);
});
it('with info and text', () => {
const markdown = source`$$custom inline$$`;
const expected = oneLineTrim`$$custom inline$$`;
assertConverting(markdown, expected);
});
});
describe('sanitize when using html', () => {
it('href attribute with link', () => {
const markdown = source`
<a href="javascript:alert();">xss</a>
<a href=" JaVaScRiPt: alert();">xss</a>
<a href="vbscript:alert();">xss</a>
<a href=" VBscript: alert(); ">xss</a>
<a href="livescript:alert();">xss</a>
<a href=" LIVEScript: alert() ;">xss</a>
123<a href=' javascript:alert();'>xss</a>
`;
const expected = source`
<a href="">xss</a>
<a href="">xss</a>
<a href="">xss</a>
<a href="">xss</a>
<a href="">xss</a>
<a href="">xss</a>
123<a href="">xss</a>
`;
assertConverting(markdown, expected);
});
it('src attribute with image', () => {
const markdown = source`
<img src="javascript:alert();">
<img src=" JaVaScRiPt: alert();">
<img src="vbscript:alert();">
<img src=" VBscript: alert(); ">
<img src=" LIVEScript: alert() ;">
`;
const expected = source`
<img src="">
<img src="">
<img src="">
<img src="">
<img src="">
`;
assertConverting(markdown, expected);
});
});
describe('should custom convertor when converting from wysiwyg to markdown', () => {
function createCustomConvertor(customConvertor: ToMdConvertorMap) {
schema = createSchema();
convertor = new Convertor(schema, customConvertor, {}, new EventEmitter());
}
it('should change delimeter', () => {
const toMdCustomConvertor = {
thematicBreak() {
return {
delim: '- - -',
};
},
};
createCustomConvertor(toMdCustomConvertor);
assertConverting('***', '- - -');
});
it('should change raw html', () => {
const toMdCustomConvertor = {
thematicBreak() {
return {
rawHTML: '<hr class="foo">',
};
},
};
createCustomConvertor(toMdCustomConvertor);
assertConverting('***', '<hr class="foo">');
});
it('should not convert raw html when returning only delimiter', () => {
const toMdCustomConvertor = {
thematicBreak() {
return {
delim: '***',
};
},
};
createCustomConvertor(toMdCustomConvertor);
assertConverting('<hr>', '***');
});
it('should convert to original value', () => {
const toMdCustomConvertor = {
thematicBreak(_: NodeInfo | MarkInfo, { origin }: ToMdConvertorContext) {
return origin!();
},
};
createCustomConvertor(toMdCustomConvertor);
assertConverting('***', '***');
});
it('should convert by mixing return values', () => {
const toMdCustomConvertor = {
heading({ node }: NodeInfo | MarkInfo, { origin }: ToMdConvertorContext) {
const { level, headingType } = node.attrs;
if (headingType === 'setext') {
const delim = level === 1 ? '========' : '------';
return { delim };
}
return origin!();
},
};
createCustomConvertor(toMdCustomConvertor);
const markdown = source`
heading1
===
heading2
---
# heading1
`;
const expected = source`
heading1
========
heading2
------
# heading1
`;
assertConverting(markdown, expected);
});
});
describe('with front matter parser option', () => {
function assertFrontMatterConverting(markdown: string, expected: string) {
const useFrontMatterParser = new Parser({
disallowedHtmlBlockTags: ['br', 'img'],
frontMatter: true,
});
const mdNode = useFrontMatterParser.parse(markdown);
const wwNode = convertor.toWysiwygModel(mdNode);
const result = convertor.toMarkdownText(wwNode!);
expect(result).toBe(expected);
}
it('should convert front matter', () => {
const markdown = source`
---
title: foo
desc: bar
---
`;
assertFrontMatterConverting(markdown, markdown);
});
});
describe('should convert html block node which is not supported as default', () => {
function createConvertorWithHTMLRenderer() {
const customHTMLRenderer = createHTMLrenderer();
const adaptor = new WwToDOMAdaptor({}, customHTMLRenderer);
const htmlSchemaMap = createHTMLSchemaMap(customHTMLRenderer, sanitizeHTML, adaptor);
const specs = createSpecs({});
schema = new Schema({
nodes: { ...specs.nodes, ...htmlSchemaMap.nodes },
marks: { ...specs.marks, ...htmlSchemaMap.marks },
});
convertor = new Convertor(schema, {}, {}, new EventEmitter());
}
beforeEach(() => {
createConvertorWithHTMLRenderer();
});
it('should convert html block node to wysiwyg ignoring sanitizer tag', () => {
const markdown =
'<iframe src="https://www.youtube.com/embed/XyenY12fzAk" height="315" width="420"></iframe>';
const expected =
'<iframe width="420" height="315" src="https://www.youtube.com/embed/XyenY12fzAk"></iframe>';
assertConverting(markdown, expected);
});
it('should convert html block element which has "=" character as the attribute value', () => {
const markdown =
'<iframe src="//player.bilibili.com/player.html?aid=588782532&bvid=BV1hB4y1K7ro&cid=360826679&page=1" height="315" width="420"></iframe>';
const expected =
'<iframe width="420" height="315" src="//player.bilibili.com/player.html?aid=588782532&bvid=BV1hB4y1K7ro&cid=360826679&page=1"></iframe>';
assertConverting(markdown, expected);
});
it('should convert html block node as the block node through inserting the blank line', () => {
const markdown = source`
para1
<iframe src="https://www.youtube.com/embed/XyenY12fzAk" width="420" height="315"></iframe>
para2
`;
const expected = source`
para1
<iframe height="315" width="420" src="https://www.youtube.com/embed/XyenY12fzAk"></iframe>
para2
`;
assertConverting(markdown, expected);
});
it('should convert html inline node', () => {
const markdown = 'inline <big class="my-big">content</big>';
assertConverting(markdown, markdown);
});
});
describe('with custom convertor when converting from markdown to wysiwyg', () => {
function createCustomConvertor(customConvertor: HTMLConvertorMap) {
schema = createSchema();
convertor = new Convertor(schema, {}, customConvertor, new EventEmitter());
}
it('should convert markdown to wysiwyg', () => {
const toHTMLConvertor: HTMLConvertorMap = {
paragraph(_: MdNode, { entering, origin, options }: Context) {
if (options.nodeId) {
return {
type: entering ? 'openTag' : 'closeTag',
outerNewLine: true,
tagName: 'p',
};
}
return origin!();
},
};
createCustomConvertor(toHTMLConvertor);
const markdown = source`
> * Wrappers
> 1. [x] React
> 2. [x] Vue
> 3. [ ] Ember
`;
assertConverting(markdown, markdown);
});
});
describe('should escape markdown text in wysiwyg', () => {
it('with markdown text', () => {
const markdown = source`
\\# heading
\\> blockquote
\\*test\\*
\\* list
`;
assertConverting(markdown, markdown);
});
it('with html text', () => {
const markdown = source`
\\<div>block\\</div>
\\<strong>bold\\</strong>
`;
assertConverting(markdown, markdown);
});
});
it('should convert empty line between lists of wysiwig to <br>', () => {
const wwNodeJson = {
type: 'doc',
content: [
{
type: 'bulletList',
content: [
{
type: 'listItem',
content: [
{ type: 'paragraph', content: [{ type: 'text', text: 'test_1' }] },
{ type: 'paragraph', content: [] },
],
},
{
type: 'listItem',
content: [{ type: 'paragraph', content: [{ type: 'text', text: 'test_2' }] }],
},
],
},
],
};
const wwNode = Node.fromJSON(schema, wwNodeJson);
const result = convertor.toMarkdownText(wwNode);
expect(result).toBe(`* test\\_1\n<br>\n* test\\_2`);
});
it('should escape the backslash, which is a plain chracter in the middle of a sentence', () => {
const markdown = source`
backslash \\in the middle of a sentence
`;
const expected = source`
backslash \\\\in the middle of a sentence
`;
assertConverting(markdown, expected);
});
});
================================================
FILE: apps/editor/src/__test__/unit/dom.spec.ts
================================================
import toArray from 'tui-code-snippet/collection/toArray';
import {
isPositionInBox,
isElemNode,
findNodes,
appendNodes,
insertBeforeNode,
removeNode,
unwrapNode,
toggleClass,
createElementWith,
closest,
empty,
appendNode,
prependNode,
} from '@/utils/dom';
describe('dom utils', () => {
let container: HTMLElement;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
container.parentNode!.removeChild(container);
});
it('isPositionInBox() returns state whether position is contained within box size', () => {
container.innerHTML = '<div class="test">foo</div>';
const el = document.querySelector('.test') as HTMLElement;
const { style } = el;
style.left = '0';
style.top = '0';
style.width = '10px';
style.height = '10px';
style.paddingLeft = '0';
style.paddingRight = '0';
style.paddingTop = '0';
style.paddingBottom = '0';
expect(isPositionInBox(style, 5, 5)).toBe(true);
expect(isPositionInBox(style, 15, 15)).toBe(false);
});
describe('isElemNode', () => {
it('returns true if passed node is ELEMENT_NODE', () => {
container.innerHTML = '<p>hi</p>';
const target = container.querySelector('p') as HTMLElement;
const result = isElemNode(target);
expect(result).toBe(true);
});
it('returns false if passed node is not ELEMENT_NODE', () => {
container.innerHTML = 'text';
const result = isElemNode(container.firstChild!);
expect(result).toBe(false);
});
});
it('appendNodes() appends last child to parent using dom element', () => {
container.innerHTML = '<div>foo</div>';
const el = document.createElement('p');
el.innerHTML = 'bar';
const target = container.querySelector('div') as HTMLElement;
appendNodes(target, el);
expect(container.innerHTML).toBe('<div>foo<p>bar</p></div>');
});
it('insertBeforeNode() inserts node in front of target node', () => {
container.innerHTML = '<div>foo</div>';
const el = document.createElement('p');
el.innerHTML = 'bar';
const target = container.querySelector('div') as HTMLElement;
insertBeforeNode(el, target);
expect(container.innerHTML).toBe('<p>bar</p><div>foo</div>');
});
it('removeNode() removes target node', () => {
container.innerHTML = '<div><p>foo</p><p>bar</p></div>';
const target = container.querySelector('p') as HTMLElement;
removeNode(target);
expect(container.innerHTML).toBe('<div><p>bar</p></div>');
});
it('unwrapNode() removes given element and insert children at the same position', () => {
const childrenHTML = '<i>emph1</i> text <i>emph2</i>';
container.innerHTML = `<p><b>${childrenHTML}</b></p>`;
const target = container.querySelector('b') as HTMLElement;
unwrapNode(target);
expect(container.innerHTML).toBe(`<p>${childrenHTML}</p>`);
});
describe('findNodes() returns nodes matching by selector', () => {
beforeEach(() => {
container.innerHTML = '<div>foo</div><div>bar</div>';
});
it('to array when found', () => {
const result = findNodes(container, 'div');
expect(result.length).toBe(2);
expect(result[0].textContent).toBe('foo');
expect(result[1].textContent).toBe('bar');
});
it('to empty array when not found', () => {
const result = findNodes(container, '.test');
expect(result.length).toBe(0);
});
});
describe('toggleClass() adds or removes specific class name of element', () => {
beforeEach(() => {
container.innerHTML = '<div class="test">foo</div>';
});
it('only toggle class', () => {
const target = container.querySelector('div')!;
toggleClass(target, 'active');
expect(target.className).toBe('test active');
toggleClass(target, 'active');
expect(target.className).toBe('test');
});
it('add or remove class by condition', () => {
const target = container.querySelector('div')!;
toggleClass(target, 'active', true);
expect(target.className).toBe('test active');
toggleClass(target, 'active1', false);
expect(target.className).toBe('test active');
toggleClass(target, 'active', false);
expect(target.className).toBe('test');
});
});
describe('createElementWith() returns created new element using', () => {
it('html string', () => {
const result = createElementWith('<p>foo</p>')!;
expect(result.textContent).toBe('foo');
});
it('dom element', () => {
const element = document.createElement('p');
element.innerHTML = 'foo';
const result = createElementWith(element)!;
expect(result.textContent).toBe('foo');
});
it('if there is target element, new element is appended to target', () => {
container.innerHTML = '<div></div>';
const target = container.querySelector('div')!;
const result = createElementWith('<p>foo</p>', target)!;
expect(result.parentNode).toBe(target);
});
});
describe('closest() finds node with', () => {
beforeEach(() => {
container.innerHTML = '<ul><li>foo</li><li class="test">bar</li></ul>';
});
it('type selector from text node', () => {
const selector = 'li';
const [target] = toArray(container.querySelectorAll('li'));
const foundNode = closest(target.firstChild!, selector);
const result = container.querySelector(selector);
expect(foundNode).toBe(result);
});
it('attribute selector from text node', () => {
const selector = '.test';
const [, target] = toArray(container.querySelectorAll('li'));
const foundNode = closest(target.firstChild!, selector);
const result = container.querySelector(selector);
expect(foundNode).toBe(result);
});
it('type selector from element node', () => {
const selector = 'UL';
const target = container.querySelector('li')!;
const foundNode = closest(target, selector);
const result = container.querySelector(selector);
expect(foundNode).toBe(result);
});
it('wrong selector', () => {
const selector = 'wrong selector';
const target = container.querySelector('li')!;
const foundNode = closest(target, selector);
expect(foundNode).toBeNull();
});
it('dom element', () => {
const target = container.querySelector('li')!;
const selector = container.querySelector('ul')!;
const foundNode = closest(target, selector)!;
expect(foundNode).toEqual(selector);
});
});
it('empty() removes all children from target node', () => {
container.innerHTML = '<div><p>foo</p><p>bar</p></div>';
const target = container.querySelector('div')!;
empty(target);
expect(container.innerHTML).toBe('<div></div>');
});
describe('appendNode() appends last child to parent using', () => {
beforeEach(() => {
container.innerHTML = '<div>foo</div>';
});
it('html string', () => {
appendNode(container.querySelector('div')!, '<p>bar</p>');
expect(container.innerHTML).toBe('<div>foo<p>bar</p></div>');
});
it('dom element', () => {
const child = document.createElement('p');
child.innerHTML = 'bar';
appendNode(container.querySelector('div')!, child);
expect(container.innerHTML).toBe('<div>foo<p>bar</p></div>');
});
});
describe('prependNode() appends first child to parent using', () => {
beforeEach(() => {
container.innerHTML = '<div>foo</div>';
});
it('html string', () => {
prependNode(container.querySelector('div')!, '<p>bar</p>');
expect(container.innerHTML).toBe('<div><p>bar</p>foo</div>');
});
it('dom element', () => {
const child = document.createElement('p');
child.innerHTML = 'bar';
prependNode(container.querySelector('div')!, child);
expect(container.innerHTML).toBe('<div><p>bar</p>foo</div>');
});
});
});
================================================
FILE: apps/editor/src/__test__/unit/editor.spec.ts
================================================
import '@/i18n/en-us';
import { oneLineTrim, stripIndents, source } from 'common-tags';
import { Emitter } from '@t/event';
import { EditorOptions } from '@t/editor';
import type { OpenTagToken } from '@toast-ui/toastmark';
import i18n from '@/i18n/i18n';
import Editor from '@/editor';
import Viewer from '@/viewer';
import * as commonUtil from '@/utils/common';
import { createHTMLrenderer } from './markdown/util';
import { cls } from '@/utils/dom';
import * as imageHelper from '@/helper/image';
const HEADING_CLS = `${cls('md-heading')} ${cls('md-heading1')}`;
const DELIM_CLS = cls('md-delimiter');
describe('editor', () => {
let container: HTMLElement,
mdEditor: HTMLElement,
mdPreview: HTMLElement,
wwEditor: HTMLElement,
editor: Editor;
function getPreviewHTML() {
return mdPreview
.querySelector(`.${cls('contents')}`)!
.innerHTML.replace(/\sdata-nodeid="\d+"|\n/g, '')
.trim();
}
describe('instance API', () => {
beforeEach(() => {
container = document.createElement('div');
editor = new Editor({
el: container,
previewHighlight: false,
widgetRules: [
{
rule: /@\S+/,
toDOM(text) {
const span = document.createElement('span');
span.innerHTML = `<a href="www.google.com">${text}</a>`;
return span;
},
},
],
});
const elements = editor.getEditorElements();
mdEditor = elements.mdEditor;
mdPreview = elements.mdPreview!;
wwEditor = elements.wwEditor!;
document.body.appendChild(container);
});
afterEach(() => {
editor.destroy();
document.body.removeChild(container);
});
describe('convertPosToMatchEditorMode', () => {
const mdPos: [number, number] = [2, 1];
const wwPos = 14;
it('should convert position to match editor mode', () => {
editor.setMarkdown('Hello World\nwelcome to the world');
editor.changeMode('wysiwyg');
expect(editor.convertPosToMatchEditorMode(mdPos)).toEqual([wwPos, wwPos]);
editor.changeMode('markdown');
expect(editor.convertPosToMatchEditorMode(wwPos)).toEqual([mdPos, mdPos]);
});
it('should occurs error when types of parameters is not matched', () => {
expect(() => {
editor.convertPosToMatchEditorMode(mdPos, wwPos);
}).toThrowError();
});
});
it('setPlaceholder()', () => {
editor.setPlaceholder('Please input text');
const expected = '<span class="placeholder ProseMirror-widget">Please input text</span>';
expect(mdEditor).toContainHTML(expected);
expect(wwEditor).toContainHTML(expected);
});
describe('getHTML()', () => {
it('basic', () => {
editor.setMarkdown('# heading\n* bullet');
const result = oneLineTrim`
<h1>heading</h1>
<ul>
<li>
<p>bullet</p>
</li>
</ul>
`;
expect(editor.getHTML()).toBe(result);
});
it('should not trigger change event when the mode is wysiwyg', () => {
const spy = jest.fn();
editor.changeMode('wysiwyg');
editor.on('change', spy);
editor.getHTML();
expect(spy).not.toHaveBeenCalled();
});
it('should be the same as wysiwyg contents', () => {
const input = source`
<p>first line</p>
<p>second line</p>
<p><br>\nthird line</p>
<p><br>\n<br>\nfourth line</p>
`;
const expected = oneLineTrim`
<p>first line</p>
<p>second line</p>
<p><br></p>
<p>third line</p>
<p><br></p>
<p><br></p>
<p>fourth line</p>
`;
editor.setHTML(input);
expect(editor.getHTML()).toBe(expected);
});
it('placeholder should be removed', () => {
editor.changeMode('wysiwyg');
editor.setPlaceholder('placeholder');
const result = oneLineTrim`
<p><br></p>
`;
expect(editor.getHTML()).toBe(result);
});
});
it('changeMode()', () => {
const spy = jest.fn();
expect(editor.isMarkdownMode()).toBe(true);
expect(editor.isWysiwygMode()).toBe(false);
editor.on('changeMode', spy);
editor.changeMode('wysiwyg');
expect(spy).toHaveBeenCalledWith('wysiwyg');
expect(editor.isMarkdownMode()).toBe(false);
expect(editor.isWysiwygMode()).toBe(true);
});
it('changePreviewStyle()', () => {
const spy = jest.fn();
expect(editor.getCurrentPreviewStyle()).toBe('tab');
editor.on('changePreviewStyle', spy);
editor.changePreviewStyle('vertical');
expect(spy).toHaveBeenCalledWith('vertical');
expect(editor.getCurrentPreviewStyle()).toBe('vertical');
});
describe('setMarkdown()', () => {
it('basic', () => {
editor.setMarkdown('# heading');
expect(mdEditor).toContainHTML(
`<div><span class="${HEADING_CLS}"><span class="${DELIM_CLS}">#</span> heading</span></div>`
);
expect(getPreviewHTML()).toBe('<h1>heading</h1>');
});
it('should parse the CRLF properly in markdown', () => {
editor.setMarkdown('# heading\r\nCRLF');
expect(mdEditor).toContainHTML(
`<div><span class="${HEADING_CLS}"><span class="${DELIM_CLS}">#</span> heading</span></div><div>CRLF</div>`
);
expect(getPreviewHTML()).toBe('<h1>heading</h1><p>CRLF</p>');
});
});
describe('setHTML()', () => {
it('basic', () => {
editor.setHTML('<h1>heading</h1>');
expect(mdEditor).toContainHTML(
`<div><span class="${HEADING_CLS}"><span class="${DELIM_CLS}">#</span> heading</span></div>`
);
expect(getPreviewHTML()).toBe('<h1>heading</h1>');
});
it('should parse the br tag as the empty block to separate between blocks', () => {
editor.setHTML('<p>a<br/>b</p>');
expect(mdEditor).toContainHTML('<div>a</div><div>b</div>');
expect(getPreviewHTML()).toBe('<p>a<br>b</p>');
});
it('should parse the br tag with the paragraph block to separate between blocks in wysiwyg', () => {
editor.setHTML(
'<h1>test title</h1><p><strong>test bold</strong><br><em>test italic</em><br>normal text</p>'
);
editor.changeMode('wysiwyg');
const expected = oneLineTrim`
<h1>test title</h1>
<p><strong>test bold</strong></p>
<p><em>test italic</em></p>
<p>normal text</p>
`;
expect(wwEditor).toContainHTML(expected);
});
it('should parse the br tag with the paragraph block to separate between blocks', () => {
const input = source`
<p>first line</p>
<p>second line</p>
<p><br>\nthird line</p>
<p><br>\n<br>\nfourth line</p>
`;
const expected = oneLineTrim`
<p>first line<br>second line</p>
<p>third line</p>
<p><br>fourth line</p>
`;
editor.setHTML(input);
expect(getPreviewHTML()).toBe(expected);
});
it('should be parsed with the same content when calling setHTML() with getHTML() API result', () => {
const input = source`
<p>first line</p>
<p>second line</p>
<p><br>\nthird line</p>
<p><br>\n<br>\nfourth line</p>
`;
editor.setHTML(input);
const mdEditorHTML = mdEditor.innerHTML;
const mdPreviewHTML = getPreviewHTML();
editor.setHTML(editor.getHTML());
expect(mdEditor).toContainHTML(mdEditorHTML);
expect(getPreviewHTML()).toBe(mdPreviewHTML);
});
});
it('reset()', () => {
editor.setMarkdown('# heading');
editor.reset();
expect(mdEditor).not.toContainHTML(
`<div><span class="${HEADING_CLS}"><span class="${DELIM_CLS}">#</span> heading</span></div>`
);
expect(getPreviewHTML()).toBe('');
});
describe('setMinHeight()', () => {
it('should set height with pixel option', () => {
editor.setMinHeight('200px');
expect(mdEditor).toHaveStyle({ minHeight: '200px' });
expect(mdPreview).toHaveStyle({ minHeight: '200px' });
expect(wwEditor).toHaveStyle({ minHeight: '200px' });
});
it('should be less than the editor height', () => {
editor.setMinHeight('400px');
expect(mdEditor).toHaveStyle({ minHeight: '225px' });
expect(mdPreview).toHaveStyle({ minHeight: '225px' });
expect(wwEditor).toHaveStyle({ minHeight: '225px' });
});
});
describe('setHeight()', () => {
it('should set height with pixel option', () => {
editor.setHeight('300px');
expect(container).not.toHaveClass('auto-height');
expect(container).toHaveStyle({ height: '300px' });
expect(mdEditor).toHaveStyle({ minHeight: '200px' });
expect(mdPreview).toHaveStyle({ minHeight: '200px' });
expect(wwEditor).toHaveStyle({ minHeight: '200px' });
});
it('should set height with auto option', () => {
editor.setHeight('auto');
expect(container).toHaveClass('auto-height');
expect(container).toHaveStyle({ height: 'auto' });
expect(mdEditor).toHaveStyle({ minHeight: '200px' });
expect(mdPreview).toHaveStyle({ minHeight: '200px' });
expect(wwEditor).toHaveStyle({ minHeight: '200px' });
});
});
it('addWidget()', () => {
const node = document.createElement('div');
node.innerHTML = 'widget';
editor.addWidget(node, 'top');
expect(document.body).toContainElement(node);
editor.changeMode('wysiwyg');
expect(document.body).not.toContainElement(node);
});
describe('replaceWithWidget()', () => {
it('in markdown', () => {
editor.replaceWithWidget([1, 1], [1, 1], '@test');
const expectedEditor = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
`;
const expectedPreview = oneLineTrim`
<p>
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
</p>
`;
expect(mdEditor).toContainHTML(expectedEditor);
expect(getPreviewHTML()).toBe(expectedPreview);
});
it('in wysiwyg', () => {
editor.changeMode('wysiwyg');
editor.replaceWithWidget(1, 1, '@test');
const expected = oneLineTrim`
<span class="tui-widget">
<span><a href="www.google.com">@test</a></span>
</span>
`;
expect(wwEditor).toContainHTML(expected);
});
});
it('exec()', () => {
// @ts-ignore
jest.spyOn(editor.commandManager, 'exec');
editor.exec('bold');
// @ts-ignore
// eslint-disable-next-line no-undefined
expect(editor.commandManager.exec).toHaveBeenCalledWith('bold', undefined);
});
it('addCommand()', () => {
const spy = jest.fn();
// @ts-ignore
const { view } = editor.mdEditor;
const { state, dispatch } = view;
editor.addCommand('markdown', 'custom', spy);
editor.exec('custom', { prop: 'prop' });
expect(spy).toHaveBeenCalledWith({ prop: 'prop' }, state, dispatch, view);
expect(spy).toHaveBeenCalled();
});
it('should be triggered only once when the event registered by addHook()', () => {
const spy = jest.fn();
const { eventEmitter } = editor;
eventEmitter.addEventType('custom');
editor.addHook('custom', spy);
editor.addHook('custom', spy);
eventEmitter.emit('custom');
expect(spy).toHaveBeenCalledTimes(1);
});
describe('insertText()', () => {
it('in markdown', () => {
editor.insertText('test');
expect(mdEditor).toContainHTML('<div>test</div>');
expect(getPreviewHTML()).toBe('<p>test</p>');
});
it('in wysiwyg', () => {
editor.changeMode('wysiwyg');
editor.insertText('test');
expect(wwEditor).toContainHTML('<p>test</p>');
});
});
describe('setSelection(), getSelection()', () => {
it('in markdown', () => {
expect(editor.getSelection()).toEqual([
[1, 1],
[1, 1],
]);
editor.setMarkdown('line1\nline2');
editor.setSelection([1, 2], [2, 4]);
expect(editor.getSelection()).toEqual([
[1, 2],
[2, 4],
]);
});
it('in wysiwyg', () => {
editor.changeMode('wysiwyg');
expect(editor.getSelection()).toEqual([1, 1]);
editor.setMarkdown('line1\nline2');
editor.setSelection(2, 8);
expect(editor.getSelection()).toEqual([2, 8]);
});
});
describe('getSelectedText()', () => {
beforeEach(() => {
editor.setMarkdown('line1\nline2');
editor.setSelection([1, 2], [2, 4]);
});
it('in markdown', () => {
expect(editor.getSelectedText()).toEqual('ine1\nlin');
expect(editor.getSelectedText([1, 2], [2, 6])).toEqual('ine1\nline2');
});
it('in wysiwyg', () => {
editor.changeMode('wysiwyg');
editor.setSelection(2, 11);
expect(editor.getSelectedText()).toEqual('ine1\nlin');
expect(editor.getSelectedText(2, 13)).toEqual('ine1\nline2');
});
});
describe('replaceSelection()', () => {
beforeEach(() => {
editor.setMarkdown('line1\nline2');
editor.setSelection([1, 2], [2, 4]);
});
it('should replace current selection in markdown', () => {
editor.replaceSelection('Replaced');
expect(mdEditor).toContainHTML('<div>lReplacede2</div>');
expect(getPreviewHTML()).toBe('<p>lReplacede2</p>');
});
it('should replace current selection in wysiwyg', () => {
editor.changeMode('wysiwyg');
editor.setSelection(2, 11);
editor.replaceSelection('Replaced');
expect(wwEditor).toContainHTML('<p>lReplacede2</p>');
});
it('should replace given selection in markdown', () => {
editor.replaceSelection('Replaced', [1, 1], [2, 1]);
expect(mdEditor).toContainHTML('<div>Replacedline2</div>');
expect(getPreviewHTML()).toBe('<p>Replacedline2</p>');
});
it('should replace given selection in wysiwyg', () => {
editor.changeMode('wysiwyg');
editor.replaceSelection('Replaced', 1, 7);
expect(wwEditor).toContainHTML('<p>Replaced</p><p>line2</p>');
});
it('should parse the CRLF properly in markdown', () => {
editor.replaceSe
gitextract_h8buw_ig/
├── .eslintrc.js
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── feature_request.md
│ │ └── question.md
│ ├── dependabot.yml
│ ├── stale.yml
│ └── workflows/
│ ├── check-types.yml
│ ├── examplePageTest.yml
│ ├── linter.yml
│ ├── plugin-test.yml
│ ├── publish-cdn.yml
│ ├── publish-doc.yml
│ ├── publish-npm-wrapper.yml
│ ├── publish-npm.yml
│ └── test.yml
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── __mocks__/
│ └── cssMock.js
├── apps/
│ ├── editor/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ └── esm/
│ │ │ └── index.html
│ │ ├── examples/
│ │ │ ├── css/
│ │ │ │ └── tuidoc-example-style.css
│ │ │ ├── data/
│ │ │ │ ├── md-default.js
│ │ │ │ └── md-plugins.js
│ │ │ ├── example01-editor-basic.html
│ │ │ ├── example02-editor-with-horizontal-preview.html
│ │ │ ├── example03-editor-with-wysiwyg-mode.html
│ │ │ ├── example04-viewer.html
│ │ │ ├── example05-viewer-using-editor-factory.html
│ │ │ ├── example06-dark-theme.html
│ │ │ ├── example07-editor-with-chart-plugin.html
│ │ │ ├── example08-editor-with-code-syntax-highlight-plugin.html
│ │ │ ├── example09-editor-with-color-syntax-plugin.html
│ │ │ ├── example10-editor-with-table-merged-cell-plugin.html
│ │ │ ├── example11-editor-with-uml-plugin.html
│ │ │ ├── example12-editor-with-all-plugins.html
│ │ │ ├── example13-creating-plugin.html
│ │ │ ├── example14-using-command.html
│ │ │ ├── example15-customizing-toolbar-buttons.html
│ │ │ ├── example16-i18n.html
│ │ │ └── example17-placeholder.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── scripts/
│ │ │ ├── createConfigVariable.js
│ │ │ ├── createIndexPage.js
│ │ │ └── webpack.config.i18n.js
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ ├── integration/
│ │ │ │ │ ├── ui/
│ │ │ │ │ │ ├── layout.spec.ts
│ │ │ │ │ │ └── toolbar.spec.ts
│ │ │ │ │ ├── vdom/
│ │ │ │ │ │ └── render.spec.ts
│ │ │ │ │ └── widget/
│ │ │ │ │ └── widgetNode.spec.ts
│ │ │ │ └── unit/
│ │ │ │ ├── convertor.spec.ts
│ │ │ │ ├── dom.spec.ts
│ │ │ │ ├── editor.spec.ts
│ │ │ │ ├── eventEmitter.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ ├── common.spec.ts
│ │ │ │ │ └── image.spec.ts
│ │ │ │ ├── markdown/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ └── syntaxHighlight.spec.ts.snap
│ │ │ │ │ ├── keymap.spec.ts
│ │ │ │ │ ├── mdCommand.spec.ts
│ │ │ │ │ ├── mdEditor.spec.ts
│ │ │ │ │ ├── mdPreview.spec.ts
│ │ │ │ │ ├── smartTask.spec.ts
│ │ │ │ │ ├── syntaxHighlight.spec.ts
│ │ │ │ │ └── util.ts
│ │ │ │ ├── sanitizer.spec.ts
│ │ │ │ ├── vdom/
│ │ │ │ │ └── template.spec.ts
│ │ │ │ ├── viewer.spec.ts
│ │ │ │ └── wysiwyg/
│ │ │ │ ├── customBlock.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ └── pasteMsoList.spec.ts
│ │ │ │ ├── keymap.spec.ts
│ │ │ │ ├── wwCommand.spec.ts
│ │ │ │ ├── wwEditor.spec.ts
│ │ │ │ ├── wwTableCommand.spec.ts
│ │ │ │ └── wwToDOMAdaptor.spec.ts
│ │ │ ├── base.ts
│ │ │ ├── commands/
│ │ │ │ ├── commandManager.ts
│ │ │ │ ├── defaultCommands.ts
│ │ │ │ └── wwCommands.ts
│ │ │ ├── convertors/
│ │ │ │ ├── convertor.ts
│ │ │ │ ├── toMarkdown/
│ │ │ │ │ ├── toMdConvertorState.ts
│ │ │ │ │ ├── toMdConvertors.ts
│ │ │ │ │ └── toMdNodeTypeWriters.ts
│ │ │ │ └── toWysiwyg/
│ │ │ │ ├── htmlToWwConvertors.ts
│ │ │ │ ├── toWwConvertorState.ts
│ │ │ │ └── toWwConvertors.ts
│ │ │ ├── css/
│ │ │ │ ├── contents.css
│ │ │ │ ├── editor.css
│ │ │ │ ├── md-syntax-highlighting.css
│ │ │ │ ├── preview-highlighting.css
│ │ │ │ └── theme/
│ │ │ │ └── dark.css
│ │ │ ├── editor.ts
│ │ │ ├── editorCore.ts
│ │ │ ├── esm/
│ │ │ │ ├── index.ts
│ │ │ │ └── indexViewer.ts
│ │ │ ├── event/
│ │ │ │ └── eventEmitter.ts
│ │ │ ├── helper/
│ │ │ │ ├── image.ts
│ │ │ │ ├── manipulation.ts
│ │ │ │ └── plugin.ts
│ │ │ ├── i18n/
│ │ │ │ ├── ar.ts
│ │ │ │ ├── cs-cz.ts
│ │ │ │ ├── de-de.ts
│ │ │ │ ├── en-us.ts
│ │ │ │ ├── es-es.ts
│ │ │ │ ├── fi-fi.ts
│ │ │ │ ├── fr-fr.ts
│ │ │ │ ├── gl-es.ts
│ │ │ │ ├── hr-hr.ts
│ │ │ │ ├── i18n.ts
│ │ │ │ ├── it-it.ts
│ │ │ │ ├── ja-jp.ts
│ │ │ │ ├── ko-kr.ts
│ │ │ │ ├── nb-no.ts
│ │ │ │ ├── nl-nl.ts
│ │ │ │ ├── pl-pl.ts
│ │ │ │ ├── pt-br.ts
│ │ │ │ ├── ru-ru.ts
│ │ │ │ ├── sv-se.ts
│ │ │ │ ├── tr-tr.ts
│ │ │ │ ├── uk-ua.ts
│ │ │ │ ├── zh-cn.ts
│ │ │ │ └── zh-tw.ts
│ │ │ ├── index.ts
│ │ │ ├── indexEditorOnlyStyle.ts
│ │ │ ├── indexViewer.ts
│ │ │ ├── markdown/
│ │ │ │ ├── helper/
│ │ │ │ │ ├── list.ts
│ │ │ │ │ ├── mdCommand.ts
│ │ │ │ │ ├── pos.ts
│ │ │ │ │ └── query.ts
│ │ │ │ ├── htmlRenderConvertors.ts
│ │ │ │ ├── marks/
│ │ │ │ │ ├── blockQuote.ts
│ │ │ │ │ ├── code.ts
│ │ │ │ │ ├── codeBlock.ts
│ │ │ │ │ ├── customBlock.ts
│ │ │ │ │ ├── emph.ts
│ │ │ │ │ ├── heading.ts
│ │ │ │ │ ├── html.ts
│ │ │ │ │ ├── link.ts
│ │ │ │ │ ├── listItem.ts
│ │ │ │ │ ├── simpleMark.ts
│ │ │ │ │ ├── strike.ts
│ │ │ │ │ ├── strong.ts
│ │ │ │ │ ├── table.ts
│ │ │ │ │ └── thematicBreak.ts
│ │ │ │ ├── mdEditor.ts
│ │ │ │ ├── mdPreview.ts
│ │ │ │ ├── nodes/
│ │ │ │ │ ├── doc.ts
│ │ │ │ │ ├── paragraph.ts
│ │ │ │ │ └── text.ts
│ │ │ │ ├── plugins/
│ │ │ │ │ ├── helper/
│ │ │ │ │ │ └── markInfo.ts
│ │ │ │ │ ├── previewHighlight.ts
│ │ │ │ │ ├── smartTask.ts
│ │ │ │ │ └── syntaxHighlight.ts
│ │ │ │ └── scroll/
│ │ │ │ ├── animation.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── offset.ts
│ │ │ │ └── scrollSync.ts
│ │ │ ├── plugins/
│ │ │ │ ├── dropImage.ts
│ │ │ │ ├── placeholder.ts
│ │ │ │ └── popupWidget.ts
│ │ │ ├── queries/
│ │ │ │ └── queryManager.ts
│ │ │ ├── sanitizer/
│ │ │ │ └── htmlSanitizer.ts
│ │ │ ├── spec/
│ │ │ │ ├── mark.ts
│ │ │ │ ├── node.ts
│ │ │ │ └── specManager.ts
│ │ │ ├── ui/
│ │ │ │ ├── components/
│ │ │ │ │ ├── contextMenu.ts
│ │ │ │ │ ├── layout.ts
│ │ │ │ │ ├── popup.ts
│ │ │ │ │ ├── switch.ts
│ │ │ │ │ ├── tabs.ts
│ │ │ │ │ └── toolbar/
│ │ │ │ │ ├── buttonHoc.ts
│ │ │ │ │ ├── customPopupBody.ts
│ │ │ │ │ ├── customToolbarItem.ts
│ │ │ │ │ ├── dropdownToolbarButton.ts
│ │ │ │ │ ├── headingPopupBody.ts
│ │ │ │ │ ├── imagePopupBody.ts
│ │ │ │ │ ├── linkPopupBody.ts
│ │ │ │ │ ├── tablePopupBody.ts
│ │ │ │ │ ├── toolbar.ts
│ │ │ │ │ ├── toolbarButton.ts
│ │ │ │ │ └── toolbarGroup.ts
│ │ │ │ ├── toolbarItemFactory.ts
│ │ │ │ └── vdom/
│ │ │ │ ├── commit.ts
│ │ │ │ ├── component.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── htm.js
│ │ │ │ ├── render.ts
│ │ │ │ ├── renderer.ts
│ │ │ │ ├── template.ts
│ │ │ │ └── vnode.ts
│ │ │ ├── utils/
│ │ │ │ ├── common.ts
│ │ │ │ ├── constants.ts
│ │ │ │ ├── dom.ts
│ │ │ │ ├── map.ts
│ │ │ │ └── markdown.ts
│ │ │ ├── viewer.ts
│ │ │ ├── widget/
│ │ │ │ ├── rules.ts
│ │ │ │ └── widgetNode.ts
│ │ │ └── wysiwyg/
│ │ │ ├── adaptor/
│ │ │ │ ├── mdLikeNode.ts
│ │ │ │ └── wwToDOMAdaptor.ts
│ │ │ ├── clipboard/
│ │ │ │ ├── paste.ts
│ │ │ │ ├── pasteMsoList.ts
│ │ │ │ └── pasteToTable.ts
│ │ │ ├── command/
│ │ │ │ ├── list.ts
│ │ │ │ └── table.ts
│ │ │ ├── helper/
│ │ │ │ ├── node.ts
│ │ │ │ ├── table.ts
│ │ │ │ └── tableOffsetMap.ts
│ │ │ ├── marks/
│ │ │ │ ├── code.ts
│ │ │ │ ├── emph.ts
│ │ │ │ ├── link.ts
│ │ │ │ ├── strike.ts
│ │ │ │ └── strong.ts
│ │ │ ├── nodes/
│ │ │ │ ├── blockQuote.ts
│ │ │ │ ├── bulletList.ts
│ │ │ │ ├── codeBlock.ts
│ │ │ │ ├── customBlock.ts
│ │ │ │ ├── doc.ts
│ │ │ │ ├── frontMatter.ts
│ │ │ │ ├── heading.ts
│ │ │ │ ├── html.ts
│ │ │ │ ├── htmlComment.ts
│ │ │ │ ├── image.ts
│ │ │ │ ├── listItem.ts
│ │ │ │ ├── orderedList.ts
│ │ │ │ ├── paragraph.ts
│ │ │ │ ├── table.ts
│ │ │ │ ├── tableBody.ts
│ │ │ │ ├── tableBodyCell.ts
│ │ │ │ ├── tableHead.ts
│ │ │ │ ├── tableHeadCell.ts
│ │ │ │ ├── tableRow.ts
│ │ │ │ ├── text.ts
│ │ │ │ └── thematicBreak.ts
│ │ │ ├── nodeview/
│ │ │ │ ├── codeBlockView.ts
│ │ │ │ ├── customBlockView.ts
│ │ │ │ └── imageView.ts
│ │ │ ├── plugins/
│ │ │ │ ├── selection/
│ │ │ │ │ ├── cellSelection.ts
│ │ │ │ │ ├── tableSelection.ts
│ │ │ │ │ └── tableSelectionView.ts
│ │ │ │ ├── tableContextMenu.ts
│ │ │ │ ├── task.ts
│ │ │ │ └── toolbarState.ts
│ │ │ ├── specCreator.ts
│ │ │ └── wwEditor.ts
│ │ ├── tsBannerGenerator.js
│ │ ├── tsconfig.json
│ │ ├── tuidoc.config.json
│ │ ├── types/
│ │ │ ├── convertor.d.ts
│ │ │ ├── editor.d.ts
│ │ │ ├── event.d.ts
│ │ │ ├── index.d.ts
│ │ │ ├── map.d.ts
│ │ │ ├── markdown.d.ts
│ │ │ ├── plugin.d.ts
│ │ │ ├── prosemirror-commands.d.ts
│ │ │ ├── prosemirror-model.d.ts
│ │ │ ├── prosemirror-transform.d.ts
│ │ │ ├── spec.d.ts
│ │ │ ├── toastmark.d.ts
│ │ │ ├── toastui-editor-viewer.d.ts
│ │ │ ├── ui.d.ts
│ │ │ └── wysiwyg.d.ts
│ │ └── webpack.config.js
│ ├── react-editor/
│ │ ├── .eslintrc.js
│ │ ├── README.md
│ │ ├── demo/
│ │ │ └── esm/
│ │ │ ├── index.html
│ │ │ └── index.jsx
│ │ ├── index.d.ts
│ │ ├── package.json
│ │ ├── rollup.config.js
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── editor.tsx
│ │ │ ├── index.ts
│ │ │ └── viewer.tsx
│ │ ├── tsconfig.json
│ │ └── webpack.config.js
│ └── vue-editor/
│ ├── .eslintrc.js
│ ├── README.md
│ ├── demo/
│ │ └── esm/
│ │ ├── index.html
│ │ └── index.js
│ ├── index.d.ts
│ ├── package.json
│ ├── rollup.config.js
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── Editor.vue
│ │ ├── Viewer.vue
│ │ ├── index.js
│ │ └── mixin/
│ │ └── option.js
│ └── webpack.config.js
├── docs/
│ ├── COMMIT_MESSAGE_CONVENTION.md
│ ├── ISSUE_TEMPLATE.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── README.md
│ ├── en/
│ │ ├── custom-block.md
│ │ ├── custom-html-renderer.md
│ │ ├── extended-autolinks.md
│ │ ├── getting-started.md
│ │ ├── i18n.md
│ │ ├── plugin.md
│ │ ├── toolbar.md
│ │ ├── viewer.md
│ │ └── widget.md
│ ├── ko/
│ │ ├── README.md
│ │ ├── custom-block.md
│ │ ├── custom-html-renderer.md
│ │ ├── extended-autolinks.md
│ │ ├── getting-started.md
│ │ ├── i18n.md
│ │ ├── plugin.md
│ │ ├── toolbar.md
│ │ ├── viewer.md
│ │ └── widget.md
│ ├── v3.0-migration-guide-ko.md
│ └── v3.0-migration-guide.md
├── jest-setup.js
├── jest.base.config.js
├── jest.config.js
├── lerna.json
├── libs/
│ └── toastmark/
│ ├── .eslintrc.js
│ ├── LICENSE
│ ├── README.md
│ ├── demo/
│ │ └── index.html
│ ├── jest.config.js
│ ├── package.json
│ ├── rollup.config.js
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── __sample__/
│ │ │ ├── index.css
│ │ │ └── index.ts
│ │ ├── __test__/
│ │ │ └── toastmark.spec.ts
│ │ ├── commonmark/
│ │ │ ├── __test__/
│ │ │ │ ├── base-examples.json
│ │ │ │ ├── base-examples.spec.ts
│ │ │ │ ├── helper.spec.ts
│ │ │ │ ├── options.spec.ts
│ │ │ │ ├── sourcepos.spec.ts
│ │ │ │ └── syntax-info.spec.ts
│ │ │ ├── blockHandlers.ts
│ │ │ ├── blockHelper.ts
│ │ │ ├── blockStarts.ts
│ │ │ ├── blocks.ts
│ │ │ ├── common.ts
│ │ │ ├── custom/
│ │ │ │ ├── __test__/
│ │ │ │ │ ├── customBlock.spec.ts
│ │ │ │ │ └── customInline.spec.ts
│ │ │ │ ├── customBlockHandler.ts
│ │ │ │ └── customBlockStart.ts
│ │ │ ├── from-code-point.ts
│ │ │ ├── frontMatter/
│ │ │ │ ├── __test__/
│ │ │ │ │ └── frontMatter.spec.ts
│ │ │ │ ├── frontMatterHandler.ts
│ │ │ │ └── frontMatterStart.ts
│ │ │ ├── gfm/
│ │ │ │ ├── __test__/
│ │ │ │ │ ├── autolinks.spec.ts
│ │ │ │ │ ├── strikethrough.spec.ts
│ │ │ │ │ ├── table.spec.ts
│ │ │ │ │ ├── tagfilter.spec.ts
│ │ │ │ │ └── taskListItem.spec.ts
│ │ │ │ ├── autoLinks.ts
│ │ │ │ ├── tableBlockHandler.ts
│ │ │ │ ├── tableBlockStart.ts
│ │ │ │ └── taskListItem.ts
│ │ │ ├── inlines.ts
│ │ │ ├── node.ts
│ │ │ ├── nodeWalker.ts
│ │ │ └── rawHtml.ts
│ │ ├── helper.ts
│ │ ├── html/
│ │ │ ├── __test__/
│ │ │ │ └── render.spec.ts
│ │ │ ├── baseConvertors.ts
│ │ │ ├── gfmConvertors.ts
│ │ │ ├── renderer.ts
│ │ │ └── tagFilter.ts
│ │ ├── index.ts
│ │ ├── nodeHelper.ts
│ │ └── toastmark.ts
│ ├── tsconfig.json
│ ├── types/
│ │ ├── index.d.ts
│ │ ├── node.d.ts
│ │ ├── parser.d.ts
│ │ ├── renderer.d.ts
│ │ └── toastMark.d.ts
│ └── webpack.config.js
├── package.json
├── plugins/
│ ├── chart/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── unit/
│ │ │ │ └── chartPlugin.spec.ts
│ │ │ ├── csv.js
│ │ │ ├── index.ts
│ │ │ └── util.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ └── index.d.ts
│ │ └── webpack.config.js
│ ├── code-syntax-highlight/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor-all-langs.html
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ ├── integration/
│ │ │ │ │ ├── __snapshots__/
│ │ │ │ │ │ ├── codeHighlightPlugin.spec.ts.snap
│ │ │ │ │ │ └── codeHighlightPluginWithAllLangs.spec.ts.snap
│ │ │ │ │ ├── codeHighlightPlugin.spec.ts
│ │ │ │ │ └── codeHighlightPluginWithAllLangs.spec.ts
│ │ │ │ └── unit/
│ │ │ │ └── languageSelectBox.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── index.ts
│ │ │ ├── indexAll.ts
│ │ │ ├── nodeViews/
│ │ │ │ ├── codeSyntaxHighlightView.ts
│ │ │ │ └── languageSelectBox.ts
│ │ │ ├── plugin.ts
│ │ │ ├── plugins/
│ │ │ │ └── codeSyntaxHighlighting.ts
│ │ │ ├── prismjs-langs.ts
│ │ │ ├── renderers/
│ │ │ │ └── toHTMLRenderers.ts
│ │ │ └── utils/
│ │ │ ├── common.ts
│ │ │ └── dom.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ └── prosemirror-transform.d.ts
│ │ └── webpack.config.js
│ ├── color-syntax/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── editor.html
│ │ │ └── esm/
│ │ │ └── index.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── integration/
│ │ │ │ └── colorSyntaxPlugin.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── i18n/
│ │ │ │ └── langs.ts
│ │ │ ├── index.ts
│ │ │ └── utils/
│ │ │ └── dom.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ ├── prosemirror-model.d.ts
│ │ │ └── tui-color-picker.d.ts
│ │ └── webpack.config.js
│ ├── table-merged-cell/
│ │ ├── README.md
│ │ ├── demo/
│ │ │ ├── data.js
│ │ │ ├── editor.html
│ │ │ ├── esm/
│ │ │ │ └── index.html
│ │ │ └── viewer.html
│ │ ├── jest.config.js
│ │ ├── package.json
│ │ ├── snowpack.config.js
│ │ ├── src/
│ │ │ ├── __test__/
│ │ │ │ └── integration/
│ │ │ │ ├── convertor.spec.ts
│ │ │ │ ├── markdown/
│ │ │ │ │ └── mergedTablePreview.spec.ts
│ │ │ │ └── wysiwyg/
│ │ │ │ ├── addColumn.spec.ts
│ │ │ │ ├── addRow.spec.ts
│ │ │ │ ├── helper/
│ │ │ │ │ ├── cellSelection.ts
│ │ │ │ │ ├── tableOffsetMap.ts
│ │ │ │ │ └── utils.ts
│ │ │ │ ├── mergeCells.spec.ts
│ │ │ │ ├── removeColumn.spec.ts
│ │ │ │ ├── removeRow.spec.ts
│ │ │ │ └── splitCells.spec.ts
│ │ │ ├── css/
│ │ │ │ └── plugin.css
│ │ │ ├── i18n/
│ │ │ │ └── langs.ts
│ │ │ ├── index.ts
│ │ │ ├── markdown/
│ │ │ │ ├── parser.ts
│ │ │ │ └── renderer.ts
│ │ │ └── wysiwyg/
│ │ │ ├── command/
│ │ │ │ ├── addColumn.ts
│ │ │ │ ├── addRow.ts
│ │ │ │ ├── direction.ts
│ │ │ │ ├── mergeCells.ts
│ │ │ │ ├── removeColumn.ts
│ │ │ │ ├── removeRow.ts
│ │ │ │ └── splitCells.ts
│ │ │ ├── commandFactory.ts
│ │ │ ├── contextMenu.ts
│ │ │ ├── renderer.ts
│ │ │ ├── tableOffsetMapMixin.ts
│ │ │ └── util.ts
│ │ ├── tsconfig.json
│ │ ├── types/
│ │ │ ├── index.d.ts
│ │ │ └── prosemirror-transform.d.ts
│ │ └── webpack.config.js
│ └── uml/
│ ├── README.md
│ ├── demo/
│ │ ├── editor.html
│ │ ├── esm/
│ │ │ └── index.html
│ │ └── viewer.html
│ ├── index.d.ts
│ ├── jest.config.js
│ ├── package.json
│ ├── snowpack.config.js
│ ├── src/
│ │ ├── __test__/
│ │ │ └── integration/
│ │ │ └── umlPlugin.spec.ts
│ │ └── index.ts
│ ├── tsconfig.json
│ └── webpack.config.js
├── scripts/
│ ├── pkg-script.js
│ └── publish-cdn.js
├── tsconfig.json
└── types/
└── tui-code-snippet.d.ts
SYMBOL INDEX (2265 symbols across 275 files)
FILE: __mocks__/cssMock.js
method process (line 2) | process() {
FILE: apps/editor/rollup.config.js
function i18nEditorImportPath (line 8) | function i18nEditorImportPath() {
function createBannerPlugin (line 19) | function createBannerPlugin(type) {
FILE: apps/editor/scripts/createConfigVariable.js
function getTestUrls (line 11) | function getTestUrls() {
function getGlobalVariable (line 28) | function getGlobalVariable() {
FILE: apps/editor/scripts/createIndexPage.js
function writeData (line 35) | function writeData(dir) {
FILE: apps/editor/scripts/webpack.config.i18n.js
function getOptimizationConfig (line 11) | function getOptimizationConfig(minify) {
function getEntries (line 26) | function getEntries() {
FILE: apps/editor/src/__test__/integration/ui/layout.spec.ts
constant EDITOR_CLASS (line 7) | const EDITOR_CLASS = 'toastui-editor';
function getElement (line 9) | function getElement(selector: string) {
function getElements (line 13) | function getElements(selector: string) {
function getEditorMain (line 17) | function getEditorMain() {
function getMdEditor (line 21) | function getMdEditor() {
function getMdPreview (line 25) | function getMdPreview() {
function getWwEditor (line 29) | function getWwEditor() {
function getMdSwitch (line 33) | function getMdSwitch() {
function getWwSwitch (line 37) | function getWwSwitch() {
function clickMdSwitch (line 41) | function clickMdSwitch() {
function clickWwSwitch (line 45) | function clickWwSwitch() {
function getMdWriteTab (line 49) | function getMdWriteTab() {
function getMdPreviewTab (line 53) | function getMdPreviewTab() {
function getScrollSyncWrapper (line 57) | function getScrollSyncWrapper() {
function clickMdWriteTab (line 63) | function clickMdWriteTab() {
function clickMdPreviewTab (line 67) | function clickMdPreviewTab() {
function assertToContainElement (line 71) | function assertToContainElement(el: HTMLElement) {
FILE: apps/editor/src/__test__/integration/ui/toolbar.spec.ts
function getElement (line 6) | function getElement(selector: string) {
function getPopUpElement (line 10) | function getPopUpElement() {
function fireMousemoveEvent (line 14) | function fireMousemoveEvent(el: HTMLElement, x: number, y: number) {
function fireMouseoverEvent (line 28) | function fireMouseoverEvent(el: HTMLElement) {
function createCustomButtonWithPopup (line 356) | function createCustomButtonWithPopup() {
function getToolbarItems (line 468) | function getToolbarItems() {
FILE: apps/editor/src/__test__/integration/vdom/render.spec.ts
type Props (line 7) | interface Props {
type State (line 14) | interface State {
class TestComponent (line 19) | class TestComponent extends Component<Props, State> {
method constructor (line 20) | constructor(props: Props) {
method show (line 28) | show() {
method hide (line 32) | hide() {
method conditionalRender (line 36) | conditionalRender() {
method mounted (line 40) | mounted() {
method updated (line 46) | updated() {
method beforeDestroy (line 52) | beforeDestroy() {
method render (line 58) | render() {
function clickShowBtn (line 170) | function clickShowBtn() {
function clickHideBtn (line 174) | function clickHideBtn() {
function clickConditionalBtn (line 178) | function clickConditionalBtn() {
function renderComponent (line 182) | function renderComponent(spies?: Record<string, jest.Mock>) {
FILE: apps/editor/src/__test__/integration/widget/widgetNode.spec.ts
function getPreviewHTML (line 13) | function getPreviewHTML() {
method toDOM (line 24) | toDOM(text) {
FILE: apps/editor/src/__test__/unit/convertor.spec.ts
function createSchema (line 17) | function createSchema() {
function assertConverting (line 34) | function assertConverting(markdown: string, expected: string) {
function createCustomConvertor (line 822) | function createCustomConvertor(customConvertor: ToMdConvertorMap) {
method thematicBreak (line 829) | thematicBreak() {
method thematicBreak (line 843) | thematicBreak() {
method thematicBreak (line 857) | thematicBreak() {
method thematicBreak (line 871) | thematicBreak(_: NodeInfo | MarkInfo, { origin }: ToMdConvertorContext) {
method heading (line 883) | heading({ node }: NodeInfo | MarkInfo, { origin }: ToMdConvertorContext) {
function assertFrontMatterConverting (line 922) | function assertFrontMatterConverting(markdown: string, expected: string) {
function createConvertorWithHTMLRenderer (line 948) | function createConvertorWithHTMLRenderer() {
function createCustomConvertor (line 1010) | function createCustomConvertor(customConvertor: HTMLConvertorMap) {
method paragraph (line 1017) | paragraph(_: MdNode, { entering, origin, options }: Context) {
FILE: apps/editor/src/__test__/unit/editor.spec.ts
constant HEADING_CLS (line 14) | const HEADING_CLS = `${cls('md-heading')} ${cls('md-heading1')}`;
constant DELIM_CLS (line 15) | const DELIM_CLS = cls('md-delimiter');
function getPreviewHTML (line 24) | function getPreviewHTML() {
method toDOM (line 40) | toDOM(text) {
function createEditor (line 652) | function createEditor(options: EditorOptions) {
method paragraph (line 916) | paragraph(_, { entering, origin }) {
method link (line 938) | link(_, { origin }) {
function mockDefaultImageBlobHook (line 1007) | function mockDefaultImageBlobHook() {
FILE: apps/editor/src/__test__/unit/eventEmitter.spec.ts
function triggerEvent (line 208) | function triggerEvent(apiName: 'emit' | 'emitReduce') {
FILE: apps/editor/src/__test__/unit/helper/image.spec.ts
function mockReadAsDataURL (line 11) | function mockReadAsDataURL() {
FILE: apps/editor/src/__test__/unit/markdown/keymap.spec.ts
function forceKeymapFn (line 19) | function forceKeymapFn(type: string, methodName: string, args: any[] = [...
function forceBackspaceKeymap (line 28) | function forceBackspaceKeymap() {
function getPreviewHTML (line 36) | function getPreviewHTML() {
function assertSelection (line 40) | function assertSelection(mdPos: Sourcepos) {
function execUndo (line 44) | function execUndo() {
FILE: apps/editor/src/__test__/unit/markdown/mdCommand.spec.ts
function execUndo (line 13) | function execUndo() {
function getPreviewHTML (line 19) | function getPreviewHTML() {
FILE: apps/editor/src/__test__/unit/markdown/mdEditor.spec.ts
function getSelectedText (line 6) | function getSelectedText() {
function getEditorHTML (line 10) | function getEditorHTML(editor: MarkdownEditor) {
FILE: apps/editor/src/__test__/unit/markdown/mdPreview.spec.ts
function getHTML (line 8) | function getHTML(preview: MarkdownPreview) {
function init (line 67) | function init(highlight: boolean) {
function setMarkdown (line 85) | function setMarkdown(markdown: string) {
function setCursor (line 89) | function setCursor(caret: MdPos) {
function blur (line 93) | function blur() {
function getHighlightedCount (line 97) | function getHighlightedCount() {
function assertHighlighted (line 101) | function assertHighlighted(tagName: string, html: string) {
function createPreviewWithHTMLRenderer (line 223) | function createPreviewWithHTMLRenderer() {
FILE: apps/editor/src/__test__/unit/markdown/smartTask.spec.ts
function dispatchKeyup (line 8) | function dispatchKeyup() {
FILE: apps/editor/src/__test__/unit/markdown/syntaxHighlight.spec.ts
function getEditorHTML (line 6) | function getEditorHTML(editor: MarkdownEditor) {
FILE: apps/editor/src/__test__/unit/markdown/util.ts
function getTextContent (line 5) | function getTextContent(editor: MarkdownEditor) {
function removeDataAttr (line 21) | function removeDataAttr(html: string) {
function createHTMLrenderer (line 25) | function createHTMLrenderer() {
class TestEditorWithNoneDelayHistory (line 50) | class TestEditorWithNoneDelayHistory extends MarkdownEditor {
method defaultPlugins (line 51) | get defaultPlugins() {
FILE: apps/editor/src/__test__/unit/vdom/template.spec.ts
class TestComponent (line 5) | class TestComponent extends Component {
method render (line 6) | render() {
FILE: apps/editor/src/__test__/unit/viewer.spec.ts
function getViewerHTML (line 8) | function getViewerHTML() {
FILE: apps/editor/src/__test__/unit/wysiwyg/customBlock.spec.ts
function createCustomBlockNode (line 10) | function createCustomBlockNode() {
method myCustom (line 22) | myCustom(node) {
FILE: apps/editor/src/__test__/unit/wysiwyg/keymap.spec.ts
constant CELL_SELECTION_CLS (line 17) | const CELL_SELECTION_CLS = cls('cell-selected');
constant CODE_BLOCK_CLS (line 18) | const CODE_BLOCK_CLS = cls('ww-code-block');
function setContent (line 24) | function setContent(content: string) {
function forceKeymapFn (line 34) | function forceKeymapFn(type: string, methodName: string, args: any[] = [...
function selectCells (line 43) | function selectCells(from: number, to: number) {
function forceBackspaceKeymap (line 478) | function forceBackspaceKeymap() {
FILE: apps/editor/src/__test__/unit/wysiwyg/wwCommand.spec.ts
constant CODE_BLOCK_CLS (line 13) | const CODE_BLOCK_CLS = cls('ww-code-block');
function setTextToEditor (line 18) | function setTextToEditor(text: string) {
function setContent (line 29) | function setContent(content: string) {
method myCustom (line 41) | myCustom(node) {
FILE: apps/editor/src/__test__/unit/wysiwyg/wwEditor.spec.ts
function assertToContainHTML (line 17) | function assertToContainHTML(html: string) {
function setContent (line 21) | function setContent(content: string) {
FILE: apps/editor/src/__test__/unit/wysiwyg/wwTableCommand.spec.ts
constant CELL_SELECTION_CLS (line 12) | const CELL_SELECTION_CLS = cls('cell-selected');
function selectCells (line 17) | function selectCells(from: number, to: number) {
function setCellSelection (line 28) | function setCellSelection(
FILE: apps/editor/src/__test__/unit/wysiwyg/wwToDOMAdaptor.spec.ts
function createText (line 14) | function createText(text: string) {
function createNode (line 18) | function createNode(
function createMark (line 26) | function createMark(type: string, attrs?: { [key: string]: any } | null) {
method code (line 32) | code() {
method heading (line 39) | heading(node, { entering }) {
method codeBlock (line 47) | codeBlock(node) {
method emph (line 63) | emph(_, { entering }) {
method nav (line 73) | nav(node) {
method big (line 83) | big(node: MdLikeNode, { entering }: Context) {
function getHTML (line 250) | function getHTML(node: Node) {
FILE: apps/editor/src/base.ts
method constructor (line 49) | constructor(eventEmitter: Emitter) {
method createState (line 63) | createState() {
method initEvent (line 70) | protected initEvent() {
method emitChangeEvent (line 77) | protected emitChangeEvent(tr: Transaction) {
method defaultPlugins (line 84) | get defaultPlugins() {
method createInputRules (line 101) | private createInputRules() {
method clearTimer (line 133) | private clearTimer() {
method createSchema (line 140) | createSchema() {
method createKeymaps (line 147) | createKeymaps(useCommandShortcut: boolean) {
method createCommands (line 158) | createCommands() {
method createPluginProps (line 162) | createPluginProps() {
method focus (line 166) | focus() {
method blur (line 175) | blur() {
method destroy (line 179) | destroy() {
method moveCursorToStart (line 187) | moveCursorToStart(focus: boolean) {
method moveCursorToEnd (line 196) | moveCursorToEnd(focus: boolean) {
method setScrollTop (line 208) | setScrollTop(top: number) {
method getScrollTop (line 212) | getScrollTop() {
method setPlaceholder (line 216) | setPlaceholder(text: string) {
method setHeight (line 221) | setHeight(height: number) {
method setMinHeight (line 225) | setMinHeight(minHeight: number) {
method getElement (line 229) | getElement() {
FILE: apps/editor/src/commands/commandManager.ts
type GetEditorType (line 5) | type GetEditorType = () => EditorType;
class CommandManager (line 6) | class CommandManager {
method constructor (line 15) | constructor(
method initEvent (line 28) | private initEvent() {
method addCommand (line 34) | addCommand(type: EditorType, name: string, command: EditorCommandFn) {
method deleteCommand (line 42) | deleteCommand(type: EditorType, name: string) {
method exec (line 50) | exec(name: string, payload?: Record<string, any>) {
FILE: apps/editor/src/commands/defaultCommands.ts
function getDefaultCommands (line 6) | function getDefaultCommands(): Record<string, EditorCommand> {
FILE: apps/editor/src/commands/wwCommands.ts
function indent (line 6) | function indent(): EditorCommand {
function outdent (line 20) | function outdent(): EditorCommand {
function getWwCommands (line 34) | function getWwCommands(): Record<string, EditorCommand> {
FILE: apps/editor/src/convertors/convertor.ts
class Convertor (line 13) | class Convertor {
method constructor (line 26) | constructor(
method getMappedPos (line 45) | getMappedPos() {
method getInfoForPosSync (line 53) | private getInfoForPosSync() {
method toWysiwygModel (line 57) | toWysiwygModel(mdNode: MdNode) {
method toMarkdownText (line 63) | toMarkdownText(wwNode: ProsemirrorNode) {
FILE: apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts
class ToMdConvertorState (line 14) | class ToMdConvertorState {
method constructor (line 31) | constructor({ nodeTypeConvertors, markTypeConvertors }: ToMdConvertors) {
method getMarkConvertor (line 42) | private getMarkConvertor(mark: Mark) {
method isInBlank (line 48) | private isInBlank() {
method markText (line 52) | private markText(mark: Mark, entering: boolean, parent: Node, index: n...
method setDelim (line 64) | setDelim(delim: string) {
method getDelim (line 68) | getDelim() {
method flushClose (line 72) | flushClose(size?: number) {
method wrapBlock (line 99) | wrapBlock(delim: string, firstDelim: string | null, node: Node, fn: ()...
method ensureNewLine (line 109) | ensureNewLine() {
method write (line 115) | write(content = '') {
method closeBlock (line 127) | closeBlock(node: Node) {
method text (line 131) | text(text: string, escaped = true) {
method convertBlock (line 144) | convertBlock(node: Node, parent: Node, index: number) {
method convertInline (line 156) | convertInline(parent: Node) {
method convertList (line 295) | convertList(node: Node, delim: string, firstDelimFn: FirstDelimFn) {
method convertTableCell (line 318) | convertTableCell(node: Node) {
method convertNode (line 343) | convertNode(parent: Node, infoForPosSync?: InfoForPosSync | null) {
FILE: apps/editor/src/convertors/toMarkdown/toMdConvertors.ts
function addBackticks (line 19) | function addBackticks(node: ProsemirrorNode, side: number) {
function getPairRawHTML (line 46) | function getPairRawHTML(rawHTML?: string[]) {
function getOpenRawHTML (line 50) | function getOpenRawHTML(rawHTML?: string) {
function getCloseRawHTML (line 54) | function getCloseRawHTML(rawHTML?: string) {
method heading (line 59) | heading({ node }) {
method codeBlock (line 74) | codeBlock({ node }) {
method blockQuote (line 84) | blockQuote({ node }) {
method bulletList (line 91) | bulletList({ node }, { inTable }) {
method orderedList (line 104) | orderedList({ node }, { inTable }) {
method listItem (line 116) | listItem({ node }, { inTable }) {
method table (line 132) | table({ node }) {
method tableHead (line 138) | tableHead({ node }) {
method tableBody (line 144) | tableBody({ node }) {
method tableRow (line 150) | tableRow({ node }) {
method tableHeadCell (line 156) | tableHeadCell({ node }) {
method tableBodyCell (line 162) | tableBodyCell({ node }) {
method image (line 168) | image({ node }) {
method thematicBreak (line 183) | thematicBreak({ node }) {
method customBlock (line 190) | customBlock({ node }) {
method frontMatter (line 199) | frontMatter({ node }) {
method widget (line 205) | widget({ node }) {
method strong (line 211) | strong({ node }, { entering }) {
method emph (line 220) | emph({ node }, { entering }) {
method strike (line 229) | strike({ node }, { entering }) {
method link (line 238) | link({ node }, { entering }) {
method code (line 257) | code({ node, parent, index = 0 }, { entering }) {
method htmlComment (line 271) | htmlComment({ node }) {
method html (line 278) | html({ node }, { entering }) {
function createNodeTypeConvertors (line 327) | function createNodeTypeConvertors(convertors: ToMdConvertorMap) {
function createMarkTypeConvertors (line 351) | function createMarkTypeConvertors(convertors: ToMdConvertorMap) {
function createMdConvertors (line 386) | function createMdConvertors(customConvertors: ToMdConvertorMap) {
FILE: apps/editor/src/convertors/toMarkdown/toMdNodeTypeWriters.ts
function convertToRawHTMLHavingInlines (line 15) | function convertToRawHTMLHavingInlines(
function convertToRawHTMLHavingBlocks (line 25) | function convertToRawHTMLHavingBlocks(
function createTableHeadDelim (line 41) | function createTableHeadDelim(textContent: string, columnAlign: ColumnAl...
method text (line 62) | text(state, { node }) {
method paragraph (line 72) | paragraph(state, { node, parent, index = 0 }) {
method heading (line 107) | heading(state, { node }, { delim }) {
method codeBlock (line 122) | codeBlock(state, { node }, { delim, text }) {
method blockQuote (line 133) | blockQuote(state, { node, parent }, { delim }) {
method bulletList (line 141) | bulletList(state, { node }, { delim }) {
method orderedList (line 146) | orderedList(state, { node }) {
method listItem (line 157) | listItem(state, { node }) {
method image (line 167) | image(state, _, { attrs }) {
method thematicBreak (line 171) | thematicBreak(state, { node }, { delim }) {
method table (line 176) | table(state, { node }) {
method tableHead (line 181) | tableHead(state, { node }, { delim }) {
method tableBody (line 200) | tableBody(state, { node }) {
method tableRow (line 204) | tableRow(state, { node }) {
method tableHeadCell (line 210) | tableHeadCell(state, { node }, { delim = '| ' }) {
method tableBodyCell (line 216) | tableBodyCell(state, { node }, { delim = '| ' }) {
method customBlock (line 222) | customBlock(state, { node }, { delim, text }) {
method frontMatter (line 233) | frontMatter(state, { node }, { text }) {
method widget (line 238) | widget(state, _, { text }) {
method html (line 242) | html(state, { node }, { text }) {
method htmlComment (line 250) | htmlComment(state, { node }, { text }) {
function write (line 256) | function write(
FILE: apps/editor/src/convertors/toWysiwyg/htmlToWwConvertors.ts
function getTextWithoutTrailingNewline (line 12) | function getTextWithoutTrailingNewline(text: string) {
function isCustomHTMLInlineNode (line 16) | function isCustomHTMLInlineNode({ schema }: ToWwConvertorState, node: Md...
function isInlineNode (line 29) | function isInlineNode({ type }: MdNode) {
function isSoftbreak (line 33) | function isSoftbreak(mdNode: MdNode | null) {
function isListNode (line 37) | function isListNode({ type, literal }: MdNode) {
function getListItemAttrs (line 52) | function getListItemAttrs({ literal }: MdNode) {
function getMatchedAttributeValue (line 59) | function getMatchedAttributeValue(rawHTML: string, ...attrNames: string[...
function createConvertors (line 69) | function createConvertors(convertors: HTMLToWwConvertorMap) {
FILE: apps/editor/src/convertors/toWysiwyg/toWwConvertorState.ts
function mergeMarkText (line 8) | function mergeMarkText(a: Node, b: Node) {
class ToWwConvertorState (line 18) | class ToWwConvertorState {
method constructor (line 27) | constructor(schema: Schema, convertors: ToWwConvertorMap) {
method top (line 34) | top() {
method push (line 38) | push(node: Node) {
method addText (line 44) | addText(text: string) {
method openMark (line 59) | openMark(mark: Mark) {
method closeMark (line 63) | closeMark(mark: MarkType) {
method addNode (line 67) | addNode(type: NodeType, attrs: Attrs, content: Node[]) {
method openNode (line 79) | openNode(type: NodeType, attrs: Attrs) {
method closeNode (line 83) | closeNode() {
method convertByDOMParser (line 93) | convertByDOMParser(root: HTMLElement) {
method closeUnmatchedHTMLInline (line 99) | private closeUnmatchedHTMLInline(node: MdNode, entering: boolean) {
method convert (line 120) | private convert(mdNode: MdNode, infoForPosSync?: InfoForPosSync) {
method convertNode (line 166) | convertNode(mdNode: MdNode, infoForPosSync?: InfoForPosSync) {
FILE: apps/editor/src/convertors/toWysiwyg/toWwConvertors.ts
function isBRTag (line 33) | function isBRTag(node: MdNode) {
function addRawHTMLAttributeToDOM (line 37) | function addRawHTMLAttributeToDOM(parent: Node) {
method text (line 52) | text(state, node) {
method paragraph (line 56) | paragraph(state, node, { entering }, customAttrs) {
method heading (line 73) | heading(state, node, { entering }, customAttrs) {
method codeBlock (line 83) | codeBlock(state, node, customAttrs) {
method list (line 92) | list(state, node, { entering }, customAttrs) {
method item (line 107) | item(state, node, { entering }, customAttrs) {
method blockQuote (line 124) | blockQuote(state, _, { entering }, customAttrs) {
method image (line 132) | image(state, node, { entering, skipChildren }, customAttrs) {
method thematicBreak (line 147) | thematicBreak(state, node, _, customAttrs) {
method strong (line 151) | strong(state, _, { entering }, customAttrs) {
method emph (line 161) | emph(state, _, { entering }, customAttrs) {
method link (line 171) | link(state, node, { entering }, customAttrs) {
method softbreak (line 188) | softbreak(state, node) {
method table (line 203) | table(state, _, { entering }, customAttrs) {
method tableHead (line 211) | tableHead(state, _, { entering }, customAttrs) {
method tableBody (line 219) | tableBody(state, _, { entering }, customAttrs) {
method tableRow (line 227) | tableRow(state, _, { entering }, customAttrs) {
method tableCell (line 235) | tableCell(state, node, { entering }) {
method strike (line 267) | strike(state, _, { entering }, customAttrs) {
method code (line 277) | code(state, node, _, customAttrs) {
method customBlock (line 285) | customBlock(state, node) {
method frontMatter (line 299) | frontMatter(state, node) {
method htmlInline (line 305) | htmlInline(state, node) {
method htmlBlock (line 331) | htmlBlock(state, node) {
method customInline (line 363) | customInline(state, node, { entering, skipChildren }) {
function createWwConvertors (line 387) | function createWwConvertors(customConvertors: HTMLConvertorMap) {
FILE: apps/editor/src/editor.ts
class ToastUIEditor (line 13) | class ToastUIEditor extends EditorCore {
method constructor (line 16) | constructor(options: EditorOptions) {
method factory (line 57) | static factory(options: (EditorOptions | ViewerOptions) & { viewer?: b...
method insertToolbarItem (line 66) | insertToolbarItem(indexInfo: IndexList, item: string | ToolbarItemOpti...
method removeToolbarItem (line 74) | removeToolbarItem(itemName: string) {
method destroy (line 81) | destroy() {
FILE: apps/editor/src/editorCore.ts
class ToastUIEditorCore (line 90) | class ToastUIEditorCore {
method constructor (line 125) | constructor(options: EditorOptions) {
method addInitEvent (line 296) | private addInitEvent() {
method addInitCommand (line 312) | private addInitCommand(mdCommands: PluginCommandMap, wwCommands: Plugi...
method getCurrentModeEditor (line 327) | private getCurrentModeEditor() {
method factory (line 336) | static factory(options: (EditorOptions | ViewerOptions) & { viewer?: b...
method setLanguage (line 345) | static setLanguage(code: string | string[], data: Record<string, strin...
method changePreviewStyle (line 353) | changePreviewStyle(style: PreviewStyle) {
method exec (line 365) | exec(name: string, payload?: Record<string, any>) {
method addCommand (line 374) | addCommand(type: EditorType, name: string, command: CommandFn) {
method on (line 389) | on(type: string, handler: Handler) {
method off (line 397) | off(type: string) {
method addHook (line 406) | addHook(type: string, handler: Handler) {
method removeHook (line 415) | removeHook(type: string) {
method focus (line 422) | focus() {
method blur (line 429) | blur() {
method moveCursorToEnd (line 437) | moveCursorToEnd(focus = true) {
method moveCursorToStart (line 445) | moveCursorToStart(focus = true) {
method setMarkdown (line 454) | setMarkdown(markdown = '', cursorToEnd = true) {
method setHTML (line 470) | setHTML(html = '', cursorToEnd = true) {
method getMarkdown (line 488) | getMarkdown() {
method getHTML (line 500) | getHTML() {
method insertText (line 527) | insertText(text: string) {
method setSelection (line 536) | setSelection(start: EditorPos, end?: EditorPos) {
method replaceSelection (line 546) | replaceSelection(text: string, start?: EditorPos, end?: EditorPos) {
method deleteSelection (line 555) | deleteSelection(start?: EditorPos, end?: EditorPos) {
method getSelectedText (line 565) | getSelectedText(start?: EditorPos, end?: EditorPos) {
method getRangeInfoOfNode (line 584) | getRangeInfoOfNode(pos?: EditorPos) {
method addWidget (line 594) | addWidget(node: Node, style: WidgetStyle, pos?: EditorPos) {
method replaceWithWidget (line 604) | replaceWithWidget(start: EditorPos, end: EditorPos, text: string) {
method setHeight (line 612) | setHeight(height: string) {
method getHeight (line 632) | getHeight() {
method setMinHeight (line 640) | setMinHeight(minHeight: string) {
method getMinHeight (line 663) | getMinHeight() {
method isMarkdownMode (line 671) | isMarkdownMode() {
method isWysiwygMode (line 679) | isWysiwygMode() {
method isViewer (line 687) | isViewer() {
method getCurrentPreviewStyle (line 695) | getCurrentPreviewStyle() {
method changeMode (line 704) | changeMode(mode: EditorType, withoutFocus?: boolean) {
method destroy (line 741) | destroy() {
method hide (line 753) | hide() {
method show (line 760) | show() {
method setScrollTop (line 768) | setScrollTop(value: number) {
method getScrollTop (line 776) | getScrollTop() {
method reset (line 783) | reset() {
method getSelection (line 802) | getSelection() {
method setPlaceholder (line 810) | setPlaceholder(placeholder: string) {
method getEditorElements (line 819) | getEditorElements() {
method convertPosToMatchEditorMode (line 833) | convertPosToMatchEditorMode(start: EditorPos, end = start, mode = this...
FILE: apps/editor/src/event/eventEmitter.ts
class EventEmitter (line 47) | class EventEmitter implements Emitter {
method constructor (line 54) | constructor() {
method listen (line 71) | listen(type: string, handler: Handler) {
method emit (line 93) | emit(type: string, ...args: any[]) {
method emitReduce (line 117) | emitReduce(type: string, source: any, ...args: any[]) {
method getTypeInfo (line 139) | private getTypeInfo(type: string) {
method hasEventType (line 154) | private hasEventType(type: string) {
method addEventType (line 162) | addEventType(type: string) {
method removeEventHandler (line 175) | removeEventHandler(eventType: string, handler?: Handler) {
method removeEventHandlerWithHandler (line 197) | private removeEventHandlerWithHandler(type: string, handler: Handler) {
method removeEventHandlerWithTypeInfo (line 215) | private removeEventHandlerWithTypeInfo(type: string, namespace: string) {
method getEvents (line 234) | getEvents() {
method holdEventInvoke (line 238) | holdEventInvoke(fn: Function) {
FILE: apps/editor/src/helper/image.ts
function addDefaultImageBlobHook (line 6) | function addDefaultImageBlobHook(eventEmitter: Emitter) {
function emitImageBlobHook (line 15) | function emitImageBlobHook(eventEmitter: Emitter, blob: File, type: stri...
function pasteImageOnly (line 26) | function pasteImageOnly(items: DataTransferItemList) {
FILE: apps/editor/src/helper/manipulation.ts
type ReplacePayload (line 6) | interface ReplacePayload {
function createParagraph (line 14) | function createParagraph(schema: Schema, content?: string | ProsemirrorN...
function createTextNode (line 23) | function createTextNode(schema: Schema, text: string, marks?: Mark[]) {
function createTextSelection (line 27) | function createTextSelection(tr: Transaction, from: number, to = from) {
function addParagraph (line 34) | function addParagraph(tr: Transaction, { pos }: ResolvedPos, schema: Sch...
function replaceTextNode (line 40) | function replaceTextNode({ state, from, startIndex, endIndex, createText...
function splitAndExtendBlock (line 56) | function splitAndExtendBlock(
FILE: apps/editor/src/helper/plugin.ts
function execPlugin (line 14) | function execPlugin(pluginInfo: EditorPluginInfo) {
function getPluginInfo (line 43) | function getPluginInfo(pluginsInfo: EditorPluginsInfo) {
FILE: apps/editor/src/i18n/i18n.ts
constant DEFAULT_CODE (line 8) | const DEFAULT_CODE = 'en-US';
class I18n (line 14) | class I18n {
method constructor (line 19) | constructor() {
method setCode (line 24) | setCode(code?: string) {
method setLanguage (line 33) | setLanguage(codes: string | string[], data: Record<string, string>) {
method get (line 47) | get(key: string, code?: string) {
FILE: apps/editor/src/markdown/helper/list.ts
type ToListContext (line 7) | interface ToListContext<T = ListItemMdNode> {
type ExtendListContext (line 15) | type ExtendListContext = Omit<ToListContext, 'startLine'>;
type ChangedListInfo (line 17) | interface ChangedListInfo {
type ToListResult (line 22) | interface ToListResult {
type ExtendedResult (line 28) | type ExtendedResult = {
type ListType (line 34) | type ListType = 'bullet' | 'ordered';
type ListToListFn (line 35) | type ListToListFn = (context: ToListContext) => ToListResult;
type NodeToListFn (line 36) | type NodeToListFn = (context: ToListContext<MdNode>) => ToListResult;
type ExtendListFn (line 37) | type ExtendListFn = (context: ExtendListContext) => ExtendedResult;
type ItemInfo (line 39) | interface ItemInfo {
type ListToList (line 45) | interface ListToList {
type NodeToList (line 51) | interface NodeToList {
type ExtendList (line 57) | interface ExtendList {
function getListType (line 70) | function getListType(text: string): ListType {
function getListDepth (line 74) | function getListDepth(mdNode: MdNode) {
function findSameDepthList (line 86) | function findSameDepthList(
function getSameDepthItems (line 112) | function getSameDepthItems({ toastMark, mdNode, line }: ToListContext) {
function textToBullet (line 120) | function textToBullet(text: string) {
function textToOrdered (line 135) | function textToOrdered(text: string, ordinalNum: number) {
function getChangedInfo (line 155) | function getChangedInfo(
function getBulletOrOrdered (line 178) | function getBulletOrOrdered(type: ListType, context: ToListContext) {
method bullet (line 185) | bullet(context) {
method ordered (line 188) | ordered(context) {
method task (line 191) | task({ mdNode, doc, line }) {
method bullet (line 205) | bullet({ doc, line }) {
method ordered (line 211) | ordered({ toastMark, doc, line, startLine }) {
method task (line 245) | task({ doc, line }) {
method bullet (line 254) | bullet({ line, doc }: ExtendListContext) {
method ordered (line 260) | ordered({ toastMark, line, mdNode, doc }: ExtendListContext) {
function getReorderedListInfo (line 283) | function getReorderedListInfo(
FILE: apps/editor/src/markdown/helper/mdCommand.ts
type ConditionFn (line 6) | type ConditionFn = (text: string) => boolean;
type Condition (line 7) | type Condition = RegExp | ConditionFn;
function toggleMark (line 9) | function toggleMark(condition: Condition, syntax: string): EditorCommand {
FILE: apps/editor/src/markdown/helper/pos.ts
function resolveSelectionPos (line 6) | function resolveSelectionPos(selection: Selection) {
function getMdLine (line 15) | function getMdLine(resolvedPos: ResolvedPos) {
function getWidgetNodePos (line 19) | function getWidgetNodePos(node: ProsemirrorNode, chPos: number, directio...
function getEditorToMdPos (line 32) | function getEditorToMdPos(doc: ProsemirrorNode, from: number, to = from)...
function getStartPosListPerLine (line 63) | function getStartPosListPerLine(doc: ProsemirrorNode, endIndex: number) {
function getMdToEditorPos (line 76) | function getMdToEditorPos(doc: ProsemirrorNode, startPos: MdPos, endPos:...
function getRangeInfo (line 94) | function getRangeInfo(selection: Selection) {
function getNodeContentOffsetRange (line 120) | function getNodeContentOffsetRange(doc: ProsemirrorNode, targetIndex: nu...
FILE: apps/editor/src/markdown/helper/query.ts
function getTextByMdLine (line 3) | function getTextByMdLine(doc: ProsemirrorNode, mdLine: number) {
function getTextContent (line 7) | function getTextContent(doc: ProsemirrorNode, index: number) {
FILE: apps/editor/src/markdown/htmlRenderConvertors.ts
type TokenAttrs (line 20) | type TokenAttrs = Record<string, any>;
method paragraph (line 25) | paragraph(_, { entering, origin, options }: Context) {
method softbreak (line 37) | softbreak(node: MdNode) {
method item (line 45) | item(node: MdNode, { entering }: Context) {
method code (line 75) | code(node: MdNode) {
method codeBlock (line 85) | codeBlock(node: MdNode) {
method customInline (line 110) | customInline(node: MdNode, { origin, entering, skipChildren }: Context) {
function getHTMLRenderConvertors (line 128) | function getHTMLRenderConvertors(
FILE: apps/editor/src/markdown/marks/blockQuote.ts
class BlockQuote (line 17) | class BlockQuote extends Mark {
method name (line 18) | get name() {
method schema (line 22) | get schema() {
method createBlockQuoteText (line 30) | private createBlockQuoteText(text: string, isBlockQuote?: boolean) {
method extendBlockQuote (line 34) | private extendBlockQuote(): Command {
method commands (line 59) | commands(): EditorCommand {
method keymaps (line 77) | keymaps() {
FILE: apps/editor/src/markdown/marks/code.ts
class Code (line 10) | class Code extends Mark {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method commands (line 41) | commands(): EditorCommand {
method keymaps (line 45) | keymaps() {
FILE: apps/editor/src/markdown/marks/codeBlock.ts
class CodeBlock (line 13) | class CodeBlock extends Mark {
method name (line 16) | get name() {
method schema (line 20) | get schema() {
method commands (line 28) | commands(): EditorCommand {
method keepIndentation (line 50) | private keepIndentation(): Command {
method keymaps (line 76) | keymaps() {
FILE: apps/editor/src/markdown/marks/customBlock.ts
class CustomBlock (line 10) | class CustomBlock extends Mark {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method commands (line 23) | commands(): EditorCommand {
FILE: apps/editor/src/markdown/marks/emph.ts
class Emph (line 10) | class Emph extends Mark {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method italic (line 23) | private italic(): EditorCommand {
method commands (line 27) | commands() {
method keymaps (line 31) | keymaps() {
FILE: apps/editor/src/markdown/marks/heading.ts
type Payload (line 10) | interface Payload {
class Heading (line 14) | class Heading extends Mark {
method name (line 15) | get name() {
method schema (line 19) | get schema() {
method createHeadingText (line 37) | private createHeadingText(level: number, text: string, curHeadingSynta...
method commands (line 49) | commands(): EditorCommand<Payload> {
FILE: apps/editor/src/markdown/marks/html.ts
class Html (line 5) | class Html extends Mark {
method name (line 6) | get name() {
method schema (line 10) | get schema() {
FILE: apps/editor/src/markdown/marks/link.ts
type CommandType (line 9) | type CommandType = 'image' | 'link';
type Payload (line 11) | interface Payload {
class Link (line 18) | class Link extends Mark {
method name (line 19) | get name() {
method schema (line 23) | get schema() {
method addLinkOrImage (line 45) | private addLinkOrImage(commandType: CommandType): EditorCommand<Payloa...
method commands (line 68) | commands() {
FILE: apps/editor/src/markdown/marks/listItem.ts
type CommandType (line 25) | type CommandType = 'bullet' | 'ordered' | 'task';
function cannotBeListNode (line 27) | function cannotBeListNode({ type, sourcepos }: MdNode, line: number) {
type RangeInfo (line 34) | interface RangeInfo {
class ListItem (line 41) | class ListItem extends Mark {
method name (line 44) | get name() {
method schema (line 48) | get schema() {
method extendList (line 73) | private extendList(): Command {
method toList (line 126) | private toList(commandType: CommandType): EditorCommand {
method changeToListPerLine (line 174) | private changeToListPerLine(
method toggleTask (line 201) | private toggleTask(): Command {
method commands (line 229) | commands() {
method keymaps (line 237) | keymaps() {
FILE: apps/editor/src/markdown/marks/simpleMark.ts
class TaskDelimiter (line 5) | class TaskDelimiter extends Mark {
method name (line 6) | get name() {
method schema (line 10) | get schema() {
class Delimiter (line 19) | class Delimiter extends Mark {
method name (line 20) | get name() {
method schema (line 24) | get schema() {
class Meta (line 33) | class Meta extends Mark {
method name (line 34) | get name() {
method schema (line 38) | get schema() {
class MarkedText (line 47) | class MarkedText extends Mark {
method name (line 48) | get name() {
method schema (line 52) | get schema() {
class TableCell (line 61) | class TableCell extends Mark {
method name (line 62) | get name() {
method schema (line 66) | get schema() {
FILE: apps/editor/src/markdown/marks/strike.ts
class Strike (line 10) | class Strike extends Mark {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method commands (line 23) | commands(): EditorCommand {
method keymaps (line 27) | keymaps() {
FILE: apps/editor/src/markdown/marks/strong.ts
class Strong (line 10) | class Strong extends Mark {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method bold (line 23) | private bold(): EditorCommand {
method commands (line 27) | commands() {
method keymaps (line 31) | keymaps() {
FILE: apps/editor/src/markdown/marks/table.ts
type Payload (line 14) | interface Payload {
type MovingTypeInfo (line 19) | interface MovingTypeInfo {
function createTableHeader (line 27) | function createTableHeader(columnCount: number) {
function createTableBody (line 31) | function createTableBody(columnCount: number, rowCount: number) {
function createTableRow (line 41) | function createTableRow(columnCount: number, delim?: boolean) {
function createTargetTypes (line 50) | function createTargetTypes(moveNext: boolean): MovingTypeInfo {
class Table (line 56) | class Table extends Mark {
method name (line 59) | get name() {
method schema (line 63) | get schema() {
method extendTable (line 71) | private extendTable(): Command {
method moveTableCell (line 112) | private moveTableCell(moveNext: boolean): Command {
method addTable (line 154) | private addTable(): EditorCommand<Payload> {
method commands (line 175) | commands() {
method keymaps (line 179) | keymaps() {
FILE: apps/editor/src/markdown/marks/thematicBreak.ts
class ThematicBreak (line 11) | class ThematicBreak extends Mark {
method name (line 12) | get name() {
method schema (line 16) | get schema() {
method hr (line 24) | private hr(): EditorCommand {
method commands (line 42) | commands() {
method keymaps (line 46) | keymaps() {
FILE: apps/editor/src/markdown/mdEditor.ts
type WindowWithClipboard (line 42) | interface WindowWithClipboard extends Window {
type MarkdownOptions (line 46) | interface MarkdownOptions {
constant EVENT_TYPE (line 52) | const EVENT_TYPE = 'cut';
class MdEditor (line 55) | class MdEditor extends EditorBase {
method constructor (line 62) | constructor(eventEmitter: Emitter, options: MarkdownOptions) {
method toggleActive (line 87) | private toggleActive(active: boolean, isMarkdownTabMounted?: boolean) {
method createClipboard (line 98) | private createClipboard() {
method createContext (line 133) | createContext() {
method createSpecs (line 141) | createSpecs() {
method createPlugins (line 168) | createPlugins() {
method createView (line 177) | createView() {
method createCommands (line 213) | createCommands() {
method captureCopy (line 217) | private captureCopy(ev: ClipboardEvent, type?: string) {
method updateMarkdown (line 240) | private updateMarkdown(tr: Transaction) {
method getChanged (line 262) | private getChanged(slice: Slice) {
method setSelection (line 278) | setSelection(start: MdPos, end = start) {
method replaceSelection (line 285) | replaceSelection(text: string, start?: MdPos, end?: MdPos) {
method deleteSelection (line 306) | deleteSelection(start?: MdPos, end?: MdPos) {
method getSelectedText (line 320) | getSelectedText(start?: MdPos, end?: MdPos) {
method getSelection (line 334) | getSelection() {
method setMarkdown (line 340) | setMarkdown(markdown: string, cursorToEnd = true) {
method addWidget (line 354) | addWidget(node: Node, style: WidgetStyle, mdPos?: MdPos) {
method replaceWithWidget (line 361) | replaceWithWidget(start: MdPos, end: MdPos, text: string) {
method getRangeInfoOfNode (line 369) | getRangeInfoOfNode(pos?: MdPos) {
method getMarkdown (line 384) | getMarkdown() {
method getToastMark (line 391) | getToastMark() {
FILE: apps/editor/src/markdown/mdPreview.ts
constant CLASS_HIGHLIGHT (line 22) | const CLASS_HIGHLIGHT = cls('md-preview-highlight');
function findTableCell (line 24) | function findTableCell(tableRow: MdNode, chOffset: number) {
type Sanitizer (line 37) | type Sanitizer = (html: string) => string;
type Options (line 39) | interface Options {
class MarkdownPreview (line 59) | class MarkdownPreview {
method constructor (line 74) | constructor(eventEmitter: Emitter, options: Options) {
method initContentSection (line 103) | private initContentSection() {
method toggleActive (line 113) | private toggleActive(active: boolean) {
method initEvent (line 117) | private initEvent(highlight: boolean) {
method removeHighlight (line 145) | private removeHighlight() {
method updateCursorNode (line 155) | private updateCursorNode(cursorNode: MdNode | null, cursorPos: MdPos) {
method getElementByNodeId (line 186) | private getElementByNodeId(nodeId: number | null) {
method update (line 192) | update(changed: EditResult[]) {
method replaceRangeNodes (line 197) | replaceRangeNodes(editResult: EditResult) {
method getRenderer (line 231) | getRenderer() {
method destroy (line 235) | destroy() {
method getElement (line 240) | getElement() {
method getHTML (line 244) | getHTML() {
method setHTML (line 248) | setHTML(html: string) {
method setHeight (line 252) | setHeight(height: number) {
method setMinHeight (line 256) | setMinHeight(minHeight: number) {
FILE: apps/editor/src/markdown/nodes/doc.ts
class Doc (line 3) | class Doc extends Node {
method name (line 4) | get name() {
method schema (line 8) | get schema() {
FILE: apps/editor/src/markdown/nodes/paragraph.ts
type SelectionInfo (line 14) | interface SelectionInfo {
type IndentSelectionInfo (line 19) | interface IndentSelectionInfo extends SelectionInfo {
type OutdentSelectionInfo (line 24) | interface OutdentSelectionInfo extends SelectionInfo {
function isBlockUnit (line 31) | function isBlockUnit(from: number, to: number, text: string) {
function isInTableCellNode (line 35) | function isInTableCellNode(doc: ProsemirrorNode, schema: Schema, selecti...
function createSelection (line 52) | function createSelection(tr: Transaction, posInfo: IndentSelectionInfo |...
class Paragraph (line 72) | class Paragraph extends Node {
method name (line 75) | get name() {
method schema (line 79) | get schema() {
method reorderList (line 98) | private reorderList(startLine: number, endLine: number) {
method indent (line 140) | private indent(tabKey = false): EditorCommand {
method outdent (line 182) | private outdent(tabKey = false): EditorCommand {
method deleteLines (line 231) | private deleteLines(): Command {
method moveDown (line 246) | private moveDown(): Command {
method moveUp (line 266) | private moveUp(): Command {
method commands (line 286) | commands() {
method keymaps (line 293) | keymaps() {
FILE: apps/editor/src/markdown/nodes/text.ts
class Text (line 3) | class Text extends Node {
method name (line 4) | get name() {
method schema (line 8) | get schema() {
FILE: apps/editor/src/markdown/plugins/helper/markInfo.ts
constant HEADING (line 22) | const HEADING = 'heading';
constant BLOCK_QUOTE (line 23) | const BLOCK_QUOTE = 'blockQuote';
constant LIST_ITEM (line 24) | const LIST_ITEM = 'listItem';
constant TABLE (line 25) | const TABLE = 'table';
constant TABLE_CELL (line 26) | const TABLE_CELL = 'tableCell';
constant CODE_BLOCK (line 27) | const CODE_BLOCK = 'codeBlock';
constant THEMATIC_BREAK (line 28) | const THEMATIC_BREAK = 'thematicBreak';
constant LINK (line 29) | const LINK = 'link';
constant CODE (line 30) | const CODE = 'code';
constant META (line 31) | const META = 'meta';
constant DELIM (line 32) | const DELIM = 'delimiter';
constant TASK_DELIM (line 33) | const TASK_DELIM = 'taskDelimiter';
constant TEXT (line 34) | const TEXT = 'markedText';
constant HTML (line 35) | const HTML = 'html';
constant CUSTOM_BLOCK (line 36) | const CUSTOM_BLOCK = 'customBlock';
type MarkType (line 44) | type MarkType =
type MarkInfo (line 53) | interface MarkInfo {
function markInfo (line 60) | function markInfo(start: MdPos, end: MdPos, type: MarkType, attrs?: Reco...
function heading (line 64) | function heading({ level, headingType }: HeadingMdNode, start: MdPos, en...
function emphasisAndStrikethrough (line 76) | function emphasisAndStrikethrough(
function markLink (line 91) | function markLink(start: MdPos, end: MdPos, linkTextStart: MdPos, lastCh...
function image (line 101) | function image({ lastChild }: LinkMdNode, start: MdPos, end: MdPos) {
function link (line 108) | function link({ lastChild, extendedAutolink }: LinkMdNode, start: MdPos,...
function code (line 116) | function code({ tickCount }: CodeMdNode, start: MdPos, end: MdPos) {
function lineBackground (line 128) | function lineBackground(parent: MdNode, start: MdPos, end: MdPos, prefix...
function codeBlock (line 153) | function codeBlock(node: CodeBlockMdNode, start: MdPos, end: MdPos, endL...
function customBlock (line 184) | function customBlock(node: MdNode, start: MdPos, end: MdPos) {
function markListItemChildren (line 208) | function markListItemChildren(node: MdNode, markType: MarkType) {
function markParagraphInBlockQuote (line 229) | function markParagraphInBlockQuote(node: MdNode) {
function blockQuote (line 246) | function blockQuote(node: MdNode, start: MdPos, end: MdPos) {
function getSpecOfListItemStyle (line 265) | function getSpecOfListItemStyle(node: MdNode): [MarkType, Record<string,...
function item (line 278) | function item(node: ListItemMdNode, start: MdPos) {
type MarkNodeFuncMapKey (line 314) | type MarkNodeFuncMapKey = keyof typeof markNodeFuncMap;
type SimpleNodeFuncMapKey (line 315) | type SimpleNodeFuncMapKey = keyof typeof simpleMarkClassNameMap;
function getMarkInfo (line 317) | function getMarkInfo(node: MdNode, start: MdPos, end: MdPos, endLine: st...
FILE: apps/editor/src/markdown/plugins/previewHighlight.ts
function getToolbarStateType (line 25) | function getToolbarStateType(mdNode: MdNode) {
function getToolbarState (line 46) | function getToolbarState(targetNode: MdNode) {
function previewHighlight (line 79) | function previewHighlight({ toastMark, eventEmitter }: MdContext) {
FILE: apps/editor/src/markdown/plugins/smartTask.ts
function smartTask (line 11) | function smartTask({ schema, toastMark }: MdContext) {
FILE: apps/editor/src/markdown/plugins/syntaxHighlight.ts
type CodeBlockPos (line 10) | interface CodeBlockPos {
type BlockPosInfo (line 15) | interface BlockPosInfo {
function syntaxHighlight (line 24) | function syntaxHighlight({ schema, toastMark }: MdContext) {
function isDifferentBlock (line 72) | function isDifferentBlock(doc: ProsemirrorNode, index: number, attrs: Re...
function addLineBackground (line 76) | function addLineBackground(
function appendMarkTr (line 97) | function appendMarkTr(tr: Transaction, schema: Schema, marks: MarkInfo[]) {
function removeBlockBackground (line 134) | function removeBlockBackground(
function cacheIndexToRemoveBackground (line 156) | function cacheIndexToRemoveBackground(doc: ProsemirrorNode, start: MdPos...
function getMarkForRemoving (line 182) | function getMarkForRemoving({ doc }: Transaction, nodes: MdNode[]) {
function getMarkForAdding (line 195) | function getMarkForAdding(node: MdNode, toastMark: ToastMark) {
FILE: apps/editor/src/markdown/scroll/animation.ts
type WinSetTimeout (line 4) | type WinSetTimeout = typeof window.setTimeout;
constant ANIMATION_TIME (line 6) | const ANIMATION_TIME = 100;
constant SCROLL_BLOCKING_RESET_DELAY (line 7) | const SCROLL_BLOCKING_RESET_DELAY = 15;
function run (line 11) | function run(deltaScrollTop: number, { syncScrollTop, releaseEventBlock ...
function animate (line 23) | function animate(
FILE: apps/editor/src/markdown/scroll/dom.ts
type El (line 6) | type El = HTMLElement | null;
function isBlankLine (line 11) | function isBlankLine(doc: ProsemirrorNode, index: number) {
function getEditorRangeHeightInfo (line 17) | function getEditorRangeHeightInfo(
function getBlankLinesHeight (line 40) | function getBlankLinesHeight(doc: ProsemirrorNode, children: HTMLCollect...
function findAncestorHavingId (line 51) | function findAncestorHavingId(el: HTMLElement, root: HTMLElement) {
function getTotalOffsetTop (line 58) | function getTotalOffsetTop(el: El, root: HTMLElement) {
function findAdjacentElementToScrollTop (line 73) | function findAdjacentElementToScrollTop(scrollTop: number, root: HTMLEle...
function findLastSiblingElementToScrollTop (line 98) | function findLastSiblingElementToScrollTop(el: El, scrollTop: number, of...
function getAdditionalPos (line 108) | function getAdditionalPos(
function getParentNodeObj (line 119) | function getParentNodeObj(previewContent: HTMLElement, mdNode: MdNode) {
function getNonNestableNodeObj (line 129) | function getNonNestableNodeObj({ mdNode, el }: { mdNode: MdNode; el: HTM...
FILE: apps/editor/src/markdown/scroll/offset.ts
function setHeight (line 6) | function setHeight(id: number, height: number) {
function setOffsetTop (line 11) | function setOffsetTop(id: number, offsetTop: number) {
function getHeight (line 16) | function getHeight(id: number) {
function getOffsetTop (line 20) | function getOffsetTop(id: number) {
function removeOffsetInfoByNode (line 24) | function removeOffsetInfoByNode(node: HTMLElement) {
function getAndSaveOffsetInfo (line 33) | function getAndSaveOffsetInfo(node: HTMLElement, root: HTMLElement, mdNo...
FILE: apps/editor/src/markdown/scroll/scrollSync.ts
constant EDITOR_BOTTOM_PADDING (line 18) | const EDITOR_BOTTOM_PADDING = 18;
type SyncCallbacks (line 20) | interface SyncCallbacks {
type PosInfo (line 25) | interface PosInfo {
type ScrollFrom (line 30) | type ScrollFrom = 'editor' | 'preview';
class ScrollSync (line 32) | class ScrollSync {
method constructor (line 55) | constructor(mdEditor: MdEditor, preview: MarkdownPreview, eventEmitter...
method addScrollSyncEvent (line 67) | private addScrollSyncEvent() {
method getMdNodeAtPos (line 91) | private getMdNodeAtPos(doc: ProsemirrorNode, posInfo: PosInfo) {
method getScrollTopByCaretPos (line 98) | private getScrollTopByCaretPos() {
method syncPreviewScrollTop (line 115) | private syncPreviewScrollTop(editing = false) {
method syncEditorScrollTop (line 163) | syncEditorScrollTop(targetNode: HTMLElement) {
method getResolvedScrollTop (line 204) | private getResolvedScrollTop(
method run (line 222) | private run(from: ScrollFrom, targetScrollTop: number, curScrollTop: n...
method clearTimer (line 241) | clearTimer() {
method destroy (line 248) | destroy() {
FILE: apps/editor/src/plugins/dropImage.ts
function dropImage (line 6) | function dropImage({ eventEmitter }: Context) {
FILE: apps/editor/src/plugins/placeholder.ts
type Options (line 5) | interface Options {
function placeholder (line 10) | function placeholder(options: Options) {
FILE: apps/editor/src/plugins/popupWidget.ts
type Widget (line 7) | interface Widget {
constant MARGIN (line 14) | const MARGIN = 5;
class PopupWidget (line 16) | class PopupWidget {
method constructor (line 23) | constructor(view: EditorView, eventEmitter: Emitter) {
method update (line 40) | update(view: EditorView) {
method destroy (line 65) | destroy() {
function addWidget (line 70) | function addWidget(eventEmitter: Emitter) {
FILE: apps/editor/src/queries/queryManager.ts
type QueryFn (line 3) | type QueryFn = (editor: Editor, payload?: Record<string, any>) => any;
method getPopupInitialValues (line 6) | getPopupInitialValues(editor, payload) {
function buildQuery (line 13) | function buildQuery(editor: Editor) {
FILE: apps/editor/src/sanitizer/htmlSanitizer.ts
constant CAN_BE_WHITE_TAG_LIST (line 4) | const CAN_BE_WHITE_TAG_LIST = ['iframe', 'embed'];
function registerTagWhitelistIfPossible (line 7) | function registerTagWhitelistIfPossible(tagName: string) {
function sanitizeHTML (line 13) | function sanitizeHTML<T extends string | HTMLElement | DocumentFragment ...
FILE: apps/editor/src/spec/mark.ts
method type (line 8) | get type() {
method setContext (line 12) | setContext(context: SpecContext) {
FILE: apps/editor/src/spec/node.ts
method type (line 8) | get type() {
method setContext (line 12) | setContext(context: SpecContext) {
FILE: apps/editor/src/spec/specManager.ts
type Spec (line 11) | type Spec = Node | Mark;
function execCommand (line 33) | function execCommand(
class SpecManager (line 42) | class SpecManager {
method constructor (line 45) | constructor(specs: Spec[]) {
method nodes (line 49) | get nodes() {
method marks (line 60) | get marks() {
method commands (line 71) | commands(view: EditorView, addedCommands?: Record<string, EditorComman...
method keymaps (line 107) | keymaps(useCommandShortcut: boolean) {
method setContext (line 122) | setContext(context: SpecContext) {
FILE: apps/editor/src/ui/components/contextMenu.ts
type State (line 7) | interface State {
type Props (line 12) | interface Props {
class ContextMenu (line 17) | class ContextMenu extends Component<Props, State> {
method constructor (line 18) | constructor(props: Props) {
method addEvent (line 27) | addEvent() {
method mounted (line 33) | mounted() {
method beforeDestroy (line 37) | beforeDestroy() {
method getMenuGroupElements (line 47) | private getMenuGroupElements() {
method render (line 85) | render() {
FILE: apps/editor/src/ui/components/layout.ts
type Props (line 11) | interface Props {
type State (line 25) | interface State {
class Layout (line 31) | class Layout extends Component<Props, State> {
method constructor (line 34) | constructor(props: Props) {
method mounted (line 46) | mounted() {
method insertToolbarItem (line 54) | insertToolbarItem(indexList: IndexList, item: string | ToolbarItemOpti...
method removeToolbarItem (line 58) | removeToolbarItem(name: string) {
method render (line 62) | render() {
method addEvent (line 106) | addEvent() {
FILE: apps/editor/src/ui/components/popup.ts
type PopupStyle (line 8) | type PopupStyle = {
type Props (line 12) | interface Props {
type State (line 20) | interface State {
constant MARGIN_FROM_RIGHT_SIDE (line 24) | const MARGIN_FROM_RIGHT_SIDE = 20;
class Popup (line 26) | class Popup extends Component<Props, State> {
method mounted (line 36) | mounted() {
method beforeDestroy (line 41) | beforeDestroy() {
method updated (line 45) | updated(prevProps: Props) {
method render (line 63) | render() {
FILE: apps/editor/src/ui/components/switch.ts
type Props (line 8) | interface Props {
type State (line 13) | interface State {
class Switch (line 17) | class Switch extends Component<Props, State> {
method constructor (line 18) | constructor(props: Props) {
method show (line 25) | show() {
method hide (line 29) | hide() {
method render (line 33) | render() {
FILE: apps/editor/src/ui/components/tabs.ts
type Props (line 7) | interface Props {
class Tabs (line 13) | class Tabs extends Component<Props> {
method toggleTab (line 14) | private toggleTab(ev: MouseEvent, activeTab: string) {
method render (line 18) | render() {
FILE: apps/editor/src/ui/components/toolbar/buttonHoc.ts
type Props (line 16) | interface Props {
type Payload (line 26) | interface Payload {
type State (line 30) | interface State {
constant TOOLTIP_INDENT (line 35) | const TOOLTIP_INDENT = 6;
function connectHOC (line 37) | function connectHOC(WrappedComponent: ComponentClass) {
FILE: apps/editor/src/ui/components/toolbar/customPopupBody.ts
type Props (line 6) | interface Props {
class CustomPopupBody (line 14) | class CustomPopupBody extends Component<Props> {
method mounted (line 15) | mounted() {
method updated (line 20) | updated(prevProps: Props) {
method render (line 25) | render() {
FILE: apps/editor/src/ui/components/toolbar/customToolbarItem.ts
type Props (line 17) | interface Props {
class CustomToolbarItemComp (line 30) | class CustomToolbarItemComp extends Component<Props> {
method mounted (line 31) | mounted() {
method updated (line 46) | updated(prevProps: Props) {
method render (line 70) | render() {
FILE: apps/editor/src/ui/components/toolbar/dropdownToolbarButton.ts
type Props (line 17) | interface Props {
type State (line 29) | interface State {
constant POPUP_INDENT (line 34) | const POPUP_INDENT = 4;
class DropdownToolbarButtonComp (line 36) | class DropdownToolbarButtonComp extends Component<Props, State> {
method constructor (line 37) | constructor(props: Props) {
method getBound (line 42) | private getBound() {
method mounted (line 59) | mounted() {
method updated (line 63) | updated() {
method beforeDestroy (line 69) | beforeDestroy() {
method render (line 77) | render() {
FILE: apps/editor/src/ui/components/toolbar/headingPopupBody.ts
type Props (line 8) | interface Props {
class HeadingPopupBody (line 13) | class HeadingPopupBody extends Component<Props> {
method execCommand (line 14) | execCommand(ev: MouseEvent) {
method render (line 22) | render() {
FILE: apps/editor/src/ui/components/toolbar/imagePopupBody.ts
constant TYPE_UI (line 12) | const TYPE_UI = 'ui';
type TabType (line 14) | type TabType = 'url' | 'file';
type Props (line 16) | interface Props {
type State (line 23) | interface State {
class ImagePopupBody (line 29) | class ImagePopupBody extends Component<Props, State> {
method constructor (line 32) | constructor(props: Props) {
method emitAddImageBlob (line 53) | private emitAddImageBlob() {
method emitAddImage (line 69) | private emitAddImage() {
method preventSelectStart (line 113) | private preventSelectStart(ev: Event) {
method updated (line 117) | updated() {
method render (line 123) | render() {
FILE: apps/editor/src/ui/components/toolbar/linkPopupBody.ts
type Props (line 12) | interface Props {
class LinkPopupBody (line 20) | class LinkPopupBody extends Component<Props> {
method initialize (line 21) | private initialize() {
method mounted (line 65) | mounted() {
method updated (line 69) | updated(prevProps: Props) {
method render (line 75) | render() {
FILE: apps/editor/src/ui/components/toolbar/tablePopupBody.ts
type Range (line 8) | interface Range {
type Props (line 13) | interface Props {
type State (line 19) | type State = Range;
constant CELL_WIDTH (line 21) | const CELL_WIDTH = 20;
constant CELL_HEIGHT (line 22) | const CELL_HEIGHT = 20;
constant MIN_ROW_INDEX (line 23) | const MIN_ROW_INDEX = 5;
constant MAX_ROW_INDEX (line 24) | const MAX_ROW_INDEX = 14;
constant MIN_COL_INDEX (line 25) | const MIN_COL_INDEX = 5;
constant MAX_COL_INDEX (line 26) | const MAX_COL_INDEX = 9;
constant MIN_ROW_SELECTION_INDEX (line 27) | const MIN_ROW_SELECTION_INDEX = 1;
constant MIN_COL_SELECTION_INDEX (line 28) | const MIN_COL_SELECTION_INDEX = 1;
constant BORDER_WIDTH (line 29) | const BORDER_WIDTH = 1;
class TablePopupBody (line 31) | class TablePopupBody extends Component<Props, State> {
method constructor (line 34) | constructor(props: Props) {
method getDescription (line 57) | private getDescription() {
method getBoundByRange (line 61) | private getBoundByRange(colIdx: number, rowIdx: number) {
method getRangeByOffset (line 68) | private getRangeByOffset(x: number, y: number) {
method getTableRange (line 75) | private getTableRange() {
method getSelectionAreaBound (line 90) | private getSelectionAreaBound() {
method getSelectionRangeByOffset (line 100) | private getSelectionRangeByOffset(x: number, y: number) {
method updated (line 109) | updated() {
method createTableArea (line 122) | private createTableArea(tableRange: Range) {
method render (line 140) | render() {
FILE: apps/editor/src/ui/components/toolbar/toolbar.ts
type TabType (line 37) | type TabType = 'write' | 'preview';
type Props (line 39) | interface Props {
type State (line 46) | interface State {
type ItemWidthMap (line 54) | interface ItemWidthMap {
constant INLINE_PADDING (line 58) | const INLINE_PADDING = 50;
class Toolbar (line 60) | class Toolbar extends Component<Props, State> {
method constructor (line 73) | constructor(props: Props) {
method insertToolbarItem (line 94) | insertToolbarItem(indexList: IndexList, item: string | ToolbarItemOpti...
method removeToolbarItem (line 108) | removeToolbarItem(name: string) {
method addEvent (line 125) | addEvent() {
method appendTooltipToRoot (line 136) | private appendTooltipToRoot() {
method hiddenScrollSync (line 145) | private hiddenScrollSync() {
method movePrevItemToDropdownToolbar (line 201) | private movePrevItemToDropdownToolbar(
method classifyToolbarItems (line 226) | private classifyToolbarItems() {
method mounted (line 272) | mounted() {
method updated (line 282) | updated(prevProps: Props) {
method beforeDestroy (line 300) | beforeDestroy() {
method render (line 306) | render() {
FILE: apps/editor/src/ui/components/toolbar/toolbarButton.ts
type Props (line 17) | interface Props {
constant DEFAULT_WIDTH (line 30) | const DEFAULT_WIDTH = 80;
class ToolbarButtonComp (line 32) | class ToolbarButtonComp extends Component<Props> {
method mounted (line 33) | mounted() {
method updated (line 37) | updated(prevProps: Props) {
method setItemWidth (line 43) | private setItemWidth() {
method render (line 79) | render() {
FILE: apps/editor/src/ui/components/toolbar/toolbarGroup.ts
type Props (line 18) | interface Props {
class ToolbarGroup (line 33) | class ToolbarGroup extends Component<Props> {
method render (line 34) | render() {
FILE: apps/editor/src/ui/toolbarItemFactory.ts
function createToolbarItemInfo (line 26) | function createToolbarItemInfo(type: string | ToolbarItemOptions): Toolb...
function createScrollSyncToolbarItem (line 30) | function createScrollSyncToolbarItem(): ToolbarItemInfo {
function createDefaultToolbarItemInfo (line 62) | function createDefaultToolbarItemInfo(type: string) {
type Payload (line 227) | interface Payload {
function createPopupInfo (line 234) | function createPopupInfo(type: string, payload: Payload): PopupInfo | nu...
function setGroupState (line 282) | function setGroupState(group: ToolbarGroupInfo) {
function groupToolbarItems (line 286) | function groupToolbarItems(toolbarItems: ToolbarItem[], hiddenScrollSync...
function toggleScrollSync (line 303) | function toggleScrollSync(toolbarItems: ToolbarGroupInfo[], hiddenScroll...
FILE: apps/editor/src/ui/vdom/commit.ts
function commit (line 5) | function commit(vnode?: VNode) {
function getParentNode (line 33) | function getParentNode(vnode: VNode) {
function diff (line 43) | function diff(vnode: VNode | null) {
FILE: apps/editor/src/ui/vdom/component.ts
method constructor (line 14) | constructor(props: T) {
method setState (line 20) | setState(state: Partial<R>) {
FILE: apps/editor/src/ui/vdom/dom.ts
type ConditionFn (line 7) | type ConditionFn = (propName: string) => boolean;
type Props (line 8) | type Props = Record<string, any>;
function createNode (line 12) | function createNode(vnode: VNode) {
function removeNode (line 25) | function removeNode(vnode: VNode, parentNode: Node) {
function innerDiff (line 33) | function innerDiff(node: Node, prevProps: Props, nextProps: Props) {
function setProps (line 56) | function setProps(node: Node, prevProps: Props, props: Props, condition?...
function setStyleProps (line 77) | function setStyleProps(node: HTMLElement, prevStyleProps: Props | null, ...
FILE: apps/editor/src/ui/vdom/render.ts
function createComponent (line 7) | function createComponent(Comp: ComponentClass, vnode: VNode) {
function buildVNode (line 19) | function buildVNode(vnode: VNode | null) {
function isSameType (line 51) | function isSameType(old: VNode | null, vnode: VNode) {
function buildChildrenVNode (line 56) | function buildChildrenVNode(parent: VNode) {
FILE: apps/editor/src/ui/vdom/renderer.ts
function destroy (line 6) | function destroy(vnode: VNode) {
function rerender (line 13) | function rerender(comp: Component) {
function render (line 33) | function render(container: HTMLElement, vnode: VNode) {
FILE: apps/editor/src/ui/vdom/template.ts
function createTextNode (line 8) | function createTextNode(text: string) {
function excludeUnnecessaryChild (line 12) | function excludeUnnecessaryChild(child: VNode, flatted: VNode[]) {
function h (line 26) | function h(type: string | ComponentClass, props: Record<string, any>, .....
FILE: apps/editor/src/ui/vdom/vnode.ts
class VNodeWalker (line 3) | class VNodeWalker {
method constructor (line 10) | constructor(current: VNode | null) {
method walk (line 16) | walk() {
class VNode (line 44) | class VNode {
method constructor (line 74) | constructor(type: string | ComponentClass, props: Record<string, any>,...
method walker (line 89) | walker() {
FILE: apps/editor/src/utils/common.ts
constant XMLSPECIAL (line 18) | const XMLSPECIAL = '[&<>"]';
function replaceUnsafeChar (line 21) | function replaceUnsafeChar(char: string) {
function escapeXml (line 36) | function escapeXml(text: string) {
function sendHostName (line 43) | function sendHostName() {
function includes (line 47) | function includes<T>(arr: T[], targetItem: T) {
function sanitizeLinkAttribute (line 66) | function sanitizeLinkAttribute(attribute: LinkAttributes) {
function repeat (line 82) | function repeat(text: string, count: number) {
function isNeedEscapeText (line 92) | function isNeedEscapeText(text: string) {
function escapeTextForLink (line 105) | function escapeTextForLink(text: string) {
function escape (line 121) | function escape(text: string) {
function quote (line 148) | function quote(text: string) {
function isNil (line 160) | function isNil(value: unknown): value is null | undefined {
function shallowEqual (line 164) | function shallowEqual(o1: Record<string, any> | null, o2: Record<string,...
function last (line 185) | function last<T>(arr: T[]) {
function between (line 189) | function between(value: number, min: number, max: number) {
function isObject (line 193) | function isObject(obj: unknown): obj is object {
function deepMergedCopy (line 197) | function deepMergedCopy<T1 extends Record<string, any>, T2 extends Recor...
function deepCopyArray (line 222) | function deepCopyArray<T extends Array<any>>(items: T): T {
function deepCopy (line 231) | function deepCopy<T extends Record<string, any>>(obj: T) {
function assign (line 248) | function assign(targetObj: Record<string, any>, obj: Record<string, any>...
function getSortedNumPair (line 263) | function getSortedNumPair(valueA: number, valueB: number) {
FILE: apps/editor/src/utils/constants.ts
constant TAG_NAME (line 1) | const TAG_NAME = '[A-Za-z][A-Za-z0-9-]*';
constant ATTRIBUTE_NAME (line 2) | const ATTRIBUTE_NAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*';
constant UNQUOTED_VALUE (line 3) | const UNQUOTED_VALUE = '[^"\'=<>`\\x00-\\x20]+';
constant SINGLE_QUOTED_VALUE (line 5) | const SINGLE_QUOTED_VALUE = "'[^']*'";
constant DOUBLE_QUOTED_VALUE (line 6) | const DOUBLE_QUOTED_VALUE = '"[^"]*"';
constant ATTRIBUTE_VALUE (line 8) | const ATTRIBUTE_VALUE = `(?:${UNQUOTED_VALUE}|${SINGLE_QUOTED_VALUE}|${D...
constant ATTRIBUTE_VALUE_SPEC (line 9) | const ATTRIBUTE_VALUE_SPEC = `${'(?:\\s*=\\s*'}${ATTRIBUTE_VALUE})`;
constant ATTRIBUTE (line 11) | const ATTRIBUTE = `${'(?:\\s+'}${ATTRIBUTE_NAME}${ATTRIBUTE_VALUE_SPEC}?)`;
constant OPEN_TAG (line 13) | const OPEN_TAG = `<(${TAG_NAME})(${ATTRIBUTE})*\\s*/?>`;
constant CLOSE_TAG (line 14) | const CLOSE_TAG = `</(${TAG_NAME})\\s*[>]`;
constant HTML_TAG (line 16) | const HTML_TAG = `(?:${OPEN_TAG}|${CLOSE_TAG})`;
constant ALTERNATIVE_TAG_FOR_BR (line 22) | const ALTERNATIVE_TAG_FOR_BR = '</p><p>';
FILE: apps/editor/src/utils/dom.ts
function isPositionInBox (line 12) | function isPositionInBox(style: CSSStyleDeclaration, offsetX: number, of...
constant CLS_PREFIX (line 23) | const CLS_PREFIX = 'toastui-editor-';
function cls (line 25) | function cls(...names: (string | [boolean, string])[]) {
function clsWithMdPrefix (line 45) | function clsWithMdPrefix(...names: string[]) {
function isTextNode (line 49) | function isTextNode(node: Node) {
function isElemNode (line 53) | function isElemNode(node: Node) {
function findNodes (line 57) | function findNodes(element: Element, selector: string) {
function appendNodes (line 67) | function appendNodes(node: Node, nodesToAppend: Node | Node[]) {
function insertBeforeNode (line 75) | function insertBeforeNode(insertedNode: Node, node: Node) {
function removeNode (line 81) | function removeNode(node: Node) {
function unwrapNode (line 87) | function unwrapNode(node: Node) {
function toggleClass (line 103) | function toggleClass(element: Element, className: string, state?: boolea...
function createElementWith (line 112) | function createElementWith(contents: string | HTMLElement, target?: HTML...
function getOuterWidth (line 130) | function getOuterWidth(el: HTMLElement) {
function closest (line 141) | function closest(node: Node, found: string | Node) {
function getTotalOffset (line 161) | function getTotalOffset(el: HTMLElement, root: HTMLElement) {
function finalizeHtml (line 178) | function finalizeHtml(html: Element, needHtmlText: boolean) {
function empty (line 197) | function empty(node: Node) {
function appendNode (line 203) | function appendNode(node: Element, appended: string | ArrayLike<Element>...
function prependNode (line 217) | function prependNode(node: Element, appended: string | ArrayLike<Element...
function setAttributes (line 231) | function setAttributes(attributes: Record<string, any>, element: HTMLEle...
function replaceBRWithEmptyBlock (line 241) | function replaceBRWithEmptyBlock(html: string) {
function removeProseMirrorHackNodes (line 268) | function removeProseMirrorHackNodes(html: string) {
FILE: apps/editor/src/utils/map.ts
class Map (line 9) | class Map<K, V> implements Mapable<K, V> {
method constructor (line 14) | constructor() {
method getKeyIndex (line 19) | private getKeyIndex(key: K) {
method get (line 23) | get(key: K): V {
method set (line 27) | set(key: K, value: V) {
method has (line 39) | has(key: K) {
method delete (line 43) | delete(key: K) {
method forEach (line 55) | forEach(callback: (value: V, key: K, map: Mapable<K, V>) => void, this...
method clear (line 63) | clear() {
FILE: apps/editor/src/utils/markdown.ts
function hasSpecificTypeAncestor (line 13) | function hasSpecificTypeAncestor(mdNode: MdNode, ...types: MdNodeType[]) {
function getMdStartLine (line 23) | function getMdStartLine(mdNode: MdNode) {
function getMdEndLine (line 27) | function getMdEndLine(mdNode: MdNode) {
function getMdStartCh (line 31) | function getMdStartCh(mdNode: MdNode) {
function getMdEndCh (line 35) | function getMdEndCh(mdNode: MdNode) {
function isMultiLineNode (line 39) | function isMultiLineNode(mdNode: MdNode) {
function isHTMLNode (line 45) | function isHTMLNode(mdNode: MdNode) {
function isStyledInlineNode (line 51) | function isStyledInlineNode(mdNode: MdNode) {
function isCodeBlockNode (line 64) | function isCodeBlockNode(mdNode: MdNode): mdNode is CodeBlockMdNode {
function isCustomBlockNode (line 68) | function isCustomBlockNode(mdNode: MdNode): mdNode is CustomBlockMdNode {
function isListNode (line 72) | function isListNode(mdNode: MdNode): mdNode is ListItemMdNode {
function isOrderedListNode (line 76) | function isOrderedListNode(mdNode: MdNode): mdNode is ListItemMdNode {
function isBulletListNode (line 80) | function isBulletListNode(mdNode: MdNode): mdNode is ListItemMdNode {
function isTableCellNode (line 84) | function isTableCellNode(mdNode: MdNode): mdNode is TableCellMdNode {
function isInlineNode (line 88) | function isInlineNode(mdNode: MdNode) {
function findClosestNode (line 107) | function findClosestNode(
function traverseParentNodes (line 123) | function traverseParentNodes(
function addOffsetPos (line 136) | function addOffsetPos(originPos: MdPos, offset: number): MdPos {
function setOffsetPos (line 140) | function setOffsetPos(originPos: MdPos, newOffset: number): MdPos {
function getInlineMarkdownText (line 144) | function getInlineMarkdownText(mdNode: MdNode) {
function isContainer (line 168) | function isContainer(node: MdNode) {
function getChildrenText (line 194) | function getChildrenText(node: MdNode) {
FILE: apps/editor/src/viewer.ts
constant TASK_ATTR_NAME (line 16) | const TASK_ATTR_NAME = 'data-task';
constant DISABLED_TASK_ATTR_NAME (line 17) | const DISABLED_TASK_ATTR_NAME = 'data-task-disabled';
constant TASK_CHECKED_CLASS_NAME (line 18) | const TASK_CHECKED_CLASS_NAME = 'checked';
function registerHTMLTagToWhitelist (line 20) | function registerHTMLTagToWhitelist(convertorMap: CustomHTMLRenderer) {
class ToastUIEditorViewer (line 49) | class ToastUIEditorViewer {
method constructor (line 58) | constructor(options: ViewerOptions) {
method toggleTask (line 145) | private toggleTask(ev: MouseEvent) {
method setMarkdown (line 166) | setMarkdown(markdown: string) {
method on (line 181) | on(type: string, handler: Handler) {
method off (line 189) | off(type: string) {
method addHook (line 198) | addHook(type: string, handler: Handler) {
method destroy (line 206) | destroy() {
method isViewer (line 216) | isViewer() {
method isMarkdownMode (line 224) | isMarkdownMode() {
method isWysiwygMode (line 232) | isWysiwygMode() {
FILE: apps/editor/src/widget/rules.ts
function unwrapWidgetSyntax (line 12) | function unwrapWidgetSyntax(text: string) {
function createWidgetContent (line 25) | function createWidgetContent(info: string, text: string) {
function widgetToDOM (line 29) | function widgetToDOM(info: string, text: string) {
function getWidgetRules (line 41) | function getWidgetRules() {
function setWidgetRules (line 45) | function setWidgetRules(rules: WidgetRule[]) {
function mergeNodes (line 52) | function mergeNodes(nodes: ProsemirrorNode[], text: string, schema: Sche...
function createNodesWithWidget (line 74) | function createNodesWithWidget(text: string, schema: Schema, ruleIndex =...
function getWidgetContent (line 117) | function getWidgetContent(widgetNode: CustomInlineMdNode) {
FILE: apps/editor/src/widget/widgetNode.ts
function widgetNodeView (line 5) | function widgetNodeView(pmNode: ProsemirrorNode) {
function isWidgetNode (line 15) | function isWidgetNode(pmNode: ProsemirrorNode) {
class Widget (line 19) | class Widget extends SpecNode {
method name (line 20) | get name() {
method schema (line 24) | get schema() {
FILE: apps/editor/src/wysiwyg/adaptor/mdLikeNode.ts
function isPmNode (line 6) | function isPmNode(node: ProsemirrorNode | Mark): node is ProsemirrorNode {
function isContainer (line 10) | function isContainer(type: string) {
function createMdLikeNode (line 35) | function createMdLikeNode(node: ProsemirrorNode | Mark): MdLikeNode {
FILE: apps/editor/src/wysiwyg/adaptor/wwToDOMAdaptor.ts
type TokenToDOM (line 21) | interface TokenToDOM<T> {
method openTag (line 29) | openTag(token, stack) {
method closeTag (line 44) | closeTag(_, stack) {
method html (line 51) | html(token, stack) {
method text (line 54) | text(token, stack) {
class WwToDOMAdaptor (line 61) | class WwToDOMAdaptor implements ToDOMAdaptor {
method constructor (line 68) | constructor(linkAttributes: LinkAttributes | null, customRenderer: Cus...
method generateTokens (line 81) | private generateTokens(node: ProsemirrorNode | Mark) {
method toDOMNode (line 105) | private toDOMNode(node: ProsemirrorNode | Mark) {
method getToDOMNode (line 114) | getToDOMNode(name: string) {
FILE: apps/editor/src/wysiwyg/clipboard/paste.ts
constant START_FRAGMENT_COMMENT (line 7) | const START_FRAGMENT_COMMENT = '<!--StartFragment-->';
constant END_FRAGMENT_COMMENT (line 8) | const END_FRAGMENT_COMMENT = '<!--EndFragment-->';
function getContentBetweenFragmentComments (line 10) | function getContentBetweenFragmentComments(html: string) {
function convertMsoTableToCompletedTable (line 21) | function convertMsoTableToCompletedTable(html: string) {
function changePastedHTML (line 36) | function changePastedHTML(html: string) {
function getMaxColumnCount (line 47) | function getMaxColumnCount(rows: Node[]) {
function createCells (line 55) | function createCells(orgRow: Node, maxColumnCount: number, cell: NodeTyp...
function copyTableHeadRow (line 73) | function copyTableHeadRow(orgRow: Node, maxColumnCount: number, schema: ...
function copyTableBodyRow (line 80) | function copyTableBodyRow(orgRow: Node, maxColumnCount: number, schema: ...
function creatTableBodyDummyRow (line 87) | function creatTableBodyDummyRow(columnCount: number, schema: Schema) {
function createRowsFromPastingTable (line 100) | function createRowsFromPastingTable(tableContent: Fragment) {
function createTableHead (line 119) | function createTableHead(tableHeadRow: Node, maxColumnCount: number, sch...
function createTableBody (line 125) | function createTableBody(tableBodyRows: Node[], maxColumnCount: number, ...
function createTableFromPastingTable (line 139) | function createTableFromPastingTable(
function changePastedSlice (line 163) | function changePastedSlice(slice: Slice, schema: Schema, isInTable: bool...
FILE: apps/editor/src/wysiwyg/clipboard/pasteMsoList.ts
constant MSO_CLASS_NAME_LIST_PARA (line 16) | const MSO_CLASS_NAME_LIST_PARA = 'p.MsoListParagraph';
type ListItemData (line 18) | interface ListItemData {
function isFromMso (line 28) | function isFromMso(html: string) {
function getListItemContents (line 32) | function getListItemContents(para: HTMLElement) {
function createListItemDataFromParagraph (line 63) | function createListItemDataFromParagraph(para: HTMLElement, index: numbe...
function addListItemDetailData (line 86) | function addListItemDetailData(data: ListItemData, prevData: ListItemDat...
function createListData (line 109) | function createListData(paras: HTMLElement[]) {
function makeList (line 128) | function makeList(listData: ListItemData[]) {
function makeListFromParagraphs (line 147) | function makeListFromParagraphs(paras: HTMLElement[]) {
function isMsoListParagraphEnd (line 154) | function isMsoListParagraphEnd(node: HTMLElement) {
function convertMsoParagraphsToList (line 165) | function convertMsoParagraphsToList(html: string) {
FILE: apps/editor/src/wysiwyg/clipboard/pasteToTable.ts
type PastingRangeInfo (line 22) | interface PastingRangeInfo {
type ReplacedCellsOffsets (line 31) | interface ReplacedCellsOffsets {
constant DUMMY_CELL_SIZE (line 38) | const DUMMY_CELL_SIZE = 4;
constant TR_NODES_SIZE (line 39) | const TR_NODES_SIZE = 2;
function getDummyCellSize (line 41) | function getDummyCellSize(dummyCellCount: number) {
function createPastingCells (line 45) | function createPastingCells(
function getPastingRangeInfo (line 79) | function getPastingRangeInfo(
function addReplacedOffsets (line 115) | function addReplacedOffsets(
function expandColumns (line 135) | function expandColumns(
function expandRows (line 175) | function expandRows(
function replaceCells (line 205) | function replaceCells(
function pasteToTable (line 224) | function pasteToTable(view: EditorView, slice: Slice) {
function setSelection (line 264) | function setSelection(view: EditorView, cellsOffsets: ReplacedCellsOffse...
function canMerge (line 281) | function canMerge(map: TableOffsetMap, pastingInfo: PastingRangeInfo) {
FILE: apps/editor/src/wysiwyg/command/list.ts
type Attrs (line 8) | interface Attrs {
type WrapperInfo (line 12) | interface WrapperInfo {
function findWrappingOutside (line 17) | function findWrappingOutside(range: NodeRange, type: NodeType) {
function findWrappingInside (line 30) | function findWrappingInside(range: NodeRange, type: NodeType) {
function findWrappers (line 51) | function findWrappers(range: NodeRange, innerRange: NodeRange, nodeType:...
function wrapInList (line 70) | function wrapInList(
function changeToList (line 122) | function changeToList(tr: Transaction, range: NodeRange, list: NodeType,...
function getBeforeLineListItem (line 154) | function getBeforeLineListItem(doc: ProsemirrorNode, offset: number) {
function toggleTaskListItems (line 165) | function toggleTaskListItems(tr: Transaction, { $from, $to }: NodeRange) {
function changeListType (line 188) | function changeListType(tr: Transaction, { $from, $to }: NodeRange, list...
function changeList (line 219) | function changeList(list: NodeType): Command {
function toggleTask (line 238) | function toggleTask(): Command {
function sinkListItem (line 257) | function sinkListItem(listItem: NodeType): Command {
function liftToOuterList (line 297) | function liftToOuterList(tr: Transaction, range: NodeRange, listItem: No...
function liftOutOfList (line 324) | function liftOutOfList(tr: Transaction, range: NodeRange) {
function liftListItem (line 377) | function liftListItem(listItem: NodeType): Command {
function splitListItem (line 398) | function splitListItem(listItem: NodeType): Command {
FILE: apps/editor/src/wysiwyg/command/table.ts
type CellPosition (line 9) | type CellPosition = [rowIdx: number, colIdx: number];
type CellOffsetFn (line 11) | type CellOffsetFn = ([rowIdx, colIdx]: CellPosition, map: TableOffsetMap...
type CellOffsetFnMap (line 13) | type CellOffsetFnMap = {
function isInFirstListItem (line 24) | function isInFirstListItem(
function isInLastListItem (line 34) | function isInLastListItem(pos: ResolvedPos) {
function canMoveToBeforeCell (line 63) | function canMoveToBeforeCell(
function canMoveToAfterCell (line 86) | function canMoveToAfterCell(
function canMoveBetweenCells (line 109) | function canMoveBetweenCells(
function canBeOutOfTable (line 131) | function canBeOutOfTable(
function addParagraphBeforeTable (line 145) | function addParagraphBeforeTable(tr: Transaction, map: TableOffsetMap, s...
function addParagraphAfterTable (line 154) | function addParagraphAfterTable(
function getRightCellOffset (line 168) | function getRightCellOffset([rowIdx, colIdx]: CellPosition, map: TableOf...
function getLeftCellOffset (line 194) | function getLeftCellOffset([rowIdx, colIdx]: CellPosition, map: TableOff...
function getUpCellOffset (line 216) | function getUpCellOffset([rowIdx, colIdx]: CellPosition, map: TableOffse...
function getDownCellOffset (line 226) | function getDownCellOffset([rowIdx, colIdx]: CellPosition, map: TableOff...
function moveToCell (line 244) | function moveToCell(
function canSelectTableNode (line 262) | function canSelectTableNode(
function selectNode (line 279) | function selectNode(tr: Transaction, pos: ResolvedPos, depth: number) {
FILE: apps/editor/src/wysiwyg/helper/node.ts
type NodeAttrs (line 4) | type NodeAttrs = Record<string, any>;
type CustomAttrs (line 6) | interface CustomAttrs {
function findNodeBy (line 11) | function findNodeBy(
function isListNode (line 34) | function isListNode({ type }: ProsemirrorNode) {
function isInListNode (line 38) | function isInListNode(pos: ResolvedPos) {
function isInTableNode (line 46) | function isInTableNode(pos: ResolvedPos) {
function findListItem (line 53) | function findListItem(pos: ResolvedPos) {
function createDOMInfoParsedRawHTML (line 57) | function createDOMInfoParsedRawHTML(tag: string) {
function createCellAttrs (line 70) | function createCellAttrs(attrs: NodeAttrs) {
function createParsedCellDOM (line 80) | function createParsedCellDOM(tag: string) {
function getDefaultCustomAttrs (line 99) | function getDefaultCustomAttrs(): CustomAttrs {
function getCustomAttrs (line 106) | function getCustomAttrs(attrs: Record<string, any>) {
FILE: apps/editor/src/wysiwyg/helper/table.ts
function createTableHeadRow (line 9) | function createTableHeadRow(columnCount: number, schema: Schema, data?: ...
function createTableBodyRows (line 23) | function createTableBodyRows(
function createDummyCells (line 48) | function createDummyCells(
function findCellElement (line 65) | function findCellElement(node: HTMLElement, root: Element) {
function findCell (line 77) | function findCell(pos: ResolvedPos) {
function getResolvedSelection (line 84) | function getResolvedSelection(selection: Selection | CellSelection) {
function getTableContentFromSlice (line 101) | function getTableContentFromSlice(slice: Slice) {
function getRowAndColumnCount (line 129) | function getRowAndColumnCount({
function setAttrs (line 141) | function setAttrs(cell: ProsemirrorNode, attrs: Record<string, any>) {
FILE: apps/editor/src/wysiwyg/helper/tableOffsetMap.ts
type CellInfo (line 5) | interface CellInfo {
type SelectionInfo (line 10) | interface SelectionInfo {
type SpanMap (line 17) | interface SpanMap {
type RowInfo (line 21) | interface RowInfo {
type SpanInfo (line 28) | interface SpanInfo {
type OffsetMap (line 35) | interface OffsetMap {
type CreateOffsetMapMixin (line 57) | type CreateOffsetMapMixin = (
class TableOffsetMap (line 66) | class TableOffsetMap {
method constructor (line 75) | constructor(table: Node, tableRows: Node[], tableStartPos: number, row...
method create (line 82) | static create(cellPos: ResolvedPos): TableOffsetMap | null {
method totalRowCount (line 115) | get totalRowCount() {
method totalColumnCount (line 119) | get totalColumnCount() {
method tableStartOffset (line 123) | get tableStartOffset() {
method tableEndOffset (line 127) | get tableEndOffset() {
method getCellInfo (line 131) | getCellInfo(rowIdx: number, colIdx: number) {
method posAt (line 135) | posAt(rowIdx: number, colIdx: number): number {
method getNodeAndPos (line 152) | getNodeAndPos(rowIdx: number, colIdx: number) {
method extendedRowspan (line 161) | extendedRowspan(rowIdx: number, colIdx: number) {
method extendedColspan (line 165) | extendedColspan(rowIdx: number, colIdx: number) {
method getRowspanCount (line 169) | getRowspanCount(rowIdx: number, colIdx: number) {
method getColspanCount (line 173) | getColspanCount(rowIdx: number, colIdx: number) {
method decreaseColspanCount (line 177) | decreaseColspanCount(rowIdx: number, colIdx: number) {
method decreaseRowspanCount (line 181) | decreaseRowspanCount(rowIdx: number, colIdx: number) {
method getColspanStartInfo (line 185) | getColspanStartInfo(rowIdx: number, colIdx: number): SpanInfo | null {
method getRowspanStartInfo (line 189) | getRowspanStartInfo(rowIdx: number, colIdx: number): SpanInfo | null {
method getCellStartOffset (line 193) | getCellStartOffset(rowIdx: number, colIdx: number) {
method getCellEndOffset (line 199) | getCellEndOffset(rowIdx: number, colIdx: number) {
method getCellIndex (line 205) | getCellIndex(cellPos: ResolvedPos): [rowIdx: number, colIdx: number] {
method getRectOffsets (line 218) | getRectOffsets(startCellPos: ResolvedPos, endCellPos = startCellPos) {
method getSpannedOffsets (line 231) | getSpannedOffsets(selectionInfo: SelectionInfo): SelectionInfo {
function mixinTableOffsetMapPrototype (line 264) | function mixinTableOffsetMapPrototype(
FILE: apps/editor/src/wysiwyg/marks/code.ts
class Code (line 9) | class Code extends Mark {
method name (line 10) | get name() {
method schema (line 14) | get schema() {
method commands (line 38) | commands(): EditorCommand {
method keymaps (line 42) | keymaps() {
FILE: apps/editor/src/wysiwyg/marks/emph.ts
class Emph (line 9) | class Emph extends Mark {
method name (line 10) | get name() {
method schema (line 14) | get schema() {
method italic (line 40) | private italic(): EditorCommand {
method commands (line 44) | commands() {
method keymaps (line 48) | keymaps() {
FILE: apps/editor/src/wysiwyg/marks/link.ts
class Link (line 13) | class Link extends Mark {
method constructor (line 16) | constructor(linkAttributes: LinkAttributes) {
method name (line 21) | get name() {
method schema (line 25) | get schema() {
method addLink (line 63) | private addLink(): EditorCommand {
method toggleLink (line 90) | private toggleLink(): EditorCommand {
method commands (line 95) | commands() {
FILE: apps/editor/src/wysiwyg/marks/strike.ts
class Strike (line 9) | class Strike extends Mark {
method name (line 10) | get name() {
method schema (line 14) | get schema() {
method commands (line 40) | commands(): EditorCommand {
method keymaps (line 44) | keymaps() {
FILE: apps/editor/src/wysiwyg/marks/strong.ts
class Strong (line 9) | class Strong extends Mark {
method name (line 10) | get name() {
method schema (line 14) | get schema() {
method bold (line 40) | private bold(): EditorCommand {
method commands (line 44) | commands() {
method keymaps (line 48) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/blockQuote.ts
class BlockQuote (line 13) | class BlockQuote extends NodeSchema {
method name (line 14) | get name() {
method schema (line 18) | get schema() {
method commands (line 33) | commands(): EditorCommand {
method keymaps (line 37) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/bulletList.ts
class BulletList (line 14) | class BulletList extends NodeSchema {
method name (line 15) | get name() {
method schema (line 19) | get schema() {
method changeList (line 34) | private changeList(): Command {
method commands (line 38) | commands() {
method keymaps (line 45) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/codeBlock.ts
class CodeBlock (line 11) | class CodeBlock extends NodeSchema {
method name (line 12) | get name() {
method schema (line 16) | get schema() {
method commands (line 52) | commands(): EditorCommand {
method moveCursor (line 56) | moveCursor(direction: 'up' | 'down'): Command {
method keymaps (line 87) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/customBlock.ts
class CustomBlock (line 6) | class CustomBlock extends NodeSchema {
method name (line 7) | get name() {
method schema (line 11) | get schema() {
method commands (line 37) | commands(): EditorCommand {
FILE: apps/editor/src/wysiwyg/nodes/doc.ts
class Doc (line 3) | class Doc extends Node {
method name (line 4) | get name() {
method schema (line 8) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/frontMatter.ts
class FrontMatter (line 8) | class FrontMatter extends NodeSchema {
method name (line 9) | get name() {
method schema (line 13) | get schema() {
method commands (line 31) | commands(): EditorCommand {
method keymaps (line 43) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/heading.ts
class Heading (line 9) | class Heading extends NodeSchema {
method name (line 10) | get name() {
method levels (line 14) | get levels() {
method schema (line 18) | get schema() {
method commands (line 50) | commands(): EditorCommand {
FILE: apps/editor/src/wysiwyg/nodes/html.ts
function getChildrenHTML (line 15) | function getChildrenHTML(node: MdNode, typeName: string) {
function getHTMLAttrsByHTMLString (line 21) | function getHTMLAttrsByHTMLString(html: string) {
function getHTMLAttrs (line 38) | function getHTMLAttrs(dom: HTMLElement) {
function sanitizeDOM (line 45) | function sanitizeDOM(
method htmlBlock (line 64) | htmlBlock(typeName: string, sanitizeHTML: Sanitizer, wwToDOMAdaptor: ToD...
method htmlInline (line 94) | htmlInline(typeName: string, sanitizeHTML: Sanitizer, wwToDOMAdaptor: To...
function createHTMLSchemaMap (line 119) | function createHTMLSchemaMap(
FILE: apps/editor/src/wysiwyg/nodes/htmlComment.ts
class HTMLComment (line 8) | class HTMLComment extends NodeSchema {
method name (line 9) | get name() {
method schema (line 13) | get schema() {
method commands (line 26) | commands(): EditorCommand {
method keymaps (line 38) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/image.ts
class Image (line 10) | class Image extends NodeSchema {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method addImage (line 57) | private addImage(): EditorCommand {
method commands (line 76) | commands() {
FILE: apps/editor/src/wysiwyg/nodes/listItem.ts
class ListItem (line 7) | class ListItem extends NodeSchema {
method name (line 8) | get name() {
method schema (line 12) | get schema() {
method liftToPrevListItem (line 62) | private liftToPrevListItem(): Command {
method keymaps (line 93) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/orderedList.ts
class OrderedList (line 10) | class OrderedList extends NodeSchema {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method commands (line 48) | commands(): EditorCommand {
method keymaps (line 52) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/paragraph.ts
class Paragraph (line 6) | class Paragraph extends NodeSchema {
method name (line 7) | get name() {
method schema (line 11) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/table.ts
type AddTablePayload (line 38) | interface AddTablePayload {
type AlignColumnPayload (line 44) | interface AlignColumnPayload {
type Direction (line 49) | const enum Direction {
type ColDirection (line 56) | type ColDirection = Direction.LEFT | Direction.RIGHT;
type RowDirection (line 57) | type RowDirection = Direction.UP | Direction.DOWN;
function getTargetRowInfo (line 59) | function getTargetRowInfo(
function getRowRanges (line 80) | function getRowRanges(map: TableOffsetMap, rowIdx: number, totalColumnCo...
class Table (line 87) | class Table extends NodeSchema {
method name (line 88) | get name() {
method schema (line 92) | get schema() {
method addTable (line 107) | private addTable(): EditorCommand<AddTablePayload> {
method removeTable (line 135) | private removeTable(): EditorCommand {
method addColumn (line 152) | private addColumn(direction: ColDirection): EditorCommand {
method removeColumn (line 179) | private removeColumn(): EditorCommand {
method addRow (line 216) | private addRow(direction: Direction.UP | Direction.DOWN): EditorCommand {
method removeRow (line 252) | private removeRow(): EditorCommand {
method alignColumn (line 285) | private alignColumn(): EditorCommand<AlignColumnPayload> {
method moveToCell (line 314) | private moveToCell(direction: Direction): Command {
method moveInCell (line 342) | private moveInCell(direction: Direction): Command {
method deleteCells (line 396) | private deleteCells(): Command {
method exitTable (line 423) | private exitTable(): Command {
method commands (line 447) | commands() {
method keymaps (line 461) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/tableBody.ts
class TableBody (line 6) | class TableBody extends NodeSchema {
method name (line 7) | get name() {
method schema (line 11) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/tableBodyCell.ts
class TableBodyCell (line 6) | class TableBodyCell extends NodeSchema {
method name (line 7) | get name() {
method schema (line 11) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/tableHead.ts
class TableHead (line 10) | class TableHead extends NodeSchema {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/tableHeadCell.ts
class TableHeadCell (line 11) | class TableHeadCell extends NodeSchema {
method name (line 12) | get name() {
method schema (line 16) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/tableRow.ts
class TableRow (line 6) | class TableRow extends NodeSchema {
method name (line 7) | get name() {
method schema (line 11) | get schema() {
FILE: apps/editor/src/wysiwyg/nodes/text.ts
class Text (line 8) | class Text extends Node {
method name (line 9) | get name() {
method schema (line 13) | get schema() {
method addSpaces (line 19) | private addSpaces(): Command {
method removeSpaces (line 33) | private removeSpaces(): Command {
method keymaps (line 56) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodes/thematicBreak.ts
constant ROOT_BLOCK_DEPTH (line 8) | const ROOT_BLOCK_DEPTH = 1;
class ThematicBreak (line 10) | class ThematicBreak extends Node {
method name (line 11) | get name() {
method schema (line 15) | get schema() {
method hr (line 30) | private hr(): EditorCommand {
method commands (line 58) | commands() {
method keymaps (line 62) | keymaps() {
FILE: apps/editor/src/wysiwyg/nodeview/codeBlockView.ts
type GetPos (line 12) | type GetPos = (() => number) | boolean;
type InputPos (line 14) | type InputPos = {
constant WRAPPER_CLASS_NAME (line 19) | const WRAPPER_CLASS_NAME = 'toastui-editor-ww-code-block';
constant CODE_BLOCK_LANG_CLASS_NAME (line 20) | const CODE_BLOCK_LANG_CLASS_NAME = 'toastui-editor-ww-code-block-language';
class CodeBlockView (line 22) | class CodeBlockView implements NodeView {
method constructor (line 39) | constructor(node: ProsemirrorNode, view: EditorView, getPos: GetPos, e...
method createElement (line 50) | private createElement() {
method createCodeBlockElement (line 66) | private createCodeBlockElement() {
method createLanguageEditor (line 82) | private createLanguageEditor({ top, right }: InputPos) {
method bindDOMEvent (line 112) | private bindDOMEvent() {
method bindEvent (line 118) | private bindEvent() {
method changeLanguage (line 145) | private changeLanguage() {
method reset (line 159) | private reset() {
method clearTimer (line 168) | private clearTimer() {
method stopEvent (line 175) | stopEvent() {
method update (line 179) | update(node: ProsemirrorNode) {
method destroy (line 189) | destroy() {
FILE: apps/editor/src/wysiwyg/nodeview/customBlockView.ts
type GetPos (line 13) | type GetPos = (() => number) | boolean;
class CustomBlockView (line 15) | class CustomBlockView implements NodeView {
method constructor (line 34) | constructor(node: ProsemirrorNode, view: EditorView, getPos: GetPos, t...
method renderToolArea (line 54) | private renderToolArea() {
method renderCustomBlock (line 70) | private renderCustomBlock() {
method createInnerViewContainer (line 87) | private createInnerViewContainer() {
method closeEditor (line 143) | private closeEditor() {
method saveAndFinishEditing (line 152) | private saveAndFinishEditing() {
method cancelEditing (line 163) | private cancelEditing() {
method dispatchInner (line 185) | private dispatchInner(tr: Transaction) {
method update (line 207) | update(node: ProsemirrorNode) {
method stopEvent (line 221) | stopEvent(event: Event): boolean {
method ignoreMutation (line 229) | ignoreMutation() {
method destroy (line 233) | destroy() {
FILE: apps/editor/src/wysiwyg/nodeview/imageView.ts
type GetPos (line 13) | type GetPos = (() => number) | boolean;
constant IMAGE_LINK_CLASS_NAME (line 15) | const IMAGE_LINK_CLASS_NAME = 'image-link';
class ImageView (line 17) | class ImageView implements NodeView {
method constructor (line 30) | constructor(node: ProsemirrorNode, view: EditorView, getPos: GetPos, e...
method createElement (line 41) | private createElement() {
method createImageElement (line 56) | private createImageElement(node: ProsemirrorNode) {
method bindEvent (line 71) | private bindEvent() {
method stopEvent (line 102) | stopEvent() {
method destroy (line 106) | destroy() {
FILE: apps/editor/src/wysiwyg/plugins/selection/cellSelection.ts
function getSelectionRanges (line 7) | function getSelectionRanges(
function createTableFragment (line 24) | function createTableFragment(tableHead: Node, tableBody: Node) {
class CellSelection (line 36) | class CellSelection extends Selection {
method constructor (line 45) | constructor(startCellPos: ResolvedPos, endCellPos = startCellPos) {
method map (line 64) | map(doc: Node, mapping: Mappable) {
method eq (line 87) | eq(cell: CellSelection) {
method content (line 95) | content() {
method toJSON (line 135) | toJSON() {
FILE: apps/editor/src/wysiwyg/plugins/selection/tableSelection.ts
constant SELECTED_CELL_CLASS_NAME (line 10) | const SELECTED_CELL_CLASS_NAME = cls('cell-selected');
function drawCellSelection (line 12) | function drawCellSelection({ selection, doc }: EditorState) {
function tableSelection (line 27) | function tableSelection() {
FILE: apps/editor/src/wysiwyg/plugins/selection/tableSelectionView.ts
type EventHandlers (line 9) | interface EventHandlers {
constant MOUSE_RIGHT_BUTTON (line 17) | const MOUSE_RIGHT_BUTTON = 2;
class TableSelection (line 19) | class TableSelection {
method constructor (line 26) | constructor(view: EditorView) {
method init (line 40) | init() {
method handleMousedown (line 44) | handleMousedown(ev: Event) {
method handleMousemove (line 63) | handleMousemove(ev: Event) {
method handleMouseup (line 81) | handleMouseup() {
method bindEvent (line 91) | bindEvent() {
method unbindEvent (line 98) | unbindEvent() {
method getCellPos (line 105) | getCellPos({ clientX, clientY }: MouseEvent) {
method setCellSelection (line 123) | setCellSelection(startCellPos: ResolvedPos, endCellPos: ResolvedPos) {
method destroy (line 139) | destroy() {
FILE: apps/editor/src/wysiwyg/plugins/tableContextMenu.ts
type ContextMenuInfo (line 9) | interface ContextMenuInfo {
function getContextMenuGroups (line 63) | function getContextMenuGroups(eventEmitter: Emitter, inTableHead: boolea...
function tableContextMenu (line 80) | function tableContextMenu(eventEmitter: Emitter) {
FILE: apps/editor/src/wysiwyg/plugins/task.ts
function task (line 7) | function task() {
FILE: apps/editor/src/wysiwyg/plugins/toolbarState.ts
type ListType (line 9) | type ListType = 'bulletList' | 'orderedList' | 'taskList';
constant EXCEPT_TYPES (line 11) | const EXCEPT_TYPES = ['image', 'link', 'customBlock', 'frontMatter'];
constant MARK_TYPES (line 12) | const MARK_TYPES = ['strong', 'strike', 'emph', 'code'];
constant LIST_TYPES (line 13) | const LIST_TYPES: ListType[] = ['bulletList', 'orderedList', 'taskList'];
function getToolbarStateType (line 15) | function getToolbarStateType(node: Node, parentNode: Node) {
function setListNodeToolbarState (line 29) | function setListNodeToolbarState(type: ToolbarStateKeys, nodeTypeState: ...
function setMarkTypeStates (line 39) | function setMarkTypeStates(
function getToolbarState (line 56) | function getToolbarState(selection: Selection, doc: Node, schema: Schema) {
function toolbarStateHighlight (line 84) | function toolbarStateHighlight(eventEmitter: Emitter) {
FILE: apps/editor/src/wysiwyg/specCreator.ts
function createSpecs (line 32) | function createSpecs(linkAttributes: LinkAttributes) {
FILE: apps/editor/src/wysiwyg/wwEditor.ts
type WindowWithClipboard (line 35) | interface WindowWithClipboard extends Window {
type WysiwygOptions (line 39) | interface WysiwygOptions {
type PluginNodeVeiwFn (line 48) | type PluginNodeVeiwFn = (node: ProsemirrorNode, view: EditorView, getPos...
type PluginNodeViews (line 50) | interface PluginNodeViews {
constant CONTENTS_CLASS_NAME (line 54) | const CONTENTS_CLASS_NAME = cls('contents');
class WysiwygEditor (line 56) | class WysiwygEditor extends EditorBase {
method constructor (line 63) | constructor(eventEmitter: Emitter, options: WysiwygOptions) {
method createSpecs (line 91) | createSpecs() {
method createContext (line 95) | createContext() {
method createSchema (line 102) | createSchema(htmlSchemaMap?: HTMLSchemaMap) {
method createPlugins (line 109) | createPlugins() {
method createPluginNodeViews (line 119) | createPluginNodeViews() {
method createView (line 133) | createView() {
method createCommands (line 205) | createCommands() {
method getHTML (line 209) | getHTML() {
method getModel (line 213) | getModel() {
method getSelection (line 217) | getSelection(): [number, number] {
method getSchema (line 223) | getSchema() {
method replaceSelection (line 227) | replaceSelection(text: string, start?: number, end?: number) {
method deleteSelection (line 243) | deleteSelection(start?: number, end?: number) {
method getSelectedText (line 251) | getSelectedText(start?: number, end?: number) {
method setModel (line 262) | setModel(newDoc: ProsemirrorNode | [], cursorToEnd = false) {
method setSelection (line 272) | setSelection(start: number, end = start) {
method addWidget (line 279) | addWidget(node: Node, style: WidgetStyle, pos?: number) {
method replaceWithWidget (line 285) | replaceWithWidget(start: number, end: number, text: string) {
method getRangeInfoOfNode (line 292) | getRangeInfoOfNode(pos?: number) {
FILE: apps/editor/tsBannerGenerator.js
constant TS_BANNER (line 9) | const TS_BANNER = [
FILE: apps/editor/types/convertor.d.ts
type Attrs (line 5) | type Attrs = { [name: string]: any } | null;
type StackItem (line 7) | interface StackItem {
type ToWwConvertorState (line 13) | interface ToWwConvertorState {
type ToWwConvertor (line 27) | type ToWwConvertor = (
type ToWwConvertorMap (line 41) | type ToWwConvertorMap = Partial<Record<string, ToWwConvertor>>;
type FirstDelimFn (line 43) | type FirstDelimFn = (index: number) => string;
type ToMdConvertorState (line 45) | interface ToMdConvertorState {
type ToDOMAdaptor (line 63) | interface ToDOMAdaptor {
type HTMLToWwConvertor (line 67) | type HTMLToWwConvertor = (state: ToWwConvertorState, node: MdNode, openT...
type HTMLToWwConvertorMap (line 69) | type HTMLToWwConvertorMap = Partial<Record<string, HTMLToWwConvertor>>;
type FlattenHTMLToWwConvertorMap (line 71) | interface FlattenHTMLToWwConvertorMap {
type NodeInfo (line 75) | interface NodeInfo {
type MarkInfo (line 81) | interface MarkInfo {
type ToMdConvertorReturnValues (line 87) | interface ToMdConvertorReturnValues {
type ToMdNodeTypeWriter (line 94) | type ToMdNodeTypeWriter = (
type ToMdNodeTypeWriterMap (line 100) | type ToMdNodeTypeWriterMap = Partial<Record<WwNodeType, ToMdNodeTypeWrit...
type ToMdMarkTypeOption (line 102) | interface ToMdMarkTypeOption {
type ToMdMarkTypeOptions (line 108) | type ToMdMarkTypeOptions = Partial<Record<WwMarkType, ToMdMarkTypeOption...
type ToMdNodeTypeConvertor (line 110) | type ToMdNodeTypeConvertor = (state: ToMdConvertorState, nodeInfo: NodeI...
type ToMdNodeTypeConvertorMap (line 112) | type ToMdNodeTypeConvertorMap = Partial<Record<WwNodeType, ToMdNodeTypeC...
type ToMdMarkTypeConvertor (line 114) | type ToMdMarkTypeConvertor = (
type ToMdMarkTypeConvertorMap (line 119) | type ToMdMarkTypeConvertorMap = Partial<Record<WwMarkType, ToMdMarkTypeC...
type ToMdConvertorContext (line 121) | interface ToMdConvertorContext {
type ToMdConvertor (line 127) | type ToMdConvertor = (
type ToMdConvertorMap (line 132) | type ToMdConvertorMap = Partial<Record<WwNodeType | MdNodeType, ToMdConv...
type ToMdConvertors (line 134) | interface ToMdConvertors {
type InfoForPosSync (line 139) | interface InfoForPosSync {
FILE: apps/editor/types/editor.d.ts
type PreviewStyle (line 23) | type PreviewStyle = 'tab' | 'vertical';
type EditorType (line 24) | type EditorType = 'markdown' | 'wysiwyg';
type WidgetStyle (line 25) | type WidgetStyle = 'top' | 'bottom';
type WidgetRule (line 26) | interface WidgetRule {
type WidgetRuleMap (line 31) | type WidgetRuleMap = Record<string, WidgetRule>;
type EventMap (line 33) | interface EventMap {
type HookCallback (line 45) | type HookCallback = (url: string, text?: string) => void;
type HookMap (line 47) | type HookMap = {
type AutolinkParser (line 51) | type AutolinkParser = (
type ExtendedAutolinks (line 59) | type ExtendedAutolinks = boolean | AutolinkParser;
type LinkAttributeNames (line 61) | type LinkAttributeNames = 'rel' | 'target' | 'hreflang' | 'type';
type LinkAttributes (line 64) | type LinkAttributes = Partial<Record<LinkAttributeNames, string>>;
type Sanitizer (line 66) | type Sanitizer = (content: string) => string;
type HTMLMdNodeConvertor (line 68) | type HTMLMdNodeConvertor = (
type HTMLMdNodeConvertorMap (line 74) | type HTMLMdNodeConvertorMap = Record<string, HTMLMdNodeConvertor>;
type CustomHTMLRenderer (line 76) | type CustomHTMLRenderer = Partial<Record<string, HTMLConvertor | HTMLMdN...
type ViewerOptions (line 78) | interface ViewerOptions {
class Viewer (line 93) | class Viewer {
type I18n (line 115) | interface I18n {
type PluginContext (line 123) | interface PluginContext {
type PluginFn (line 146) | type PluginFn = (context: PluginContext, options?: any) => PluginInfo | ...
type EditorPlugin (line 147) | type EditorPlugin = PluginFn | [PluginFn, any];
type ContextInfo (line 148) | type ContextInfo = {
type EditorPluginInfo (line 154) | type EditorPluginInfo = ContextInfo & {
type EditorPluginsInfo (line 158) | type EditorPluginsInfo = ContextInfo & {
type EditorOptions (line 162) | interface EditorOptions {
type Slots (line 192) | interface Slots {
class EditorCore (line 198) | class EditorCore {
class Editor (line 292) | class Editor extends EditorCore {
type SelectionPos (line 298) | type SelectionPos = Sourcepos | [from: number, to: number];
type EditorPos (line 299) | type EditorPos = MdPos | number;
type NodeRangeInfo (line 300) | interface NodeRangeInfo {
type Base (line 305) | interface Base {
type SchemaMap (line 379) | type SchemaMap = Record<string, NodeSpec | MarkSpec>;
type HTMLSchemaMap (line 380) | interface HTMLSchemaMap {
FILE: apps/editor/types/event.d.ts
type Handler (line 3) | interface Handler {
type Emitter (line 8) | interface Emitter {
type EmitterConstructor (line 18) | interface EmitterConstructor {
type EventTypes (line 22) | type EventTypes =
FILE: apps/editor/types/map.d.ts
type Mapable (line 1) | interface Mapable<K, V> {
FILE: apps/editor/types/markdown.d.ts
type TableRowMdNode (line 3) | interface TableRowMdNode extends MdNode {
type TableBodyMdNode (line 7) | interface TableBodyMdNode extends MdNode {
type TableHeadMdNode (line 11) | interface TableHeadMdNode extends MdNode {
type MdLikeNode (line 18) | interface MdLikeNode {
type HTMLMdNode (line 38) | interface HTMLMdNode {
FILE: apps/editor/types/plugin.d.ts
type PluginProp (line 12) | type PluginProp = (eventEmitter?: Emitter) => Plugin;
type PluginNodeViews (line 14) | type PluginNodeViews = (
type NodeViewPropMap (line 21) | type NodeViewPropMap = Record<string, PluginNodeViews>;
type CommandFn (line 23) | type CommandFn<T = DefaultPayload> = (
type PluginCommandMap (line 29) | type PluginCommandMap = Record<string, CommandFn>;
type PluginToolbarItem (line 31) | interface PluginToolbarItem {
type PluginInfo (line 37) | interface PluginInfo {
type PluginInfoResult (line 49) | interface PluginInfoResult {
FILE: apps/editor/types/prosemirror-commands.d.ts
type Command (line 8) | interface Command<S extends Schema = any> {
type Keymap (line 12) | interface Keymap<S extends Schema = any> {
FILE: apps/editor/types/prosemirror-model.d.ts
type Fragment (line 4) | interface Fragment {
type ProsemirrorNode (line 10) | type ProsemirrorNode = Model.Node;
type NodeType (line 12) | interface NodeType {
FILE: apps/editor/types/prosemirror-transform.d.ts
type Step (line 5) | interface Step {
type Transform (line 11) | interface Transform {
FILE: apps/editor/types/spec.d.ts
type Context (line 8) | interface Context {
type MdContext (line 13) | interface MdContext extends Context {
type SpecContext (line 17) | interface SpecContext extends Context {
type MdSpecContext (line 21) | interface MdSpecContext extends SpecContext {
type DefaultPayload (line 25) | type DefaultPayload = Record<string, any>;
type Payload (line 26) | type Payload<T> = T extends infer P ? P : any;
type Dispatch (line 28) | type Dispatch = (tr: Transaction) => void;
type EditorCommand (line 29) | type EditorCommand<T = DefaultPayload> = (payload?: Payload<T>) => Command;
type EditorCommandMap (line 30) | type EditorCommandMap<T = DefaultPayload> = Record<string, EditorCommand...
type EditorCommandFn (line 31) | type EditorCommandFn<T = DefaultPayload> = (payload?: Payload<T>) => boo...
type EditorAllCommandMap (line 32) | type EditorAllCommandMap<T = DefaultPayload> = Record<string, EditorComm...
type SpecManager (line 34) | interface SpecManager {
FILE: apps/editor/types/toastmark.d.ts
type BlockNodeType (line 2) | type BlockNodeType =
type InlineNodeType (line 23) | type InlineNodeType =
type MdNodeType (line 36) | type MdNodeType = BlockNodeType | InlineNodeType;
type Pos (line 38) | type Pos = [number, number];
type MdPos (line 39) | type MdPos = Pos;
type Sourcepos (line 40) | type Sourcepos = [Pos, Pos];
type NodeWalker (line 42) | interface NodeWalker {
type MdNode (line 51) | interface MdNode {
type BlockMdNode (line 72) | interface BlockMdNode extends MdNode {
type ListData (line 83) | interface ListData {
type ListMdNode (line 95) | interface ListMdNode extends BlockMdNode {
type ListItemMdNode (line 99) | interface ListItemMdNode extends BlockMdNode {
type HeadingMdNode (line 104) | interface HeadingMdNode extends BlockMdNode {
type CodeBlockMdNode (line 109) | interface CodeBlockMdNode extends BlockMdNode {
type TableColumn (line 117) | interface TableColumn {
type TableMdNode (line 121) | interface TableMdNode extends BlockMdNode {
type TableCellMdNode (line 125) | interface TableCellMdNode extends BlockMdNode {
type RefDefMdNode (line 134) | interface RefDefMdNode extends BlockMdNode {
type CustomBlockMdNode (line 140) | interface CustomBlockMdNode extends BlockMdNode {
type HtmlBlockMdNode (line 146) | interface HtmlBlockMdNode extends BlockMdNode {
type LinkMdNode (line 150) | interface LinkMdNode extends MdNode {
type CodeMdNode (line 157) | interface CodeMdNode extends MdNode {
type CustomInlineMdNode (line 161) | interface CustomInlineMdNode extends MdNode {
type AutolinkParser (line 165) | type AutolinkParser = (
type CustomParser (line 173) | type CustomParser = (
type CustomParserMap (line 177) | type CustomParserMap = Partial<Record<MdNodeType, CustomParser>>;
type RefDefState (line 179) | type RefDefState = {
type RefMap (line 187) | type RefMap = {
type RefLinkCandidateMap (line 191) | type RefLinkCandidateMap = {
type RefDefCandidateMap (line 198) | type RefDefCandidateMap = {
type ParserOptions (line 202) | interface ParserOptions {
class Parser (line 213) | class Parser {
type HTMLConvertor (line 252) | type HTMLConvertor = (
type HTMLConvertorMap (line 258) | type HTMLConvertorMap = Partial<Record<string, HTMLConvertor>>;
type RendererOptions (line 260) | interface RendererOptions {
type Context (line 268) | interface Context {
type TagToken (line 277) | interface TagToken {
type OpenTagToken (line 283) | interface OpenTagToken extends TagToken {
type CloseTagToken (line 290) | interface CloseTagToken extends TagToken {
type TextToken (line 294) | interface TextToken {
type RawHTMLToken (line 299) | interface RawHTMLToken {
type HTMLToken (line 305) | type HTMLToken = OpenTagToken | CloseTagToken | TextToken | RawHTMLToken;
class Renderer (line 307) | class Renderer {
type RemovedNodeRange (line 319) | interface RemovedNodeRange {
type EditResult (line 324) | interface EditResult {
type EventName (line 329) | type EventName = 'change';
type EventHandlerMap (line 331) | type EventHandlerMap = {
class ToastMark (line 335) | class ToastMark {
FILE: apps/editor/types/ui.d.ts
type PopupOptions (line 1) | interface PopupOptions {
type ToolbarButtonOptions (line 7) | interface ToolbarButtonOptions {
type ToolbarCustomOptions (line 18) | interface ToolbarCustomOptions {
type ToolbarButtonInfo (line 29) | type ToolbarButtonInfo = {
type Component (line 33) | interface Component<T = {}, R = {}> {
type VNodeWalker (line 46) | interface VNodeWalker {
type VNode (line 56) | interface VNode {
type ComponentClass (line 84) | interface ComponentClass {
type Pos (line 88) | interface Pos {
type TooltipStyle (line 93) | type TooltipStyle = {
type PopupInfo (line 97) | interface PopupInfo {
type PopupInitialValues (line 106) | type PopupInitialValues = Record<string, any>;
type TabInfo (line 108) | interface TabInfo {
type ToolbarItemState (line 113) | interface ToolbarItemState {
type ToolbarStateMap (line 118) | interface ToolbarStateMap {
type ToolbarStateKeys (line 134) | type ToolbarStateKeys = keyof ToolbarStateMap;
type ToolbarItemInfo (line 136) | type ToolbarItemInfo = ToolbarCustomOptions | ToolbarButtonInfo;
type ToolbarGroupInfo (line 137) | type ToolbarGroupInfo = ToolbarItemInfo[] & { hidden?: boolean };
type ToolbarItemOptions (line 138) | type ToolbarItemOptions = ToolbarCustomOptions | ToolbarButtonOptions;
type ToolbarItem (line 139) | type ToolbarItem = (string | ToolbarItemOptions)[];
type ExecCommand (line 141) | type ExecCommand = (command: string, payload?: Record<string, any>) => v...
type HidePopup (line 142) | type HidePopup = () => void;
type SetPopupInfo (line 143) | type SetPopupInfo = (info: PopupInfo) => void;
type SetItemWidth (line 144) | type SetItemWidth = (name: string, width: number) => void;
type ShowTooltip (line 145) | type ShowTooltip = (el: HTMLElement) => void;
type HideTooltip (line 146) | type HideTooltip = () => void;
type GetBound (line 147) | type GetBound = (el: HTMLElement, active?: boolean) => Pos;
type ContextMenuItem (line 149) | interface ContextMenuItem {
type IndexList (line 156) | interface IndexList {
type DefaultUI (line 161) | interface DefaultUI {
FILE: apps/editor/types/wysiwyg.d.ts
type WwNodeType (line 4) | type WwNodeType =
type WwMarkType (line 29) | type WwMarkType = 'strong' | 'emph' | 'strike' | 'link' | 'code' | 'html';
type CellSelection (line 31) | interface CellSelection extends Selection {
type ColumnAlign (line 36) | type ColumnAlign = 'left' | 'right' | 'center';
FILE: apps/editor/webpack.config.js
constant ENTRY_EDITOR (line 14) | const ENTRY_EDITOR = './src/index.ts';
constant ENTRY_ONLY_STYLE (line 15) | const ENTRY_ONLY_STYLE = './src/indexEditorOnlyStyle.ts';
constant ENTRY_VIEWER (line 16) | const ENTRY_VIEWER = './src/indexViewer.ts';
function addFileManagerPlugin (line 21) | function addFileManagerPlugin(config) {
function addCopyPluginForThemeCss (line 37) | function addCopyPluginForThemeCss(config) {
function addMinifyPlugin (line 49) | function addMinifyPlugin(config) {
function addAnalyzerPlugin (line 62) | function addAnalyzerPlugin(config, type) {
function setDevelopConfig (line 71) | function setDevelopConfig(config) {
function setProductionConfig (line 90) | function setProductionConfig(config) {
function setProductionConfigForAll (line 106) | function setProductionConfigForAll(config) {
FILE: apps/react-editor/index.d.ts
type EventMapping (line 5) | interface EventMapping {
type EventNames (line 17) | type EventNames = keyof EventMapping;
type EditorProps (line 19) | type EditorProps = Omit<EditorOptions, 'el'> & Partial<EventMapping>;
type ViewerProps (line 20) | type ViewerProps = Omit<ViewerOptions, 'el'> & Partial<EventMapping>;
class Editor (line 22) | class Editor extends Component<EditorProps> {
class Viewer (line 28) | class Viewer extends Component<ViewerProps> {
FILE: apps/react-editor/src/editor.tsx
method getRootElement (line 10) | getRootElement() {
method getInstance (line 14) | getInstance() {
method getBindingEventNames (line 18) | getBindingEventNames() {
method bindEventHandlers (line 24) | bindEventHandlers(props: EditorProps) {
method getInitEvents (line 33) | getInitEvents() {
method componentDidMount (line 46) | componentDidMount() {
method shouldComponentUpdate (line 54) | shouldComponentUpdate(nextProps: EditorProps) {
method render (line 71) | render() {
FILE: apps/react-editor/src/viewer.tsx
class ViewerComponent (line 5) | class ViewerComponent extends React.Component<ViewerProps> {
method getRootElement (line 10) | getRootElement() {
method getInstance (line 14) | getInstance() {
method getBindingEventNames (line 18) | getBindingEventNames() {
method bindEventHandlers (line 24) | bindEventHandlers(props: ViewerProps) {
method getInitEvents (line 33) | getInitEvents() {
method componentDidMount (line 46) | componentDidMount() {
method shouldComponentUpdate (line 54) | shouldComponentUpdate(nextProps: ViewerProps) {
method render (line 60) | render() {
FILE: apps/vue-editor/demo/esm/index.js
method data (line 48) | data() {
FILE: apps/vue-editor/index.d.ts
type FunctionKeys (line 5) | type FunctionKeys<T extends object> = {
type EditorFnKeys (line 9) | type EditorFnKeys = FunctionKeys<ToastuiEditor>;
type ViewerFnKeys (line 10) | type ViewerFnKeys = FunctionKeys<ToastuiEditorViewer>;
class Editor (line 12) | class Editor extends Vue {
class Viewer (line 21) | class Viewer extends Vue {
FILE: apps/vue-editor/rollup.config.js
function transpile (line 8) | function transpile() {
FILE: apps/vue-editor/src/mixin/option.js
method data (line 20) | data() {
method invoke (line 46) | invoke(methodName, ...args) {
method destroyed (line 56) | destroyed() {
FILE: libs/toastmark/src/__sample__/index.ts
type TokenTypes (line 34) | type TokenTypes = typeof tokenTypes;
FILE: libs/toastmark/src/__test__/toastmark.spec.ts
function removeIdAttrFromAllNode (line 7) | function removeIdAttrFromAllNode(root: Node) {
function assertParseResult (line 19) | function assertParseResult(doc: ToastMark, lineTexts: string[], options?...
function assertResultNodes (line 31) | function assertResultNodes(doc: ToastMark, nodes: Node[], startIdx = 0) {
FILE: libs/toastmark/src/commonmark/__test__/helper.spec.ts
function pos (line 3) | function pos(line1: number, col1: number, line2: number, col2: number) {
function convertToArrayTree (line 10) | function convertToArrayTree(root: BlockNode, attrs: (keyof BlockNode)[]) {
FILE: libs/toastmark/src/commonmark/__test__/options.spec.ts
method emph (line 169) | emph(node: Node, { entering }) {
method text (line 177) | text(node: Node) {
FILE: libs/toastmark/src/commonmark/blockHandlers.ts
type Process (line 26) | const enum Process {
type BlockHandler (line 37) | interface BlockHandler {
method continue (line 45) | continue() {
method finalize (line 48) | finalize() {}
method canContain (line 49) | canContain() {
method continue (line 56) | continue() {
method finalize (line 59) | finalize() {}
method canContain (line 60) | canContain(t) {
method continue (line 67) | continue() {
method finalize (line 70) | finalize(_, block: ListNode) {
method canContain (line 91) | canContain(t) {
method continue (line 98) | continue(parser) {
method finalize (line 111) | finalize() {}
method canContain (line 112) | canContain(t) {
method continue (line 119) | continue(parser, container: ListNode) {
method canContain (line 134) | canContain(t) {
method continue (line 141) | continue() {
method finalize (line 145) | finalize() {}
method canContain (line 146) | canContain() {
method continue (line 153) | continue() {
method finalize (line 157) | finalize() {}
method canContain (line 158) | canContain() {
method continue (line 165) | continue(parser, container: CodeBlockNode) {
method finalize (line 198) | finalize(_, block: CodeBlockNode) {
method canContain (line 219) | canContain() {
method continue (line 226) | continue(parser, container: HtmlBlockNode) {
method finalize (line 231) | finalize(_, block) {
method canContain (line 235) | canContain() {
method continue (line 242) | continue(parser) {
method finalize (line 245) | finalize(parser, block) {
method canContain (line 265) | canContain() {
FILE: libs/toastmark/src/commonmark/blockHelper.ts
constant CODE_INDENT (line 3) | const CODE_INDENT = 4;
constant C_TAB (line 4) | const C_TAB = 9;
constant C_NEWLINE (line 5) | const C_NEWLINE = 10;
constant C_GREATERTHAN (line 6) | const C_GREATERTHAN = 62;
constant C_LESSTHAN (line 7) | const C_LESSTHAN = 60;
constant C_SPACE (line 8) | const C_SPACE = 32;
constant C_OPEN_BRACKET (line 9) | const C_OPEN_BRACKET = 91;
function endsWithBlankLine (line 17) | function endsWithBlankLine(block: BlockNode) {
function peek (line 36) | function peek(ln: string, pos: number) {
function isBlank (line 44) | function isBlank(s: string) {
function isSpaceOrTab (line 48) | function isSpaceOrTab(c: number) {
FILE: libs/toastmark/src/commonmark/blockStarts.ts
type Matched (line 19) | const enum Matched {
type BlockStart (line 24) | interface BlockStart {
function parseListMarker (line 47) | function parseListMarker(parser: Parser, container: ListNode): ListData ...
function listsMatch (line 122) | function listsMatch(listData: ListData, itemData: ListData) {
function isDisallowedDeepHeading (line 130) | function isDisallowedDeepHeading(parser: Parser, node: BlockNode) {
FILE: libs/toastmark/src/commonmark/blocks.ts
function document (line 31) | function document() {
class Parser (line 49) | class Parser implements BlockParser {
method constructor (line 73) | constructor(options?: Partial<ParserOptions>) {
method advanceOffset (line 104) | advanceOffset(count: number, columns = false) {
method advanceNextNonspace (line 132) | advanceNextNonspace() {
method findNextNonspace (line 138) | findNextNonspace() {
method addLine (line 164) | addLine() {
method addChild (line 182) | addChild(tag: BlockNodeType, offset: number) {
method closeUnmatchedBlocks (line 199) | closeUnmatchedBlocks() {
method finalize (line 216) | finalize(block: BlockNode, lineNumber: number) {
method processInlines (line 227) | processInlines(block: BlockNode) {
method incorporateLine (line 258) | incorporateLine(ln: string) {
method parse (line 405) | parse(input: string, lineTexts?: string[]) {
method partialParseStart (line 435) | partialParseStart(lineNumber: number, lines: string[]) {
method partialParseExtends (line 453) | partialParseExtends(lines: string[]) {
method partialParseFinish (line 459) | partialParseFinish() {
method setRefMaps (line 466) | setRefMaps(
method clearRefMaps (line 476) | clearRefMaps() {
FILE: libs/toastmark/src/commonmark/common.ts
constant ENTITY (line 4) | const ENTITY = '&(?:#x[a-f0-9]{1,6}|#[0-9]{1,7}|[a-z][a-z0-9]{1,31});';
constant C_BACKSLASH (line 5) | const C_BACKSLASH = 92;
constant ESCAPABLE (line 7) | const ESCAPABLE = '[!"#$%&\'()*+,./:;<=>?@[\\\\\\]^_`{|}~-]';
constant XMLSPECIAL (line 9) | const XMLSPECIAL = '[&<>"]';
function unescapeString (line 20) | function unescapeString(s: string) {
function normalizeURI (line 27) | function normalizeURI(uri: string) {
function replaceUnsafeChar (line 35) | function replaceUnsafeChar(s: string) {
function escapeXml (line 50) | function escapeXml(s: string) {
function repeat (line 57) | function repeat(str: string, count: number): string {
function last (line 65) | function last<T>(arr: T[]) {
function isEmpty (line 72) | function isEmpty(str: string) {
FILE: libs/toastmark/src/commonmark/custom/__test__/customBlock.spec.ts
method myCustom (line 7) | myCustom(node) {
FILE: libs/toastmark/src/commonmark/custom/customBlockHandler.ts
method continue (line 9) | continue(parser, container: CustomBlockNode) {
method finalize (line 26) | finalize(_, block: CustomBlockNode) {
method canContain (line 41) | canContain() {
FILE: libs/toastmark/src/commonmark/frontMatter/frontMatterHandler.ts
method continue (line 6) | continue(parser, container: BlockNode) {
method finalize (line 18) | finalize(_, block: BlockNode) {
method canContain (line 25) | canContain() {
FILE: libs/toastmark/src/commonmark/gfm/autoLinks.ts
constant DOMAIN (line 6) | const DOMAIN = '(?:[w-]+.)*[A-Za-z0-9-]+.[A-Za-z0-9-]+';
constant PATH (line 7) | const PATH = '[^<\\s]*[^<?!.,:*_?~\\s]';
constant EMAIL (line 8) | const EMAIL = '[\\w.+-]+@(?:[\\w-]+\\.)+[\\w-]+';
function trimUnmatchedTrailingParens (line 10) | function trimUnmatchedTrailingParens(source: string) {
function trimTrailingEntity (line 34) | function trimTrailingEntity(source: string) {
type LinkInfo (line 38) | interface LinkInfo {
function parseEmailLink (line 44) | function parseEmailLink(source: string) {
function parseUrlLink (line 62) | function parseUrlLink(source: string) {
function baseAutolinkParser (line 80) | function baseAutolinkParser(source: string) {
function convertExtAutoLinks (line 86) | function convertExtAutoLinks(walker: NodeWalker, autolinkParser: boolean...
FILE: libs/toastmark/src/commonmark/gfm/tableBlockHandler.ts
method continue (line 5) | continue() {
method finalize (line 8) | finalize() {}
method canContain (line 9) | canContain(t: MdNodeType) {
method continue (line 16) | continue() {
method finalize (line 19) | finalize() {}
method canContain (line 20) | canContain(t: MdNodeType) {
method continue (line 27) | continue() {
method finalize (line 30) | finalize() {}
method canContain (line 31) | canContain(t: MdNodeType) {
method continue (line 38) | continue() {
method finalize (line 41) | finalize() {}
method canContain (line 42) | canContain(t: MdNodeType) {
method continue (line 49) | continue() {
method finalize (line 52) | finalize() {}
method canContain (line 53) | canContain() {
method continue (line 60) | continue() {
method finalize (line 63) | finalize() {}
method canContain (line 64) | canContain(t: MdNodeType) {
method continue (line 71) | continue() {
method finalize (line 74) | finalize() {}
method canContain (line 75) | canContain() {
FILE: libs/toastmark/src/commonmark/gfm/tableBlockStart.ts
function parseRowContent (line 7) | function parseRowContent(content: string): [number, string[]] {
function generateTableCells (line 33) | function generateTableCells(
function getColumnFromDelimCell (line 75) | function getColumnFromDelimCell(cellNode: TableCellNode) {
FILE: libs/toastmark/src/commonmark/gfm/taskListItem.ts
function taskListItemFinalize (line 7) | function taskListItemFinalize(_: Parser, block: ListNode) {
FILE: libs/toastmark/src/commonmark/inlines.ts
constant C_NEWLINE (line 13) | const C_NEWLINE = 10;
constant C_ASTERISK (line 14) | const C_ASTERISK = 42;
constant C_UNDERSCORE (line 15) | const C_UNDERSCORE = 95;
constant C_BACKTICK (line 16) | const C_BACKTICK = 96;
constant C_OPEN_BRACKET (line 17) | const C_OPEN_BRACKET = 91;
constant C_CLOSE_BRACKET (line 18) | const C_CLOSE_BRACKET = 93;
constant C_TILDE (line 19) | const C_TILDE = 126;
constant C_LESSTHAN (line 20) | const C_LESSTHAN = 60;
constant C_BANG (line 21) | const C_BANG = 33;
constant C_BACKSLASH (line 22) | const C_BACKSLASH = 92;
constant C_AMPERSAND (line 23) | const C_AMPERSAND = 38;
constant C_OPEN_PAREN (line 24) | const C_OPEN_PAREN = 40;
constant C_CLOSE_PAREN (line 25) | const C_CLOSE_PAREN = 41;
constant C_COLON (line 26) | const C_COLON = 58;
constant C_SINGLEQUOTE (line 27) | const C_SINGLEQUOTE = 39;
constant C_DOUBLEQUOTE (line 28) | const C_DOUBLEQUOTE = 34;
constant C_DOLLAR (line 29) | const C_DOLLAR = 36;
constant ESCAPED_CHAR (line 32) | const ESCAPED_CHAR = `\\\\${ESCAPABLE}`;
type DelimiterCC (line 66) | type DelimiterCC =
type Delimiter (line 74) | type Delimiter = {
type Bracket (line 85) | type Bracket = {
class InlineParser (line 96) | class InlineParser {
method constructor (line 112) | constructor(options: ParserOptions) {
method sourcepos (line 118) | sourcepos(start: number, end?: number): [number, number] | Sourcepos {
method nextLine (line 129) | nextLine() {
method match (line 136) | match(re: RegExp) {
method peek (line 147) | peek() {
method spnl (line 155) | spnl() {
method parseBackticks (line 166) | parseBackticks(block: BlockNode) {
method parseBackslash (line 213) | parseBackslash(block: BlockNode) {
method parseAutolink (line 234) | parseAutolink(block: BlockNode) {
method parseHtmlTag (line 261) | parseHtmlTag(block: BlockNode) {
method scanDelims (line 278) | scanDelims(cc: number) {
method handleDelim (line 334) | handleDelim(cc: DelimiterCC, block: BlockNode) {
method removeDelimiter (line 377) | removeDelimiter(delim: Delimiter) {
method removeDelimitersBetween (line 389) | removeDelimitersBetween(bottom: Delimiter, top: Delimiter) {
method processEmphasis (line 401) | processEmphasis(stackBottom: Delimiter | null) {
method parseLinkTitle (line 572) | parseLinkTitle() {
method parseLinkDestination (line 582) | parseLinkDestination() {
method parseLinkLabel (line 627) | parseLinkLabel() {
method parseOpenBracket (line 636) | parseOpenBracket(block: BlockNode) {
method parseBang (line 650) | parseBang(block: BlockNode) {
method parseCloseBracket (line 672) | parseCloseBracket(block: BlockNode) {
method addBracket (line 801) | addBracket(node: Node, index: number, image: boolean) {
method removeBracket (line 816) | removeBracket() {
method parseEntity (line 823) | parseEntity(block: BlockNode) {
method parseString (line 835) | parseString(block: BlockNode) {
method parseNewline (line 873) | parseNewline(block: BlockNode) {
method parseReference (line 900) | parseReference(block: BlockNode, refMap: RefMap) {
method mergeTextNodes (line 993) | mergeTextNodes(walker: NodeWalker) {
method getReferenceDefSourcepos (line 1023) | getReferenceDefSourcepos(block: BlockNode): Sourcepos {
method parseInline (line 1062) | parseInline(block: BlockNode) {
method parse (line 1121) | parse(block: BlockNode) {
FILE: libs/toastmark/src/commonmark/node.ts
function isContainer (line 23) | function isContainer(node: Node) {
function getNodeById (line 52) | function getNodeById(id: number) {
function removeNodeById (line 56) | function removeNodeById(id: number) {
function removeAllNode (line 60) | function removeAllNode() {
class Node (line 64) | class Node implements MdNode {
method constructor (line 79) | constructor(nodeType: MdNodeType, sourcepos?: Sourcepos) {
method isContainer (line 91) | isContainer() {
method unlink (line 95) | unlink() {
method replaceWith (line 111) | replaceWith(node: Node) {
method insertAfter (line 116) | insertAfter(sibling: Node) {
method insertBefore (line 132) | insertBefore(sibling: Node) {
method appendChild (line 146) | appendChild(child: Node) {
method prependChild (line 159) | prependChild(child: Node) {
method walker (line 172) | walker() {
class BlockNode (line 177) | class BlockNode extends Node implements BlockMdNode {
method constructor (line 187) | constructor(nodeType: BlockNodeType, sourcepos?: Sourcepos) {
class ListNode (line 193) | class ListNode extends BlockNode implements ListMdNode {
class HeadingNode (line 197) | class HeadingNode extends BlockNode implements HeadingMdNode {
class CodeBlockNode (line 202) | class CodeBlockNode extends BlockNode implements CodeBlockMdNode {
class TableNode (line 211) | class TableNode extends BlockNode implements TableMdNode {
class TableCellNode (line 215) | class TableCellNode extends BlockNode implements TableCellMdNode {
class RefDefNode (line 223) | class RefDefNode extends BlockNode implements RefDefMdNode {
class CustomBlockNode (line 229) | class CustomBlockNode extends BlockNode implements CustomBlockMdNode {
class HtmlBlockNode (line 235) | class HtmlBlockNode extends BlockNode implements HtmlBlockMdNode {
class LinkNode (line 239) | class LinkNode extends Node implements LinkMdNode {
class CodeNode (line 246) | class CodeNode extends Node implements CodeMdNode {
class CustomInlineNode (line 250) | class CustomInlineNode extends Node implements CustomInlineMdNode {
function createNode (line 266) | function createNode(type: MdNodeType, sourcepos?: Sourcepos) {
function isCodeBlock (line 306) | function isCodeBlock(node: Node): node is CodeBlockNode {
function isHtmlBlock (line 310) | function isHtmlBlock(node: Node): node is HtmlBlockNode {
function isHeading (line 314) | function isHeading(node: Node): node is HeadingNode {
function isList (line 318) | function isList(node: Node): node is ListNode {
function isTable (line 322) | function isTable(node: Node): node is TableNode {
function isRefDef (line 326) | function isRefDef(node: Node): node is RefDefNode {
function isCustomBlock (line 330) | function isCustomBlock(node: Node): node is CustomBlockNode {
function isCustomInline (line 334) | function isCustomInline(node: Node) {
function text (line 338) | function text(s: string, sourcepos?: Sourcepos) {
FILE: libs/toastmark/src/commonmark/nodeWalker.ts
class NodeWalker (line 4) | class NodeWalker implements BaseNodeWalker {
method constructor (line 9) | constructor(root: Node) {
method next (line 15) | next() {
method resumeAt (line 46) | resumeAt(node: Node, entering: boolean) {
FILE: libs/toastmark/src/commonmark/rawHtml.ts
constant TAGNAME (line 1) | const TAGNAME = '[A-Za-z][A-Za-z0-9-]*';
constant ATTRIBUTENAME (line 2) | const ATTRIBUTENAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*';
constant UNQUOTEDVALUE (line 3) | const UNQUOTEDVALUE = '[^"\'=<>`\\x00-\\x20]+';
constant SINGLEQUOTEDVALUE (line 5) | const SINGLEQUOTEDVALUE = "'[^']*'";
constant DOUBLEQUOTEDVALUE (line 6) | const DOUBLEQUOTEDVALUE = '"[^"]*"';
constant ATTRIBUTEVALUE (line 8) | const ATTRIBUTEVALUE = `(?:${UNQUOTEDVALUE}|${SINGLEQUOTEDVALUE}|${DOUBL...
constant ATTRIBUTEVALUESPEC (line 9) | const ATTRIBUTEVALUESPEC = `${'(?:\\s*=\\s*'}${ATTRIBUTEVALUE})`;
constant ATTRIBUTE (line 10) | const ATTRIBUTE = `${'(?:\\s+'}${ATTRIBUTENAME}${ATTRIBUTEVALUESPEC}?)`;
constant OPENTAG (line 12) | const OPENTAG = `<${TAGNAME}${ATTRIBUTE}*\\s*/?>`;
constant CLOSETAG (line 13) | const CLOSETAG = `</${TAGNAME}\\s*[>]`;
constant HTMLCOMMENT (line 15) | const HTMLCOMMENT = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->';
constant PROCESSINGINSTRUCTION (line 16) | const PROCESSINGINSTRUCTION = '[<][?].*?[?][>]';
constant DECLARATION (line 17) | const DECLARATION = '<![A-Z]+\\s+[^>]*>';
constant CDATA (line 18) | const CDATA = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>';
constant HTMLTAG (line 20) | const HTMLTAG = `(?:${OPENTAG}|${CLOSETAG}|${HTMLCOMMENT}|${PROCESSINGIN...
FILE: libs/toastmark/src/helper.ts
function last (line 4) | function last<T>(arr: T[] | string) {
function normalizeReference (line 11) | function normalizeReference(str: string) {
function iterateObject (line 20) | function iterateObject<T>(obj: T, iteratee: (key: keyof T, value: T[keyo...
function omit (line 26) | function omit<T extends object>(obj: T, ...propNames: (keyof T)[]) {
function isEmptyObj (line 34) | function isEmptyObj<T extends object>(obj: T) {
function clearObj (line 38) | function clearObj<T extends object>(obj: T) {
FILE: libs/toastmark/src/html/__test__/render.spec.ts
method paragraph (line 94) | paragraph(_, { entering, origin }) {
method tableCell (line 117) | tableCell(_, { origin }) {
FILE: libs/toastmark/src/html/baseConvertors.ts
constant CUSTOM_SYNTAX_LENGTH (line 13) | const CUSTOM_SYNTAX_LENGTH = 4;
method heading (line 16) | heading(node, { entering }) {
method text (line 24) | text(node) {
method softbreak (line 31) | softbreak(_, { options }) {
method linebreak (line 38) | linebreak() {
method emph (line 45) | emph(_, { entering }) {
method strong (line 52) | strong(_, { entering }) {
method paragraph (line 59) | paragraph(node, { entering }) {
method thematicBreak (line 74) | thematicBreak() {
method blockQuote (line 83) | blockQuote(_, { entering }) {
method list (line 92) | list(node, { entering }) {
method item (line 108) | item(_, { entering }) {
method htmlInline (line 116) | htmlInline(node, { options }) {
method htmlBlock (line 122) | htmlBlock(node, { options }) {
method code (line 136) | code(node) {
method codeBlock (line 144) | codeBlock(node) {
method link (line 161) | link(node: Node, { entering }) {
method image (line 177) | image(node: Node, { getChildrenText, skipChildren }) {
method customBlock (line 194) | customBlock(node, context, convertors) {
method frontMatter (line 215) | frontMatter(node) {
method customInline (line 229) | customInline(node, context, convertors) {
FILE: libs/toastmark/src/html/gfmConvertors.ts
method strike (line 5) | strike(_, { entering }) {
method item (line 12) | item(node: Node, { entering }) {
method table (line 51) | table(_, { entering }) {
method tableHead (line 59) | tableHead(_, { entering }) {
method tableBody (line 67) | tableBody(_, { entering }) {
method tableRow (line 75) | tableRow(node: Node, { entering }) {
method tableCell (line 113) | tableCell(node: Node, { entering }) {
FILE: libs/toastmark/src/html/renderer.ts
function getChildrenText (line 27) | function getChildrenText(node: Node) {
class Renderer (line 41) | class Renderer implements HTMLRenderer {
method constructor (line 48) | constructor(customOptions?: Partial<RendererOptions>) {
method createConvertors (line 55) | private createConvertors() {
method getConvertors (line 87) | getConvertors() {
method getOptions (line 91) | getOptions() {
method render (line 95) | render(rootNode: Node): string {
method renderHTMLNode (line 146) | renderHTMLNode(node: HTMLToken) {
method generateOpenTagString (line 163) | private generateOpenTagString(node: OpenTagToken) {
method generateCloseTagString (line 185) | private generateCloseTagString({ tagName }: CloseTagToken) {
method addNewLine (line 189) | private addNewLine() {
method addOuterNewLine (line 195) | private addOuterNewLine(node: TagToken | RawHTMLToken) {
method addInnerNewLine (line 201) | private addInnerNewLine(node: TagToken) {
method renderTextNode (line 207) | private renderTextNode(node: TextToken) {
method renderRawHtmlNode (line 211) | private renderRawHtmlNode(node: RawHTMLToken) {
method renderElementNode (line 217) | private renderElementNode(node: OpenTagToken | CloseTagToken) {
FILE: libs/toastmark/src/html/tagFilter.ts
function filterDisallowedTags (line 15) | function filterDisallowedTags(str: string) {
FILE: libs/toastmark/src/nodeHelper.ts
type Compare (line 4) | const enum Compare {
function comparePos (line 10) | function comparePos(p1: Pos, p2: Pos) {
function compareRangeAndPos (line 26) | function compareRangeAndPos([startPos, endPos]: Sourcepos, pos: Pos) {
function getAllParents (line 36) | function getAllParents(node: Node) {
function removeNextUntil (line 45) | function removeNextUntil(node: Node, last: Node) {
function getChildNodes (line 69) | function getChildNodes(parent: Node) {
function insertNodesBefore (line 79) | function insertNodesBefore(target: Node, nodes: Node[]) {
function prependChildNodes (line 85) | function prependChildNodes(parent: Node, nodes: Node[]) {
function updateNextLineNumbers (line 91) | function updateNextLineNumbers(base: Node | null, diff: number) {
function compareRangeAndLine (line 109) | function compareRangeAndLine([startPos, endPos]: Sourcepos, line: number) {
function findChildNodeAtLine (line 119) | function findChildNodeAtLine(parent: Node, line: number) {
function lastLeafNode (line 135) | function lastLeafNode(node: Node) {
function sameLineTopAncestor (line 142) | function sameLineTopAncestor(node: Node) {
function findFirstNodeAtLine (line 153) | function findFirstNodeAtLine(parent: Node, line: number) {
function findNodeAtPosition (line 178) | function findNodeAtPosition(parent: Node, pos: Pos) {
function toString (line 202) | function toString(node: Node | null) {
function findNodeById (line 213) | function findNodeById(id: number) {
function invokeNextUntil (line 217) | function invokeNextUntil(callback: Function, start: Node | null, end: No...
function isUnlinked (line 232) | function isUnlinked(id: number) {
FILE: libs/toastmark/src/toastmark.ts
type ParseResult (line 42) | type ParseResult = EditResult & { nextNode: Node | null };
function canBeContinuedListItem (line 44) | function canBeContinuedListItem(lineText: string) {
function canBeContinuedTableBody (line 54) | function canBeContinuedTableBody(lineText: string) {
function createRefDefState (line 58) | function createRefDefState(node: RefDefNode) {
class ToastMark (line 69) | class ToastMark implements ToastMarkParser {
method constructor (line 79) | constructor(contents?: string, options?: Partial<ParserOptions>) {
method updateLineTexts (line 93) | private updateLineTexts(startPos: Pos, endPos: Pos, newText: string) {
method updateRootNodeState (line 109) | private updateRootNodeState() {
method replaceRangeNodes (line 135) | private replaceRangeNodes(
method getNodeRange (line 156) | private getNodeRange(startPos: Pos, endPos: Pos) {
method trigger (line 168) | private trigger(eventName: EventName, param: any) {
method extendEndLine (line 174) | private extendEndLine(line: number) {
method parseRange (line 181) | private parseRange(
method getRemovedNodeRange (line 229) | private getRemovedNodeRange(
method markDeletedRefMap (line 246) | private markDeletedRefMap(extStartNode: BlockNode | null, extEndNode: ...
method replaceWithNewRefDefState (line 265) | private replaceWithNewRefDefState(nodes: BlockNode[]) {
method replaceWithRefDefCandidate (line 282) | private replaceWithRefDefCandidate() {
method getRangeWithRefDef (line 299) | private getRangeWithRefDef(
method parse (line 324) | private parse(startPos: Pos, endPos: Pos, lineDiff = 0): ParseResult {
method parseRefLink (line 351) | private parseRefLink() {
method removeUnlinkedCandidate (line 371) | private removeUnlinkedCandidate() {
method editMarkdown (line 383) | editMarkdown(startPos: Pos, endPos: Pos, newText: string) {
method getLineTexts (line 404) | getLineTexts() {
method getRootNode (line 408) | getRootNode() {
method findNodeAtPosition (line 412) | findNodeAtPosition(pos: Pos) {
method findFirstNodeAtLine (line 420) | findFirstNodeAtLine(line: number) {
method on (line 424) | on(eventName: EventName, callback: () => void) {
method off (line 428) | off(eventName: EventName, callback: Function) {
method findNodeById (line 434) | findNodeById(id: number) {
method removeAllNode (line 438) | removeAllNode() {
FILE: libs/toastmark/types/node.d.ts
type BlockNodeType (line 1) | type BlockNodeType =
type InlineNodeType (line 22) | type InlineNodeType =
type MdNodeType (line 35) | type MdNodeType = BlockNodeType | InlineNodeType;
type Pos (line 37) | type Pos = [number, number];
type Sourcepos (line 38) | type Sourcepos = [Pos, Pos];
type NodeWalker (line 40) | interface NodeWalker {
type MdNode (line 49) | interface MdNode {
type BlockMdNode (line 70) | interface BlockMdNode extends MdNode {
type ListData (line 81) | interface ListData {
type ListMdNode (line 93) | interface ListMdNode extends BlockMdNode {
type ListItemMdNode (line 97) | interface ListItemMdNode extends BlockMdNode {
type HeadingMdNode (line 102) | interface HeadingMdNode extends BlockMdNode {
type CodeBlockMdNode (line 107) | interface CodeBlockMdNode extends BlockMdNode {
type TableColumn (line 115) | interface TableColumn {
type TableMdNode (line 119) | interface TableMdNode extends BlockMdNode {
type TableCellMdNode (line 123) | interface TableCellMdNode extends BlockMdNode {
type CustomBlockMdNode (line 132) | interface CustomBlockMdNode extends BlockMdNode {
type RefDefMdNode (line 136) | interface RefDefMdNode extends BlockMdNode {
type CustomBlockMdNode (line 142) | interface CustomBlockMdNode extends BlockMdNode {
type HtmlBlockMdNode (line 148) | interface HtmlBlockMdNode extends BlockMdNode {
type LinkMdNode (line 152) | interface LinkMdNode extends MdNode {
type CodeMdNode (line 159) | interface CodeMdNode extends MdNode {
type CustomInlineMdNode (line 163) | interface CustomInlineMdNode extends MdNode {
FILE: libs/toastmark/types/parser.d.ts
type AutolinkParser (line 3) | type AutolinkParser = (
type CustomParser (line 11) | type CustomParser = (
type CustomParserMap (line 15) | type CustomParserMap = Partial<Record<MdNodeType, CustomParser>>;
type RefDefState (line 17) | type RefDefState = {
type RefMap (line 25) | type RefMap = {
type RefLinkCandidateMap (line 29) | type RefLinkCandidateMap = {
type RefDefCandidateMap (line 36) | type RefDefCandidateMap = {
type ParserOptions (line 40) | interface ParserOptions {
class BlockParser (line 51) | class BlockParser {
FILE: libs/toastmark/types/renderer.d.ts
type HTMLConvertor (line 3) | type HTMLConvertor = (
type HTMLConvertorMap (line 9) | type HTMLConvertorMap = Partial<Record<MdNodeType | string, HTMLConverto...
type RendererOptions (line 11) | interface RendererOptions {
type Context (line 19) | interface Context {
type TagToken (line 28) | interface TagToken {
type OpenTagToken (line 34) | interface OpenTagToken extends TagToken {
type CloseTagToken (line 41) | interface CloseTagToken extends TagToken {
type TextToken (line 45) | interface TextToken {
type RawHTMLToken (line 50) | interface RawHTMLToken {
type HTMLToken (line 56) | type HTMLToken = OpenTagToken | CloseTagToken | TextToken | RawHTMLToken;
class HTMLRenderer (line 58) | class HTMLRenderer {
FILE: libs/toastmark/types/toastMark.d.ts
type RemovedNodeRange (line 4) | interface RemovedNodeRange {
type EditResult (line 9) | interface EditResult {
type EventName (line 14) | type EventName = 'change';
type EventHandlerMap (line 16) | type EventHandlerMap = {
class ToastMark (line 20) | class ToastMark {
FILE: plugins/chart/src/index.ts
constant DEFAULT_DELIMITER (line 48) | const DEFAULT_DELIMITER = /\s+/;
constant DELIMITERS (line 49) | const DELIMITERS = [',', '\t'];
constant MINIMUM_DELIM_CNT (line 50) | const MINIMUM_DELIM_CNT = 2;
constant SUPPORTED_CHART_TYPES (line 51) | const SUPPORTED_CHART_TYPES = ['bar', 'column', 'line', 'area', 'pie'];
constant CATEGORY_CHART_TYPES (line 52) | const CATEGORY_CHART_TYPES = ['line', 'area'];
constant DEFAULT_DIMENSION_OPTIONS (line 53) | const DEFAULT_DIMENSION_OPTIONS = {
constant RESERVED_KEYS (line 61) | const RESERVED_KEYS = ['type', 'url'];
type ChartType (line 71) | type ChartType = keyof typeof chart;
type ChartOptions (line 72) | type ChartOptions = BaseOptions & { editorChart: { type?: ChartType; url...
type ChartInstance (line 73) | type ChartInstance = BarChart | ColumnChart | AreaChart | LineChart | Pi...
type ChartData (line 74) | type ChartData = {
type ParserCallback (line 78) | type ParserCallback = (parsedInfo?: { data: ChartData; options?: ChartOp...
type OnSuccess (line 79) | type OnSuccess = (res: { data: any }) => void;
function parse (line 81) | function parse(text: string, callback: ParserCallback) {
function detectDelimiter (line 105) | function detectDelimiter(text: string) {
function parseToChartData (line 123) | function parseToChartData(text: string, delimiter?: string | RegExp) {
function createOptionKeys (line 169) | function createOptionKeys(keyString: string) {
function parseToChartOption (line 187) | function parseToChartOption(text: string) {
function getAdjustedDimension (line 225) | function getAdjustedDimension(size: 'auto' | number, containerWidth: num...
function getChartDimension (line 229) | function getChartDimension(
function setDefaultOptions (line 249) | function setDefaultOptions(
function destroyChart (line 276) | function destroyChart() {
function renderChart (line 288) | function renderChart(
function generateId (line 328) | function generateId() {
function clearTimer (line 334) | function clearTimer() {
function chartPlugin (line 352) | function chartPlugin(
FILE: plugins/chart/src/util.ts
function trimKeepingTabs (line 1) | function trimKeepingTabs(text: string) {
function isNumeric (line 5) | function isNumeric(text: string) {
function clamp (line 11) | function clamp(value: number, min: number, max: number) {
FILE: plugins/chart/types/index.d.ts
type PluginOptions (line 3) | interface PluginOptions {
FILE: plugins/chart/webpack.config.js
function getOutputConfig (line 9) | function getOutputConfig(isProduction, isCDN, minify) {
function getExternalsConfig (line 44) | function getExternalsConfig() {
function getOptimizationConfig (line 57) | function getOptimizationConfig(isProduction, minify) {
FILE: plugins/code-syntax-highlight/src/__test__/integration/codeHighlightPlugin.spec.ts
function getPreviewHTML (line 21) | function getPreviewHTML() {
function getWwEditorHTML (line 28) | function getWwEditorHTML() {
FILE: plugins/code-syntax-highlight/src/__test__/integration/codeHighlightPluginWithAllLangs.spec.ts
function getPreviewHTML (line 18) | function getPreviewHTML() {
function getWwEditorHTML (line 25) | function getWwEditorHTML() {
FILE: plugins/code-syntax-highlight/src/indexAll.ts
function plugin (line 17) | function plugin(context: PluginContext): PluginInfo {
FILE: plugins/code-syntax-highlight/src/nodeViews/codeSyntaxHighlightView.ts
type GetPos (line 11) | type GetPos = (() => number) | boolean;
type CodeBlockPos (line 13) | type CodeBlockPos = { top: number; right: number };
constant WRAPPER_CLASS_NAME (line 15) | const WRAPPER_CLASS_NAME = 'ww-code-block-highlighting';
function getCustomAttrs (line 17) | function getCustomAttrs(attrs: Record<string, any>) {
class CodeSyntaxHighlightView (line 23) | class CodeSyntaxHighlightView implements NodeView {
method constructor (line 33) | constructor(
method createElement (line 52) | private createElement() {
method createCodeBlockElement (line 73) | private createCodeBlockElement() {
method bindDOMEvent (line 94) | private bindDOMEvent() {
method bindEvent (line 102) | private bindEvent() {
method openLanguageSelectBox (line 126) | private openLanguageSelectBox(pos: CodeBlockPos) {
method changeLanguage (line 136) | private changeLanguage(language: string) {
method reset (line 154) | private reset() {
method stopEvent (line 163) | stopEvent() {
method update (line 167) | update(node: ProsemirrorNode) {
method destroy (line 177) | destroy() {
function createCodeSyntaxHighlightView (line 192) | function createCodeSyntaxHighlightView(languages: string[]) {
FILE: plugins/code-syntax-highlight/src/nodeViews/languageSelectBox.ts
constant WRAPPER_CLASS_NAME (line 11) | const WRAPPER_CLASS_NAME = 'code-block-language';
constant INPUT_CLASS_NANE (line 12) | const INPUT_CLASS_NANE = 'code-block-language-input';
constant LIST_CLASS_NAME (line 13) | const LIST_CLASS_NAME = 'code-block-language-list';
constant LANG_ATTR (line 14) | const LANG_ATTR = 'data-language';
constant CODE_BLOCK_PADDING (line 16) | const CODE_BLOCK_PADDING = 10;
function getButtonsHTML (line 18) | function getButtonsHTML(languages: string[]) {
class LanguageSelectBox (line 24) | class LanguageSelectBox {
method constructor (line 43) | constructor(rootEl: HTMLElement, eventEmitter: Emitter, languages: str...
method createElement (line 53) | private createElement() {
method createInputElement (line 66) | private createInputElement() {
method createLanguageListElement (line 82) | private createLanguageListElement() {
method bindDOMEvent (line 99) | private bindDOMEvent() {
method bindEvent (line 107) | private bindEvent() {
method activateSelectBox (line 168) | private activateSelectBox() {
method inactivateSelectBox (line 173) | private inactivateSelectBox() {
method toggleFocus (line 179) | private toggleFocus() {
method storeInputLanguage (line 187) | private storeInputLanguage() {
method activateButtonByIndex (line 196) | private activateButtonByIndex(index: number) {
method selectLanguage (line 209) | private selectLanguage(selectedLanguage: string) {
method selectPrevLanguage (line 214) | private selectPrevLanguage() {
method selectNextLanguage (line 224) | private selectNextLanguage() {
method hideList (line 234) | private hideList() {
method show (line 238) | show() {
method hide (line 242) | hide() {
method setLanguage (line 246) | setLanguage(language: string) {
method destroy (line 259) | destroy() {
FILE: plugins/code-syntax-highlight/src/plugin.ts
function codeSyntaxHighlightPlugin (line 10) | function codeSyntaxHighlightPlugin(
FILE: plugins/code-syntax-highlight/src/plugins/codeSyntaxHighlighting.ts
type ChildNodeInfo (line 11) | interface ChildNodeInfo {
type HighlightedNodeInfo (line 16) | interface HighlightedNodeInfo {
constant NODE_TYPE (line 21) | const NODE_TYPE = 'codeBlock';
function findCodeBlocks (line 23) | function findCodeBlocks(doc: ProsemirrorNode) {
function parseTokens (line 35) | function parseTokens(
function getDecorations (line 68) | function getDecorations(doc: ProsemirrorNode, context: PluginContext, pr...
function codeSyntaxHighlighting (line 101) | function codeSyntaxHighlighting(context: PluginContext, prism: PrismJs) {
FILE: plugins/code-syntax-highlight/src/renderers/toHTMLRenderers.ts
constant BACKTICK_COUNT (line 5) | const BACKTICK_COUNT = 3;
function getHTMLRenderers (line 7) | function getHTMLRenderers(prism: PrismJs) {
FILE: plugins/code-syntax-highlight/src/utils/common.ts
function flatten (line 1) | function flatten<T>(arr: T[]): T[] {
FILE: plugins/code-syntax-highlight/src/utils/dom.ts
function stringToNumber (line 1) | function stringToNumber(value: string) {
function isPositionInBox (line 5) | function isPositionInBox(style: CSSStyleDeclaration, offsetX: number, of...
function removeNode (line 20) | function removeNode(node: Node) {
constant CLS_PREFIX (line 26) | const CLS_PREFIX = 'toastui-editor-';
function cls (line 28) | function cls(...names: string[]) {
FILE: plugins/code-syntax-highlight/types/index.d.ts
type PrismJs (line 4) | type PrismJs = typeof Prism & {
type Window (line 9) | interface Window {
type PluginOptions (line 14) | type PluginOptions = {
FILE: plugins/code-syntax-highlight/types/prosemirror-transform.d.ts
type Transform (line 5) | interface Transform {
FILE: plugins/code-syntax-highlight/webpack.config.js
constant ENTRY (line 13) | const ENTRY = './src/index.ts';
constant ENTRY_ALL_LANG (line 14) | const ENTRY_ALL_LANG = './src/indexAll.ts';
function getOutputConfig (line 16) | function getOutputConfig(isProduction, isCDN, isAll, minify) {
function getOptimizationConfig (line 54) | function getOptimizationConfig(isProduction, minify) {
FILE: plugins/color-syntax/src/__test__/integration/colorSyntaxPlugin.spec.ts
function removeDataAttr (line 7) | function removeDataAttr(html: string) {
function assertWwEditorHTML (line 17) | function assertWwEditorHTML(html: string) {
function assertMdPreviewHTML (line 25) | function assertMdPreviewHTML(html: string) {
FILE: plugins/color-syntax/src/i18n/langs.ts
function addLangs (line 3) | function addLangs(i18n: I18n) {
FILE: plugins/color-syntax/src/index.ts
constant PREFIX (line 11) | const PREFIX = 'toastui-editor-';
function createApplyButton (line 13) | function createApplyButton(text: string) {
function createToolbarItemOption (line 22) | function createToolbarItemOption(colorPickerContainer: HTMLDivElement, i...
function createSelection (line 35) | function createSelection(
function getCurrentEditorEl (line 52) | function getCurrentEditorEl(colorPickerEl: HTMLElement, containerClassNa...
type ColorPickerOption (line 58) | interface ColorPickerOption {
function colorSyntaxPlugin (line 75) | function colorSyntaxPlugin(
FILE: plugins/color-syntax/src/utils/dom.ts
function hasClass (line 1) | function hasClass(element: HTMLElement, className: string) {
function findParentByClassName (line 5) | function findParentByClassName(el: HTMLElement, className: string) {
function removeProseMirrorHackNodes (line 15) | function removeProseMirrorHackNodes(html: string) {
FILE: plugins/color-syntax/types/index.d.ts
type PluginOptions (line 3) | interface PluginOptions {
FILE: plugins/color-syntax/types/prosemirror-model.d.ts
type Fragment (line 2) | interface Fragment {
FILE: plugins/color-syntax/types/tui-color-picker.d.ts
type ColorPickerOption (line 1) | interface ColorPickerOption {
type ColorPicker (line 7) | interface ColorPicker {
FILE: plugins/color-syntax/webpack.config.js
function getOutputConfig (line 13) | function getOutputConfig(isProduction, isCDN, minify) {
function getExternalsConfig (line 52) | function getExternalsConfig() {
function getOptimizationConfig (line 65) | function getOptimizationConfig(isProduction, minify) {
FILE: plugins/table-merged-cell/src/__test__/integration/convertor.spec.ts
function assertMdEditorText (line 8) | function assertMdEditorText(markdownText: string) {
function assertWYSIWYGHTML (line 12) | function assertWYSIWYGHTML(html: string) {
FILE: plugins/table-merged-cell/src/__test__/integration/markdown/mergedTablePreview.spec.ts
function removeDataAttr (line 8) | function removeDataAttr(html: string) {
function assertMdPreviewHTML (line 15) | function assertMdPreviewHTML(html: string) {
FILE: plugins/table-merged-cell/src/__test__/integration/wysiwyg/helper/cellSelection.ts
function getSelectionRanges (line 7) | function getSelectionRanges(
function createTableFragment (line 24) | function createTableFragment(tableHead: Node, tableBody: Node) {
class CellSelection (line 36) | class CellSelection extends Selection {
method constructor (line 45) | constructor(startCellPos: ResolvedPos, endCellPos = startCellPos) {
method map (line 64) | map(doc: Node, mapping: Mappable) {
method eq (line 87) | eq(cell: CellSelection) {
method content (line 95) | content() {
method toJSON (line 135) | toJSON() {
FILE: plugins/table-merged-cell/src/__test__/integration/wysiwyg/helper/tableOffsetMap.ts
type CellInfo (line 4) | interface CellInfo {
type SelectionInfo (line 9) | interface SelectionInfo {
type SpanMap (line 16) | interface SpanMap {
type RowInfo (line 20) | interface RowInfo {
function getSortedNumPair (line 27) | function getSortedNumPair(valueA: number, valueB: number) {
class TableOffsetMap (line 31) | class TableOffsetMap {
method constructor (line 40) | constructor(table: Node, tableRows: Node[], tableStartPos: number, row...
method create (line 47) | static create(cellPos: ResolvedPos): TableOffsetMap | null {
method totalRowCount (line 73) | get totalRowCount() {
method totalColumnCount (line 77) | get totalColumnCount() {
method tableStartOffset (line 81) | get tableStartOffset() {
method tableEndOffset (line 85) | get tableEndOffset() {
method getCellInfo (line 89) | getCellInfo(rowIdx: number, colIdx: number) {
method posAt (line 93) | posAt(rowIdx: number, colIdx: number): number {
method getNodeAndPos (line 110) | getNodeAndPos(rowIdx: number, colIdx: number) {
method extendedRowspan (line 116) | extendedRowspan(rowIdx: number, colIdx: number) {
method extendedColspan (line 122) | extendedColspan(rowIdx: number, colIdx: number) {
method getRowspanCount (line 128) | getRowspanCount(rowIdx: number, colIdx: number) {
method getColspanCount (line 134) | getColspanCount(rowIdx: number, colIdx: number) {
method decreaseColspanCount (line 140) | decreaseColspanCount(rowIdx: number, colIdx: number) {
method decreaseRowspanCount (line 149) | decreaseRowspanCount(rowIdx: number, colIdx: number) {
method getColspanStartInfo (line 158) | getColspanStartInfo(rowIdx: number, colIdx: number) {
method getRowspanStartInfo (line 176) | getRowspanStartInfo(rowIdx: number, colIdx: number) {
method getSpannedOffsets (line 194) | getSpannedOffsets(selectionInfo: SelectionInfo): SelectionInfo {
method getCellStartOffset (line 236) | getCellStartOffset(rowIdx: number, colIdx: number) {
method getCellEndOffset (line 242) | getCellEndOffset(rowIdx: number, colIdx: number) {
method getCellIndex (line 248) | getCellIndex(cellPos: ResolvedPos): [rowIdx: number, colIdx: number] {
method getRectOffsets (line 261) | getRectOffsets(startCellPos: ResolvedPos, endCellPos = startCellPos) {
function extendPrevRowspan (line 275) | function extendPrevRowspan(prevRowInfo: RowInfo, rowInfo: RowInfo) {
function extendPrevColspan (line 296) | function extendPrevColspan(
function createOffsetMap (line 317) | function createOffsetMap(headOrBody: Node, startOffset: number, startFro...
FILE: plugins/table-merged-cell/src/__test__/integration/wysiwyg/helper/utils.ts
function assertWYSIWYGHTML (line 4) | function assertWYSIWYGHTML(editor: Editor, html: string) {
function createEditor (line 11) | function createEditor() {
function removeProseMirrorHackNodes (line 38) | function removeProseMirrorHackNodes(html: string) {
FILE: plugins/table-merged-cell/src/__test__/integration/wysiwyg/mergeCells.spec.ts
function setCellSelection (line 21) | function setCellSelection(startPos: number, endPos: number) {
FILE: plugins/table-merged-cell/src/__test__/integration/wysiwyg/splitCells.spec.ts
function setCellSelection (line 21) | function setCellSelection(startPos: number, endPos: number) {
FILE: plugins/table-merged-cell/src/i18n/langs.ts
function addLangs (line 3) | function addLangs(i18n: I18n) {
FILE: plugins/table-merged-cell/src/index.ts
function tableMergedCellPlugin (line 12) | function tableMergedCellPlugin(context: PluginContext): PluginInfo {
FILE: plugins/table-merged-cell/src/markdown/parser.ts
type Attrs (line 4) | interface Attrs {
type CellSpanInfo (line 8) | type CellSpanInfo = [spanCount: number, content: string];
function getSpanInfo (line 10) | function getSpanInfo(content: string, type: SpanType, oppositeType: Span...
function extendTableCellIndexWithRowspanMap (line 23) | function extendTableCellIndexWithRowspanMap(
method tableRow (line 59) | tableRow(node: MergedTableRowMdNode, { entering }) {
method tableCell (line 75) | tableCell(node: MergedTableCellMdNode, { entering }) {
FILE: plugins/table-merged-cell/src/markdown/renderer.ts
method tableRow (line 7) | tableRow(node: MergedTableRowMdNode, { entering, origin }) {
method tableCell (line 45) | tableCell(node: MergedTableCellMdNode, { entering, origin }) {
FILE: plugins/table-merged-cell/src/wysiwyg/command/addColumn.ts
type ColDirection (line 6) | type ColDirection = Direction.LEFT | Direction.RIGHT;
function getTargetColInfo (line 8) | function getTargetColInfo(
function createAddColumnCommand (line 30) | function createAddColumnCommand(
FILE: plugins/table-merged-cell/src/wysiwyg/command/addRow.ts
type RowDirection (line 7) | type RowDirection = Direction.UP | Direction.DOWN;
function getTargetRowInfo (line 9) | function getTargetRowInfo(
function createAddRowCommand (line 35) | function createAddRowCommand(
FILE: plugins/table-merged-cell/src/wysiwyg/command/direction.ts
type Direction (line 2) | const enum Direction {
FILE: plugins/table-merged-cell/src/wysiwyg/command/mergeCells.ts
type RangeInfo (line 12) | interface RangeInfo {
function createMergeCellsCommand (line 19) | function createMergeCellsCommand(context: PluginContext, OffsetMap: Tabl...
function setSpanToRootCell (line 87) | function setSpanToRootCell(tr: Transaction, fragment: Fragment, rangeInf...
function appendFragment (line 102) | function appendFragment(rowIdx: number, colIdx: number, fragment: Fragme...
FILE: plugins/table-merged-cell/src/wysiwyg/command/removeColumn.ts
function createRemoveColumnCommand (line 5) | function createRemoveColumnCommand(
FILE: plugins/table-merged-cell/src/wysiwyg/command/removeRow.ts
function getRowRanges (line 5) | function getRowRanges(map: TableOffsetMap, rowIdx: number) {
function createRemoveRowCommand (line 21) | function createRemoveRowCommand(context: PluginContext, OffsetMap: Table...
FILE: plugins/table-merged-cell/src/wysiwyg/command/splitCells.ts
function getColspanEndIdx (line 7) | function getColspanEndIdx(rowIdx: number, colIdx: number, map: TableOffs...
function judgeInsertToNextRow (line 18) | function judgeInsertToNextRow(
function createSplitCellsCommand (line 33) | function createSplitCellsCommand(context: PluginContext, OffsetMap: Tabl...
function setCellSelection (line 95) | function setCellSelection(
FILE: plugins/table-merged-cell/src/wysiwyg/commandFactory.ts
function createCommands (line 11) | function createCommands(context: PluginContext, OffsetMap: TableOffsetMa...
FILE: plugins/table-merged-cell/src/wysiwyg/contextMenu.ts
constant TABLE_CELL_SELECT_CLASS (line 4) | const TABLE_CELL_SELECT_CLASS = '.toastui-editor-cell-selected';
function hasSpanAttr (line 6) | function hasSpanAttr(tableCell: Element) {
function hasSpanningCell (line 12) | function hasSpanningCell(headOrBody: Element) {
function isCellSelected (line 16) | function isCellSelected(headOrBody: Element) {
function createMergedTableContextMenu (line 20) | function createMergedTableContextMenu(context: PluginContext, tableCell:...
function addMergedTableContextMenu (line 44) | function addMergedTableContextMenu(context: PluginContext) {
FILE: plugins/table-merged-cell/src/wysiwyg/renderer.ts
type ColumnAlign (line 4) | type ColumnAlign = 'left' | 'right' | 'center';
constant DELIM_LENGH (line 5) | const DELIM_LENGH = 3;
function repeat (line 7) | function repeat(text: string, count: number) {
function createTableHeadDelim (line 17) | function createTableHeadDelim(textContent: string, columnAlign: ColumnAl...
function createDelim (line 37) | function createDelim(node: ProsemirrorNode) {
method tableHead (line 52) | tableHead(nodeInfo) {
method tableHeadCell (line 72) | tableHeadCell(nodeInfo) {
method tableBodyCell (line 75) | tableBodyCell(nodeInfo) {
FILE: plugins/table-merged-cell/src/wysiwyg/tableOffsetMapMixin.ts
method extendedRowspan (line 5) | extendedRowspan(rowIdx: number, colIdx: number) {
method extendedColspan (line 10) | extendedColspan(rowIdx: number, colIdx: number) {
method getRowspanCount (line 15) | getRowspanCount(rowIdx: number, colIdx: number) {
method getColspanCount (line 20) | getColspanCount(rowIdx: number, colIdx: number) {
method decreaseColspanCount (line 25) | decreaseColspanCount(rowIdx: number, colIdx: number) {
method decreaseRowspanCount (line 33) | decreaseRowspanCount(rowIdx: number, colIdx: number) {
method getColspanStartInfo (line 41) | getColspanStartInfo(rowIdx: number, colIdx: number) {
method getRowspanStartInfo (line 58) | getRowspanStartInfo(rowIdx: number, colIdx: number) {
method getSpannedOffsets (line 75) | getSpannedOffsets(selectionInfo: SelectionInfo): SelectionInfo {
function extendPrevRowspan (line 118) | function extendPrevRowspan(prevRowInfo: RowInfo, rowInfo: RowInfo) {
function extendPrevColspan (line 139) | function extendPrevColspan(
FILE: plugins/table-merged-cell/src/wysiwyg/util.ts
function findNodeBy (line 6) | function findNodeBy(pos: ResolvedPos, condition: (node: Node, depth: num...
function findCell (line 26) | function findCell(pos: ResolvedPos) {
function getResolvedSelection (line 33) | function getResolvedSelection(selection: Selection, context: PluginConte...
function getRowAndColumnCount (line 50) | function getRowAndColumnCount({
function setAttrs (line 59) | function setAttrs(cell: Node, attrs: Record<string, any>) {
function getCellSelectionClass (line 63) | function getCellSelectionClass(selection: Selection) {
function createDummyCells (line 69) | function createDummyCells(
FILE: plugins/table-merged-cell/types/index.d.ts
type TableBodyMdNode (line 12) | interface TableBodyMdNode extends MdNode {
type TableHeadMdNode (line 16) | interface TableHeadMdNode extends MdNode {
type SpanType (line 23) | type SpanType = '@cols' | '@rows';
type MergedTableRowMdNode (line 25) | interface MergedTableRowMdNode extends MdNode {
type MergedTableCellMdNode (line 34) | interface MergedTableCellMdNode extends TableCellMdNode {
type CellSelection (line 40) | interface CellSelection extends Selection {
type CellInfo (line 46) | interface CellInfo {
type SelectionInfo (line 52) | interface SelectionInfo {
type SpanMap (line 59) | interface SpanMap {
type RowInfo (line 63) | interface RowInfo {
type SpanInfo (line 70) | interface SpanInfo {
type TableOffsetMapFactory (line 77) | interface TableOffsetMapFactory {
type TableOffsetMap (line 81) | interface TableOffsetMap {
type CommandFn (line 103) | type CommandFn = PluginCommandMap[keyof PluginCommandMap];
FILE: plugins/table-merged-cell/types/prosemirror-transform.d.ts
type Transform (line 5) | interface Transform {
FILE: plugins/table-merged-cell/webpack.config.js
function getOutputConfig (line 13) | function getOutputConfig(isProduction, isCDN, minify) {
function getOptimizationConfig (line 51) | function getOptimizationConfig(isProduction, minify) {
FILE: plugins/uml/index.d.ts
type PluginOptions (line 3) | interface PluginOptions {
FILE: plugins/uml/src/__test__/integration/umlPlugin.spec.ts
function removeDataAttr (line 8) | function removeDataAttr(html: string) {
function assertWwEditorHTML (line 18) | function assertWwEditorHTML(html: string) {
function assertMdPreviewHTML (line 24) | function assertMdPreviewHTML(html: string) {
FILE: plugins/uml/src/index.ts
constant DEFAULT_RENDERER_URL (line 11) | const DEFAULT_RENDERER_URL = '//www.plantuml.com/plantuml/png/';
function createUMLTokens (line 13) | function createUMLTokens(text: string, rendererURL: string): HTMLToken[] {
function umlPlugin (line 38) | function umlPlugin(_: PluginContext, options: PluginOptions = {}): Plugi...
FILE: plugins/uml/webpack.config.js
function getOutputConfig (line 9) | function getOutputConfig(isProduction, isCDN, minify) {
function getExternalsConfig (line 44) | function getExternalsConfig(isProduction, isCDN) {
function getOptimizationConfig (line 52) | function getOptimizationConfig(isProduction, minify) {
FILE: scripts/publish-cdn.js
constant LOCAL_DIST_PATH (line 7) | const LOCAL_DIST_PATH = path.join(__dirname, '../apps/editor/dist/cdn');
constant STORAGE_API_URL (line 8) | const STORAGE_API_URL = 'https://api-storage.cloud.toast.com/v1';
constant IDENTITY_API_URL (line 9) | const IDENTITY_API_URL = 'https://api-identity.infrastructure.cloud.toas...
function getTOASTCloudContainer (line 16) | async function getTOASTCloudContainer(token) {
function getTOASTCloudToken (line 29) | async function getTOASTCloudToken() {
function publishToCdn (line 52) | function publishToCdn(token, localPath, cdnPath) {
function publish (line 76) | async function publish() {
Condensed preview — 498 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,009K chars).
[
{
"path": ".eslintrc.js",
"chars": 1942,
"preview": "module.exports = {\n root: true,\n plugins: ['prettier', '@typescript-eslint'],\n extends: ['tui/es6', 'plugin:prettier/"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 827,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: Bug\nassignees: ''\n---\n\n## Describe the "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 751,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: Enhancement, Need Discussion\nassigne"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 738,
"preview": "---\nname: Question\nabout: Create a question about the Editor\ntitle: ''\nlabels: Question\nassignees: ''\n---\n\n<!--\n To mak"
},
{
"path": ".github/dependabot.yml",
"chars": 549,
"preview": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where "
},
{
"path": ".github/stale.yml",
"chars": 1009,
"preview": "# Configuration for probot-stale - https://github.com/probot/stale\n\n# Number of days of inactivity before an Issue or Pu"
},
{
"path": ".github/workflows/check-types.yml",
"chars": 431,
"preview": "name: Editor Check Types\non: pull_request\njobs: \n check-types:\n name: Check Types\n runs-on: ubuntu-latest\n ste"
},
{
"path": ".github/workflows/examplePageTest.yml",
"chars": 1156,
"preview": "name: detect runtime error\n\non:\n schedule:\n - cron: '0 22 * * *'\njobs:\n makeUrl:\n runs-on: ubuntu-latest\n env"
},
{
"path": ".github/workflows/linter.yml",
"chars": 419,
"preview": "name: Editor Lint Code Base\non: pull_request\njobs: \n lint:\n name: Lint Code Base\n runs-on: ubuntu-latest\n step"
},
{
"path": ".github/workflows/plugin-test.yml",
"chars": 1054,
"preview": "name: Plugin Unit, Integration Test\non: pull_request\njobs: \n plugin-test:\n name: Unit, Integration Test\n runs-on:"
},
{
"path": ".github/workflows/publish-cdn.yml",
"chars": 2673,
"preview": "name: Cdn Publish\non: [workflow_dispatch]\njobs:\n pre-check:\n runs-on: ubuntu-latest\n steps:\n - name: Checkou"
},
{
"path": ".github/workflows/publish-doc.yml",
"chars": 3771,
"preview": "name: Doc Publish\non: [workflow_dispatch]\njobs:\n pre-check:\n runs-on: ubuntu-latest\n steps:\n - name: Checkou"
},
{
"path": ".github/workflows/publish-npm-wrapper.yml",
"chars": 2946,
"preview": "name: Wrapper Npm Publish\non: [workflow_dispatch]\njobs:\n pre-check:\n runs-on: ubuntu-latest\n steps:\n - name:"
},
{
"path": ".github/workflows/publish-npm.yml",
"chars": 3574,
"preview": "name: Npm Publish\non: [workflow_dispatch]\njobs:\n checkVersion:\n name: Check package version\n runs-on: ubuntu-late"
},
{
"path": ".github/workflows/test.yml",
"chars": 646,
"preview": "name: Editor Unit, Integration Test\non: pull_request\njobs: \n test:\n name: Unit, Integration Test\n runs-on: ubuntu"
},
{
"path": ".gitignore",
"chars": 585,
"preview": "# Logs\nlogs\n*.log\n\n# Runtime data\npids\n*.pid\n*.seed\n\n# Directory for instrumented libs generated by jscoverage/JSCover\nl"
},
{
"path": ".prettierignore",
"chars": 11,
"preview": "*.md\n*.html"
},
{
"path": ".prettierrc.js",
"chars": 61,
"preview": "module.exports = {\n printWidth: 100,\n singleQuote: true\n};\n"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3229,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "CONTRIBUTING.md",
"chars": 5091,
"preview": "# Contributing to TOAST UI\n\nFirst off, thanks for taking the time to contribute! 🎉 😘 ✨\n\nThe following is a set of guidel"
},
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2020 NHN Cloud Corp.\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "README.md",
"chars": 11494,
"preview": "# \n\n> GFM Markdown and WYSIWYG Editor - Produc"
},
{
"path": "__mocks__/cssMock.js",
"chars": 76,
"preview": "module.exports = {\n process() {\n return 'module.exports = {};';\n },\n};\n"
},
{
"path": "apps/editor/README.md",
"chars": 5454,
"preview": "# \n\n[</title"
},
{
"path": "apps/editor/examples/example17-placeholder.html",
"chars": 1291,
"preview": "<!DOCTYPE html>\n<html>\n <head lang=\"en\">\n <meta charset=\"UTF-8\" />\n <title>17. Placeholder</title>\n <link rel="
},
{
"path": "apps/editor/jest.config.js",
"chars": 236,
"preview": "// eslint-disable-next-line @typescript-eslint/no-var-requires\nconst base = require('../../jest.base.config');\n\nmodule.e"
},
{
"path": "apps/editor/package.json",
"chars": 3053,
"preview": "{\n \"name\": \"@toast-ui/editor\",\n \"version\": \"3.2.2\",\n \"description\": \"GFM Markdown Wysiwyg Editor - Productive and Ex"
},
{
"path": "apps/editor/rollup.config.js",
"chars": 1656,
"preview": "import typescript from '@rollup/plugin-typescript';\nimport commonjs from '@rollup/plugin-commonjs';\nimport { nodeResolve"
},
{
"path": "apps/editor/scripts/createConfigVariable.js",
"chars": 988,
"preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst fs = require('fs');\nconst path = require('path');\nconst co"
},
{
"path": "apps/editor/scripts/createIndexPage.js",
"chars": 1193,
"preview": "/* eslint-disable @typescript-eslint/no-var-requires */\n\nconst fs = require('fs');\nconst path = require('path');\nconst d"
},
{
"path": "apps/editor/scripts/webpack.config.i18n.js",
"chars": 2241,
"preview": "/* eslint-disable @typescript-eslint/no-var-requires */\nconst path = require('path');\nconst webpack = require('webpack')"
},
{
"path": "apps/editor/snowpack.config.js",
"chars": 273,
"preview": "/** @type {import(\"snowpack\").SnowpackUserConfig } */\nmodule.exports = {\n mount: {\n 'demo/esm': '/',\n 'src/img': "
},
{
"path": "apps/editor/src/__test__/integration/ui/layout.spec.ts",
"chars": 8819,
"preview": "import { cls } from '@/utils/dom';\nimport '@/i18n/en-us';\nimport { Editor } from '@/index';\nimport { Emitter } from '@t/"
},
{
"path": "apps/editor/src/__test__/integration/ui/toolbar.spec.ts",
"chars": 17286,
"preview": "import { cls } from '@/utils/dom';\nimport { fireEvent, getByLabelText, getByText, screen } from '@testing-library/dom';\n"
},
{
"path": "apps/editor/src/__test__/integration/vdom/render.spec.ts",
"chars": 8322,
"preview": "import { oneLineTrim } from 'common-tags';\nimport { render } from '@/ui/vdom/renderer';\nimport { Component } from '@/ui/"
},
{
"path": "apps/editor/src/__test__/integration/widget/widgetNode.spec.ts",
"chars": 11565,
"preview": "import { oneLineTrim } from 'common-tags';\nimport Editor from '@/editorCore';\nimport { cls } from '@/utils/dom';\nimport "
},
{
"path": "apps/editor/src/__test__/unit/convertor.spec.ts",
"chars": 25366,
"preview": "import { source, oneLineTrim } from 'common-tags';\n\nimport { Context, MdNode, Parser, HTMLConvertorMap } from '@toast-ui"
},
{
"path": "apps/editor/src/__test__/unit/dom.spec.ts",
"chars": 8084,
"preview": "import toArray from 'tui-code-snippet/collection/toArray';\nimport {\n isPositionInBox,\n isElemNode,\n findNodes,\n appe"
},
{
"path": "apps/editor/src/__test__/unit/editor.spec.ts",
"chars": 30116,
"preview": "import '@/i18n/en-us';\nimport { oneLineTrim, stripIndents, source } from 'common-tags';\nimport { Emitter } from '@t/even"
},
{
"path": "apps/editor/src/__test__/unit/eventEmitter.spec.ts",
"chars": 6113,
"preview": "import EventEmitter from '@/event/eventEmitter';\n\n/* eslint-disable @typescript-eslint/no-empty-function */\ndescribe('ev"
},
{
"path": "apps/editor/src/__test__/unit/helper/common.spec.ts",
"chars": 844,
"preview": "import { deepCopy, deepCopyArray, deepMergedCopy, includes } from '@/utils/common';\n\nit('\"deepCopy\" should copy the obje"
},
{
"path": "apps/editor/src/__test__/unit/helper/image.spec.ts",
"chars": 1303,
"preview": "import EventEmitter from '@/event/eventEmitter';\nimport { addDefaultImageBlobHook, emitImageBlobHook } from '@/helper/im"
},
{
"path": "apps/editor/src/__test__/unit/markdown/__snapshots__/syntaxHighlight.spec.ts.snap",
"chars": 8694,
"preview": "// Jest Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`markdown editor syntax highlight atx heading 1`] = `\n<div>\n <span "
},
{
"path": "apps/editor/src/__test__/unit/markdown/keymap.spec.ts",
"chars": 23991,
"preview": "import { oneLineTrim, source, stripIndent } from 'common-tags';\nimport { redo, undo } from 'prosemirror-history';\nimport"
},
{
"path": "apps/editor/src/__test__/unit/markdown/mdCommand.spec.ts",
"chars": 26311,
"preview": "import { oneLineTrim, source, stripIndent } from 'common-tags';\nimport { undo } from 'prosemirror-history';\nimport { Toa"
},
{
"path": "apps/editor/src/__test__/unit/markdown/mdEditor.spec.ts",
"chars": 3057,
"preview": "import { ToastMark } from '@toast-ui/toastmark';\nimport MarkdownEditor from '@/markdown/mdEditor';\nimport EventEmitter f"
},
{
"path": "apps/editor/src/__test__/unit/markdown/mdPreview.spec.ts",
"chars": 6685,
"preview": "import { MdPos, ToastMark } from '@toast-ui/toastmark';\nimport MarkdownPreview, { CLASS_HIGHLIGHT } from '@/markdown/mdP"
},
{
"path": "apps/editor/src/__test__/unit/markdown/smartTask.spec.ts",
"chars": 1340,
"preview": "import { ToastMark } from '@toast-ui/toastmark';\nimport MarkdownEditor from '@/markdown/mdEditor';\nimport EventEmitter f"
},
{
"path": "apps/editor/src/__test__/unit/markdown/syntaxHighlight.spec.ts",
"chars": 3728,
"preview": "import { ToastMark } from '@toast-ui/toastmark';\nimport MarkdownEditor from '@/markdown/mdEditor';\nimport EventEmitter f"
},
{
"path": "apps/editor/src/__test__/unit/markdown/util.ts",
"chars": 1524,
"preview": "import { HTMLConvertorMap } from '@toast-ui/toastmark';\nimport { history } from 'prosemirror-history';\nimport MarkdownEd"
},
{
"path": "apps/editor/src/__test__/unit/sanitizer.spec.ts",
"chars": 5648,
"preview": "import { registerTagWhitelistIfPossible, sanitizeHTML } from '@/sanitizer/htmlSanitizer';\n\ndescribe('sanitizeHTML', () ="
},
{
"path": "apps/editor/src/__test__/unit/vdom/template.spec.ts",
"chars": 2897,
"preview": "import { VNode } from '@t/ui';\nimport html from '@/ui/vdom/template';\nimport { Component } from '@/ui/vdom/component';\n\n"
},
{
"path": "apps/editor/src/__test__/unit/viewer.spec.ts",
"chars": 1733,
"preview": "import { oneLineTrim } from 'common-tags';\nimport Viewer from '@/viewer';\nimport { createHTMLrenderer, removeDataAttr } "
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/customBlock.spec.ts",
"chars": 1477,
"preview": "import { oneLineTrim } from 'common-tags';\nimport { HTMLConvertorMap } from '@toast-ui/toastmark';\nimport { ToDOMAdaptor"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/helper/pasteMsoList.spec.ts",
"chars": 5087,
"preview": "import { oneLineTrim } from 'common-tags';\n\nimport { convertMsoParagraphsToList } from '@/wysiwyg/clipboard/pasteMsoList"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/keymap.spec.ts",
"chars": 14055,
"preview": "import { oneLineTrim } from 'common-tags';\n\nimport { DOMParser } from 'prosemirror-model';\nimport {\n chainCommands,\n d"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/wwCommand.spec.ts",
"chars": 21426,
"preview": "import { oneLineTrim } from 'common-tags';\n\nimport { DOMParser } from 'prosemirror-model';\n\nimport WysiwygEditor from '@"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/wwEditor.spec.ts",
"chars": 4918,
"preview": "import { oneLineTrim } from 'common-tags';\n\nimport { DOMParser } from 'prosemirror-model';\n\nimport WysiwygEditor from '@"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/wwTableCommand.spec.ts",
"chars": 25128,
"preview": "import { oneLineTrim } from 'common-tags';\n\nimport WysiwygEditor from '@/wysiwyg/wwEditor';\nimport EventEmitter from '@/"
},
{
"path": "apps/editor/src/__test__/unit/wysiwyg/wwToDOMAdaptor.spec.ts",
"chars": 9652,
"preview": "import { Fragment, ProsemirrorNode } from 'prosemirror-model';\nimport { oneLineTrim } from 'common-tags';\nimport { Headi"
},
{
"path": "apps/editor/src/base.ts",
"chars": 6689,
"preview": "import { Schema } from 'prosemirror-model';\nimport { EditorState, Plugin, Transaction } from 'prosemirror-state';\nimport"
},
{
"path": "apps/editor/src/commands/commandManager.ts",
"chars": 1454,
"preview": "import { EditorType } from '@t/editor';\nimport { EditorAllCommandMap, EditorCommandFn } from '@t/spec';\nimport { Emitter"
},
{
"path": "apps/editor/src/commands/defaultCommands.ts",
"chars": 368,
"preview": "import { deleteSelection, selectAll } from 'prosemirror-commands';\nimport { undo, redo } from 'prosemirror-history';\n\nim"
},
{
"path": "apps/editor/src/commands/wwCommands.ts",
"chars": 964,
"preview": "import { isInListNode } from '@/wysiwyg/helper/node';\nimport { sinkListItem, liftListItem } from '@/wysiwyg/command/list"
},
{
"path": "apps/editor/src/convertors/convertor.ts",
"chars": 2163,
"preview": "import { Node as ProsemirrorNode, Schema } from 'prosemirror-model';\nimport { HTMLConvertorMap, MdNode, MdPos } from '@t"
},
{
"path": "apps/editor/src/convertors/toMarkdown/toMdConvertorState.ts",
"chars": 9158,
"preview": "import { Node, Mark } from 'prosemirror-model';\n\nimport { includes, escape, last } from '@/utils/common';\n\nimport { WwNo"
},
{
"path": "apps/editor/src/convertors/toMarkdown/toMdConvertors.ts",
"chars": 10203,
"preview": "import { ProsemirrorNode } from 'prosemirror-model';\n\nimport isUndefined from 'tui-code-snippet/type/isUndefined';\n\nimpo"
},
{
"path": "apps/editor/src/convertors/toMarkdown/toMdNodeTypeWriters.ts",
"chars": 6685,
"preview": "import { ProsemirrorNode } from 'prosemirror-model';\n\nimport inArray from 'tui-code-snippet/array/inArray';\n\nimport { es"
},
{
"path": "apps/editor/src/convertors/toWysiwyg/htmlToWwConvertors.ts",
"chars": 6938,
"preview": "import { MdNode } from '@toast-ui/toastmark';\nimport { sanitizeHTML } from '@/sanitizer/htmlSanitizer';\n\nimport {\n HTML"
},
{
"path": "apps/editor/src/convertors/toWysiwyg/toWwConvertorState.ts",
"chars": 4292,
"preview": "import { Schema, Node, NodeType, Mark, MarkType, DOMParser } from 'prosemirror-model';\nimport { MdNode } from '@toast-ui"
},
{
"path": "apps/editor/src/convertors/toWysiwyg/toWwConvertors.ts",
"chars": 11315,
"preview": "import {\n MdNode,\n HeadingMdNode,\n CodeBlockMdNode,\n ListItemMdNode,\n LinkMdNode,\n TableCellMdNode,\n CustomBlockM"
},
{
"path": "apps/editor/src/css/contents.css",
"chars": 13766,
"preview": "/* \n z-index basis\n -1: pseudo element\n 20 - preview, wysiwyg\n 30 - wysiwyg code block language editor, popup, conte"
},
{
"path": "apps/editor/src/css/editor.css",
"chars": 18384,
"preview": "/* height */\n.auto-height,\n.auto-height .toastui-editor-defaultUI {\n height: auto;\n}\n\n.auto-height .toastui-editor-md-c"
},
{
"path": "apps/editor/src/css/md-syntax-highlighting.css",
"chars": 2799,
"preview": ".toastui-editor-md-heading1 {\n font-size: 24px;\n}\n\n.toastui-editor-md-heading2 {\n font-size: 22px;\n}\n\n.toastui-editor-"
},
{
"path": "apps/editor/src/css/preview-highlighting.css",
"chars": 944,
"preview": ".toastui-editor-contents .toastui-editor-md-preview-highlight {\n position: relative;\n z-index: 0;\n}\n\n.toastui-editor-c"
},
{
"path": "apps/editor/src/css/theme/dark.css",
"chars": 16898,
"preview": "@charset \"utf-8\";\n.toastui-editor-dark.toastui-editor-defaultUI {\n border-color: #494c56;\n color: #eee;\n}\n\n.toastui-ed"
},
{
"path": "apps/editor/src/editor.ts",
"chars": 2575,
"preview": "import { EditorOptions, ViewerOptions } from '@t/editor';\nimport { DefaultUI, VNode, IndexList, ToolbarItemOptions } fro"
},
{
"path": "apps/editor/src/editorCore.ts",
"chars": 26466,
"preview": "import { DOMParser } from 'prosemirror-model';\nimport forEachOwnProperties from 'tui-code-snippet/collection/forEachOwnP"
},
{
"path": "apps/editor/src/esm/index.ts",
"chars": 149,
"preview": "import EditorCore from '@/editorCore';\nimport Editor from '@/editor';\n\nimport '@/i18n/en-us';\n\nexport default Editor;\nex"
},
{
"path": "apps/editor/src/esm/indexViewer.ts",
"chars": 55,
"preview": "import Viewer from '@/viewer';\n\nexport default Viewer;\n"
},
{
"path": "apps/editor/src/event/eventEmitter.ts",
"chars": 5778,
"preview": "import isUndefined from 'tui-code-snippet/type/isUndefined';\nimport isFalsy from 'tui-code-snippet/type/isFalsy';\nimport"
},
{
"path": "apps/editor/src/helper/image.ts",
"chars": 1044,
"preview": "import toArray from 'tui-code-snippet/collection/toArray';\n\nimport { HookCallback } from '@t/editor';\nimport { Emitter }"
},
{
"path": "apps/editor/src/helper/manipulation.ts",
"chars": 2116,
"preview": "import { TextSelection, Transaction, EditorState } from 'prosemirror-state';\nimport { ProsemirrorNode, Schema, Mark, Res"
},
{
"path": "apps/editor/src/helper/plugin.ts",
"chars": 3394,
"preview": "import isArray from 'tui-code-snippet/type/isArray';\nimport { Plugin, PluginKey, Selection, TextSelection } from 'prosem"
},
{
"path": "apps/editor/src/i18n/ar.ts",
"chars": 1606,
"preview": "/**\n * @fileoverview I18N for Arabic\n * @author Amira Salah <amira.salah@itworx.com>\n */\nimport Editor from '../editorCo"
},
{
"path": "apps/editor/src/i18n/cs-cz.ts",
"chars": 1726,
"preview": "/**\n * @fileoverview I18N for Czech\n * @author Dmitrij Tkačenko <dmitrij.tkacenko@scalesoft.cz>\n */\nimport Editor from '"
},
{
"path": "apps/editor/src/i18n/de-de.ts",
"chars": 1759,
"preview": "/**\n * @fileoverview I18N for German\n * @author Jann-Niklas Kiepert <jannkiepert@vivaldi.net>\n */\nimport Editor from '.."
},
{
"path": "apps/editor/src/i18n/en-us.ts",
"chars": 1676,
"preview": "/**\n * @fileoverview I18N for English\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport Editor "
},
{
"path": "apps/editor/src/i18n/es-es.ts",
"chars": 1802,
"preview": "/**\n * @fileoverview I18N for Spanish\n * @author Enrico Lamperti <oss@elamperti.com>\n */\nimport Editor from '../editorCo"
},
{
"path": "apps/editor/src/i18n/fi-fi.ts",
"chars": 1737,
"preview": "/**\n * @fileoverview I18N for Finnish\n * @author Tomi Mynttinen <pikseli@iki.fi>\n */\nimport Editor from '../editorCore';"
},
{
"path": "apps/editor/src/i18n/fr-fr.ts",
"chars": 1857,
"preview": "/**\n * @fileoverview I18N for French\n * @author Stanislas Michalak <stanislas.michalak@gmail.com>\n */\nimport Editor from"
},
{
"path": "apps/editor/src/i18n/gl-es.ts",
"chars": 1770,
"preview": "/**\n * @fileoverview I18N for Spanish\n * @author Aida Vidal <avidal@emapic.es>\n */\n\nimport Editor from '../editorCore';\n"
},
{
"path": "apps/editor/src/i18n/hr-hr.ts",
"chars": 1733,
"preview": "/**\n * @fileoverview I18N for Croatian\n * @author Hrvoje A. <hrvoj3e@gmail.com>\n */\nimport Editor from '../editorCore';\n"
},
{
"path": "apps/editor/src/i18n/i18n.ts",
"chars": 1367,
"preview": "/**\n * @fileoverview Implements i18n\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport extend f"
},
{
"path": "apps/editor/src/i18n/it-it.ts",
"chars": 1833,
"preview": "/**\n * @fileoverview I18N for Italian\n * @author Massimo Redaelli <massimo@typish.io>\n */\nimport Editor from '../editorC"
},
{
"path": "apps/editor/src/i18n/ja-jp.ts",
"chars": 1406,
"preview": "/**\n * @fileoverview I18N for Japanese\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport Editor"
},
{
"path": "apps/editor/src/i18n/ko-kr.ts",
"chars": 1398,
"preview": "/**\n * @fileoverview I18N for Korean\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport Editor f"
},
{
"path": "apps/editor/src/i18n/nb-no.ts",
"chars": 1700,
"preview": "/**\n * @fileoverview I18N for Norwegian\n * @author Anton Reytarovskiy <reitarovskii.toh@gmail.com>\n */\nimport Editor fro"
},
{
"path": "apps/editor/src/i18n/nl-nl.ts",
"chars": 1778,
"preview": "/**\n * @fileoverview I18N for Dutch\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport Editor fr"
},
{
"path": "apps/editor/src/i18n/pl-pl.ts",
"chars": 1756,
"preview": "/**\n * @fileoverview I18N for Polish\n * @author Marcin Mikołajczak <me@m4sk.in>\n */\nimport Editor from '../editorCore';\n"
},
{
"path": "apps/editor/src/i18n/pt-br.ts",
"chars": 1820,
"preview": "/**\n * @fileoverview I18N for Português\n * @author Nícolas Huber <nicolasluishuber@gmail.com>\n */\nimport Editor from '.."
},
{
"path": "apps/editor/src/i18n/ru-ru.ts",
"chars": 1817,
"preview": "/**\n * @fileoverview I18N for Russian\n * @author Stepan Samko <stpnsamko@gmail.com>\n * @author Veaceslav Grimalschi <gri"
},
{
"path": "apps/editor/src/i18n/sv-se.ts",
"chars": 1696,
"preview": "/**\n * @fileoverview I18N for Swedish\n * @author Magnus Aspling <magnus@yug.se>\n */\nimport Editor from '../editorCore';\n"
},
{
"path": "apps/editor/src/i18n/tr-tr.ts",
"chars": 1688,
"preview": "/**\n * @fileoverview I18N for Turkish\n * @author Mesut Gölcük <mesutgolcuk@gmail.com>\n */\nimport Editor from '../editorC"
},
{
"path": "apps/editor/src/i18n/uk-ua.ts",
"chars": 1786,
"preview": "/**\n * @fileoverview I18N for Ukrainian\n * @author Nikolya <k_m_i@i.ua>\n */\nimport Editor from '../editorCore';\n\nEditor."
},
{
"path": "apps/editor/src/i18n/zh-cn.ts",
"chars": 1322,
"preview": "/**\n * @fileoverview I18N for Chinese\n * @author NHN Cloud FE Development Lab <dl_javascript@nhn.com>\n */\nimport Editor "
},
{
"path": "apps/editor/src/i18n/zh-tw.ts",
"chars": 1325,
"preview": "/**\n * @fileoverview I18N for Traditional Chinese\n * @author Tzu-Ray Su <raysu3329@gmail.com>\n */\nimport Editor from '.."
},
{
"path": "apps/editor/src/index.ts",
"chars": 339,
"preview": "import EditorCore from './editorCore';\nimport Editor from './editor';\n\nimport 'prosemirror-view/style/prosemirror.css';\n"
},
{
"path": "apps/editor/src/indexEditorOnlyStyle.ts",
"chars": 111,
"preview": "import '@/css/editor.css';\nimport '@/css/preview-highlighting.css';\nimport '@/css/md-syntax-highlighting.css';\n"
},
{
"path": "apps/editor/src/indexViewer.ts",
"chars": 85,
"preview": "import Viewer from './viewer';\n\nimport '@/css/contents.css';\n\nexport default Viewer;\n"
},
{
"path": "apps/editor/src/markdown/helper/list.ts",
"chars": 9020,
"preview": "import { ProsemirrorNode, Schema } from 'prosemirror-model';\nimport { ListItemMdNode, MdNode, ToastMark } from '@toast-u"
},
{
"path": "apps/editor/src/markdown/helper/mdCommand.ts",
"chars": 1540,
"preview": "import isFunction from 'tui-code-snippet/type/isFunction';\nimport { EditorCommand } from '@t/spec';\nimport { createTextS"
},
{
"path": "apps/editor/src/markdown/helper/pos.ts",
"chars": 3967,
"preview": "import { AllSelection, Selection } from 'prosemirror-state';\nimport { ProsemirrorNode, ResolvedPos } from 'prosemirror-m"
},
{
"path": "apps/editor/src/markdown/helper/query.ts",
"chars": 282,
"preview": "import { ProsemirrorNode } from 'prosemirror-model';\n\nexport function getTextByMdLine(doc: ProsemirrorNode, mdLine: numb"
},
{
"path": "apps/editor/src/markdown/htmlRenderConvertors.ts",
"chars": 5628,
"preview": "import isFunction from 'tui-code-snippet/type/isFunction';\nimport {\n HTMLConvertorMap,\n MdNode,\n ListItemMdNode,\n Co"
},
{
"path": "apps/editor/src/markdown/marks/blockQuote.ts",
"chars": 2589,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { Command } from 'prosemirror-commands';\nimport { EditorComman"
},
{
"path": "apps/editor/src/markdown/marks/code.ts",
"chars": 1212,
"preview": "import { DOMOutputSpec, Mark as ProsemirrorMark } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimp"
},
{
"path": "apps/editor/src/markdown/marks/codeBlock.ts",
"chars": 2611,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { Command } from 'prosemirror-commands';\nimport { EditorComman"
},
{
"path": "apps/editor/src/markdown/marks/customBlock.ts",
"chars": 1386,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { clsWithMdPrefix } from '@/utils/dom';\nimport Mark from '@/sp"
},
{
"path": "apps/editor/src/markdown/marks/emph.ts",
"chars": 775,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimport { clsWithMdPrefix } f"
},
{
"path": "apps/editor/src/markdown/marks/heading.ts",
"chars": 1966,
"preview": "import { DOMOutputSpec, Mark as ProsemirrorMark } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimp"
},
{
"path": "apps/editor/src/markdown/marks/html.ts",
"chars": 350,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { clsWithMdPrefix } from '@/utils/dom';\nimport Mark from '@/sp"
},
{
"path": "apps/editor/src/markdown/marks/link.ts",
"chars": 1852,
"preview": "import { DOMOutputSpec, Mark as ProsemirrorMark } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimp"
},
{
"path": "apps/editor/src/markdown/marks/listItem.ts",
"chars": 8206,
"preview": "import { DOMOutputSpec, Mark as ProsemirrorMark } from 'prosemirror-model';\nimport { Transaction } from 'prosemirror-sta"
},
{
"path": "apps/editor/src/markdown/marks/simpleMark.ts",
"chars": 1316,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { clsWithMdPrefix } from '@/utils/dom';\nimport Mark from '@/sp"
},
{
"path": "apps/editor/src/markdown/marks/strike.ts",
"chars": 728,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimport { clsWithMdPrefix } f"
},
{
"path": "apps/editor/src/markdown/marks/strong.ts",
"chars": 789,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { EditorCommand } from '@t/spec';\nimport { clsWithMdPrefix } f"
},
{
"path": "apps/editor/src/markdown/marks/table.ts",
"chars": 6172,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport { Command } from 'prosemirror-commands';\nimport type { Transac"
},
{
"path": "apps/editor/src/markdown/marks/thematicBreak.ts",
"chars": 1335,
"preview": "import { DOMOutputSpec } from 'prosemirror-model';\nimport type { Transaction } from 'prosemirror-state';\nimport { Editor"
},
{
"path": "apps/editor/src/markdown/mdEditor.ts",
"chars": 11773,
"preview": "import { Transaction } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { Fragment, Slice"
},
{
"path": "apps/editor/src/markdown/mdPreview.ts",
"chars": 6928,
"preview": "import off from 'tui-code-snippet/domEvent/off';\nimport addClass from 'tui-code-snippet/domUtil/addClass';\nimport remove"
},
{
"path": "apps/editor/src/markdown/nodes/doc.ts",
"chars": 171,
"preview": "import Node from '@/spec/node';\n\nexport class Doc extends Node {\n get name() {\n return 'doc';\n }\n\n get schema() {\n"
},
{
"path": "apps/editor/src/markdown/nodes/paragraph.ts",
"chars": 8896,
"preview": "import { DOMOutputSpec, ProsemirrorNode, Schema } from 'prosemirror-model';\nimport { Transaction, Selection } from 'pros"
},
{
"path": "apps/editor/src/markdown/nodes/text.ts",
"chars": 171,
"preview": "import Node from '@/spec/node';\n\nexport class Text extends Node {\n get name() {\n return 'text';\n }\n\n get schema() "
},
{
"path": "apps/editor/src/markdown/plugins/helper/markInfo.ts",
"chars": 8852,
"preview": "import {\n MdNodeType,\n MdPos,\n HeadingMdNode,\n LinkMdNode,\n CodeMdNode,\n MdNode,\n CodeBlockMdNode,\n CustomBlockM"
},
{
"path": "apps/editor/src/markdown/plugins/previewHighlight.ts",
"chars": 2809,
"preview": "import { MdNode, MdPos } from '@toast-ui/toastmark';\nimport { Plugin } from 'prosemirror-state';\nimport { MdContext } fr"
},
{
"path": "apps/editor/src/markdown/plugins/smartTask.ts",
"chars": 2240,
"preview": "import { Plugin } from 'prosemirror-state';\nimport { EditorView } from 'prosemirror-view';\nimport { MdPos } from '@toast"
},
{
"path": "apps/editor/src/markdown/plugins/syntaxHighlight.ts",
"chars": 6640,
"preview": "import { MdNode, MdPos, EditResult, ToastMark } from '@toast-ui/toastmark';\nimport { Plugin, Transaction } from 'prosemi"
},
{
"path": "apps/editor/src/markdown/scroll/animation.ts",
"chars": 1317,
"preview": "import { SyncCallbacks } from './scrollSync';\n\n// @TODO: apply bezier and raq\ntype WinSetTimeout = typeof window.setTime"
},
{
"path": "apps/editor/src/markdown/scroll/dom.ts",
"chars": 3675,
"preview": "import { ProsemirrorNode } from 'prosemirror-model';\nimport { MdNode } from '@toast-ui/toastmark';\nimport { includes } f"
},
{
"path": "apps/editor/src/markdown/scroll/offset.ts",
"chars": 1436,
"preview": "import toArray from 'tui-code-snippet/collection/toArray';\nimport { getTotalOffsetTop } from './dom';\n\nconst offsetInfoM"
},
{
"path": "apps/editor/src/markdown/scroll/scrollSync.ts",
"chars": 7993,
"preview": "import { ProsemirrorNode } from 'prosemirror-model';\nimport { EditorView } from 'prosemirror-view';\nimport { ToastMark }"
},
{
"path": "apps/editor/src/plugins/dropImage.ts",
"chars": 828,
"preview": "import { Plugin } from 'prosemirror-state';\nimport forEachArray from 'tui-code-snippet/collection/forEachArray';\nimport "
},
{
"path": "apps/editor/src/plugins/placeholder.ts",
"chars": 940,
"preview": "import { Plugin } from 'prosemirror-state';\nimport { DecorationSet, Decoration } from 'prosemirror-view';\nimport addClas"
},
{
"path": "apps/editor/src/plugins/popupWidget.ts",
"chars": 2227,
"preview": "import { EditorView } from 'prosemirror-view';\nimport { Plugin, PluginKey } from 'prosemirror-state';\nimport css from 't"
},
{
"path": "apps/editor/src/queries/queryManager.ts",
"chars": 517,
"preview": "import type { EditorCore as Editor } from '@t/editor';\n\ntype QueryFn = (editor: Editor, payload?: Record<string, any>) ="
},
{
"path": "apps/editor/src/sanitizer/htmlSanitizer.ts",
"chars": 836,
"preview": "import DOMPurify from 'dompurify';\nimport { includes } from '@/utils/common';\n\nconst CAN_BE_WHITE_TAG_LIST = ['iframe', "
},
{
"path": "apps/editor/src/spec/mark.ts",
"chars": 485,
"preview": "import { Keymap } from 'prosemirror-commands';\nimport { MarkSpec } from 'prosemirror-model';\nimport { SpecContext, Edito"
},
{
"path": "apps/editor/src/spec/node.ts",
"chars": 485,
"preview": "import { Keymap } from 'prosemirror-commands';\nimport { NodeSpec } from 'prosemirror-model';\nimport { SpecContext, Edito"
},
{
"path": "apps/editor/src/spec/specManager.ts",
"chars": 3135,
"preview": "import { EditorView } from 'prosemirror-view';\nimport { keymap } from 'prosemirror-keymap';\nimport { EditorAllCommandMap"
},
{
"path": "apps/editor/src/ui/components/contextMenu.ts",
"chars": 2299,
"preview": "import { ContextMenuItem, ExecCommand, Pos, VNode } from '@t/ui';\nimport { Emitter } from '@t/event';\nimport { closest, "
},
{
"path": "apps/editor/src/ui/components/layout.ts",
"chars": 3915,
"preview": "import { EditorType, PreviewStyle } from '@t/editor';\nimport { Emitter } from '@t/event';\nimport { IndexList, ToolbarIte"
},
{
"path": "apps/editor/src/ui/components/popup.ts",
"chars": 2392,
"preview": "import { ExecCommand, HidePopup, PopupInfo, Pos } from '@t/ui';\nimport { Emitter } from '@t/event';\nimport { closest, cl"
},
{
"path": "apps/editor/src/ui/components/switch.ts",
"chars": 1289,
"preview": "import { Emitter } from '@t/event';\nimport { EditorType } from '@t/editor';\nimport i18n from '@/i18n/i18n';\nimport { cls"
},
{
"path": "apps/editor/src/ui/components/tabs.ts",
"chars": 1116,
"preview": "import { TabInfo } from '@t/ui';\nimport i18n from '@/i18n/i18n';\nimport { cls } from '@/utils/dom';\nimport html from '.."
},
{
"path": "apps/editor/src/ui/components/toolbar/buttonHoc.ts",
"chars": 2591,
"preview": "import css from 'tui-code-snippet/domUtil/css';\nimport {\n ExecCommand,\n SetPopupInfo,\n ToolbarItemInfo,\n SetItemWidt"
},
{
"path": "apps/editor/src/ui/components/toolbar/customPopupBody.ts",
"chars": 706,
"preview": "import { ExecCommand, HidePopup } from '@t/ui';\nimport { Emitter } from '@t/event';\nimport html from '@/ui/vdom/template"
},
{
"path": "apps/editor/src/ui/components/toolbar/customToolbarItem.ts",
"chars": 2288,
"preview": "import {\n ExecCommand,\n SetPopupInfo,\n SetItemWidth,\n GetBound,\n HideTooltip,\n ShowTooltip,\n ToolbarCustomOptions"
},
{
"path": "apps/editor/src/ui/components/toolbar/dropdownToolbarButton.ts",
"chars": 3296,
"preview": "import {\n ExecCommand,\n SetPopupInfo,\n ToolbarItemInfo,\n GetBound,\n HideTooltip,\n ShowTooltip,\n ToolbarButtonInfo"
},
{
"path": "apps/editor/src/ui/components/toolbar/headingPopupBody.ts",
"chars": 1161,
"preview": "import { Emitter } from '@t/event';\nimport { ExecCommand } from '@t/ui';\nimport { closest } from '@/utils/dom';\nimport i"
},
{
"path": "apps/editor/src/ui/components/toolbar/imagePopupBody.ts",
"chars": 5214,
"preview": "import removeClass from 'tui-code-snippet/domUtil/removeClass';\nimport addClass from 'tui-code-snippet/domUtil/addClass'"
},
{
"path": "apps/editor/src/ui/components/toolbar/linkPopupBody.ts",
"chars": 2869,
"preview": "import addClass from 'tui-code-snippet/domUtil/addClass';\nimport removeClass from 'tui-code-snippet/domUtil/removeClass'"
},
{
"path": "apps/editor/src/ui/components/toolbar/tablePopupBody.ts",
"chars": 4328,
"preview": "import { Emitter } from '@t/event';\nimport { ExecCommand, Pos } from '@t/ui';\nimport { cls } from '@/utils/dom';\nimport "
},
{
"path": "apps/editor/src/ui/components/toolbar/toolbar.ts",
"chars": 10114,
"preview": "import throttle from 'tui-code-snippet/tricks/throttle';\nimport forEachArray from 'tui-code-snippet/collection/forEachAr"
},
{
"path": "apps/editor/src/ui/components/toolbar/toolbarButton.ts",
"chars": 2590,
"preview": "import {\n ExecCommand,\n SetPopupInfo,\n SetItemWidth,\n GetBound,\n HideTooltip,\n ShowTooltip,\n ToolbarButtonInfo,\n}"
},
{
"path": "apps/editor/src/ui/components/toolbar/toolbarGroup.ts",
"chars": 1408,
"preview": "import {\n ExecCommand,\n SetPopupInfo,\n ToolbarGroupInfo,\n SetItemWidth,\n GetBound,\n HideTooltip,\n ShowTooltip,\n "
},
{
"path": "apps/editor/src/ui/toolbarItemFactory.ts",
"chars": 7727,
"preview": "import isString from 'tui-code-snippet/type/isString';\nimport addClass from 'tui-code-snippet/domUtil/addClass';\nimport "
},
{
"path": "apps/editor/src/ui/vdom/commit.ts",
"chars": 1930,
"preview": "import isFunction from 'tui-code-snippet/type/isFunction';\nimport { innerDiff, removeNode } from './dom';\nimport { VNode"
},
{
"path": "apps/editor/src/ui/vdom/component.ts",
"chars": 626,
"preview": "import { Component as IComponent, VNode } from '@t/ui';\nimport { shallowEqual } from '@/utils/common';\nimport { rerender"
},
{
"path": "apps/editor/src/ui/vdom/dom.ts",
"chars": 2892,
"preview": "import isObject from 'tui-code-snippet/type/isObject';\nimport isNumber from 'tui-code-snippet/type/isNumber';\nimport { s"
},
{
"path": "apps/editor/src/ui/vdom/htm.js",
"chars": 1933,
"preview": "import { assign } from '@/utils/common';\n\n// @TODO: change syntax with our convention\n/* eslint-disable */\nexport defaul"
},
{
"path": "apps/editor/src/ui/vdom/render.ts",
"chars": 2584,
"preview": "import isFunction from 'tui-code-snippet/type/isFunction';\nimport { ComponentClass } from '@t/ui';\nimport { VNode } from"
},
{
"path": "apps/editor/src/ui/vdom/renderer.ts",
"chars": 865,
"preview": "import { Component } from '@t/ui';\nimport { commit } from './commit';\nimport { buildVNode } from './render';\nimport { VN"
},
{
"path": "apps/editor/src/ui/vdom/template.ts",
"chars": 1236,
"preview": "import html from './htm';\nimport isBoolean from 'tui-code-snippet/type/isBoolean';\nimport isString from 'tui-code-snippe"
},
{
"path": "apps/editor/src/ui/vdom/vnode.ts",
"chars": 1717,
"preview": "import { Component, ComponentClass } from '@t/ui';\n\nclass VNodeWalker {\n current: VNode | null;\n\n root: VNode | null;\n"
},
{
"path": "apps/editor/src/utils/common.ts",
"chars": 7189,
"preview": "import isUndefined from 'tui-code-snippet/type/isUndefined';\nimport isNull from 'tui-code-snippet/type/isNull';\nimport s"
},
{
"path": "apps/editor/src/utils/constants.ts",
"chars": 860,
"preview": "const TAG_NAME = '[A-Za-z][A-Za-z0-9-]*';\nconst ATTRIBUTE_NAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*';\nconst UNQUOTED_VALUE = '["
},
{
"path": "apps/editor/src/utils/dom.ts",
"chars": 7454,
"preview": "import toArray from 'tui-code-snippet/collection/toArray';\nimport isArray from 'tui-code-snippet/type/isArray';\nimport i"
},
{
"path": "apps/editor/src/utils/map.ts",
"chars": 1278,
"preview": "import inArray from 'tui-code-snippet/array/inArray';\nimport { Mapable } from '@t/map';\n\n/**\n * @class\n * @ignore\n * @cl"
},
{
"path": "apps/editor/src/utils/markdown.ts",
"chars": 4856,
"preview": "import {\n CodeBlockMdNode,\n CustomBlockMdNode,\n LinkMdNode,\n ListItemMdNode,\n MdNode,\n MdNodeType,\n TableCellMdNo"
}
]
// ... and 298 more files (download for full content)
About this extraction
This page contains the full source code of the nhn/tui.editor GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 498 files (1.8 MB), approximately 545.4k tokens, and a symbol index with 2265 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.