Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

medium-editor

Package Overview
Dependencies
Maintainers
6
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

medium-editor - npm Package Compare versions

Comparing version 5.19.1 to 5.20.0

62

API.md

@@ -40,5 +40,10 @@ # MediumEditor Object API (v5.0.0)

- [`delay(fn)`](#delayfn)
- [`getContent(index)`](#getcontentindex)
- [`getExtensionByName(name)`](#getextensionbynamename)
- [`resetContent(element)`](#resetcontentelement)
- [`serialize()`](#serialize)
- [`setContent(html, index)`](#setcontenthtml-index)
- [Static Functions/Properties](#static-functionsproperties)
- [`getEditorFromElement(element)`](#geteditorfromelementelement)
- [`version`](#version)

@@ -440,2 +445,12 @@ <!-- END doctoc generated TOC please keep comment here to allow auto update -->

***
### `getContent(index)`
Returns the trimmed html content for the first editor **element**, or the **element** at `index`.
**Arguments**
1. _**index** (`integer`)_: _**OPTIONAL**_
* Index of the editor **element** to retrieve the content from. Defaults to 0 when not provided (returns content of the first editor **element**).
***
### `getExtensionByName(name)`

@@ -452,2 +467,13 @@

***
### `resetContent(element)`
Reset the content of all editor **elements** to their value at the time they were added to the editor. If a specific editor **element** is provided, only the content of that element will be reset.
**Arguments**
1. _**element** (`DOMElement`)_: _**OPTIONAL**_
* Specific editor **element** to reset the content of.
***
### `serialize()`

@@ -460,4 +486,3 @@

Sets the innerHTML content for the element at `index`.
Trigger the `editableInput` event.
Sets the html content for the first editor **element**, or the **element** at `index`. Ensures the the `editableInput` event is triggered.

@@ -469,3 +494,32 @@ **Arguments**

2. _**index** (`integer`)_:
* Index of the element to set the content on. Defaults to 0 when not provided.
2. _**index** (`integer`)_: _**OPTIONAL**_
* Index of the editor **element** to set the content of. Defaults to 0 when not provided (sets content of the first editor **element**).
***
## Static Functions/Properties
### `getEditorFromElement(element)`
Given an editor **element**, retrieves the instance of MediumEditor which created/is monitoring the **element**
**Arguments**
1. _**element** (`DOMElement`)_:
* An editor **element** which is part of a MediumEditor instance
### `version`
Object containing data about the version of the current MediumEditor library
**Properties of 'version'**
1. _**major** (`Number`)_
* The major version number (ie the `3` in `"3.2.1"`)
2. _**minor** (`Number`)_
* The minor version number (ie the `2` in `"3.2.1"`)
3. _**revision** (`Number`)_
* The revision (aka "patch") version number (ie the `1` in `"3.2.1"`)
4. _**preRelease** (`String`)_
* The pre-release version tag (ie the `"rc.1"` in `"5.0.0-rc.1"`)
5. _**toString** (`Function`)_
* Returns the full version number as a string (ie `"5.0.0-rc.1"`)

@@ -0,1 +1,10 @@

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

@@ -2,0 +11,0 @@ ==================

@@ -45,2 +45,3 @@ # MediumEditor Options (v5.0.0)

- [`previewValueSelector`](#previewvalueselector)
- [`showOnEmptyLinks`](#showonemptylinks)
- [Disabling Anchor Preview](#disabling-anchor-preview)

@@ -339,2 +340,8 @@ - [Placeholder Options](#placeholder-options)

***
#### `showOnEmptyLinks`
**Default:** `true`
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.
***
#### `showWhenToolbarIsVisible`

@@ -341,0 +348,0 @@ **Default:** `false`

10

package.json
{
"name": "medium-editor",
"version": "5.19.1",
"version": "5.20.0",
"author": "Davi Ferreira <hi@daviferreira.com>",

@@ -46,2 +46,3 @@ "contributors": [

"grunt-bump": "0.7.0",
"grunt-cli": "1.2.0",
"grunt-contrib-concat": "0.5.1",

@@ -67,6 +68,7 @@ "grunt-contrib-connect": "0.11.2",

"scripts": {
"test": "grunt test --verbose",
"test:ci": "grunt travis --verbose",
"start": "open ./demo/index.html"
"test": "node node_modules/grunt-cli/bin/grunt test --verbose",
"test:ci": "node node_modules/grunt-cli/bin/grunt travis --verbose",
"start": "open ./demo/index.html",
"build": "node node_modules/grunt-cli/bin/grunt"
}
}

@@ -13,3 +13,3 @@ # MediumEditor

![Supportd Browsers](https://cloud.githubusercontent.com/assets/2444240/12874138/d3960a04-cd9b-11e5-8cc5-8136d82cf5f6.png)
![Supported Browsers](https://cloud.githubusercontent.com/assets/2444240/12874138/d3960a04-cd9b-11e5-8cc5-8136d82cf5f6.png)

@@ -255,2 +255,3 @@ [![NPM info](https://nodei.co/npm/medium-editor.png?downloads=true)](https://www.npmjs.com/package/medium-editor)

* __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`

@@ -560,9 +561,15 @@ To disable the anchor preview, set the value of the `anchorPreview` option to `false`:

* __.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 MediumtEditor instance:
It is possible to dynamically add new elements to your existing MediumEditor instance:

@@ -573,3 +580,3 @@ ```javascript

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

@@ -592,3 +599,3 @@ editor.addElements('.editable');

Straight forward, just call `removeElements` with the elemnt 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.
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.

@@ -633,3 +640,3 @@ ```javascript

So for most modern browsers (Chrome, Firefox, Safari, etc.), the `input` event works just fine. Infact, `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](https://connect.microsoft.com/IE/feedback/details/794285/ie10-11-input-event-does-not-fire-on-div-with-contenteditable-set) and is _mostly_ supported in Microsoft Edge, but not fully.
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](https://connect.microsoft.com/IE/feedback/details/794285/ie10-11-input-event-does-not-fire-on-div-with-contenteditable-set) and is _mostly_ supported in Microsoft Edge, but not fully.

@@ -636,0 +643,0 @@ 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`.

@@ -142,2 +142,5 @@ /*global fireEvent, selectElementContentsAndFire */

// textbox should contain the url
expect(anchor.getInput().value).toEqual('http://test.com');
// the checkboxes should be unchecked

@@ -310,3 +313,3 @@ expect(anchor.getAnchorTargetCheckbox().checked).toBe(false);

// https://github.com/yabwe/medium-editor/issues/1047
it('should display the anchor form in the toolbar when clicked when showWhenToolbarIsVisible is set to true adn toolbar is visible', function () {
it('should display the anchor form in the toolbar when clicked when showWhenToolbarIsVisible is set to true and toolbar is visible', function () {
var editor = this.newMediumEditor('.editor', {

@@ -313,0 +316,0 @@ anchorPreview: {

@@ -58,2 +58,75 @@ /*global fireEvent, selectElementContents,

describe('getContent', function () {
it('should retrieve the content of the first element', function () {
var editor = this.newMediumEditor('.editor');
expect(editor.getContent()).toEqual('lore ipsum');
});
it('should retrieve the content of the element at the specified index', function () {
var otherHTML = 'something different';
this.createElement('div', 'editor', otherHTML);
var editor = this.newMediumEditor('.editor');
expect(editor.getContent(1)).toEqual(otherHTML);
});
it('should return null if no element exists', function () {
var editor = this.newMediumEditor('.no-valid-selector');
expect(editor.getContent()).toBeNull();
});
});
describe('resetContent', function () {
it('should reset the content of all editor elements to their initial values', function () {
var initialOne = this.el.innerHTML,
initialTwo = 'Lorem ipsum dolor',
elementTwo = this.createElement('div', 'editor', initialTwo),
editor = this.newMediumEditor('.editor');
editor.setContent('<p>changed content</p>');
expect(this.el.innerHTML).not.toEqual(initialOne);
editor.setContent('<p>changed content</p>', 1);
expect(elementTwo.innerHTML).not.toEqual(initialTwo);
editor.resetContent();
expect(this.el.innerHTML).toEqual(initialOne);
expect(elementTwo.innerHTML).toEqual(initialTwo);
});
it('should reset the content of a specific element when provided', function () {
var initialOne = this.el.innerHTML,
initialTwo = 'Lorem ipsum dolor',
elementTwo = this.createElement('div', 'editor', initialTwo),
editor = this.newMediumEditor('.editor');
editor.setContent('<p>changed content</p>');
expect(this.el.innerHTML).not.toEqual(initialOne);
editor.setContent('<p>changed content</p>', 1);
expect(elementTwo.innerHTML).not.toEqual(initialTwo);
editor.resetContent(elementTwo);
expect(this.el.innerHTML).not.toEqual(initialOne);
expect(elementTwo.innerHTML).toEqual(initialTwo);
});
it('should not reset anything if an invalid element is provided', function () {
var initialOne = this.el.innerHTML,
initialTwo = 'Lorem ipsum dolor',
elementTwo = this.createElement('div', 'editor', initialTwo),
dummyElement = this.createElement('div', 'not-editor', '<p>dummy element</p>'),
editor = this.newMediumEditor('.editor');
editor.setContent('<p>changed content</p>');
expect(this.el.innerHTML).not.toEqual(initialOne);
editor.setContent('<p>changed content</p>', 1);
expect(elementTwo.innerHTML).not.toEqual(initialTwo);
editor.resetContent(dummyElement);
expect(this.el.innerHTML).not.toEqual(initialOne);
expect(elementTwo.innerHTML).not.toEqual(initialTwo);
});
});
describe('saveSelection/restoreSelection', function () {

@@ -257,2 +330,19 @@ it('should be applicable if html changes but text does not', function () {

});
describe('getEditorFromElement', function () {
it('should return the editor instance the element belongs to', function () {
var elTwo = this.createElement('div', 'editor-two', 'lore ipsum'),
editorOne = this.newMediumEditor('.editor'),
editorTwo = this.newMediumEditor('.editor-two');
expect(editorOne.elements[0]).toBe(this.el);
expect(editorTwo.elements[0]).toBe(elTwo);
expect(MediumEditor.getEditorFromElement(this.el)).toBe(editorOne);
expect(MediumEditor.getEditorFromElement(elTwo)).toBe(editorTwo);
});
it('should return null if the element is not within an editor', function () {
expect(MediumEditor.getEditorFromElement(this.el)).toBeNull();
});
});
});
describe('Elements TestCase', function () {
'use strict';
describe('Initialization', function () {
beforeEach(function () {
setupTestHelpers.call(this);
this.el = this.createElement('div', 'editor', 'lore ipsum');
});
beforeEach(function () {
setupTestHelpers.call(this);
this.el = this.createElement('div', 'editor', 'lore ipsum');
});
afterEach(function () {
this.cleanupTest();
});
afterEach(function () {
this.cleanupTest();
});
describe('Initialization', function () {
it('should set element contenteditable attribute to true', function () {

@@ -52,3 +52,46 @@ var editor = this.newMediumEditor('.editor');

});
it('should set the data-medium-editor-editor-index attribute to be the id of the editor instance', function () {
var editor = this.newMediumEditor('.editor');
expect(editor.elements[0]).toBe(this.el);
expect(parseInt(this.el.getAttribute('data-medium-editor-editor-index'))).toBe(editor.id);
});
});
describe('Destroy', function () {
it('should remove the contenteditable attribute', function () {
var editor = this.newMediumEditor('.editor');
expect(this.el.getAttribute('contenteditable')).toEqual('true');
editor.destroy();
expect(this.el.hasAttribute('contenteditable')).toBe(false);
});
it('should remove the medium-editor-element attribute', function () {
var editor = this.newMediumEditor('.editor');
expect(this.el.getAttribute('data-medium-editor-element')).toEqual('true');
editor.destroy();
expect(this.el.hasAttribute('data-medium-editor-element')).toBe(false);
});
it('should remove the role attribute', function () {
var editor = this.newMediumEditor('.editor');
expect(this.el.getAttribute('role')).toEqual('textbox');
editor.destroy();
expect(this.el.hasAttribute('role')).toBe(false);
});
it('should remove the aria-multiline attribute', function () {
var editor = this.newMediumEditor('.editor');
expect(this.el.getAttribute('aria-multiline')).toEqual('true');
editor.destroy();
expect(this.el.hasAttribute('aria-multiline')).toBe(false);
});
it('should remove the data-medium-editor-editor-index attribute', function () {
var editor = this.newMediumEditor('.editor');
expect(parseInt(this.el.getAttribute('data-medium-editor-editor-index'))).toBe(editor.id);
editor.destroy();
expect(this.el.hasAttribute('data-medium-editor-editor-index')).toBe(false);
});
});
});

@@ -1,2 +0,2 @@

/*global selectElementContentsAndFire */
/*global selectElementContentsAndFire, fireEvent */

@@ -287,2 +287,36 @@ describe('Extensions TestCase', function () {

});
it('should be able to prevent blur on the editor when user iteracts with extension elements', function () {
var sampleElOne = this.createElement('button', null, 'Test Button'),
sampleElTwo = this.createElement('textarea', null, 'Test Div'),
externalEl = this.createElement('div', 'external-element', 'External Element'),
TempExtension = MediumEditor.Extension.extend({
getInteractionElements: function () {
return [sampleElOne, sampleElTwo];
}
}),
editor = this.newMediumEditor('.editor', {
extensions: {
'temp-extension': new TempExtension()
}
}),
spy = jasmine.createSpy('handler');
selectElementContentsAndFire(editor.elements[0]);
jasmine.clock().tick(1);
expect(editor.getExtensionByName('toolbar').isDisplayed()).toBe(true);
editor.subscribe('blur', spy);
fireEvent(sampleElTwo, 'mousedown');
fireEvent(sampleElTwo, 'mouseup');
fireEvent(sampleElTwo, 'click');
jasmine.clock().tick(51);
expect(spy).not.toHaveBeenCalled();
fireEvent(externalEl, 'mousedown');
fireEvent(document.body, 'mouseup');
fireEvent(document.body, 'click');
expect(spy).toHaveBeenCalled();
});
});

@@ -289,0 +323,0 @@

@@ -61,2 +61,6 @@ /*global fireEvent */

it('should create unique div ids for multiple textareas', function () {
var origDateNow = Date.now;
Date.now = function () {
return 1464448478887;
};
for (var i = 0; i < 12; i++) {

@@ -70,5 +74,10 @@ var ta = this.createElement('textarea', 'editor');

});
Date.now = origDateNow;
});
it('should create unique medium-editor-textarea-ids across all editor instances', function () {
var origDateNow = Date.now;
Date.now = function () {
return 1464448478887;
};
var tas = [];

@@ -87,2 +96,3 @@ for (var i = 0; i < 12; i++) {

});
Date.now = origDateNow;
});

@@ -96,2 +106,17 @@

});
it('should reset the value of created div when form containing textarea is reset', function () {
var form = this.createElement('form', null, null, true),
initialContent = this.el.value;
form.appendChild(this.el);
document.body.appendChild(form);
var editor = this.newMediumEditor('.editor');
expect(editor.elements[0].innerHTML).toEqual(initialContent);
editor.setContent('<p>custom content</p>');
expect(editor.elements[0].innerHTML).not.toEqual(initialContent);
form.reset();
expect(editor.elements[0].innerHTML).toEqual(initialContent);
});
});

@@ -211,2 +236,24 @@

});
it('should reset the value of created div when form containing textarea is reset', function () {
var form = this.createElement('form', null, null, true),
initialContent = 'initial text',
otherTextarea = this.createElement('textarea', 'editor', initialContent, true),
editor = this.newMediumEditor('.editor');
otherTextarea.value = initialContent;
expect(editor.elements.length).toBe(1);
form.appendChild(otherTextarea);
document.body.appendChild(form);
editor.addElements(otherTextarea);
var createdDiv = editor.elements[1];
expect(createdDiv.innerHTML).toEqual(initialContent);
editor.setContent('<p>custom content</p>', 1);
expect(createdDiv.innerHTML).not.toEqual(initialContent);
form.reset();
expect(createdDiv.innerHTML).toEqual(initialContent);
});
});

@@ -213,0 +260,0 @@

@@ -336,6 +336,6 @@ (function () {

function createContentEditable(textarea, id, doc) {
var div = doc.createElement('div'),
function createContentEditable(textarea) {
var div = this.options.ownerDocument.createElement('div'),
now = Date.now(),
uniqueId = 'medium-editor-' + now + '-' + id,
uniqueId = 'medium-editor-' + now,
atts = textarea.attributes;

@@ -345,5 +345,5 @@

// to make a unique-id, ensure that the id is actually unique on the page
while (doc.getElementById(uniqueId)) {
while (this.options.ownerDocument.getElementById(uniqueId)) {
now++;
uniqueId = 'medium-editor-' + now + '-' + id;
uniqueId = 'medium-editor-' + now;
}

@@ -365,2 +365,12 @@

// If textarea has a form, listen for reset on the form to clear
// the content of the created div
if (textarea.form) {
this.on(textarea.form, 'reset', function (event) {
if (!event.defaultPrevented) {
this.resetContent(this.options.ownerDocument.getElementById(uniqueId));
}
}.bind(this));
}
textarea.classList.add('medium-editor-hidden');

@@ -375,6 +385,6 @@ textarea.parentNode.insertBefore(

function initElement(element, id) {
function initElement(element, editorId) {
if (!element.getAttribute('data-medium-editor-element')) {
if (element.nodeName.toLowerCase() === 'textarea') {
element = createContentEditable(element, id, this.options.ownerDocument);
element = createContentEditable.call(this, element);

@@ -407,6 +417,13 @@ // Make sure we only attach to editableInput once for <textarea> elements

var elementId = MediumEditor.util.guid();
element.setAttribute('data-medium-editor-element', true);
element.setAttribute('role', 'textbox');
element.setAttribute('aria-multiline', true);
element.setAttribute('medium-editor-index', MediumEditor.util.guid());
element.setAttribute('data-medium-editor-editor-index', editorId);
// TODO: Merge data-medium-editor-element and medium-editor-index attributes for 6.0.0
// medium-editor-index is not named correctly anymore and can be re-purposed to signify
// whether the element has been initialized or not
element.setAttribute('medium-editor-index', elementId);
initialContent[elementId] = element.innerHTML;

@@ -630,2 +647,4 @@ this.events.attachAllEventsToElement(element);

var initialContent = {};
MediumEditor.prototype = {

@@ -649,2 +668,3 @@ // NOT DOCUMENTED - exposed for backwards compatability

addToEditors.call(this, this.options.contentWindow);
this.events = new MediumEditor.Events(this);

@@ -660,3 +680,2 @@ this.elements = [];

this.isActive = true;
addToEditors.call(this, this.options.contentWindow);

@@ -696,2 +715,3 @@ // Call initialization helpers

element.removeAttribute('medium-editor-index');
element.removeAttribute('data-medium-editor-editor-index');

@@ -1155,2 +1175,11 @@ // Remove any elements created for textareas

getContent: function (index) {
index = index || 0;
if (this.elements[index]) {
return this.elements[index].innerHTML.trim();
}
return null;
},
checkContentChanged: function (editable) {

@@ -1161,2 +1190,20 @@ editable = editable || MediumEditor.selection.getSelectionElement(this.options.contentWindow);

resetContent: function (element) {
// For all elements that exist in the this.elements array, we can assume:
// - Its initial content has been set in the initialContent object
// - It has a medium-editor-index attribute which is the key value in the initialContent object
if (element) {
var index = this.elements.indexOf(element);
if (index !== -1) {
this.setContent(initialContent[element.getAttribute('medium-editor-index')], index);
}
return;
}
this.elements.forEach(function (el, idx) {
this.setContent(initialContent[el.getAttribute('medium-editor-index')], idx);
}, this);
},
addElements: function (selector) {

@@ -1173,3 +1220,3 @@ // Convert elements into an array

// Initialize all new elements (we check that in those functions don't worry)
element = initElement.call(this, element);
element = initElement.call(this, element, this.id);

@@ -1206,2 +1253,11 @@ // Add new elements to our internal elements array

};
MediumEditor.getEditorFromElement = function (element) {
var index = element.getAttribute('data-medium-editor-editor-index'),
win = element && element.ownerDocument && (element.ownerDocument.defaultView || element.ownerDocument.parentWindow);
if (win && win._mediumEditors && win._mediumEditors[index]) {
return win._mediumEditors[index];
}
return null;
};
}());
(function () {
'use strict';
function isElementDescendantOfExtension(extensions, element) {
return extensions.some(function (extension) {
if (typeof extension.getInteractionElements !== 'function') {
return false;
}
var extensionElements = extension.getInteractionElements();
if (!extensionElements) {
return false;
}
if (!Array.isArray(extensionElements)) {
extensionElements = [extensionElements];
}
return extensionElements.some(function (el) {
return MediumEditor.util.isDescendant(el, element, true);
});
});
}
var Events = function (instance) {

@@ -380,11 +400,7 @@ this.base = instance;

updateFocus: function (target, eventObj) {
var toolbar = this.base.getExtensionByName('toolbar'),
toolbarEl = toolbar ? toolbar.getToolbarElement() : null,
anchorPreview = this.base.getExtensionByName('anchor-preview'),
previewEl = (anchorPreview && anchorPreview.getPreviewElement) ? anchorPreview.getPreviewElement() : null,
hadFocus = this.base.getFocusedElement(),
var hadFocus = this.base.getFocusedElement(),
toFocus;
// For clicks, we need to know if the mousedown that caused the click happened inside the existing focused element.
// If so, we don't want to focus another element
// For clicks, we need to know if the mousedown that caused the click happened inside the existing focused element
// or one of the extension elements. If so, we don't want to focus another element
if (hadFocus &&

@@ -394,4 +410,3 @@ eventObj.type === 'click' &&

(MediumEditor.util.isDescendant(hadFocus, this.lastMousedownTarget, true) ||
MediumEditor.util.isDescendant(toolbarEl, this.lastMousedownTarget, true) ||
MediumEditor.util.isDescendant(previewEl, this.lastMousedownTarget, true))) {
isElementDescendantOfExtension(this.base.extensions, this.lastMousedownTarget))) {
toFocus = hadFocus;

@@ -412,6 +427,5 @@ }

// Check if the target is external (not part of the editor, toolbar, or anchorpreview)
// Check if the target is external (not part of the editor, toolbar, or any other extension)
var externalEvent = !MediumEditor.util.isDescendant(hadFocus, target, true) &&
!MediumEditor.util.isDescendant(toolbarEl, target, true) &&
!MediumEditor.util.isDescendant(previewEl, target, true);
!isElementDescendantOfExtension(this.base.extensions, target);

@@ -418,0 +432,0 @@ if (toFocus !== hadFocus) {

@@ -179,2 +179,15 @@ (function () {

/* getInteractionElements: [function ()]
*
* If the extension renders any elements that the user can interact with,
* this method should be implemented and return the root element or an array
* containing all of the root elements. MediumEditor will call this function
* during interaction to see if the user clicked on something outside of the editor.
* The elements are used to check if the target element of a click or
* other user event is a descendant of any extension elements.
* This way, the editor can also count user interaction within editor elements as
* interactions with the editor, and thus not trigger 'blur'
*/
getInteractionElements: undefined,
/************************ Helpers ************************

@@ -181,0 +194,0 @@ * The following are helpers that are either set by MediumEditor

@@ -37,2 +37,7 @@ (function () {

getInteractionElements: function () {
return this.getPreviewElement();
},
// TODO: Remove this function in 6.0.0
getPreviewElement: function () {

@@ -159,3 +164,3 @@ return this.anchorPreview;

var opts = {
url: activeAnchor.attributes.href.value,
value: activeAnchor.attributes.href.value,
target: activeAnchor.getAttribute('target'),

@@ -162,0 +167,0 @@ buttonClass: activeAnchor.getAttribute('class')

@@ -24,2 +24,3 @@ # Extensions

* [`queryCommandState()`](#querycommandstate)
* [`getInteractionElements()`](#getinteractionelements)
* [`isActive()`](#isactive)

@@ -238,5 +239,12 @@ * [`isAlreadyApplied(node)`](#isalreadyappliednode)

***
### `getInteractionElements()`
If the extension renders any elements that the user can interact with, this method should be implemented and return the root element or an array containing all of the root elements.
MediumEditor will call this function during interaction to see if the user clicked on something outside of the editor. The elements are used to check if the target element of a click or other user event is a descendant of any extension elements. This way, the editor can also count user interaction within editor elements as interactions with the editor, and thus not trigger 'blur'
***
### `isActive()`
If implemented, this method will be called from MediumEditor to determine whether the button has already been set as 'active'.
If implemented, this method will be called from MediumEditor to determine whether the button has already been set as 'active'.

@@ -257,3 +265,3 @@ If it returns `true`, this extension/button will be skipped for checking its active state as MediumEditor responds to the change in selection.

* This method will NOT be called if `checkState()` has been implemented.
* This method will NOT be called if `checkState()` has been implemented.
* This method will NOT be called if `queryCommandState()` is implemented and returns a non-null value when called.

@@ -279,3 +287,3 @@

If implemented, this method is called when MediumEditor knows that this extension has not been applied to the current selection. Curently, this is called at the beginning of each state change for the editor & toolbar.
If implemented, this method is called when MediumEditor knows that this extension has not been applied to the current selection. Curently, this is called at the beginning of each state change for the editor & toolbar.

@@ -547,3 +555,3 @@ After calling this, MediumEditor will attempt to update the extension, either via `checkState()` or the combination of `queryCommandState()`, `isAlreadyApplied(node)`, `isActive()`, and `setActive()`

action: 'bold'
// ... other properties/methods ...

@@ -567,3 +575,3 @@ })

aria: 'bold text'
// ... other properties/methods ...

@@ -575,6 +583,6 @@ })

### `tagNames` _(Array)_
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.
**NOTE:**
**NOTE:**

@@ -586,3 +594,3 @@ `tagNames` is not used if `useQueryState` is set to `true`.

The following would create a custom button extension which would be 'active' in the toolbar if the selection is within a `<b>` or a `<strong>` tag:
```js

@@ -595,3 +603,3 @@ var CustomButtonExtension = MediumEditor.extensions.button.extend({

tagNames: ['b', 'strong'],
// ... other properties/methods ...

@@ -611,3 +619,3 @@ })

**NOTE:**
**NOTE:**

@@ -630,3 +638,3 @@ `style` is not used if `useQueryState` is set to `true`.

},
// ... other properties/methods ...

@@ -633,0 +641,0 @@ })

@@ -192,2 +192,6 @@ (function () {

getInteractionElements: function () {
return this.getToolbarElement();
},
getToolbarElement: function () {

@@ -194,0 +198,0 @@ if (!this.toolbar) {

@@ -18,3 +18,3 @@ MediumEditor.parseVersionString = function (release) {

// grunt-bump looks for this:
'version': '5.19.1'
'version': '5.20.0'
}).version);

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc