A toolkit for building WYSIWYG editors with Mobiledoc

Overview

Mobiledoc Kit

CI Build Status

Sauce Test Status

Mobiledoc Logo

Mobiledoc Kit is a framework-agnostic library for building WYSIWYG editors supporting rich content via cards.

Libraries

This repository hosts the core Mobiledoc Kit library. If you want to use Mobiledoc Kit to create a WYSIWYG editor you have the following options:

Environment Library
Plain JavaScript mobiledoc-kit (this repo)
Ember ember-mobiledoc-editor
React react-mobiledoc-editor

If you only want to use the Mobiledoc-Kit runtime, for rendering mobiledoc posts only (not editing or creating them), you can use:

Output Format/Environment Library
Plain JavaScript In-Browser (DOM) mobiledoc-dom-renderer
Server-Side Rendering (HTML) see mobiledoc-dom-renderer's Rendering HTML section
Server-Side Rendering (Text-only, e.g. SEO) mobiledoc-text-renderer
In-Browser (DOM) Rendering, with Ember ember-mobiledoc-dom-renderer
React Server and Browser Renderer mobiledoc-react-renderer
๐Ÿ”ฎ Render Mobiledoc as VDOM by passing React or React-like createElement function mobiledoc-vdom-renderer

Mobiledoc is a deliberately simple and terse format, and you are encouraged to write your own renderer if you have other target output formats (e.g., a PDF renderer, an iOS Native Views Renderer, etc.).

Demo

Try a demo at bustle.github.io/mobiledoc-kit/demo.

API Documentation

API Documentation is available online.

Intro to Mobiledoc Kit

  • Posts are serialized to a JSON format called Mobiledoc instead of to HTML. Mobiledoc can be rendered for the web, mobile web, or in theory on any platform. Mobiledoc is portable and fast.
  • The editor makes limited use of Content Editable, the siren-song of doomed web editor technologies.
  • Mobiledoc is designed for rich content. We call rich sections of an article "cards" and rich inline elements "atoms" and implementing a new one doesn't require an understanding of Mobiledoc editor internals. Adding a new atom or card takes an afternoon, not several days. To learn more, see the docs for Atoms, Cards and Mobiledoc Renderers

To learn more about the ideas behind Mobiledoc and the editor (note that the editor used to be named Content-Kit), see these blog posts:

The Mobiledoc kit saves posts in Mobiledoc format.

Usage

The Mobiledoc.Editor class is invoked with an element to render into and optionally a Mobiledoc to load. For example:

const simpleMobiledoc = {
  version: "0.3.2",
  markups: [],
  atoms: [],
  cards: [],
  sections: [
    [1, "p", [
      [0, [], 0, "Welcome to Mobiledoc"]
    ]]
  ]
};
const element = document.querySelector('#editor');
const options = { mobiledoc: simpleMobiledoc };
const editor = new Mobiledoc.Editor(options);
editor.render(element);

options is an object which may include the following properties:

  • mobiledoc - [object] A mobiledoc object to load and edit.
  • placeholder - [string] default text to show before a user starts typing.
  • spellcheck - [boolean] whether to enable spellcheck. Defaults to true.
  • autofocus - [boolean] When true, focuses on the editor when it is rendered.
  • undoDepth - [number] How many undo levels should be available. Default value is five. Set this to zero to disable undo/redo.
  • cards - [array] The list of cards that the editor may render
  • atoms - [array] The list of atoms that the editor may render
  • cardOptions - [object] Options passed to cards and atoms
  • unknownCardHandler - [function] This will be invoked by the editor-renderer whenever it encounters an unknown card
  • unknownAtomHandler - [function] This will be invoked by the editor-renderer whenever it encounters an unknown atom
  • parserPlugins - [array] See DOM Parsing Hooks
  • tooltipPlugin - [object] Optional plugin for customizing tooltip appearance

The editor leverages unicode characters, so HTML documents must opt in to UTF8. For example this can be done by adding the following to an HTML document's <head>:

<meta charset="utf-8" />

Editor API

  • editor.serialize(version="0.3.2") - serialize the current post for persistence. Returns Mobiledoc.
  • editor.destroy() - teardown the editor event listeners, free memory etc.
  • editor.disableEditing() - stop the user from being able to edit the current post with their cursor. Programmatic edits are still allowed.
  • editor.enableEditing() - allow the user to make edits directly to a post's text.
  • editor.editCard(cardSection) - change the card to its edit mode (will change immediately if the card is already rendered, or will ensure that when the card does get rendered it will be rendered in the "edit" state initially)
  • editor.displayCard(cardSection) - same as editCard except in display mode.
  • editor.range - Read the current Range object for the cursor.

Position API

A Position object represents a location in a document. For example your cursor may be at a position, text may be inserted at a position, and a range has a starting position and an ending position.

Position objects are returned by several APIs, for example deleteRange returns a position. Some methods, like splitSection accept a position as an argument.

A position can be created for any point in a document with section#toPosition(offset).

Position API includes:

  • position.section - The section of this position
  • position.offset - The character offset of this position in the section.
  • position.marker - Based on the section and offset, the marker this position is on. A position may not always have a marker (for example a cursor before or after a card).
  • position.toRange(endPosition) - Create a range based on two positions. Accepts the direction of the range as a second optional argument.
  • position.isEqual(otherPosition) - Is this position the same as another
  • position.move(characterCount) - Move a number of characters to the right (positive number) or left (negative number)
  • position.moveWord(direction) - Move a single word in a given direction.

Range API

Range represents a range of a document. A range has a starting position (head), ending position (tail), and a direction (for example highlighting text left-to-right is a forward direction, highlighting right-to-left is a backward direction).

Ranges are returned by several APIs, but most often you will be interested in the current range selected by the user (be it their cursor or an actual selection). This can be accessed at editor#range. Several post editor APIs expect a range as an argument, for example setRange or deleteRange.

Ranges sport several public APIs for manipulation, each of which returns a new, unique range instance:

  • range.head - The position on the range closer to the start of the document.
  • range.tail - The position on the range closer to the end of the document.
  • range.isCollapsed - A range is collapsed when its head and tail are the same position.
  • range.focusedPosition - If a range has a forward direction, then tail. If it has a backward direction, then head.
  • range.extend(characterCount) - Grow a range one character in whatever its direction is.
  • range.move(direction) - If the range is collapsed, move the range forward one character. If it is not, collapse it in the direction passed.
  • range.expandByMarker(callback) - In both directions attempt grow the range as long as callback returns true. callback is passed each marker as the range is grown.

Editor Lifecycle Hooks

API consumers may want to react to given interaction by the user (or by a programmatic edit of the post). Lifecycle hooks provide notification of change and opportunity to edit the post where appropriate.

Register a lifecycle hook by calling the hook name on the editor with a callback function. For example:

