1.0.1 • Published 3 years ago

@mdefy/markdown-editor-core v1.0.1

Weekly downloads
2
License
MIT
Repository
github
Last release
3 years ago

Markdown Editor Core

Markdown Editor Core is a WYSIWYG markdown editor based on the JavaScript text editor CodeMirror.

The editor shipped with this library can be used standalone to write Markdown in an efficient way with nice highlighting. However, this library is mainly intended to work as a universal core component for other Markdown Editors, that are e.g. implemented for big JS-based frameworks or other JS systems. Therefore, Markdown Editor Core provides a simple and clear API for all common actions necessary when writing markdown and the editor is highly configurable.

The goal of this library is to provide a fully working text editor which can be controlled by its API, without establishing a specific view or adding further visual components like toolbar buttons as known from other fully-WYSIWYG editors. This makes it easily extensible and customizable for your needs, while setting you free from thinking about text manipulation.

Markdown Editor Core was developed for and in parallel with Ngx Markdown Editor. Thus, the latter is one example of how this library can be used. In the same way, components could be implemented for React or Vue or your custom JS app.

Table of contents

How to install

Run

npm i markdown-editor-core

or

yarn add markdown-editor-core

Load CodeMirror's stylesheet for its default theme and other required stylings; e.g. by including it into your index.html:

<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css" />

How to use

To instantiate MarkdownEditor, you must specify a wrapper element and you can pass an optional configuration object.

const wrapper = document.getElementById('my-wrapper-element') as HTMLElement; // required
const options: MarkdownEditorOptions = { ... };                               // optional

const mde = new MarkdownEditor(wrapper, options);

You can also replace an existing textarea with the Markdown Editor.

const textarea = document.getElementById('my-textarea') as HTMLTextareaElement; // required
const options: MdeFromTextareaOptions = { ... };                                // optional

const mde = new MarkdownEditorFromTextarea(textarea, options);

It is possible to synchronize the editor's content with the content of the textarea in two ways:

  • either manually via mde.syncTextarea()
  • or automatically by setting the option autoSync to true.

You can also switch back to the textarea via mde.toTextarea() (this destroys the Markdown Editor instance).

Configuration options

Shortcuts

The default keymap is as follows (on Mac "Ctrl" is replaced with "Cmd"):

ActionShortcut
increaseHeadingLevelAlt-H
decreaseHeadingLevelShift-Alt-H
toggleBoldCtrl-B
toggleItalicCtrl-I
toggleStrikethroughCtrl-K
toggleUnorderedListCtrl-L
toggleOrderedListShift-Ctrl-L
toggleCheckListShift-Ctrl-Alt-L
toggleQuoteCtrl-Q
insertLinkCtrl-M
insertImageLinkShift-Ctrl-M
insertTableCtrl-Alt-T
insertHorizontalRuleShift-Ctrl--
toggleInlineCodeCtrl-7
insertCodeBlockShift-Ctrl-7
openMarkdownGuideF1
toggleRichTextModeAlt-R
downloadAsFileShift-Ctrl-S
importFromFileCtrl-Alt-I
formatContentAlt-F

You can customize the individual shortcuts inside MarkdownEditorOptions via options.shortcuts.

For shortcuts that come built-in with CodeMirror, see CodeMirror documentation.

If you want to specify your own shortcuts via CodeMirror, mind the correct order of special keys: Shift-Cmd-Ctrl-Alt (see here). You can add new shortcuts using mde.addShortcut(hotkeys, void) or remove existing ones using mde.removeShortcut(hotkeys).

Theming

How to change the editor's styling

The editor's view can be customized using CodeMirror themes. The default theme of CodeMirror is "default" (results in the class .cm-s-default), which basically presents a blank editor and defines the default styles for the markup highlighting.

To apply a customized theme with the name "example"

  • specify { theme: 'example' } in the MarkdownEditorOptions,
  • define the CSS class .cm-s-example in a CSS file, and
  • make sure to load the CSS file with your app.

With such a theme you can customize CodeMirror's visual appearance and behavior. For further details visit the dedicated section on CodeMirror.

If you only want to extend the default theme, you can either define new stylings for the class .cm-s-default and make sure that the "default" theme is applied or you can create your own additional theme and specify two themes in the MarkdownEditorOptions: { theme: 'default additional-theme' }.

How to change the markup styling (e.g. heading, bold, ...)

The markup stylings work with CodeMirror classes as well and can (and should!) therefore be part of a CodeMirror theme. If you want to change the styling of "bold" markup for example, then define a new style for .cm-bold. Again, this should preferably be done within a theme (also see "How to use your own theme").

The classes for markup styling are:

Markup typeClass
Heading.cm-header
Bold.cm-bold
Italic.cm-italic
Strikethrough.cm-strikethrough
List level 1.cm-list-level-1, .cm-list
List level 2.cm-list-level-2, .cm-list
List level > 2.cm-list-level-gt-2, .cm-list
Quote.cm-quote
Link (hyperlink in general).cm-link
Link text (part inside "...").cm-link-text
Link href (part inside "(...)").cm-link-href, .cm-link
Email link.cm-link-email, .cm-link
Inline link ("http\://...").cm-link-inline, .cm-link
Image.cm-image
Image alt text.cm-image-alt-text
Image marker ("!").cm-image-marker
Horizontal rule.cm-hr
Code.cm-code
Emoji.cm-emoji
Tokens.cm-token

