Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

medium-editor

yabwe66.9kMIT5.23.3TypeScript support: definitely-typed

Medium.com WYSIWYG editor clone.

contenteditable, editor, medium, wysiwyg, rich-text

readme

# MediumEditor

This is a clone of medium.com inline editor toolbar.

MediumEditor has been written using vanilla JavaScript, no additional frameworks required.

screenshot

Join the chat at https://gitter.im/yabwe/medium-editor

Browser Support

Saucelabs Build Status

Supported Browsers

NPM info

Travis build status Dependency Status devDependency Status Coverage Status

Basic usage

Demo

demo: http://yabwe.github.io/medium-editor/

Installation

Via npm:

Run in your console: npm install medium-editor

Via bower:

bower install medium-editor

Via an external CDN

  • Using jsDelivr.

    For the latest version:

    <script src="//cdn.jsdelivr.net/npm/medium-editor@latest/dist/js/medium-editor.min.js"></script>
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/medium-editor@latest/dist/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">

    For a custom one:

    <script src="//cdn.jsdelivr.net/npm/medium-editor@5.23.2/dist/js/medium-editor.min.js"></script>
    <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/medium-editor@5.23.2/dist/css/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
  • Using CDNJS.

Manual installation:

Download the latest release and attach medium editor's stylesheets to your page:

Find the files to below mentioned linking in the dist folder. (./medium-editor/dist/...)

<link rel="stylesheet" href="css/medium-editor.css"> <!-- Core -->
<link rel="stylesheet" href="css/themes/default.css"> <!-- or any other theme -->

Usage

The next step is to reference the editor's script

<script src="js/medium-editor.js"></script>

You can now instantiate a new MediumEditor object:

<script>var editor = new MediumEditor('.editable');</script>

The above code will transform all the elements with the .editable class into HTML5 editable contents and add the medium editor toolbar to them.

You can also pass a list of HTML elements:

var elements = document.querySelectorAll('.editable'),
    editor = new MediumEditor(elements);

MediumEditor also supports textarea. If you provide a textarea element, the script will create a new div with contentEditable=true, hide the textarea and link the textarea value to the div HTML content.

Integrating with various frameworks

People have contributed wrappers around MediumEditor for integrating with different frameworks and tech stacks. Take a look at the list of existing Wrappers and Integrations that have already been written for MediumEditor!

MediumEditor Options

View the MediumEditor Options documentation on all the various options for MediumEditor.

Options to customize medium-editor are passed as the second argument to the MediumEditor constructor. Example:

var editor = new MediumEditor('.editor', {
    // options go here
});

Core options

  • activeButtonClass: CSS class added to active buttons in the toolbar. Default: 'medium-editor-button-active'
  • buttonLabels: type of labels on the buttons. Values: false | 'fontawesome'. Default: false

NOTE:

Using 'fontawesome' as the buttonLabels requires version 4.1.0 of the fontawesome css to be on the page to ensure all icons will be displayed correctly

  • delay: time in milliseconds to show the toolbar or anchor tag preview. Default: 0
  • disableReturn: enables/disables the use of the return-key. You can also set specific element behavior by using setting a data-disable-return attribute. Default: false
  • disableDoubleReturn: allows/disallows two (or more) empty new lines. You can also set specific element behavior by using setting a data-disable-double-return attribute. Default: false
  • disableExtraSpaces: when set to true, it disallows spaces at the beginning and end of the element. Also it disallows entering 2 consecutive spaces between 2 words. Default: false
  • disableEditing: enables/disables adding the contenteditable behavior. Useful for using the toolbar with customized buttons/actions. You can also set specific element behavior by using setting a data-disable-editing attribute. Default: false
  • elementsContainer: specifies a DOM node to contain MediumEditor's toolbar and anchor preview elements. Default: document.body
  • extensions: extension to use (see Custom Buttons and Extensions) for more. Default: {}
  • spellcheck: Enable/disable native contentEditable automatic spellcheck. Default: true
  • targetBlank: enables/disables target="_blank" for anchor tags. Default: false

Toolbar options

The toolbar for MediumEditor is implemented as a built-in extension which automatically displays whenever the user selects some text. The toolbar can hold any set of defined built-in buttons, but can also hold any custom buttons passed in as extensions.

Options for the toolbar are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    toolbar: {
        /* These are the default options for the toolbar,
           if nothing is passed this is what is used */
        allowMultiParagraphSelection: true,
        buttons: ['bold', 'italic', 'underline', 'anchor', 'h2', 'h3', 'quote'],
        diffLeft: 0,
        diffTop: -10,
        firstButtonClass: 'medium-editor-button-first',
        lastButtonClass: 'medium-editor-button-last',
        relativeContainer: null,
        standardizeSelectionStart: false,
        static: false,
        /* options which only apply when static is true */
        align: 'center',
        sticky: false,
        updateOnEmptySelection: false
    }
});
  • allowMultiParagraphSelection: enables/disables whether the toolbar should be displayed when selecting multiple paragraphs/block elements. Default: true
  • buttons: the set of buttons to display on the toolbar. Default: ['bold', 'italic', 'underline', 'anchor', 'h2', 'h3', 'quote']
  • diffLeft: value in pixels to be added to the X axis positioning of the toolbar. Default: 0
  • diffTop: value in pixels to be added to the Y axis positioning of the toolbar. Default: -10
  • firstButtonClass: CSS class added to the first button in the toolbar. Default: 'medium-editor-button-first'
  • lastButtonClass: CSS class added to the last button in the toolbar. Default: 'medium-editor-button-last'
  • relativeContainer: DOMElement to append the toolbar to instead of the body. When passed, the toolbar will also be positioned relative instead of absolute. Default: null
  • standardizeSelectionStart: enables/disables standardizing how the beginning of a range is decided between browsers whenever the selected text is analyzed for updating toolbar buttons status. Default: false
  • static: enable/disable the toolbar always displaying in the same location relative to the medium-editor element. Default: false
Options which only apply when the static option is being used:
  • align: left|center|right - When the static option is true, this aligns the static toolbar relative to the medium-editor element. Default: center
  • sticky: When the static option is true, this enables/disables the toolbar "sticking" to the viewport and staying visible on the screen while the page scrolls. Default: false
  • updateOnEmptySelection: When the static option is true, this enables/disables updating the state of the toolbar buttons even when the selection is collapsed (there is no selection, just a cursor). Default: false

To disable the toolbar (which also disables the anchor-preview extension), set the value of the toolbar option to false:

var editor = new MediumEditor('.editable', {
    toolbar: false
});

Button Options