editor.didUpdatePost(postEditor => {
  let { range } = editor;
  let cursorSection = range.head.section;

  if (cursorSection.text === 'add-section-when-i-type-this') {
    let section = editor.builder.createMarkupSection('p');
    postEditor.insertSectionBefore(section, cursorSection.next);
    postEditor.setRange(new Mobiledoc.Range(section.headPosition));
  }
});

The available lifecycle hooks are:

  • editor.didUpdatePost(postEditor => {}) - An opportunity to use the postEditor and possibly change the post before rendering begins.
  • editor.willRender() - After all post mutation has finished, but before the DOM is updated.
  • editor.didRender() - After the DOM has been updated to match the edited post.
  • editor.willDelete((range, direction, unit)) - Provides range, direction and unit to identify the coming deletion.
  • editor.didDelete((range, direction, unit)) - Provides range, direction and unit to identify the completed deletion.
  • editor.cursorDidChange() - When the cursor (or selection) changes as a result of arrow-key movement or clicking in the document.
  • editor.onTextInput() - When the user adds text to the document (see example)
  • editor.inputModeDidChange() - The active section(s) or markup(s) at the current cursor position or selection have changed. This hook can be used with Editor#activeMarkups, Editor#activeSections, and Editor#activeSectionAttributes to implement a custom toolbar.
  • editor.beforeToggleMarkup(({markup, range, willAdd}) => {...}) - Register a callback that will be called before editor#toggleMarkup is applied. If any callback returns literal false, the toggling of markup will be canceled. (Toggling markup done via the postEditor, e.g. editor.run(postEditor => postEditor.toggleMarkup(...)) will skip this callback.
  • editor.willCopy(({html, text, mobiledoc}) => {...}) - Called before the serialized versions of the selected markup is copied to the system pasteboard.

For more details on the lifecycle hooks, see the Editor documentation.

Programmatic Post Editing

A major goal of the Mobiledoc kit is to allow complete customization of user interfaces using the editing surface. The programmatic editing API allows the creation of completely custom interfaces for buttons, hot-keys, and other interactions.

To change the post in code, use the editor.run API. For example, the following usage would mark currently selected text as "strong":

editor.run(postEditor => {
  postEditor.toggleMarkup('strong');
});

It is important that you make changes to posts, sections, and markers through the run and postEditor API. This API allows the Mobiledoc editor to conserve and better understand changes being made to the post.

editor.run(postEditor => {
  const mention = postEditor.builder.createAtom("mention", "Jane Doe", { id: 42 });
  // insert at current cursor position:
  // or should the user have to grab the current position from the editor first?
  postEditor.insertMarkers(editor.range.head, [mention]);
});

For more details on the API of postEditor, see the API documentation.

For more details on the API for the builder, required to create new sections atoms, and markers, see the builder API.

Configuring hot keys

The Mobiledoc editor allows the configuration of hot keys and text expansions. For instance, the hot-key command-B to make selected text bold, is registered internally as:

const boldKeyCommand = {
  str: 'META+B',
  run(editor) {
    editor.run(postEditor => postEditor.toggleMarkup('strong'));
  }
};
editor.registerKeyCommand(boldKeyCommand);

All key commands must have str and run properties as shown above.

str describes the key combination to use and may be a single key, or modifier(s) and a key separated by +, e.g.: META+K (cmd-K), META+SHIFT+K (cmd-shift-K)

Modifiers can be any of CTRL, META, SHIFT, or ALT.

The key can be any of the alphanumeric characters on the keyboard, or one of the following special keys:

BACKSPACE, TAB, ENTER, ESC, SPACE, PAGEUP, PAGEDOWN, END, HOME, LEFT, UP, RIGHT, DOWN, INS, DEL

Overriding built-in keys

You can override built-in behavior by simply registering a hot key with the same name. For example, to submit a form instead of entering a new line when enter is pressed you could do the following:

const enterKeyCommand = {
  str: 'enter',
  run(editor) {
    // submit the form
  }
};
editor.registerKeyCommand(enterKeyCommand);

To fall-back to the default behavior, return false from run.

Responding to text input

The editor exposes a hook onTextInput that can be used to programmatically react to text that the user enters. Specify a handler object with text or match properties and a run callback function, and the editor will invoke the callback when the text before the cursor ends with text or matches match. The callback is called after the matching text has been inserted. It is passed the editor instance and an array of matches (either the result of match.exec on the matching user-entered text, or an array containing only the text).

editor.onTextInput({
  text: 'X',
  run(editor) {
    // This callback is called after user types 'X'
  }
});

editor.onTextInput({
  match: /\d\dX$/,  // Note the "$" end anchor
  run(editor) {
    // This callback is called after user types number-number-X
  }
});

The editor has several default text input handlers that are defined in src/js/editor/text-input-handlers.js.

To remove default text input handlers call the unregister function.

editor.unregisterAllTextInputHandlers();

\n special-case match character

When writing a matching string it is common to use \s at the end of a match regex, thus triggering the handler for a given string when the users presses the space or tab key.

When the enter key is pressed no actual characters are added to a document. Instead a new section is created following the current section. Despite this, you may use \n in a match regex to capture moments when the enter key is pressed. For example if you wanted to process a URL for auto-linking you might want to process the string on both the space key and when the user hits enter.

Since \s is a superset of \n, that makes the following regex a valid match for a hand-typed URL after the user presses space or enter:

/\b(https?:\/\/[^\s]+)\s$/

DOM Parsing hooks

A developer can override the default parsing behavior for leaf DOM nodes in pasted HTML.

For example, when an img tag is pasted it may be appropriate to fetch that image, upload it to an authoritative source, and create a specific kind of image card with the new URL in its payload.

A demonstration of this:

function imageToCardParser(node, builder, {addSection, addMarkerable, nodeFinished}) {
  if (node.nodeType !== 1 || node.tagName !== 'IMG') {
    return;
  }
  const payload = { src: node.src };
  const cardSection = builder.createCardSection('my-image', payload);
  addSection(cardSection);
  nodeFinished();
}
const options = {
  parserPlugins: [imageToCardParser]
};
const editor = new Mobiledoc.Editor(options);
const element = document.querySelector('#editor');
editor.render(element);

Parser hooks are called with three arguments:

  • node - The node of DOM being parsed. This may be a text node or an element.
  • builder - The abstract model builder.
  • env - An object containing three callbacks to modify the abstract
    • addSection - Close the current section and add a new one
    • addMarkerable - Add a markerable (marker or atom) to the current section
    • nodeFinished - Bypass all remaining parse steps for this node

Note that you must call nodeFinished to stop a DOM node from being parsed by the next plugin or the default parser.

Tooltip Plugins

Developers can customize the appearance of tooltips (e.g. those shown when a user hovers over a link element) by specificying a tooltip plugin. A tooltip plugin is an object that implements the renderLink method.

The renderLink method is called with three arguments:

  • tooltip - The DOM element of the tooltip UI.
  • link - The DOM element (HTMLAnchorElement) of the link to display a tooltip for.
  • actions - An object containing functions that can be called in response to user interaction.
    • editLink - A function that, when called, prompts the user to edit the href of the link element in question.