The last table row entry "tokens" refers to all markup tokens like **, _, [], (), etc. and only applies if highlightTokens is enabled in the MarkdownEditorOptions. If this is true, then all tokens have the class .cm-token. Additionally every token is given an individual class corresponding to the markup type to which it belongs to and eventually a "token level class". This means, you can easily style all tokens in the same way or each token type individually.

Examples:

  • The ** tokens for bold text have the classes cm-strong cm-token cm-token-strong
  • A > token for quotation in the second level (second token of >>) has the classes cm-quote cm-quote-2 cm-token cm-token-quote cm-token-quote-2.

Here is a list of all CodeMirror token classes:

Token typeClass
Heading #.cm-token-header, .cm-token-header-[n]
Bold **.cm-token-strong
Italic _.cm-token-em
Strikethrough ~~.cm-token-strikethrough
Unordered list -.cm-token-list, .cm-token-list-ul
Ordered list 1..cm-token-list, .cm-token-list-ol
Checklist - [x].cm-token-list, .cm-token-list-ul ("-" token); .cm-token-task ("x" token)
Quote >.cm-token-quote, .cm-token-quote-[n]
Link []().cm-token-link ("[]" token); .cm-token-link-string ("()" token)
Image ![]().cm-token-image ("![]" token); .cm-token-link-string ("()" token)
Inline Code `.cm-token-code
Code block ```.cm-token-code-block

How to contribute

First of all, contributions in any way are very welcome! And a big thank you to all who decide to so!! :)

The code is neither perfect nor complete. If you have any suggestions, requirements or even just comments, please let me know and I will do my best do incorporate them! The even better (and probably faster) way for requesting code modifications, however, are pull requests. I am very happy about all code contributions as time is often rare around here... :)

Writing issues

When writing issues, please give a clear description of the current state and what you are unhappy about. Then, if possible, propose your solution or at least leave a short statement of your thoughts about it.

Making pull requests

Recipe for making a pull request:

  1. Fork and checkout repo locally.
  2. Install Yarn, if you do not have it yet. For example via npm i yarn -g.
  3. Open a command line, move to the project directory and run yarn to install all dependencies.
  4. Make your code changes. (Please mind the style guidelines.)
  5. Use yarn run start to test your changes in the demo app.
  6. Check the docs whether they need to be changed.
  7. Push the changes to your fork.
  8. Make a pull request to the master branch of this repo. Please provide a meaningful title for the PR and give a concise description.

Project setup

Package manager

This project uses Yarn as package manager. So you must use this one to install dependencies when contributing code. The scripts in package.json still work with npm, although it is recommended to always use yarn throughout the project.

FYI: The main reason to move from npm to Yarn was, that Yarn is able to execute shell scripts platform-independent in the native console. I.e. it also understands paths with forward slashes like ./path/to/script.sh on windows and can execute it inside CMD. My claim is to provide a platform-independent project setup and the described issue comes into effect, for example, when running the build script in package.json.

Commit rules

We use Commitlint to guarantee structured commit messages. This means you must write commit messages that meet the rules of Commitlint. If you are not familiar with Commitlint, you can use the CLI tool Commitizen by running yarn run commit, which assists you to write conventional messages. You can also install Commitizen globally on your system, if you want to use the shorter cli commands cz or git cz.

Coding style guidelines

There are not many strict guidelines to keep in mind, but please adapt to the project's code style when contributing. Only two more things shall be mentioned here:

  1. We use Prettier to ensure consistent formatting! Therefore, you should install a Prettier plugin for your IDE. Further it is highly recommended to enable "Format on save", which is also set as the project's default for VSCode.

    There is a pre-commit git hook for Prettier, which checks the formatting of all files. Occasionally it might happen that this hook fails although you have "Format on save" enabled. This is usually due to wrong line endings, e.g. caused by yarn add ... or some other file-writing script or tool. In this case, run yarn run format:write to let Prettier correct the wrong formatting and then try to commit again. Unfortunately, the format:write command cannot be set as a pre-commit hook as it is not known in general, which files need to be staged afterwards.

  2. The methods in markdown-editor.ts are grouped into 5 sections as you can see when inspecting the file. Please put new methods at the end of the corresponding section:

    • Basic Editor API: basic actions like toggleBold
    • Extended Editor API: extended actions like downloadAsFile, usually do not change the content
    • Developer API: methods useful for developers using this library
    • Markdown Editor Options: methods for getting or setting MarkdownEditorOptions
    • Private methods: all private methods (all methods in previous sections should be public or protected)

A word on tests

As you might have noticed, this project does not contain any tests. Well yes, I have noticed that, too... and I really hope to be able to add tests in the future some time. However, it has not been very easy to decide what to test and what not so far. Because it is a highly interactive application, it contains a lot of edge cases, far more than standard cases (of which most are directly visible to human's eye anyway). Especially the multiple-cursor mode of CodeMirror increases the number of test branches tremendously. In addition, it is quite hard to draw a line between testing the Markdown Editor (which is the goal) and testing CodeMirror, which is already tested quite well.

Those issues are clearly not an excuse to omit tests totally, but they drove me to the decision to postpone writing tests a bit as I wanted to finally come to the point, where this project is ready for release. However, this is why it was even more important for me to provide a detailed documentation both in code files and in this Readme.

Finally, due to the high number of edge cases, I would like to encourage you again to contribute - either by writing issues or by explicitly fixing things in code - whenever you discover bugs or odd behavior! I believe, helping each other out by quickly pointing those problems is a very good and also effective way, too, in order to improve an applications quality.