Button behavior can be modified by passing an object into the buttons array instead of a string. This allow for overriding some of the default behavior of buttons. The following options are some of the basic parts of buttons that you may override, but any part of the MediumEditor.Extension.prototype can be overridden via these button options. (Check out the source code for buttons to see what all can be overridden).

  • name: name of the button being overridden
  • action: argument to pass to MediumEditor.execAction() when the button is clicked.
  • aria: value to add as the aria-label attribute of the button element displayed in the toolbar. This is also used as the tooltip for the button.
  • tagNames: array of element tag names that would indicate that this button has already been applied. If this action has already been applied, the button will be displayed as 'active' in the toolbar.
    • Example: For 'bold', if the text is ever within a <b> or <strong> tag that indicates the text is already bold. So the array of tagNames for bold would be: ['b', 'strong']
    • NOTE: This is not used if useQueryState is set to true.
  • style: A pair of css property & value(s) that indicate that this button has already been applied. If this action has already been applied, the button will be displayed as 'active' in the toolbar.
    • Example: For 'bold', if the text is ever within an element with a 'font-weight' style property set to 700 or 'bold', that indicates the text is already bold. So the style object for bold would be { prop: 'font-weight', value: '700|bold' }
    • NOTE: This is not used if useQueryState is set to true.
    • Properties of the style object:
      • prop: name of the css property
      • value: value(s) of the css property (multiple values can be separated by a '|')
  • useQueryState: Enables/disables whether this button should use the built-in document.queryCommandState() method to determine whether the action has already been applied. If the action has already been applied, the button will be displayed as 'active' in the toolbar
    • Example: For 'bold', if this is set to true, the code will call document.queryCommandState('bold') which will return true if the browser thinks the text is already bold, and false otherwise
  • contentDefault: Default innerHTML to put inside the button
  • contentFA: The innerHTML to use for the content of the button if the buttonLabels option for MediumEditor is set to 'fontawesome'
  • classList: An array of classNames (strings) to be added to the button
  • attrs: A set of key-value pairs to add to the button as custom attributes to the button element.

Example of overriding buttons (here, the goal is to mimic medium by having <kbd>H1</kbd> and <kbd>H2</kbd> buttons which actually produce <h2> and <h3> tags respectively):

var editor = new MediumEditor('.editable', {
    toolbar: {
        buttons: [
            'bold',
            'italic',
            {
                name: 'h1',
                action: 'append-h2',
                aria: 'header type 1',
                tagNames: ['h2'],
                contentDefault: '<b>H1</b>',
                classList: ['custom-class-h1'],
                attrs: {
                    'data-custom-attr': 'attr-value-h1'
                }
            },
            {
                name: 'h2',
                action: 'append-h3',
                aria: 'header type 2',
                tagNames: ['h3'],
                contentDefault: '<b>H2</b>',
                classList: ['custom-class-h2'],
                attrs: {
                    'data-custom-attr': 'attr-value-h2'
                }
            },
            'justifyCenter',
            'quote',
            'anchor'
        ]
    }
});

Anchor Preview options

The anchor preview is a built-in extension which automatically displays a 'tooltip' when the user is hovering over a link in the editor. The tooltip will display the href of the link, and when click, will open the anchor editing form in the toolbar.

Options for the anchor preview 'tooltip' are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    anchorPreview: {
        /* These are the default options for anchor preview,
           if nothing is passed this is what it used */
        hideDelay: 500,
        previewValueSelector: 'a'
    }
}
});
  • hideDelay: time in milliseconds to show the anchor tag preview after the mouse has left the anchor tag. Default: 500
  • previewValueSelector: the default selector to locate where to put the activeAnchor value in the preview. You should only need to override this if you've modified the way in which the anchor-preview extension renders. Default: 'a'
  • showWhenToolbarIsVisible: determines whether the anchor tag preview shows up when the toolbar is visible. You should set this value to true if the static option for the toolbar is true and you want the preview to show at the same time. Default: false
  • showOnEmptyLinks: determines whether the anchor tag preview shows up on link with href as '' or '#something'. You should set this value to false if you do not want the preview to show up in such use cases. Default: true

To disable the anchor preview, set the value of the anchorPreview option to false:

var editor = new MediumEditor('.editable', {
    anchorPreview: false
});
NOTE:
  • If the toolbar is disabled (via toolbar: false option or data-disable-toolbar attribute) the anchor-preview is automatically disabled.
  • If the anchor editing form is not enabled, clicking on the anchor-preview will not allow the href of the link to be edited

Placeholder Options

The placeholder handler is a built-in extension which displays placeholder text when the editor is empty.

Options for placeholder are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    placeholder: {
        /* This example includes the default options for placeholder,
           if nothing is passed this is what it used */
        text: 'Type your text',
        hideOnClick: true
    }
});
  • text: Defines the default placeholder for empty contenteditables when placeholder is not set to false. You can overwrite it by setting a data-placeholder attribute on the editor elements. Default: 'Type your text'

  • hideOnClick: Causes the placeholder to disappear as soon as the field gains focus. Default: true. To hide the placeholder only after starting to type, and to show it again as soon as field is empty, set this option to false.

To disable the placeholder, set the value of the placeholder option to false:

var editor = new MediumEditor('.editable', {
    placeholder: false
});

Anchor Form options

The anchor form is a built-in button extension which allows the user to add/edit/remove links from within the editor. When 'anchor' is passed in as a button in the list of buttons, this extension will be enabled and can be triggered by clicking the corresponding button in the toolbar.

Options for the anchor form are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    toolbar: {
        buttons: ['bold', 'italic', 'underline', 'anchor']
    },
    anchor: {
        /* These are the default options for anchor form,
           if nothing is passed this is what it used */
        customClassOption: null,
        customClassOptionText: 'Button',
        linkValidation: false,
        placeholderText: 'Paste or type a link',
        targetCheckbox: false,
        targetCheckboxText: 'Open in new window'
    }
}
});
  • customClassOption: custom class name the user can optionally have added to their created links (ie 'button'). If passed as a non-empty string, a checkbox will be displayed allowing the user to choose whether to have the class added to the created link or not. Default: null
  • customClassOptionText: text to be shown in the checkbox when the customClassOption is being used. Default: 'Button'
  • linkValidation: enables/disables check for common URL protocols on anchor links. Converts invalid url characters (ie spaces) to valid characters using encodeURI. Default: false
  • placeholderText: text to be shown as placeholder of the anchor input. Default: 'Paste or type a link'
  • targetCheckbox: enables/disables displaying a "Open in new window" checkbox, which when checked changes the target attribute of the created link. Default: false
  • targetCheckboxText: text to be shown in the checkbox enabled via the targetCheckbox option. Default: 'Open in new window'

Paste Options

The paste handler is a built-in extension which attempts to filter the content when the user pastes. How the paste handler filters is configurable via specific options.

Options for paste handling are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    paste: {
        /* This example includes the default options for paste,
           if nothing is passed this is what it used */
        forcePlainText: true,
        cleanPastedHTML: false,
        cleanReplacements: [],
        cleanAttrs: ['class', 'style', 'dir'],
        cleanTags: ['meta'],
        unwrapTags: []
    }
});
  • forcePlainText: Forces pasting as plain text. Default: true
  • cleanPastedHTML: cleans pasted content from different sources, like google docs etc. Default: false
  • preCleanReplacements: custom pairs (2 element arrays) of RegExp and replacement text to use during paste when forcePlainText or cleanPastedHTML are true OR when calling cleanPaste(text) helper method. These replacements are executed before builtin replacements. Default: []
  • cleanReplacements: custom pairs (2 element arrays) of RegExp and replacement text to use during paste when forcePlainText or cleanPastedHTML are true OR when calling cleanPaste(text) helper method. These replacements are executed after builtin replacements. Default: []
  • cleanAttrs: list of element attributes to remove during paste when cleanPastedHTML is true or when calling cleanPaste(text) or pasteHTML(html,options) helper methods. Default: ['class', 'style', 'dir']
  • cleanTags: list of element tag names to remove during paste when cleanPastedHTML is true or when calling cleanPaste(text) or pasteHTML(html,options) helper methods. Default: ['meta']
  • unwrapTags: list of element tag names to unwrap (remove the element tag but retain its child elements) during paste when cleanPastedHTML is true or when calling cleanPaste(text) or pasteHTML(html,options) helper methods. Default: []

KeyboardCommands Options

The keyboard commands handler is a built-in extension for mapping key-combinations to actions to execute in the editor.

Options for KeyboardCommands are passed as an object that is a member of the outer options object. Example:

var editor = new MediumEditor('.editable', {
    keyboardCommands: {
        /* This example includes the default options for keyboardCommands,
           if nothing is passed this is what it used */
        commands: [
            {
                command: 'bold',
                key: 'B',
                meta: true,
                shift: false,
                alt: false
            },
            {
                command: 'italic',
                key: 'I',
                meta: true,
                shift: false,
                alt: false
            },
            {
                command: 'underline',
                key: 'U',
                meta: true,
                shift: false,
                alt: false
            }
        ],
    }
});
  • commands: Array of objects describing each command and the combination of keys that will trigger it. Required for each object:
    • command: argument passed to editor.execAction() when key-combination is used
      • if defined as false, the shortcut will be disabled
    • key: keyboard character that triggers this command
    • meta: whether the ctrl/meta key has to be active or inactive
    • shift: whether the shift key has to be active or inactive
    • alt: whether the alt key has to be active or inactive

To disable the keyboard commands, set the value of the keyboardCommands option to false:

var editor = new MediumEditor('.editable', {
    keyboardCommands: false
});

The auto-link handler is a built-in extension which automatically turns URLs entered into the text field into HTML anchor tags (similar to the functionality of Markdown). This feature is OFF by default.

To enable built-in auto-link support, set the value of the autoLink option to true:

var editor = new MediumEditor('.editable', {
    autoLink: true
});

Image Dragging Options

The image dragging handler is a built-in extension for handling dragging & dropping images into the contenteditable. This feature is ON by default.

To disable built-in image dragging, set the value of the imageDragging option to false:

var editor = new MediumEditor('.editable', {
    imageDragging: false
});

Disable File Dragging

To stop preventing drag & drop events and disable file dragging in general, provide a dummy ImageDragging extension.

var editor = new MediumEditor('.editor', {
    extensions: {
        'imageDragging': {}
    }
});

Due to the state of code in 5.0.0, the editor ALWAYS prevented any drag and drop actions. We will have a better way to disable file dragging in 6.*

Options Example:

var editor = new MediumEditor('.editable', {
    delay: 1000,
    targetBlank: true,
    toolbar: {
        buttons: ['bold', 'italic', 'quote'],
        diffLeft: 25,
        diffTop: 10,
    },
    anchor: {
        placeholderText: 'Type a link',
        customClassOption: 'btn',
        customClassOptionText: 'Create Button'
    },
    paste: {
        cleanPastedHTML: true,
        cleanAttrs: ['style', 'dir'],
        cleanTags: ['label', 'meta'],
        unwrapTags: ['sub', 'sup']
    },
    anchorPreview: {
        hideDelay: 300
    },
    placeholder: {
        text: 'Click to edit'
    }
});

Buttons

By default, MediumEditor supports buttons for most of the commands for document.execCommand() that are well-supported across all its supported browsers.

Default buttons.

MediumEditor, by default, will show only the buttons listed here to avoid a huge toolbar:

  • bold
  • italic
  • underline
  • anchor (built-in support for collecting a url via the anchor extension)
  • h2
  • h3
  • quote

All buttons.

These are all the built-in buttons supported by MediumEditor.

  • bold
  • italic
  • underline
  • strikethrough
  • subscript
  • superscript
  • anchor
  • image (this simply converts selected text to an image tag)
  • quote
  • pre
  • orderedlist
  • unorderedlist
  • indent (moves the selected text up one level)
  • outdent (moves the selected text down one level)
  • justifyLeft
  • justifyCenter
  • justifyRight
  • justifyFull
  • h1
  • h2
  • h3
  • h4
  • h5
  • h6
  • removeFormat (clears inline style formatting, preserves blocks)
  • html (parses selected html and converts into actual html elements)

Themes

Check out the Wiki page for a list of available themes: https://github.com/yabwe/medium-editor/wiki/Themes

API

View the MediumEditor Object API documentation on the Wiki for details on all the methods supported on the MediumEditor object.

Initialization methods

  • MediumEditor(elements, options): Creates an instance of MediumEditor
  • .destroy(): tears down the editor if already setup, removing all DOM elements and event handlers
  • .setup(): rebuilds the editor if it has already been destroyed, recreating DOM elements and attaching event handlers
  • .addElements(): add elements to an already initialized instance of MediumEditor
  • .removeElements(): remove elements from an already initialized instance of MediumEditor

Event Methods

  • .on(target, event, listener, useCapture): attach a listener to a DOM event which will be detached when MediumEditor is deactivated
  • .off(target, event, listener, useCapture): detach a listener to a DOM event that was attached via on()
  • .subscribe(event, listener): attaches a listener to a custom medium-editor event
  • .unsubscribe(event, listener): detaches a listener from a custom medium-editor event
  • .trigger(name, data, editable): manually triggers a custom medium-editor event

Selection Methods

  • .checkSelection(): manually trigger an update of the toolbar and extensions based on the current selection
  • .exportSelection(): return a data representation of the selected text, which can be applied via importSelection()
  • .importSelection(selectionState): restore the selection using a data representation of previously selected text (ie value returned by exportSelection())
  • .getFocusedElement(): returns an element if any contenteditable element monitored by MediumEditor currently has focused
  • .getSelectedParentElement(range): get the parent contenteditable element that contains the current selection
  • .restoreSelection(): restore the selection to what was selected when saveSelection() was called
  • .saveSelection(): internally store the set of selected text
  • .selectAllContents(): expands the selection to contain all text within the focused contenteditable
  • .selectElement(element): change selection to be a specific element and update the toolbar to reflect the selection
  • .stopSelectionUpdates(): stop the toolbar from updating to reflect the state of the selected text
  • .startSelectionUpdates(): put the toolbar back into its normal updating state

Editor Action Methods

  • .cleanPaste(text): convert text to plaintext and replace current selection with result
  • .createLink(opts): creates a link via the native document.execCommand('createLink') command
  • .execAction(action, opts): executes an built-in action via document.execCommand
  • .pasteHTML(html, options): replace the current selection with html
  • .queryCommandState(action): wrapper around the browser's built in document.queryCommandState(action) for checking whether a specific action has already been applied to the selection.

Helper Methods

  • .delay(fn): delay any function from being executed by the amount of time passed as the delay option
  • .getContent(index): gets the trimmed innerHTML of the element at index
  • .getExtensionByName(name): get a reference to an extension with the specified name
  • .resetContent(element): reset the content of all elements or a specific element to its value when added to the editor initially
  • .serialize(): returns a JSON object with elements contents
  • .setContent(html, index): sets the innerHTML to html of the element at index

Static Methods/Properties

  • .getEditorFromElement(element): retrieve the instance of MediumEditor that is monitoring the provided editor element
  • .version: the version information for the MediumEditor library

Dynamically add/remove elements to your instance

It is possible to dynamically add new elements to your existing MediumEditor instance:

var editor = new MediumEditor('.editable');
editor.subscribe('editableInput', this._handleEditableInput.bind(this));

// imagine an ajax fetch/any other dynamic functionality which will add new '.editable' elements to the DOM

editor.addElements('.editable');
// OR editor.addElements(document.getElementsByClassName('editable'));
// OR editor.addElements(document.querySelectorAll('.editable'));

Passing an elements or array of elements to addElements(elements) will:

  • Add the given element or array of elements to the internal this.elements array.
  • Ensure the element(s) are initialized with the proper attributes and event handlers as if the element had been passed during instantiation of the editor.
  • For any <textarea> elements:
    • Hide the <textarea>
    • Create a new <div contenteditable=true> element and add it to the elements array.
    • Ensure the 2 elements remain sync'd.
  • Be intelligent enough to run the necessary code only once per element, no matter how often you will call it.

Removing elements dynamically

Straight forward, just call removeElements with the element or array of elements you to want to tear down. Each element itself will remain a contenteditable - it will just remove all event handlers and all references to it so you can safely remove it from DOM.

editor.removeElements(document.querySelector('#myElement'));
// OR editor.removeElements(document.getElementById('myElement'));
// OR editor.removeElements('#myElement');

// in case you have jQuery and don't exactly know when an element was removed, for example after routing state change
var removedElements = [];
editor.elements.forEach(function (element) {
    // check if the element is still available in current DOM
    if (!$(element).parents('body').length) {
        removedElements.push(element);
    }
});

editor.removeElements(removedElements);

Capturing DOM changes

For observing any changes on contentEditable, use the custom 'editableInput' event exposed via the subscribe() method:

var editor = new MediumEditor('.editable');
editor.subscribe('editableInput', function (event, editable) {
    // Do some work
});

This event is supported in all browsers supported by MediumEditor (including IE9+ and Edge)! To help with cases when one instance of MediumEditor is monitoring multiple elements, the 2nd argument passed to the event handler (editable in the example above) will be a reference to the contenteditable element that has actually changed.

This is handy when you need to capture any modifications to the contenteditable element including:

  • Typing
  • Cutting/Pasting
  • Changes from clicking on buttons in the toolbar
  • Undo/Redo

Why is this interesting and why should you use this event instead of just attaching to the input event on the contenteditable element?

So for most modern browsers (Chrome, Firefox, Safari, etc.), the input event works just fine. In fact, editableInput is just a proxy for the input event in those browsers. However, the input event is not supported for contenteditable elements in IE 9-11 and is mostly supported in Microsoft Edge, but not fully.

So, to properly support the editableInput event in Internet Explorer and Microsoft Edge, MediumEditor uses a combination of the selectionchange and keypress events, as well as monitoring calls to document.execCommand.

Extensions & Plugins

Check the documentation in order to learn how to develop extensions for MediumEditor.

A list of existing extensions and plugins, such as Images and Media embeds, Tables and Markdown can be found here.

Development

To run the demo locally:

  1. Clone this repo locally
  2. Run npm install from your console at the root
  3. Run node index.js from the root
  4. Navigate to http://localhost:8088/demo/index.html to view the demo

MediumEditor development tasks are managed by Grunt. To install all the necessary packages, just invoke:

npm install

To run all the test and build the dist files for testing on demo pages, just invoke:

grunt

These are the other available grunt tasks:

  • js: runs jslint and jasmine tests and creates minified and concatenated versions of the script;
  • css: runs autoprefixer and csslint
  • test: runs jasmine tests, jslint and csslint
  • watch: watch for modifications on script/scss files
  • spec: runs a task against a specified file

The source files are located inside the src directory. Be sure to make changes to these files and not files in the dist directory.

Contributing

Kill some bugs :)

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Test your changes to the best of your ability.
  4. Update the documentation to reflect your changes if they add or changes current functionality.
  5. Commit your changes (git commit -am 'Added some feature') without files from the dist directory.
  6. Push to the branch (git push origin my-new-feature)
  7. Create new Pull Request

Code Consistency

To help create consistent looking code throughout the project, we use a few tools to help us. They have plugins for most popular editors/IDEs to make coding for our project, but you should use them in your project as well!

JSHint

We use JSHint on each build to find easy-to-catch errors and potential problems in our js. You can find our JSHint settings in the .jshintrc file in the root of the project.

jscs

We use jscs on each build to enforce some code style rules we have for our project. You can find our jscs settings in the .jscsrc file in the root of the project.

EditorConfig

We use EditorConfig to maintain consistent coding styles between various editors and IDEs. You can find our settings in the .editorconfig file in the root of the project.

Easy First Bugs

Looking for something simple for a first contribution? Try fixing an easy first bug!

Contributors (100+ and counting!)

https://github.com/yabwe/medium-editor/graphs/contributors

Is Your Org Using MediumEditor?

Add your org here and we can add you to our landing page!

License

MIT: https://github.com/yabwe/medium-editor/blob/master/LICENSE

changelog

5.23.3 / 2017-12-20

  • Fix medium-editor-insert plugin css fixes on beagle theme #1361
  • Update jsDelivr links #1366 & #1367
  • Fix Firefox console warning causing issues #1370
  • Do not check only for null targets or it will fail when it's undefined. #1373
  • Fix crash when 'extensions' in 'isElementDescendantOfExtension' is undefined #1362
  • Fix Jasmine Unit Test errors #1385
  • Fix null error on pastedPlain.split #1397
  • Fix broken browser tests #1396

5.23.2 / 2017-08-02

  • Add noopener & noreferrer into targetBlank #1355
  • Add undefined check and fallback in Paste extension #1346

5.23.1 / 2017-06-27

  • Remove src from bower ignored files #1330
  • Add label-checkbox relation in CreateLink form #1275 #1340

5.23.0 / 2017-03-02

  • Only add schemes to URLs with hostnames #1258
  • Fix problem with addClassToAnchors #1293
  • Adding new 'html' button from #1235 #1291
  • Don't encode fragment as part of linkValidation #1257