The renderLink method is responsible for populating the passed tooltip element with the correct content to display to the user based on the link in question. This allows Mobiledoc users to, for example, provide localized tooltip text via their system of choice.

const MyTooltip = {
  renderLink(tooltip, link, { editLink }) {
    tooltip.innerHTML = `${i18n.translate('URL: ')} ${link.href}`;
    const button = document.createElement('button');
    button.innerText = i18n.translate('Edit');
    button.addEventListener('click', editLink);
    tooltip.append(button);
  }
}
const editor = new Mobiledoc.Editor({
  tooltipPlugin: MyTooltip
});
const element = document.querySelector('#editor');
editor.render(element);

Caveats

Mobiledoc Kit and the Grammarly extension

mobiledoc-kit and the Grammarly extension do not play well together (see issue 422). Until this is resolved, you can avoid any such problems by disabling Grammarly for the mobiledoc-kit instances on your page. To do this, add the data-gramm="false" attribute to the mobiledoc-kit main DOM element.

Contributing

Fork the repo, write a test, make a change, open a PR.

Tests, Linting, Formatting

Install dependencies via yarn:

  • Node.js is required
  • Install yarn globally: npm install -g yarn or brew install yarn
  • Install dependencies with yarn: yarn install

Run tests via the built-in broccoli server:

  • yarn start
  • open http://localhost:4200/tests

Or run headless tests via testem:

  • yarn test

Tests in CI are run at Github Actions via Saucelabs (see the test:ci yarn script).

Run linter

  • yarn lint

Run formatting

  • yarn format

Demo

To run the demo site locally:

  • yarn start
  • open http://localhost:4200/website/demo/

The assets for the demo are in assets/demo.

Debugging

A debugging environment that prints useful information about the active Mobiledoc editor can be access by:

  • yarn start
  • open http://localhost:4200/website/demo/debug.html

Getting Help

If you notice a bug or have a feature request please open an issue on github. If you have a question about usage you can post in the slack channel (automatic invites available from our slackin app) or on StackOverflow using the mobiledoc-kit tag.

Releasing (Implementer notes)

  • Use np (yarn install -g np)
  • np <version> (e.g. np 0.12.0)
  • git push <origin> --tags

Deploy the demo

The demo website is hosted at bustle.github.io/mobiledoc-kit/demo.

To preview the website, start the server and visit http://localhost:4200/assets/demo/. The code for this website can be found in assets/demo/. Note that the development server does not rebuild jsdoc.

To publish a new version:

  • yarn run build:website - This builds the website into website/ and commits it
  • yarn run deploy:website - Pushes the website/ subtree to the gh-pages branch of your origin at github

Development of Mobiledoc and the supporting libraries was generously funded by Bustle Digital Group.