5.22.2 / 2017-01-19

  • Efficiency: Compile RegEx once #1230
  • Error in console at link selection #1249
  • Check for this.anchorPreview when hiding #1280
  • Save some CPU calculations #1271

5.22.1 / 2016-09-29

  • Fix encoded urls (in linkValidaton) #1219
  • Fix CommonJS environment #1221

5.22.0 / 2016-09-03

  • Add new extensions to extensions README #1188
  • Fix iframe div #1179
  • Fix placeholder text color in flat theme #1192
  • Add unwrapTags option to paste extension #1177
  • Remove first empty paragraph on backspace #1187
  • Update grunt-contrib-jasmine #1185
  • Added Embed Button links to README #1183

5.21.1 / 2016-08-11

  • Make linkValidation allow hash links #1143
  • Fix toolbar in absolute container #1152
  • Fix caret issue in blockquote #1162
  • Handle new Google Docs font weights #1168
  • Add external button example #1175

5.21.0 / 2016-06-21

  • Fix issue with electron environment #1125
  • Fix for paste and placeholder extensions & add/remove element events #1124
  • Placeholder is visible when only empty table is in Editor #1128

5.20.2 / 2016-06-17

(5.20.1 was skipped because of a bad release)

  • Fix test failure in Chrome 51 #1114
  • Fix slow CSS selector #1115
  • Improve documentation for toolbar.relativeContainer option #1122
  • Fix cursor rendering incorrectly in Firefox #1113

5.20.0 / 2016-06-02

  • Fix anchor-preview bug where click preview no longer prefills href into anchor form
  • Add getEditorFromElement for retrieving an editor instance from an editor element
  • Respect form.reset for textarea elements within forms passed into the editor
  • Add getContent + resetContent helpers for retrieving/reverting content of editors
  • Add support for extensions preventing blur on editor when user interacts with extension elements

5.19.1 / 2016-05-28

  • Add feature for toggling anchor preview for empty or # links
  • Fix keyboard paste to properly fire editablePaste
  • Standardize editablePaste to always fire with mock event object

5.18.0 / 2016-05-21

  • Add support calling document.execCommand with arbitrary argument from execAction
    • Also deprecate custom execAction option names in favor of standard .value
  • Fix error from addElements when initializing editor with no elements

5.17.0 / 2016-05-17

  • Improved paste handling
    • Includes proper support for keyboard paste in firefox
    • More cleanup when pasting from Word
  • Introduce support for adding and removing elements from an existing editor instances
    • New addElements and removeElements methods
  • Add checkContentChanged method for manually triggering editableInput
  • Add selection.selectRange helper method

5.16.1 / 2016-04-14

  • Fix incorrect word breaking

5.16.0 / 2016-04-12

  • Add support for multiple targets for attaching/detach event handlers
  • Add support for chaining calls to attach/detach events
  • Fix issue with click anchor-preview when using showWhenToolbarIsVisible
  • Fix IE issue with line-breaking within editor
  • Fix Firefox error when using elements other than divs as editor

5.15.1 / 2016-04-05

  • Fix link validation in anchor extension
  • Improve performance when dealing with a lot of data
  • Enable functions to be used as keyboard commands

5.15.0 / 2016-03-23

  • Use class instead of inline style for hiding/showing anchor form
  • Add helpers for hiding/showing form into form extension base class
  • Fix issue where auto-link extension re-enabled IE's built-in auto-link when other instances still existed
  • Fix anchor form to display form before attempting to position correctly
  • Add new selection.clearSelection() helper method for moving cursor to beginning/end of selection

5.14.4 / 2016-02-25

  • editableInput event fixes
    • Fix issue with event not triggering when dragging in images
    • Fix issue with event not triggering on autolink
    • Fix issue with event not triggering on insertHTML in Edge
  • Fix issue with hitting enter when directly inside figcaption and other block elements

5.14.3 / 2016-02-22

  • Fix behaviour of "Open in new window" checkbox for Firefox
  • Added instruction to disable file dragging all together
  • Fix issue with image dragging and dropping at end of target
  • Fix issue with extra space when space already exists

5.14.2 / 2016-02-10

  • Support Microsoft Edge
    • Fallback to custom insertHTML command instead of built-in command for Edge
    • Use shim code for detecting input on contenteditable for Edge
    • Fix issue with converting blockquotes to paragraphs in Edge
    • Update documentation, fix tests, and include Edge in browser testing

5.14.1 / 2016-02-05

  • Fix issue with saving selection after newline and whitespace text nodes
  • Fix import/export selection to prefer start of nodes over end of nodes
  • Fix for getClosestBlockContainer utility function
  • Fix for getTopBlockContainer utility function
  • Deprecate getFirstTextNode utility function

5.14.0 / 2016-01-31

  • Added pre clean replacements
  • Fixed an infinite loop
  • Handled enter event for empty h2/h3 tag

5.13.0 / 2016-01-18

  • Added stickyTopOffset option to keep on the screen a sticky toolbar
  • Fixed misplacement of buttons when selection is near to the right edge
  • Updated dev dependencies
  • Added reference to README for who is using medium-editor

5.12.0 / 2015-12-15

  • Fix issue with image-only selections
  • Trim src when using the image toolbar button
  • Fix auto linking with comments
  • Documented the process of releasing a new version

5.11.0 / 2015-12-05

  • Updated table extension demo
  • Removed the carriage return character from a demo file
  • Updated checkLinkFormat function to support more schemes
  • Fixed issue with disableExtraSpaces option to allow space at the end of line
  • Use editableInput instead of input event for textarea syncing
  • Fixed style for correct positioning of placeholder
  • Allowed to remove blockquote by pressing delete at beginning of the quote
  • Fixed failing test cases in IE9 and IE10

5.10.0 / 2015-10-30

  • Added disableExtraSpaces option for preventing errant spaces
  • Added editalbeKeydownSpace event
  • Fix issue with return key at the end of text with bad formatting
  • Added new font name extension (beta)
  • Documentation updates and cleanup

5.9.0 / 2015-10-19

  • Add showWhenToolbarIsVisible option for displaying anchor-preview when toolbar is visible
  • Remove trailing whitespace when creating links via anchor extension
  • Fix issue with escaping list items via pressing enter
  • Fix font-awesome links in demo pages
  • Updates to documentation around creating links

5.8.3 / 2015-10-08

  • Fix changing link on images

5.8.2 / 2015-09-21

  • Fix type of elements which can contain auto-links

5.8.1 / 2015-09-16

  • Fix inconsistancies and errors in isDescendant utility method

5.8.0 / 2015-09-13

  • Added relativeContainer options for the toolbar
  • Fix issue with auto-linking across consecutive list-items
  • Added beagle theme

5.7.0 / 2015-08-21

  • Fix backwards compatability issue with how keyboard commands extension handles 'alt'
  • Rewrite which event placeholder extension listens to for hiding/showing placeholder
    • Fix issue where placeholder is not hidden when calling setContent()
    • Fix issue where placeholder is displayed incorrectly when hideOnClick option is true