Comments
  • Entering logograms issues in macOS

    Entering logograms issues in macOS

    This is the issue from the Ghost project. https://github.com/TryGhost/Ghost/issues/8319

    (The issue was submitted by @mach)

    Issue Summary

    On Ghost Alpha's new text editor, Japanese text can't be typed correctly with Japanese IME (input method).

    image

    Steps to Reproduce

    Select Japanese IME (either Apple's JapaneseIM or Google's Japanese IME)
    Type "watasi"
    Press Enter key
    

    Expected Result

    At step 2: "watasi" should be converted to "ใ‚ใŸใ—" At step 3: "ใ‚ใŸใ—" should be converted to "็ง" Actual Result

    At step 2: "watasi" is converted to "wใ‚ใŸใ—" At step 3: "wใ‚ใŸใ—" is converted to "w" Technical details:

    Ghost Version: 1.0.0-alpha.19
    Node Version: v6.10.2
    Browser/OS: Google Chrome / macOS Sierra
    Database: MySQL 5.7.17
    
    bug 
    opened by disordinary 37
  • Lists and the Grammarly extension do not work well together on Chrome

    Lists and the Grammarly extension do not work well together on Chrome

    Grammarly is a widely used extension for grammar correction. Unfortunately, it does not play well with lists in Mobiledoc Kit on Chrome. If you go to https://bustlelabs.github.io/mobiledoc-kit/demo/ and add a list, you will see that moving the cursor does not function well anymore (it jumps back to its initial position) and memory and CPU usage also goes up.

    I'm investigating what it could be linked to and if something on our side can be done to make it play well with Grammarly, or if something needs to be done on their side.

    enhancement 
    opened by YoranBrondsema 20
  • Card/Renderer unification RFC

    Card/Renderer unification RFC

    Existing methods and inconsistencies

    We now have published, quasi-official renderers for dom, html and text

    When rendering cards, these renders have different expectations for named hooks that contain setup and teardown methods:

    | renderer: | dom | html | text | | --- | --- | --- | --- | | card property name: | "display" and "edit" | "html" | "text" |

    Since the DOM renderer is used both by the editor (to render cards in either "display" or "edit" mode on the editor surface) and for display-only environment (i.e., rendering cards that are displayed to a user reading an article on a site), the display#setup hook has special semantics for inferring its rendering environment based on the presence of an edit property in the env argument to setup():

    let card = {
      name: 'some-card',
      display: {
        setup(element, options, env, payload) {
          if (env.edit) { // <-- the `edit` env property is only provided when rendering
                               // the card for the editor
            // do stuff that only happens in the editor, like showing an
            // "edit" or "remove" button
          } else {
            // do stuff that only happens when displayed to an end-user on a web page
          }
        }
      }
    };
    

    Another inconsistency is in the way the setup method works for the different renderers:

    | renderer: | dom | html | text | | --- | --- | --- | --- | | setup method 1st arg: | element | buffer | n/a | | how to "render" : | create dom nodes, append to element | call buffer.push(string) repeatedly to add HTML strings to the output | return a string (the 1st arg to setup is unused) |

    Suggestions for unification

    • Rename hooks to match renderers: rename the display hook to dom so that it matches the name of its rendering context
    • Clarify the difference between dom-rendering for the editor and for display-only situations: Either create new hooks for the editor (unsure what is best, perhaps editor-display and editor-edit) or add a more expressive property to the env like context or isInEditor that a card can use to determine whether to show editor-specific UI (instead of inferring from the presence of env.edit)
    • Unify the 1st argument to setup: I propose a buffer object that only has a single method push. In dom rendering scenarios, for each node you wanted to append to the card you'd call buffer.push(node). In html rendering scenarios you'd push a string of HTML. In text-rendering scenarios you'd push a string of text.

    feedback welcome @mixonic @rlivsey

    opened by bantic 17
  • Added support to CMD+Left/Right for Mac navigation

    Added support to CMD+Left/Right for Mac navigation

    In MacOS, in addition to CTRL+A and E for "Home" and "End", another commonly used combination is CMD+Left for Home, and CMD+Right for End.

    This commit adds those shortcuts, and pulls out the "getStartOfLine" and "getEndOfLine" functions out so they can respond to multiple command keys.

    Regarding tests: I didn't find any tests for the existing Home/End key commands, so I didn't add anymore. But I have run the test suite and have noted no regressions.

    opened by atonse 16
  • [WIP] Use Rollup to package mobiledoc-kit

    [WIP] Use Rollup to package mobiledoc-kit

    This is the main branch to update the build system of mobiledoc-kit to use rollup instead of the https://github.com/bustle/broccoli-multi-builder.

    We now have rollup producing a cjs, amd, global, and esm package in the final distribution. The test file similarly uses rollup to wrap up all of the tests and associated dependencies.

    Work remaining:

    • [x] Audit packages that depend on old AMD packages e.g. import X from โ€˜mobiledoc-kit/something to find all the non-top-level imports. Rollup only produces a single define in AMD as it "roll"s up everything inside of that.
    • [ ] Fix the circular dependency between cursor/position and cursor/range
    • [ ] Fix the circular dependency between parsers/dom and parsers/section
    • [x] Release PR https://github.com/bustle/mobiledoc-kit/pull/662 and audit associated addons that depend on MOBILEDOC_VERSION
    • [x] Receive general feedback from consumers

    List of known consumers from libraries.io:

    • Bustle/romper
    • yapp
    • cardstack
    • ghost
    • ember-template-input
      • Already tested a version of this package with this addon and tests were green

    To test this I'll be using npm pack on this branch to produce a tar file that is representative of how NPM itself would serve the package and install it in our audit addon/library/repository and run their tests to ensure no (or at least limited) breakage.

    /cc @iezer

    opened by rondale-sc 15
  • Atoms

    Atoms

    Work in progress thoughts on Atoms

    Will implement #222

    • [x] render atom in renderers/editor-dom.js
    • [x] parse v0.3 mobiledoc in parsers/mobiledoc.js
    • [x] render v0.3 mobiledoc in renderers/mobiledoc.js
    • [x] support atoms in text renderer - bustlelabs/mobiledoc-text-renderer#5
    • [x] support atoms in DOM renderer - bustlelabs/mobiledoc-dom-renderer#20
    • [x] support atoms in HTML renderer - bustlelabs/mobiledoc-html-renderer#15
    • [x] atoms should set contenteditable to false
    • [x] parse atoms in DOMParser
    • [x] handle cursors (eg when no content before/after)
    • [x] handle deletion

    Maybe:

    • [x] add default unknownAtomHandler implementation which just renders the value?
    opened by rlivsey 14
  • [WIP] Centering / section justification tracking issue

    [WIP] Centering / section justification tracking issue

    The main chunks of work necessary for this are as follows:

    • [x] Update the format itself to allow section attributes (we can handle those _section (baseclass))
      • This will be done similarly to how markups handle attributes (for example: PostNodeBuilder#createMarkup)
        • We will create one valid section attribute of data-md-text-align. The data-md- namespace for attributes will be where we create any future section attributes. Like with markers arbitrary attributes (like class, style, etc) are not part of the spec though it seems like that has not stopped anyone from adding them.
    • [x] Update the editor renderer to handle section attributes
      • This will be handled very similarly to how markups are currently handled in editor renderer (for example EditorDOM#createElementFromMarkup) We'll likely need to add something to the EditorDom to wrap sections in an element with a style tag for centering et, al
    • [x] Update DOMRenderer to handle section attributes
    • [x] Update TextRenderer to not fail when attributes are present on section. This is mostly just to prevent errors when MD format changes since we don't/can't do anything with section style information in text rendering (basically this is just a noop for section attributes)
    opened by rondale-sc 13
  • WIP ignore IME key clicks

    WIP ignore IME key clicks

    Partial fix for #548. This fixes Korean and Japanese input (using Input Method Editor IME) for most cases.

    Editor is still broken when entering text at the beginning of a section. Still working on that. Fixing this will probably involve fixing #589, ie. don't do a full re-render when not needed. This also effects spellcheck and Android input.

    Basically the keys Enter, Backspace, Space, Tab, and Arrows are all used to navigate and select within the IME editor so we want mobiledoc to ignore those.

    Illustration of the bug:

    Pressing Enter

    Pressing Backspace

    • Pressing backspace seems to duplicate the previous character

    After fixed

    Still broken at start of section

    • Notice the "w" goes straight to the document and is not part of the IME input
    opened by iezer 13
  • Is this project still active?

    Is this project still active?

    We recently ported our complete internal RTE to use mobiledoc-kit under the hood and I also saw that Ghost switched their editor as well.

    I really love this project and would love to see it flourish. It solves a huge amount of issues we had with previous editors. Also I love the idea of doing the spec of the format sort-of separately from the actual implementation.

    However, as I was browsing through the open issues + pull request, I sort of noticed that there is not a lot of activity from the side of the maintainers / members. The last release is around 4 months old. So my question: is this project still active? Is there some way we can help?

    opened by apfelbox 13
  • Migrating content to mobiledoc format - parsing html server side

    Migrating content to mobiledoc format - parsing html server side

    Hi! Is there a way to parse existing html to mobiledoc format server side? I want to migrate my content to mobiledoc format.

    In node.js I was trying to do something like this:

    const parser = require('../mobiledoc-kit/dist/commonjs/mobiledoc-kit/parsers/html').default;
    const builder = require('../mobiledoc-kit/dist/commonjs/mobiledoc-kit/models/post-node-builder').default;
    const p = new parser(builder);
    p.parse('<p> hello </p>');
    

    but it requires browser environment (error: ReferenceError: document is not defined);

    opened by kmoskwiak 11
  • Create atom or card when matching a regex in the editor

    Create atom or card when matching a regex in the editor

    Basically, I'd like some sort of hook that can be called whenever a regex is matched anywhere in the editor. This could be due to pasting or typing.

    We're writing an API that allows third parties to install handlers for when certain patterns of text are entered into our editor. The end result will be that when the match is found, they will be able to create an "entity" to replace it. This entity is essentially a block of JSON data and a type (very analogous to a card). This API will also have methods for the third party to determine the presentation of this entity both in the editor as well as when the message is posted to a chat window.

    Think of a simple case of entering a hash tag, which would be something like #GameOfThrones. A third party application should be able to match on that, and use it to, for example, get a twitter stream and present the most recent tweet related to that hashtag.

    So for us, some sort of event that's fired whenever the regex is matched passing the matching text, and then a clear way to replace that text with an atom or card.

    It would be really nice if the event is fired only when it is clear that the entry of the matching text is completed. In my mind that would be when the cursor is outside of the matched text.

    opened by Ondoher 11
  • Unable to use in typescript project

    Unable to use in typescript project

    I'm currently evaluating different wysiwyg editor projects (Slate, Quill, Tiptap) and I wanted to check mobile doc out.

    Sadly I get following errors when trying to use it:

    Error: node_modules/mobiledoc-kit/dist/mobiledoc.d.ts:406:9 - error TS2611: 'isBlank' is defined as a property in class '{ _tagName: string | null; tagName: string; isValidTagName(normalizedTagName: string): boolean; type: Type; isSection: boolean; isMarkerable: boolean; isNested: boolean; isListItem: boolean; ... 20 more ...; prev: any; }', but is overridden here in 'Markerable' as an accessor.
    
    406     get isBlank(): boolean;
                ~~~~~~~
    
    
    Error: node_modules/mobiledoc-kit/dist/mobiledoc.d.ts:437:9 - error TS2611: 'length' is defined as a property in class '{ _tagName: string | null; tagName: string; isValidTagName(normalizedTagName: string): boolean; type: Type; isSection: boolean; isMarkerable: boolean; isNested: boolean; isListItem: boolean; ... 20 more ...; prev: any; }', but is overridden here in 'Markerable' as an accessor.
    
    437     get length(): number;
                ~~~~~~
    
    
    Error: node_modules/mobiledoc-kit/dist/mobiledoc.d.ts:515:9 - error TS2611: 'post' is defined as a property in class 'Markerable', but is overridden here in 'ListItem' as an accessor.
    
    515     get post(): Option<Post> | undefined;
                ~~~~
    
    
    Error: node_modules/mobiledoc-kit/dist/mobiledoc.d.ts:562:9 - error TS2611: 'isBlank' is defined as a property in class '{ _tagName: string | null; tagName: string; isValidTagName(normalizedTagName: string): boolean; type: Type; isSection: boolean; isMarkerable: boolean; isNested: boolean; isListItem: boolean; ... 20 more ...; prev: any; } & Attributable', but is overridden here in 'ListSection' as an accessor.
    
    562     get isBlank(): boolean;
                ~~~~~~~
    

    I'm using typescript 4.8.3

    opened by ColinFrick 2
  • export PostEditor as public API

    export PostEditor as public API

    Exports PostEditor as a public API and properly privatizes certain members. Since it is passed to editor.run which is used heavily in advanced usage, it's important for it to be documented/stable.

    opened by gpoitch 0
  • [WIP][PROOF OF CONCEPT] Line Breaks ๐Ÿคก

    [WIP][PROOF OF CONCEPT] Line Breaks ๐Ÿคก

    This is a POC for adding line breaks (or similar tags) into mobiledoc by creating custom atoms.

    I worked on this a long time ago. It is not ready but creating a PR for visibility.

    opened by ZeeJab 0
  • Text suggestions and autocorrect don't work on iOS

    Text suggestions and autocorrect don't work on iOS

    When typing into the editor on iOS, the text suggestion bar doesn't behave normally:

    • The first letter typed acts as if it is its own word (for example, typing "H" suggests "h I", "h is", "h you").
    • Further letters typed do not update the suggestions.
    • Typos are not suggested for autocorrect, even when they would be in other contexts.

    Based on my research into this issue, it seems to be related to calling preventDefault() on the key events. Using onbeforeinput instead does not have this problem.

    Video: https://user-images.githubusercontent.com/12983479/145438053-7c590790-52fe-42ff-a994-225f2005035c.mov

    Tested on https://bustle.github.io/mobiledoc-kit/demo/debug.html using Safari on iOS 15.1. Originally reported as https://github.com/TryGhost/Ghost/issues/13097.

    bug 
    opened by JBYoshi 4
  • Multiple space โ†’ nbsp translation has poor line wrapping behavior

    Multiple space โ†’ nbsp translation has poor line wrapping behavior

    mobiledoc-kit currently renders multiple consecutive spaces by replacing each space-space pair with space-nbsp (#209). Depending on the text width, this results in the left margin being misaligned when a line is wrapped at that point. Emphasizing nbsp with _ to illustrate the problem:

    This is a sentence that is followed by two
    spaces. _This is a sentence that is followed
    by three spaces. _ This is another sentence.
    
    This is a sentence that is
    followed by two spaces.
    _This is a sentence that is
    followed by three spaces.
    _ This is another sentence.
    

    To fix this, it would be better to replace each sequence of n spaces with n โˆ’ 1 nbsps followed by 1 space. This can be done with regexp lookahead:

    text.replace(/ (?= )/g, "\u00A0")
    
    This is a sentence that is followed by two
    spaces._ This is a sentence that is followed
    by three spaces.__ This is another sentence.
    
    This is a sentence that is
    followed by two spaces._
    This is a sentence that is
    followed by three spaces.__
    This is another sentence.
    

    It might be better to disable the nbsp translation entirely and rely on CSS white-space: pre-wrap, but thatโ€™d be a bigger change.

    (The same issue is present in other repositories like mobiledoc-dom-renderer, mobiledoc-html-renderer, mobiledoc-apple-news-renderer; I assume I donโ€™t need to file separate issues for each one.)

    opened by andersk 4
Releases(v0.15.0)
  • v0.15.0(Sep 1, 2022)

    No breaking API changes. Typescript types were added so user ts code could now fail type-checking, so doing a major version bump.

    • Add css in "exports" section of package.json by @romgere in https://github.com/bustle/mobiledoc-kit/pull/774
    • Build tooling updates by @gpoitch in https://github.com/bustle/mobiledoc-kit/pull/775
    • Fix Linting by @gpoitch in https://github.com/bustle/mobiledoc-kit/pull/777
    • Typescript ^4 by @gpoitch in https://github.com/bustle/mobiledoc-kit/pull/778
    • Generate Typescript Type Definitions by @gpoitch in https://github.com/bustle/mobiledoc-kit/pull/779

    Full Changelog: https://github.com/bustle/mobiledoc-kit/compare/v0.14.2...v0.15.0

    Source code(tar.gz)
    Source code(zip)
  • v0.14.2(Aug 22, 2022)

  • v0.14.1(Aug 11, 2022)

    • Add package-lock, use npm run (87a046f)
    • Create SECURITY.md (2943be1)
    • Fix emoji input on iOS (#764) (305b1a2), closes https://github.com/bustle/mobiledoc-kit/issues/764 https://github.com/TryGhost/Ghost/issues/11541
    • Update CI: run on PRs, use node 16 (#766) (083112d), closes https://github.com/bustle/mobiledoc-kit/issues/766
    • Update dependencies 8/11/22 (#767) (4b40e51), closes https://github.com/bustle/mobiledoc-kit/issues/767
    Source code(tar.gz)
    Source code(zip)
  • v0.14.0(May 25, 2022)

  • v0.13.3(Sep 23, 2021)

    • v0.13.3 33cbf1d
    • Merge pull request #759 from bustle/th/rm-grammarly-caveats 3b6438d
    • Update README.md 5dd5647
    • Merge pull request #758 from bustle/claytongentry/export-html-processing-modules 9fb972e
    • Export modules useful for HTML processing 2121de6
    • Add GitHub Actions CI ๐ŸŽท (#753) 9ee86ce
    • Typescriptify VII ๐Ÿ“บ (#751) 79a37b6

    https://github.com/bustle/mobiledoc-kit/compare/v0.13.2...v0.13.3

    Source code(tar.gz)
    Source code(zip)
  • v0.13.2(Nov 6, 2020)

  • v0.13.2-pre.0(Oct 7, 2020)

    • Typescriptify Phase V ๐Ÿงžโ€โ™‚๏ธ๐Ÿงžโ€โ™€๏ธ (#744) 974a8e9
    • Upgrade DEPZ ๐Ÿฆ˜ (#743) d27f98d
    • Typescriptify Phase IV ๐Ÿ’ƒ๐Ÿ•บ (#742) b7e109b
    • Typescriptify Phase III ๐Ÿฉ ๐Ÿ• (#741) ed3dcc2
    • Upgrade DEPZ ๐Ÿฉ (#740) 9bb0b49
    • Typescriptify Phase II ๐Ÿ (#737) 44fc8ea
    • Merge pull request #739 from sutori/0-3-2-in-docs adabc3e
    • Merge pull request #738 from ruiokada/fix_ime_bugs 5211b9a
    • Move to 0.3.2 in docs 12c9973
    • Fix grammar in test description e779803
    • Fix IME bugs * Suppress mutations when using an IME on a blank line * Ignore control keydowns when IME is active * Handle carriage return keypresses e40114d
    • Typescriptify Phase I ๐Ÿฆฉ๐Ÿฆฉ (#733) 3d96e5a
    • ๐ŸงŸโ€โ™€๏ธ๐Ÿงžโ€โ™‚๏ธ Merge pull request #732 from bustle/zeejab/prettier 83cd11c
    • Update ReadME ๐Ÿ’ฝ bfcd8cf
    • Adds eslint + fixes linting errors ๐Ÿงžโ€โ™‚๏ธ 2ecfd5c
    • Adds prettier + applies formatting ๐ŸงŸโ€โ™€๏ธ 2a3472a

    https://github.com/bustle/mobiledoc-kit/compare/v0.13.1...v0.13.2-pre.0

    Source code(tar.gz)
    Source code(zip)
  • v0.12.5(Oct 6, 2020)

  • v0.13.1(May 27, 2020)

  • v0.13.1-pre.1(May 22, 2020)

    • ๐ŸญMerge pull request #731 from bustle/zeejab/tooltip-timer f46f64b
    • ๐ŸฟMerge pull request #730 from bustle/zeejab/update-packz b780676
    • ๐Ÿง›โ€โ™€๏ธMerge pull request #724 from bustle/zeejab/willcopy 2effba1
    • Shorten hide timer for tooltip ๐Ÿญ c2fd820
    • Adds documentation for willCopy ๐ŸŽ€ be4324e
    • Adds a willCopy hook to the editor ๐Ÿง›โ€โ™€๏ธ f5f0cb8
    • Upgrade depz ๐Ÿฟ 56650a0

    https://github.com/bustle/mobiledoc-kit/compare/v0.13.1-pre.0...v0.13.1-pre.1

    Source code(tar.gz)
    Source code(zip)
  • v0.13.1-pre.0(May 18, 2020)

    • Merge pull request #729 from bustle/zeejab/ignore-built 1b9f57c
    • Add compiled website assets to gitignore ๐ŸŽ… 19181ad
    • Merge pull request #728 from bustle/th/del-tag-valid-strikethrough-markup 29f3c03
    • ๐ŸฆœMerge pull request #726 from bustle/zeejab/link-editz d9f6e95
    • Fix positionElementCenteredBelow to center tooltip correctly ๐Ÿง›โ€โ™‚๏ธ 8c914a5
    • Add del tag as valid markup 610eb75
    • Remove extra styles ๐ŸงŠ 2ab79f3
    • built website from 0b4496ba250f0e3d169ab76ff6b5c61ae5fa72d2 43a2f34
    • built website from e91884741ed5f63b372485546d5dae3ffd5b5bf9 0b4496b
    • Cleanup + test + documentation ๐Ÿ‘ฃ๐Ÿ‘ฃ e918847
    • Fix/build docs ๐Ÿ” 41a7f92
    • Adds link editing ๐Ÿฆœ 093305a

    https://github.com/bustle/mobiledoc-kit/compare/v0.13.0...v0.13.1-pre.0

    Source code(tar.gz)
    Source code(zip)
  • v0.13.0(Mar 27, 2020)

    • Correct CHANGELOG for 0.13.0-pre.1 ๐Ÿฉธ (2adc9be)
    • Update README w/ correct path ๐Ÿšฃโ€โ™€๏ธ (1425b87)
    • Update to latest conventional-changelog-cli ๐Ÿ‘บ (2ee356b)
    • Update website assets ๐Ÿคธโ€โ™€๏ธ (67e7bc4)

    https://github.com/bustle/mobiledoc-kit/compare/v0.13.0-pre.1...v.0.13.0

    Source code(tar.gz)
    Source code(zip)
  • v0.13.0-pre.1(Mar 22, 2020)

    • Use Rollup ๐Ÿฃ for build (48f5689)
    • Add debug page to README (33d5033)
    • Build + Server website ๐ŸฆŠ (6c8462b)
    • built website from 8cbf2aac75e12ea7f24332dfc1542eb0b132946d (f68c315)
    • built website from b9a86afaf1a268957ca7ff2e517c6a09aee0aba8 (c5288be)
    • built website from f68c3152be5f44ad87c3c17ca2f300d627e70d6c (6910fbd)
    • Cleanup ๐Ÿšดโ€โ™€๏ธ (43ab0f1)
    • Okay add back connectVersion but newer (a344910)
    • Refactor debug.js to remove jQuery ๐Ÿฆบ (b9a86af)
    • Remove bower.json (2e940a4)
    • Remove global ๐Ÿฆบ (451bd47)
    • Remove IE11 from tested browsers (57dd1d1)
    • Remove jquery from website ๐Ÿช (8cbf2aa)
    • Remove Saucie connectVersion (49c5a7c)
    • Upgrade to rollup v2 (5bd0c4c)
    • Use Node 12 on Travis (f1c3829)
    • Use Safari latest (1ff9ea4)
    • v0.13.0-pre.1 (9994a56)
    • WIP cleanup โ›‘ (f7a1042)

    https://github.com/bustle/mobiledoc-kit/compare/v0.12.4...v0.13.0-pre.1

    Source code(tar.gz)
    Source code(zip)
  • v0.12.4(Mar 13, 2020)

    • ๐Ÿ› Fixed parser plugin handling of top-level comment nodes (96710ce)
    • code style (11d3c5e)
    • code style (a2cbc85)
    • Fix link tooltips for any font (c4a0b63)
    • Fixed section parser handling of markup sections inside lists (b13bebb)
    • Fixed spaces added by section parser from newlines in html (ac5f673)
    • Improved section parser handling of blockquote>p (6229b88)
    • lint (e18703b)
    • Make text selection test asynchronous ๐Ÿ”ฅ (192dcb6)
    • Restrict dom selector assertion to the qunit fixture element ๐Ÿฆจ (2e2d60a)
    • Shrink range to only include sections with non-zero selection when toggling sections ๐Ÿ” (071a555)
    • updating model.post.trimTo && editor.post.toggleSection to ignor tail if not selected. Adding tests (17433a0)
    • Use wait helper instead of setTimeout in async tests (b547d4d)

    https://github.com/bustle/mobiledoc-kit/compare/v0.12.3...v0.12.4

    Source code(tar.gz)
    Source code(zip)
  • v0.12.3(Jan 28, 2020)

  • v0.12.2(Jan 10, 2020)

  • v0.12.1(Sep 20, 2019)

    Note: The previous version was released as v0.12.0-0 (a prerelease version) due to an issue with the CI infrastructure. v0.12.1 supersedes v0.12.0-0 and there is no v0.12.0 release.

    • Add button in demo to toggle blockquote (4005732)
    • Add Editor#activeSectionAttributes to support toolbar state for new section attributes in mobiledoc (0f65798)
    • Fix #689: Original range should be remembered after toggleSection (95146e0), closes #689
    • Fix #694: Alignment of a section is removed when pressing "Enter" (4fadc60), closes #694
    • Remove redundant CSS from demo.css (020dee3)
    • Replace Array.find with detect utility function ๐Ÿฆˆ (ea54c6b)
    • Replace Array.includes with utility function for IE11 compat ๐Ÿฒ (5535e08)
    • Replace for..of with forEach ๐Ÿฅ“ (529478f)
    • Replace Object.entries with utility function ๐Ÿฅด (ebed97a)
    • Set default range for 'setAttribute' in PostEditor (53b36d7)
    • Specify Sauce Connect version ๐Ÿพ (654943d)
    • Update testem/sauce labs dependencies ๐Ÿ„ (105f62b)

    https://github.com/bustle/mobiledoc-kit/compare/v0.12.0-0...v0.12.1

    Source code(tar.gz)
    Source code(zip)
  • v0.12.0-0(Jul 16, 2019)

    • Remove node_modules/ path from scripts in package.json (#687) 00a1c46
    • Implement Mobiledoc 0.3.2 (text alignment attribute) (continued) (#688) 9d842fb
    • Bump spec to 0.3.2, optional section attributes (#681) 0449e15
    • Fix sectionParser obliterating plain text content in certain circumstances (#685) e5f877f
    • Merge pull request #684 from bustle/dalia/demo-copy-update c73613a
    • Copy update in demo 77de471
    • ๐Ÿ› Fixed range#expandByMarker not expanding to beginning/end of section (#677) 0000d1d
    • Merge pull request #679 from kevinansfield/fix-missing-top-level-atoms 9e5f064
    • ๐Ÿ› Fixed atoms with no text value being removed when parsing top-level markerables 4828dd6
    • Uncomment "FIXME" Google Docs nested uls test (#678) 358cd9d

    https://github.com/bustle/mobiledoc-kit/compare/v0.11.2...v0.12.0-0

    Source code(tar.gz)
    Source code(zip)
  • v0.10.21(Mar 2, 2018)

  • v0.10.15(Mar 10, 2017)

    • chore: Replace deprecated mobiledoc-html-renderer with mobiledoc-dom-renderer (#538) (2295cfc)
    • chore: Upgrade broccoli dependencies (#539) (3155800)
    • chore: Upgrade saucie to latest (#540) (9662756)
    • style(css): Drop LESS dependency (#537) (e9d0276)
    • Allows users to add an optional name attribute to a keyCommand object as passed to the `registerKe (0cc12d3)
    • docs(README): added vue-mobiledoc-editor to library options (#531) (c0d4cf3)

    For more, see the Changelog

    Source code(tar.gz)
    Source code(zip)
  • v0.10.11(Sep 14, 2016)

  • v0.10.10(Sep 13, 2016)

    • feat(textInput): able to unregister single or all text input handlers (#484) (68a60ae) @eguitarz
    • feat(UI): Export toggleLink (#491) (3335357) @joshfrench
    • feat(willHandleNewline): add willHandleNewline hook (#489) (f1d2262) @eguitarz
    • docs(grammarly): DOC - Add section about disabling Grammarly (#490) (bbf3cfd) @YoranBrondsema
    • fix(deprecate): Make deprecate accept conditional argument (#488) (059fd66)
    Source code(tar.gz)
    Source code(zip)
  • v0.10.9(Aug 31, 2016)

    • fix(onTextInput): Ensure onTextInput is triggered by tab character (#479) (a0aaa3a), closes #400
    • fix(newlines). Remove newline chars in text nodes (\n) when parsing HTML (#478) (6036b90), closes #333
    • fix(range) Allow reading range from DOM when editor is disabled (#476) (6969f5c), closes #475
    • refactor(cleanup) Remove unused methods from Post, Markerable (#474) (235f7a3)
    Source code(tar.gz)
    Source code(zip)
  • v0.10.8(Aug 25, 2016)

    • feat(atom): Implement Atom save hook (#472) (3ef3bc3), closes #399
    • fix(atoms): Avoid rerendering atoms when section content changes. (#471) (a59ae74), closes #421
    • fix(placeholder): Use '__has-no-content' class name to display placeholder text (#461) (11452fe), closes #407 #171
    • refactor(tests): Refactor deletion tests to be terser (#469) (eeb9e19)

    Possible BREAKING CHANGE: The placeholder text is now absolutely positioned (at top: 0) of the editor div. If a user has applied their own padding to the editor div the placeholder may not show up in the correct location. The solution is to add a CSS rule that overrides the top to match the value of the padding-top:

    .__mobiledoc-editor.__has-no-content:after {
      top: <value of padding-top>;
    }
    

    Also: The editor now has a min-height: 1em; to ensure that the placeholder has a space in which to be displayed.

    Source code(tar.gz)
    Source code(zip)
  • v0.10.7(Aug 24, 2016)

    • fix(paste): Fix insertion into blank section (#466) (a3d274d), closes #466 #462
    • fix(paste): Handle paste card at start of middle list item (#468) (939a541), closes #467
    • doc(jsdoc): Fix JSDocs violations and typo (#463) (843f381), closes #463
    • doc(jsdoc): Make building docs part of testing, to avoid jsdocs errors (#464) (039fd04)
    • feat(post): Refactor rendering of editor element (#460) (c9d4067), closes #335
    Source code(tar.gz)
    Source code(zip)
  • v0.10.6(Aug 23, 2016)

    • feat(delete): add delete hooks in lifecycle (#454) (f7c72cd)
    • feat(delete): add range, direction and unit to delete hook (#455) (2884ebf)
    • fix(paste): Allow inserting multiple markup sections onto a list item (#459) (1898cf5), closes #456
    Source code(tar.gz)
    Source code(zip)
  • v0.10.5(Aug 23, 2016)

    • fix(links): Ensure that CTRL+K on Windows toggles link. Fixes #452 (#453) (3220534), closes #452 #453
    • style(links): Add nobreak to links in the editor so toolips are always accessible (#449) (b75bb7d)
    • docs(changelog): Update changelog manually (2ceb39d)
    Source code(tar.gz)
    Source code(zip)
  • v0.10.4(Aug 4, 2016)

    • Add buildWithText test helper, postEditor#deleteRange (3327408) (#442)
    • Add postEditor#deleteAtPosition, deprecate deleteFrom (92c3eb6) (#442)
    • Add toRange and toPosition methods to Position, Section, Post (c7ec6eb), closes #258 (#446)
    • Refactor deleteRange (54f56cc) (#444)
    • remove post#sectionsContainedBy(range) (27ba974) (#442)
    • update mobiledoc-pretty-json-renderer to ^2.0.1 (9ff9f13) (#447)
    • Use "version" script instead of postversion with --amend --no-edit (13abc9d) (#448)
    • docs: replaceWithListSection and replaceWithHeaderSection (2b65ad5)
    • Tests: Extract MockEditor, run, renderBuiltAbstract, docs for buildFromText (b473a27) (#442)
    Source code(tar.gz)
    Source code(zip)
  • v0.10.3(Jul 26, 2016)

  • v0.10.2(Jul 26, 2016)

    • Refocus editor after toggling markup when no selection #436, closes #369
    • Add forward/backward inclusivity rules for markups #438 , closes #402 #392
    • Add support for word deletion on Mac (opt+del) and PC (ctrl+del) #437, closes #169
    • Remove deprecated Post#cloneRange Editor#registerExpansion, Editor#on #439
    Source code(tar.gz)
    Source code(zip)
Owner
Bustle
Open source projects and forks from the Bustle engineering team.
Bustle
A React framework for building text editors.

Draft.js Draft.js is a JavaScript rich text editor framework, built for React and backed by an immutable model. Extensible and Customizable: We provid

Facebook 22.3k Jan 4, 2023
A completely customizable framework for building rich text editors. (Currently in beta.)

A completely customizable framework for building rich text editors. Why? ยท Principles ยท Demo ยท Examples ยท Documentation ยท Contributing! Slate lets you

Ian Storm Taylor 26.2k Dec 30, 2022
Collection of tools for building rich text editors.

psst we have great documentation at https://bangle.dev What is bangle.dev ? bangle.dev is a collection of components for building powerful editing exp

null 553 Dec 29, 2022
The next generation Javascript WYSIWYG HTML Editor.

Froala Editor V3 Froala WYSIWYG HTML Editor is one of the most powerful JavaScript rich text editors ever. Slim - only add the plugins that you need (

Froala 5k Jan 1, 2023
A modern, simple and elegant WYSIWYG rich text editor.

jQuery-Notebook A simple, clean and elegant WYSIWYG rich text editor for web aplications Note: Check out the fully functional demo and examples here.

Raphael Cruzeiro 1.7k Dec 12, 2022
Quill is a modern WYSIWYG editor built for compatibility and extensibility.

Note: This branch and README covers the upcoming 2.0 release. View 1.x docs here. Quill Rich Text Editor Quickstart โ€ข Documentation โ€ข Development โ€ข Co

Quill 34.3k Jan 2, 2023
Medium.com WYSIWYG editor clone. Uses contenteditable API to implement a rich text solution.

If you would be interested in helping to maintain one of the most successful WYSIWYG text editors on github, let us know! (See issue #1503) MediumEdit

yabwe 15.7k Jan 4, 2023
A lightweight and amazing WYSIWYG JavaScript editor - 20kB only (8kB gzip)

Supporting Trumbowyg Trumbowyg is an MIT-licensed open source project and completely free to use. However, the amount of effort needed to maintain and

Alexandre Demode 3.8k Jan 7, 2023
Simple, beautiful wysiwyg editor

This repo is no longer maintained. bootstrap3-wysiwyg is much better Overview Bootstrap-wysihtml5 is a javascript plugin that makes it easy to create

James Hollingworth 4.2k Dec 30, 2022
Raptor, an HTML5 WYSIWYG content editor!

Raptor Editor Raptor Editor is a user-focused extensible WYSIWYG website content editor - check out the Demo. It is designed to be user and developer

PANmedia 533 Sep 24, 2022
Super simple WYSIWYG editor

Summernote Super simple WYSIWYG Editor. Summernote Summernote is a JavaScript library that helps you create WYSIWYG editors online. Home page: https:/

Summernote 11k Jan 7, 2023
๐Ÿž๐Ÿ“ Markdown WYSIWYG Editor. GFM Standard + Chart & UML Extensible.

TOAST UI Editor v3 major update planning ?? ?? ?? TOAST UI Editor is planning a v3 major update for 2021. You can see our detail RoadMap here! GFM Mar

NHN 15.5k Jan 3, 2023
A powerful WYSIWYG rich text web editor by pure javascript

KothingEditor A powerful WYSIWYG rich text web editor by pure javascript Demo : kothing.github.io/editor The KothingEditor is a lightweight, flexible,

Kothing 34 Dec 25, 2022
The best enterprise-grade WYSIWYG editor. Fully customizable with countless features and plugins.

CKEditor 4 - Smart WYSIWYG HTML editor A highly configurable WYSIWYG HTML editor with hundreds of features, from creating rich text content with capti

CKEditor Ecosystem 5.7k Dec 27, 2022
An Easy and Fast WYSIWYG Editor

Simditor Simditor is a browser-based WYSIWYG text editor. It is used by Tower -- a popular project management web application. Supported Browsers: IE1

ๅฝฉ็จ‹่ฎพ่ฎก 5k Jan 3, 2023
Pure javascript based WYSIWYG html editor, with no dependencies.

SunEditor Pure javscript based WYSIWYG web editor, with no dependencies Demo : suneditor.com The Suneditor is a lightweight, flexible, customizable WY

Yi JiHong 1.1k Jan 2, 2023
WYSIWYG editor developed as jQuery plugin

RichText WYSIWYG editor developed as jQuery plugin. Requirements jQuery (v.3+, v.3.2+ recommended) FontAwesome (v.4.7.0 / v.5+) src/jquery.richtext.mi

Bob 95 Dec 30, 2022
A lightweight HTML and BBCode WYSIWYG editor

SCEditor v3.1.1 A lightweight WYSIWYG BBCode and XHTML editor. For more information visit sceditor.com Usage Include the SCEditor JavaScript: <link re

Sam 566 Dec 23, 2022
An Open, Extensible Framework for building Web3D Engine, Editor

Meta3D (Meta3D is under development, not product ready) Meta3D is an Open, Extensible Framework for building Web3D Engine, Editor. read Meta3Dไป‹็ป for m

Wonder Technology 54 Dec 29, 2022