5.6.3 / 2015-08-18

  • Ensure textarea ids are unique on entire page
  • Fix broken auto-link within block elements other than paragraphs
  • Fix issue with editor element being removed in IE11
  • Remove references to global variables from internal code

5.6.2 / 2015-08-11

  • Fix a regression in the paste extension related to pasteHTML function

5.6.1 / 2015-08-10

  • Fix issue with creating anchors and restoring selection at the beginning of paragraphs
  • Fix issue with creating anchors and restoring selection within list items and nested blocks
  • Ensure CTRL + M is respected as a way to insert new lines

5.6.0 / 2015-08-07

  • Add new 'tim' theme for medium-editor toolbar
  • Fix issue Chrome generated comment tags when pasting
  • Fix issue where 'editableInput' is triggered multiple times when creating links

5.5.4 / 2015-08-04

  • Fix issue with anchor and selection inconsitencies in IE

5.5.3 / 2015-08-03

  • Fix issue with replacing a pre-existing link
  • Fix issue with selection after creating a link after empty paragraphs

5.5.2 / 2015-08-02

  • Fix issue where block elements where cleaned up incorrectly when pasting
  • Fix anchor form checkboxes to reflect status of selected link
  • Fix issue with creating links in same paragraph as another link
  • Fix issue with creating links after empty paragraphs
  • Ensure all attributes are copied from textareas to divs

5.5.1 / 2015-07-23

  • Fix appearance of anchor form when checkboxes are present
  • Fix breaking issue with standardizeSelectionStart option

5.5.0 / 2015-07-21

  • Add setContent method into core API, which triggers editableInput

5.4.1 / 2015-07-20

  • Fix issue where custom anchor-preview extensions weren't overriding built-in anchor preview
  • Add documentation from wiki into the source code

5.4.0 / 2015-07-16

  • Add support for including 'alt' key in keyboard-commands

5.3.0 / 2015-07-07

  • Fix issue with disabling image drag & drop via imageDragging option
    • Deprecate image-dragging extension
    • Introduce file-dragging extension
  • Ensure autolink urls respect targetBlank option
  • Expose importSelection and exportSelection as generic Selection helpers

5.2.0 / 2015-06-29

  • Move allowMultiParagraphSelection into toolbar options
    • Deprecate global allowMultiParagraphSelection option
  • Fix issue with allowMultiParagraphSelection option over empty elements
  • Fix issue with creating links producing multiple anchor tags
  • Fix issue where anchor preview displays while toolbar is visible
  • Add demo pages for example extension and example button

5.1.0 / 2015-06-26

  • Add showToolbarDefaultAction helper method to form extension
  • Ensure elements generated for textareas have a unique id
  • Ensure all added attributes are removed during destroy
  • Cleanup divs generated by Chrome during justify actions
  • Add parameter to anchorPreview.positionPreview for reusability

5.0.0 / 2015-06-18

  • All deprecated functions have been removed
  • Keyboard Shorcuts are now part of an extension and not attached to specific button/commands
  • Placeholders are now part of an extension with its own dedicated options
  • Toolbar is now an extension with its own dedicated options
  • firstHeader and secondHeader are gone you should use h1 thru h6
  • Support pre-releases
  • Buttons
    • The array of buttons can now contain objects, for overriding any part of the button object
      • This replaces the custom object value for the buttonLabels option
  • API
    • Unique id for MediumEditor instance will now remain unique (regardless of how many instances are created)
    • .statics references are gone
    • .trigger supports triggering events without needing to declare the event
    • .callExtensions(), .setToolbarPosition(), and .hideToolbarDefaultActions() have been removed
  • Extension
    • .window & .document are now exposed as members of the Extension
    • init no longer is passed MediumEditor instance as first argument
  • CSS
    • All classes are now medium-editor prefixed
  • Util
    • getProp, derives, getSelectionData, setObject & getObject are gone
    • getSelectionRange & getSelectionStart are now in Selection

4.12.5 / 2015-06-16

  • Fix issue with restoring selection within nested block elements

4.12.4 / 2015-06-15

  • Ensure auto-link will never select an empty element (br, hr, input, etc.)

4.12.3 / 2015-06-12

  • Fix bug with un-linked auto-links causing unexpected cursor positioning

4.12.2 / 2015-06-10

  • Fix broken keyboard shortcuts

4.12.1 / 2015-06-02

  • Fix break with updateOnEmptySelection option for static toolbars

4.12.0 / 2015-06-01

  • Fix pasting links when targetBlank option is being used
  • Fix for spellcheck option after destroy
  • Fix over-reaching keyboard shortcuts for commands
  • Expose new 'positionToolbar' custom event
  • Add new isKey() helper in util
  • Add cleanup on destroy for auto-link and placeholder extensions
  • Base extension changes
    • Add getEditorElements(), getEditorId(), and getEditorOption() helpers
    • Add on(), off(), subscribe(), and execAction() helpers
    • Introduce destroy() lifecycle method + deprecate deactivate()

4.11.1 / 2015-05-26

  • Fix issue with auto-linked text after manually unlinking
  • Fix some incorrect TLDs for auto-link

4.11.0 / 2015-05-26

  • Add hideToolbar and showToolbar custom events
  • Add hideOnClick option for placeholder extension
  • Fix issue with linebreaks in Safari
  • Fix issue with calling setup again after destroy
  • Add support for CDN hosting
  • Pass window and document to each extension
  • Deprecate .parent property of extensions

4.10.2 / 2015-05-21

  • Auto-Link Fixes
    • Don't auto-link text after it is manually unlinked
    • Trigger auto-linking when focus is lost (ie Tab key)
    • Fix issue where link appears and immediately disappears when hitting Enter in IE11
    • Fix issue where hostname with more than three w's only auto-links final three w's in the name
    • Fix issue where valid urls were not auto-linked
    • Fix issue where some text was auto-linked when it shouldn't be

4.10.1 / 2015-05-20

  • Fix paste issue with plain-text containing multiple paragraphs
  • Fix issue with incorrect cursor positon after creating a list
  • Fix disabledDoubleReturn option within a sentence
  • Allow for nested contenteditables
  • New style of passing options for anchor-preview and anchor
  • Introduce extensions.button + extensions.form as extendable base extensions
  • Convert anchor, fontsize, and anchor-preview to updated extensions model

4.9.0 / 2015-05-18

  • New auto-link support for detecting urls and converting them to links
  • Fix target _blank issue for links in Firefox
  • Don't show placeholders for empty lists
  • Allow for overriding image drag and drop via extension

4.8.1 / 2015-05-13

  • Fix error thrown when loading MediumEditor js from head

4.8.0 / 2015-05-11

  • Expose new 'editableInput' event for monitoring changes to editor
  • Cleanup contenteditable elements created for textareas

4.7.3 / 2015-05-07

  • Update version number in dist files

4.7.2 / 2015-05-06

  • Add shortcut to insert a link (ctrl/cmd + k)
  • Fix this.getAttribute is not a function error

4.7.1 / 2015-04-30

  • Make anchor preview wrap for long links
  • Fix issue when clean pasting spans with child nodes

4.7.0 / 2015-04-27

  • Expose importSelection + exportSelection helper methods
  • Fix issue with initialization of MediumEditor using textarea
  • Introduce jscs

4.6.0 / 2015-04-22

  • Add 'beta' version of fontSize button/form
  • Add option for enabling/disabling spellcheck
  • Add titles to toolbar buttons for tooltips
  • Use actual anchor tag in anchor preview
  • Fix anchor preview issue with tags nested inside anchors

  • Speed up travis builds

  • Convert paste handler into overrideable extension

4.5.2 / 2015-04-14

  • Fix blur event detection when clicking on elements that don't clear focus

4.5.1 / 2015-04-14

  • Fix broken 'paste.cleanPastedHtml' option and rename to 'paste.cleanPastedHTML'

4.5.0 / 2015-04-13

  • Expose 'unsubscribe' for custom events
  • Detach custom events when editor is destroyed
  • Fix fontawesome url in demo page

4.4.0 / 2015-04-11

  • Expose smart 'blur' and 'focus' events which account for toolbar interaction
  • Expose selectElement method for selecting text and updating toolbar
  • Fix always wrapping pasted text in a

    tag

4.3.0 / 2015-04-10

  • Add override options for pasteHTML and cleanPaste
  • Support overriding of scss theme variables
  • Fix for justify button states in IE
  • New helpers for manipulating nested objects
  • Internal tooling prep for options and defaults

4.2.0 / 2015-04-05

  • Add textarea support

4.1.1 / 2015-04-01

  • Fix .version issue

4.1.0 / 2015-03-29

  • Expose Util and Selection methods externally via MediumEditor.util and MediumEditor.selection
  • Expose MediumEditor.version for version info
  • Add support for custom cleaning of attributes and tags for .pasteHTML
  • Move from jslint to jshint

4.0.3 / 2015-03-27

  • Introduce 'removeFormat' button, for removing formatting from selection
  • Fix issues with focus/blur when using standardizeSelectionStart option

4.0.2 / 2015-03-26

  • Fix bug causing toolbar to disappaer on click in safari (rollback fix from 4.0.1)
  • Break up anchor form extension logic into more overrideable parts

4.0.1 / 2015-03-24

  • Fix issue with dragged in image sizes
  • Fix issues with focus/blur when using standardizeSelectionStart option

4.0.0 / 2015-03-23

  • Introduced custom events (consumable externally)
  • Reduce API surface area
    • Deprecated activate & deactivated. Exposed setup and destroy as replacements
    • Updated documentation to reflect API changes
  • HTML standardization around list items
  • Fixed throttling
  • Added superscript & subscript css
  • Added better paste cleaning for Microsoft Word
  • Convert anchor preview into overrideable extension
  • Added disableAnchorPreview option

3.0.9 / 2015-03-10

  • Extract toolbar
  • Extract anchor preview

3.0.8 / 2015-02-27

  • MIT License
  • Use code from selection.js which is duplicated in core.js
  • Fix bug in paste handling + increase paste coverage

3.0.7 / 2015-02-26

  • Ensure static toolbar won't render outside window + minimize when toolbar overflows
  • Fix flashing static-toolbar bug
  • Fix bug with sticky-toolbar when scrolling past bottom of contenteditable
  • Fix css declaration of linear-gradient
  • Fix AMD "Uncaught TypeError: undefined is not a function" issue
  • Account for 'full' actions when doing queryCommandState
  • Fix bugs in modified queryCommandState calls

3.0.0 / 2015-02-23

  • Extract anchor form code from core code and convert into an extension
  • Expose onShowToolbar and onHideToolbar as options
  • Change button method names (now setActive and setInactive) to differentiate from core's activate and deactivate
  • Simplify blur check selection
  • Add Sauce Labs configuration to automate cross-browser testing
  • Add IE9 polyfill to repo
  • Let 'meta' key trigger shortcuts

2.4.6 / 2015-02-18

  • Add basic support to keyboard shortcuts

2.4.5 / 2015-02-17

  • Fix main file reference in npm package

2.4.3 / 2015-02-16

  • Introduce full content actions

2.4.2 / 2015-02-15

  • Fix disableDoubleReturn option

2.4.1 / 2015-02-15

  • Fix isListItemChild call

2.4.0 / 2015-02-15

  • Split source code into several files for better development flow
  • Make saveSelection and restoreSelection more consistant cross browser
  • Use document.queryCommandState for some button toolbar states
  • Add selection storage
  • Call extensions deactivate when deactivating the editor
  • Turn Anchor button into an extension

2.3.0 / 2015-02-11

  • Fix various selection and positioning bugs
  • Introduce commands as combination of buttons and extensions
  • Update aria label so that setting secondHeader activates the toolbar
  • Don't use styles for detecting underline + strikethrough
  • Fix 'imageDragging: false' option
  • Fix list item tab identation
  • Add extension onHide command

2.2.0 / 2015-02-05

  • Fix bug in getSelectedParentElement + Fix tests in browsers
  • Fall back to shimmed insertHTML in cases where firefox throws when calling insertHTML
  • Prevent "Argument not optional" error
  • Prevent infinite loop after findAdjacentTextNodeWithContent
  • Remove cleanups from contenteditable false areas
  • Firefox fix: Don't modify value of input before calling execCommand()
  • Fix selection issue for clean pasted html test case in firefox
  • Add image drag and drop support

2.1.3 / 2015-01-31

  • Fix issue with multiple elements with the same class on the same editor instance

2.1.2 / 2015-01-30

  • Specify default npm registry (http://registry.npmjs.org)

2.1.1 / 2015-01-30

  • Adds support for newlines in placeholder attribute
  • Adds support and documentation for new toolbar extensions
  • Adds support for changing 'open in new window' label text
  • Fixes bug where nodeValue could unexpectedly be null
  • A couple of fixes to make tests a bit more reliable when run in the browser

2.1.0 / 2015-01-27

  • Handles ESC key in link editor
  • Standardizes usage of setTimeout for UX delays vs debouncing vs deferring
  • Adds an optional onShowToolbar method
  • Supports enabling/disabling checkSelection updates externally
  • Standardizes where in the DOM a range begins
  • Adds ARIA role information
  • Fixes off() not removing any event listeners
  • Misc minor bug fixes and improvements

2.0.0 / 2015-01-06

  • Adds static toolbar feature
  • Now uses textContent instead of innerText
  • Fixes plain text paste on IE
  • Hides placeholder on mouse click
  • Adds a 'collapse' option to 'selectElementContents' helper
  • Allows toolbar button states to change when selection is collapsed
  • In hideToolbarActions, calls an optional 'onHideToolbar' method
  • Ensures that ul.id and anchor.id are unique
  • Avoids grabbing selection on keypress for contenteditable except for spacebar
  • Supports disabling anchorForm, avoiding unnecessary event handling and element creation
  • Supports disabling placeholders, including not attaching event handlers when not needed
  • Various minor bug fixes and improvements

1.9.13 / 2014-11-24

  • Adds a strikethrough option in buttonLabel
  • Now uses options.elementsContainer to calculate ID
  • Removes events during deactivate

1.9.10 / 2014-11-17

  • Adds custom doc and win functionality, now you can specify the editor container
  • Minor bugfixes

1.9.8 / 2014-10-21

  • Fixes 'this' out of scope

1.9.7 / 2014-10-20

  • Adds justify buttons
  • Fix #308 by passing clipboard content through self.htmlEntities before inserting
  • Minor bug fixes

1.9.4 / 2014-09-16

  • Adds support for tab based indenting and outdenting of
      and
      1. Adds a save button to the anchor form
      2. Improves toolbar positioning
      3. Adds anchorButton and anchorButtonClass options

    1.9.0 / 2014-08-08

    • Extensions
    • Disables the toolbar when selecting within an element that has contenteditable="false"
    • Fixes hidden placeholder content override

    1.8.14 / 2014-06-11

    • Fixes bug where if you had an empty blockquote the placeholder would still be active
    • Fixes bug that would create link without values
    • Exposes save/restoreSelection()
    • Allows customization of active/first/last button classes
    • Adds a script to run app from the cli
    • Adds protocols to checkLinkFormat regex

    1.8.8 / 2014-05-08

    • Fixes unlink behavior on Firefox
    • Fixes white space behavior at the end of anchors

    1.8.6 / 2014-05-03

    • Adds non-minified CSS files to bower.json

    1.8.5 / 2014-05-01

    • Changes to the element list or element selector now take effect on reactivation
    • Changed innerHTML to textContent to prevent XSS through twisted href values
    • Checks for data-disable-return on element on paste
    • Adds disableEditing and elementsContainer options

    1.8.0 / 2014-04-12

    • Removes anchor preview listeners on deactivate
    • Implements clean paste
    • Adds an option to validate links
    • Adds a basic extensions support
    • Misc minor fixes

    1.7.5 / 2014-03-30

    • Fixes isActive toggling
    • Removes anchor preview default value

    1.7.3 / 2014-03-22

    • Fixes activate/deactivate behavior

    1.7.2 / 2014-03-22

    • Removes DOM elements created by MediumEditor on deactivate

    1.7.1 / 2014-03-22

    • Prevents new lines with shift+enter when disableReturn is set to true

    1.7.0 / 2014-03-22

    • Removes compass dependency by using grunt with libsass
    • Fixes subscript button markup
    • Fixes anchor preview behavior for empty links and anchors
    • Adds a new option to disable double returns

    1.6.7 / 2014-03-13

    • Allows initialization with a single DOM node
    • Adds indent and outdent buttons

    1.6.5 / 2014-03-08

    • fixes some minor paste bugs
    • adds a delay option for anchor toolbar
    • fixes anchor toolbar initial positioning
    • fixes heading and blockquote on IE

    1.6.1 / 2014-03-04

    • fixes case where clicking anchor preview and then clicking into the anchorInput causes hideToolbarActions to be called
    • fixes window resize when toolbar element is not created

    1.6.0 / 2014-02-27

    • Reorganizes CSS files
    • Removes unused method bindElementToolbarEvents
    • Adds a preview toolbar for anchors
    • Removes paste event binding on deactivate

    1.5.4 / 2014-02-12

    • Fixes filenames for main in bower.json
    • Removes window resize event listener on deactivate

    1.5.3 / 2014-01-22

    • Adds bootstrap theme
    • Adds image button that converts selected text into an image tag
    • Removes normalize.css dependency

    1.5.0 / 2014-01-16

    • Adds 3 new themes: Roman, Mani e Flat

    1.4.5 / 2014-01-13

    • Adds ability to set custom labels on buttons
    • Updates uglify
    • Fixes bug where pressing enter on formatted list item would generate a new list instead of a new list item

    1.4.0 / 2013-12-13

    • Adds new extra buttons: pre and strikethrough
    • Fixes placeholder bug on paste
    • Various code improvements
    • Prevents returns using shift when disableReturn is set to true
    • Improves CSS to avoid conflicts

    1.3.5 / 2013-11-27

    • Fixes problem with text selection ending outside the container div
    • Implements serialize method
    • Adds a targetBlank option
    • Fixes Firefox box-sizing declarations

    1.3.1 / 2013-11-19

    • Fixes toolbar binding button issue with multi-editor mode

    1.3.0 / 2013-11-18

    • Fixes data-disable-return not preventing paragraph creation
    • Improves getSelectionElement() to work in any case
    • Fixes multi element selection bug
    • Fixes Issues #88 & #89
    • Improves binding for multiple editor instance, checkSelection() is called only once per instance
    • Improves allowMultiParagraphSelection filter by removing empty tags elements before counting
    • Considers header tags has a paragraph too (same as medium)

    1.2.2 / 2013-11-07

    • Removes blur event listener when disabling the toolbar
    • Adds a light gradient opacity to the toolbar
    • Fixes bug that would keep toolbar alive when moving out of the anchor input

    1.2.1 / 2013-11-07

    • Fixes empty selectionNode.el bug
    • Prevents toolbar opening when changing to selection elements with the toolbar disabled
    • Adds a transition to the toolbar when moving across elements

    1.2.0 / 2013-11-06

    • Fixes issue on deactivation without enabled toolbar
    • Fixes checkSelection error when disableToolbar option is enabled
    • Adds new option to disable multiple paragraph selection
    • Prevents paragraph creation on paste when disableReturn is set to true

    1.1.6 / 2013-10-24

    • Adds extra buttons: superscript, subscript, ordered list and unordered list

    1.1.5 / 2013-10-23

    • Changes buttons blacklist to whitelist

    1.1.4 / 2013-10-13

    • Exports MediumEditor as module
    • Changes "Underline" button to display "U" instead of "S"

    1.1.3 / 2013-10-08

    • Pasted text is now wrapped into P elements

    1.1.2 / 2013-10-06

    • Changes the editor to use the formatBlock command to handle block elements
    • Fixes placeholder for empty elements

    1.1.1 / 2013-10-04

    • Normalizes styles and scripts
    • Improves bower manifest

    1.1.0 / 2013-10-03

    • Adds an option to disable the toolbar and maintain only the contenteditable behavior
    • Adds an option to disable returns
    • Adds an placeholder option for the contenteditable areas

    1.0.3 / 2013-10-01

    • Fixes toolbar positioning on screen top

    1.0.2 / 2013-09-24

    • Adds the possibility to pass an element list directly into initialization
    • Fixes issue with initial positioning when some actions are disabled
    • Don't rely on :last-child to style first/last element, as they may be hidden

    1.0.1 / 2013-09-20

    • Changes demo texto to something more friendly
    • Fixes shift+enter behavior

    1.0.0 / 2013-08-26

    • Initial release