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

medium-editor

Package Overview
Dependencies
Maintainers
4
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 4.10.2 to 4.11.0

2

bower.json
{
"name": "medium-editor",
"version": "4.10.2",
"version": "4.11.0",
"homepage": "http://daviferreira.github.io/medium-editor/",

@@ -5,0 +5,0 @@ "authors": [

@@ -0,1 +1,12 @@

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

@@ -2,0 +13,0 @@ ==================

{
"name": "medium-editor",
"version": "4.10.2",
"version": "4.11.0",
"author": "Davi Ferreira <hi@daviferreira.com>",

@@ -5,0 +5,0 @@ "contributors": [

@@ -38,2 +38,11 @@ # MediumEditor

**Via CDNJS**
[CDNJS hosts this library](https://cdnjs.com/libraries/medium-editor) and you can load it from CDN this way:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/medium-editor/4.10.1/medium-editor.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/medium-editor/4.10.1/medium-editor.min.css" type="text/css" media="screen" charset="utf-8">
```
**Manual installation:**

@@ -97,4 +106,2 @@

* __lastButtonClass__: CSS class added to the last button in the toolbar. Default: 'medium-editor-button-last'
* __onShowToolbar__: optional callback that will be called each time the toolbar is actually shown for this instance of medium-editor.
* __onHideToolbar__: optional callback that will be called each time the toolbar is actually hidden for this instance of medium-editor.
* __staticToolbar__: enable/disable the toolbar always displaying in the same location relative to the medium-editor element. Default: false

@@ -101,0 +108,0 @@ * __stickyToolbar__: enable/disable the toolbar "sticking" to the medium-editor element when the page is being scrolled. Default: false

@@ -192,2 +192,20 @@ /*global describe, it, expect, spyOn,

});
it('with ctrl key, should not call formatBlock', function () {
this.el.innerHTML = '<p>lorem ipsum</p>';
var editor = this.newMediumEditor('.editor'),
p = editor.elements[0].querySelector('p');
spyOn(document, 'execCommand').and.callThrough();
placeCursorInsideElement(p, 0);
fireEvent(p, 'keyup', {
keyCode: Util.keyCode.ENTER,
ctrlKey: true
});
expect(document.execCommand).not.toHaveBeenCalledWith('formatBlock', false, 'p');
});
});

@@ -194,0 +212,0 @@

@@ -322,2 +322,34 @@ /*global describe, it, expect, jasmine,

});
describe('Setup some listeners', function () {
var links = [
'externalInteraction',
'blur',
'focus',
'editableInput',
'editableClick',
'editableBlur',
'editableKeypress',
'editableKeyup',
'editableKeydown',
'editableKeydownEnter',
'editableKeydownTab',
'editableKeydownDelete',
'editableMouseover',
'editableDrag',
'editableDrop',
'editablePaste'
];
links.forEach(function (listener) {
it('should setup "' + listener + '" listener', function () {
var editor = this.newMediumEditor('.editor'),
events = new Events(editor);
events.setupListener(listener);
expect(events.listeners[listener]).toBe(true);
});
});
});
});

@@ -56,3 +56,3 @@ /*global MediumEditor, describe, it, expect, spyOn,

it('should call init (and pass the instance of itself) on extensions if the method exists', function () {
it('should call init (and pass the deprecated instance of itself) on extensions if the method exists', function () {
var ExtensionOne = function () {

@@ -85,2 +85,35 @@ this.init = function (me) {

});
it('should set window and document properties on each extension', function () {
var TempExtension = MediumEditor.Extension.extend({}),
extInstance = new TempExtension(),
fakeDocument = {
body: document.body,
documentElement: document.documentElement,
querySelectorAll: function () {
return document.querySelectorAll.apply(document, arguments);
},
createElement: function () {
return document.createElement.apply(document, arguments);
}
},
fakeWindow = {
addEventListener: function () {
return window.addEventListener.apply(window, arguments);
},
removeEventListener: function () {
return window.removeEventListener.apply(window, arguments);
}
};
this.newMediumEditor('.editor', {
ownerDocument: fakeDocument,
contentWindow: fakeWindow,
extensions: {
'temp-extension': extInstance
}
});
expect(extInstance.window).toBe(fakeWindow);
expect(extInstance.document).toBe(fakeDocument);
});
});

@@ -110,3 +143,2 @@

Sub = Extension.extend({
parent: true,
y: 10

@@ -221,47 +253,62 @@ });

describe('Set data in extensions', function () {
var ExtensionOne = function () {
this.parent = true;
},
ExtensionTwo = function () {},
extOne = new ExtensionOne(),
extTwo = new ExtensionTwo();
it('should set the base property to an instance of MediumEditor', function () {
var extOne = new MediumEditor.Extension(),
editor = this.newMediumEditor('.editor', {
extensions: {
'one': extOne
}
});
it('should check if extension class has parent attribute', function () {
var editor = this.newMediumEditor('.editor', {
extensions: {
'one': extOne,
'two': extTwo
}
});
expect(editor instanceof MediumEditor).toBeTruthy();
expect(extOne.parent).toBeTruthy();
expect(extTwo.parent).toBeUndefined();
expect(extOne.base instanceof MediumEditor).toBeTruthy();
});
it('should set the base attribute to be an instance of editor', function () {
var editor = this.newMediumEditor('.editor', {
extensions: {
'one': extOne,
'two': extTwo
}
});
it('should not set the base property when deprecated parent attribute is set to false', function () {
var TempExtension = MediumEditor.Extension.extend({
parent: false
}),
editor = this.newMediumEditor('.editor', {
extensions: {
'temp': new TempExtension()
}
});
expect(editor instanceof MediumEditor).toBeTruthy();
expect(extOne.base instanceof MediumEditor).toBeTruthy();
expect(extTwo.base).toBeUndefined();
expect(editor.getExtensionByName('temp').base).toBeUndefined();
});
it('should set the name of the extension', function () {
this.newMediumEditor('.editor', {
extensions: {
'one': extOne,
'two': extTwo
}
});
it('should not override the base or name properties of an extension if overriden', function () {
var TempExtension = MediumEditor.Extension.extend({
name: 'tempExtension',
base: 'something'
}),
editor = this.newMediumEditor('.editor', {
extensions: {
'one': new TempExtension()
}
});
expect(editor.getExtensionByName('one')).toBeUndefined();
expect(editor.getExtensionByName('tempExtension').base).toBe('something');
});
it('should set the name of property of extensions', function () {
var ExtensionOne = function () {},
ExtensionTwo = function () {},
extOne = new ExtensionOne(),
extTwo = new ExtensionTwo(),
editor = this.newMediumEditor('.editor', {
extensions: {
'one': extOne,
'two': extTwo
}
});
expect(extOne.name).toBe('one');
expect(extTwo.name).toBe('two');
expect(editor.getExtensionByName('one')).toBe(extOne);
expect(editor.getExtensionByName('two')).toBe(extTwo);
});
});
});

@@ -36,4 +36,4 @@ /*global MediumEditor, describe, it, expect, spyOn,

var editor = this.newMediumEditor('.test');
expect(editor.id).toBe(undefined);
expect(editor.setup).not.toHaveBeenCalled();
expect(editor.isActive).toBeFalsy();
expect(editor.events).toBeUndefined();
expect(editor.toolbar).toBeUndefined();

@@ -89,2 +89,11 @@ expect(editor.getExtensionByName('anchor')).toBeUndefined();

});
it('should be available after destroying and calling setup again', function () {
var editor = this.newMediumEditor('.editor');
expect(editor.elements.length).toBe(1);
editor.destroy();
expect(editor.elements.length).toBe(0);
editor.setup();
expect(editor.elements.length).toBe(1);
});
});

@@ -202,2 +211,2 @@

});
});
});

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

/*global describe, it, expect,
/*global describe, it, expect, Util,
afterEach, beforeEach, fireEvent, setupTestHelpers,

@@ -71,2 +71,17 @@ Placeholder */

it('should NOT remove the placeholder on click', function () {
var editor = this.newMediumEditor('.editor', { placeholder: { hideOnClick: false }});
expect(editor.elements[0].className).toContain('medium-editor-placeholder');
fireEvent(editor.elements[0], 'click');
expect(editor.elements[0].className).toContain('medium-editor-placeholder');
fireEvent(editor.elements[0], 'blur');
expect(editor.elements[0].className).toContain('medium-editor-placeholder');
this.el.innerHTML = '<p>lorem</p><p id="target">ipsum</p><p>dolor</p>';
fireEvent(document.getElementById('target'), 'keypress');
expect(editor.elements[0].className).not.toContain('medium-editor-placeholder');
this.el.innerHTML = '';
fireEvent(editor.elements[0], 'keyup', { keyCode: Util.keyCode.DELETE });
expect(editor.elements[0].className).toContain('medium-editor-placeholder');
});
it('should add a placeholder to empty elements on blur', function () {

@@ -73,0 +88,0 @@ this.el.innerHTML = 'some text';

/*global MediumEditor, describe, it, expect, spyOn,
afterEach, beforeEach, selectElementContents,
fireEvent, setupTestHelpers, jasmine, selectElementContentsAndFire,
placeCursorInsideElement, Toolbar */
placeCursorInsideElement, Toolbar*/

@@ -78,3 +78,61 @@ describe('Toolbar TestCase', function () {

it('should call onShowToolbar when toolbar is shwon and onHideToolbar when toolbar is hidden', function () {
it('should trigger the showToolbar custom event when toolbar is shown', function () {
var editor = this.newMediumEditor('.editor'),
callback = jasmine.createSpy();
this.el.innerHTML = 'specOnShowToolbarTest';
editor.subscribe('showToolbar', callback);
selectElementContentsAndFire(this.el, { eventToFire: 'focus' });
expect(callback).toHaveBeenCalledWith({}, this.el);
});
it('should trigger the hideToolbar custom event when toolbar is hidden', function () {
var editor = this.newMediumEditor('.editor'),
callback = jasmine.createSpy();
this.el.innerHTML = 'specOnShowToolbarTest';
editor.subscribe('hideToolbar', callback);
selectElementContentsAndFire(this.el, { eventToFire: 'focus' });
// Remove selection and call check selection, which should make the toolbar be hidden
jasmine.clock().tick(1);
window.getSelection().removeAllRanges();
editor.checkSelection();
expect(callback).toHaveBeenCalledWith({}, this.el);
});
it('should be possible to listen to toolbar events from extensions', function () {
var callbackShow = jasmine.createSpy('show'),
callbackHide = jasmine.createSpy('hide'),
TestExtension = MediumEditor.Extension.extend({
parent: true,
init: function () {
this.base.subscribe('showToolbar', callbackShow);
this.base.subscribe('hideToolbar', callbackHide);
}
}),
editor = this.newMediumEditor('.editor', {
extensions: { 'testExtension': new TestExtension() }
});
this.el.innerHTML = 'specOnShowToolbarTest';
selectElementContentsAndFire(this.el, { eventToFire: 'focus' });
expect(callbackShow).toHaveBeenCalledWith({}, this.el);
// Remove selection and call check selection, which should make the toolbar be hidden
jasmine.clock().tick(1);
window.getSelection().removeAllRanges();
editor.checkSelection();
expect(callbackHide).toHaveBeenCalledWith({}, this.el);
});
it('should call deprecated onShowToolbar option when toolbar is shown and deprecated onHideToolbar option when toolbar is hidden', function () {
var editor,

@@ -81,0 +139,0 @@ temp = {

@@ -1,5 +0,5 @@

/*global Util, ButtonsData, Button,
Selection, FontSizeForm, Extension, extensionDefaults,
Toolbar, AutoLink, ImageDragging, Events, editorDefaults,
DefaultButton, AnchorExtension, FontSizeExtension, AnchorPreviewDeprecated */
/*global Util, ButtonsData, Selection, Extension,
extensionDefaults, Toolbar, Events, editorDefaults,
DefaultButton, AnchorExtension, FontSizeExtension,
AnchorPreviewDeprecated*/

@@ -152,3 +152,3 @@ function MediumEditor(elements, options) {

this.options.ownerDocument.execCommand('unlink', false, null);
} else if (!event.shiftKey) {
} else if (!event.shiftKey && !event.ctrlKey) {
// only format block if this is not a header tag

@@ -190,9 +190,34 @@ if (!/h\d/.test(tagName)) {

function setExtensionDefaults(extension, defaults) {
Object.keys(defaults).forEach(function (prop) {
if (extension[prop] === undefined) {
extension[prop] = defaults[prop];
}
});
return extension;
}
function initExtension(extension, name, instance) {
if (extension.parent) {
extension.base = instance;
if (typeof extension.parent !== 'undefined') {
Util.warn('Extension .parent property has been deprecated. ' +
'The .base property for extensions will always be set to MediumEditor in version 5.0.0');
}
var extensionDefaults = {
'window': instance.options.contentWindow,
'document': instance.options.ownerDocument
};
// TODO: Deprecated (Remove .parent check in v5.0.0)
if (extension.parent !== false) {
extensionDefaults.base = instance;
}
// Add default options into the extension
extension = setExtensionDefaults(extension, extensionDefaults);
// Call init on the extension
if (typeof extension.init === 'function') {
// Passing instance into init() will be deprecated in v5.0.0
extension.init(instance);
}
// Set extension name (if not already set)
if (!extension.name) {

@@ -372,5 +397,3 @@ extension.name = name;

var defaultsBC = {
text: (typeof this.options.placeholder === 'string') ? this.options.placeholder : undefined, // deprecated
'window': this.options.contentWindow,
'document': this.options.ownerDocument
text: (typeof this.options.placeholder === 'string') ? this.options.placeholder : undefined // deprecated
};

@@ -387,4 +410,2 @@

hideDelay: this.options.anchorPreviewHideDelay, // deprecated
'window': this.options.contentWindow,
'document': this.options.ownerDocument,
diffLeft: this.options.diffLeft,

@@ -407,5 +428,3 @@ diffTop: this.options.diffTop,

targetCheckbox: this.options.anchorTarget, // deprecated
targetCheckboxText: this.options.anchorInputCheckboxLabel, // deprecated
'window': this.options.contentWindow,
'document': this.options.ownerDocument
targetCheckboxText: this.options.anchorInputCheckboxLabel // deprecated
};

@@ -424,5 +443,3 @@

disableReturn: this.options.disableReturn,
targetBlank: this.options.targetBlank,
'window': this.options.contentWindow,
'document': this.options.ownerDocument
targetBlank: this.options.targetBlank
};

@@ -442,2 +459,9 @@

// add toolbar custom events to the list of known events by the editor
// we need to have this for the initialization of extensions
// initToolbar is called after initCommands
// add toolbar custom events to the list of known events by the editor
this.createEvent('showToolbar');
this.createEvent('hideToolbar');
buttons.forEach(function (buttonName) {

@@ -451,6 +475,6 @@ if (extensions[buttonName]) {

} else if (buttonName === 'fontsize') {
ext = initExtension(new FontSizeForm(), buttonName, this);
ext = initExtension(new MediumEditor.extensions.fontSize(), buttonName, this);
this.commands.push(ext);
} else if (ButtonsData.hasOwnProperty(buttonName)) {
ext = initExtension(new Button(ButtonsData[buttonName]), buttonName, this);
ext = initExtension(new MediumEditor.extensions.button(ButtonsData[buttonName]), buttonName, this);
this.commands.push(ext);

@@ -478,7 +502,7 @@ }

if (shouldAddDefaultAutoLink.call(this)) {
this.commands.push(initExtension(new AutoLink(), 'auto-link', this));
this.commands.push(initExtension(new MediumEditor.extensions.autoLink(), 'auto-link', this));
}
if (shouldAddDefaultImageDragging.call(this)) {
this.commands.push(initExtension(new ImageDragging(), 'image-dragging', this));
this.commands.push(initExtension(new MediumEditor.extensions.imageDragging(), 'image-dragging', this));
}

@@ -504,3 +528,5 @@

['disableAnchorPreview', 'anchorPreview: false'],
['disablePlaceholders', 'placeholder: false']
['disablePlaceholders', 'placeholder: false'],
['onShowToolbar', 'showToolbar custom event'],
['onHideToolbar', 'hideToolbar custom event']
];

@@ -575,6 +601,3 @@ // warn about using deprecated properties

this.options = mergeOptions.call(this, this.defaults, options);
createElementsArray.call(this, elements);
if (this.elements.length === 0) {
return;
}
this.origElements = elements;

@@ -599,2 +622,7 @@ if (!this.options.elementsContainer) {

createElementsArray.call(this, this.origElements);
if (this.elements.length === 0) {
return;
}
this.events = new Events(this);

@@ -666,2 +694,10 @@ this.isActive = true;

createEvent: function (event) {
this.events.defineCustomEvent(event);
},
trigger: function (name, data, editable) {
this.events.triggerCustomEvent(name, data, editable);
},
delay: function (fn) {

@@ -668,0 +704,0 @@ var self = this;

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

/*global Util */
/*global Util*/

@@ -58,3 +58,3 @@ var Events;

this.setupListener(event);
// If we don't suppot this custom event, don't do anything
// If we don't support this custom event, don't do anything
if (this.listeners[event]) {

@@ -76,2 +76,6 @@ if (!this.customEvents[event]) {

defineCustomEvent: function (event) {
this.listeners[event] = true;
},
indexOfCustomListener: function (event, listener) {

@@ -201,3 +205,2 @@ if (!this.customEvents[event] || !this.customEvents[event].length) {

// Listening to browser events to emit events medium-editor cares about
setupListener: function (name) {

@@ -209,122 +212,122 @@ if (this.listeners[name]) {

switch (name) {
case 'externalInteraction':
// Detecting when user has interacted with elements outside of MediumEditor
this.attachDOMEvent(this.options.ownerDocument.body, 'mousedown', this.handleBodyMousedown.bind(this), true);
this.attachDOMEvent(this.options.ownerDocument.body, 'click', this.handleBodyClick.bind(this), true);
this.attachDOMEvent(this.options.ownerDocument.body, 'focus', this.handleBodyFocus.bind(this), true);
this.listeners[name] = true;
break;
case 'blur':
// Detecting when focus is lost
this.setupListener('externalInteraction');
this.listeners[name] = true;
break;
case 'focus':
// Detecting when focus moves into some part of MediumEditor
this.setupListener('externalInteraction');
this.listeners[name] = true;
break;
case 'editableInput':
// setup cache for knowing when the content has changed
this.contentCache = [];
this.base.elements.forEach(function (element) {
this.contentCache[element.getAttribute('medium-editor-index')] = element.innerHTML;
case 'externalInteraction':
// Detecting when user has interacted with elements outside of MediumEditor
this.attachDOMEvent(this.options.ownerDocument.body, 'mousedown', this.handleBodyMousedown.bind(this), true);
this.attachDOMEvent(this.options.ownerDocument.body, 'click', this.handleBodyClick.bind(this), true);
this.attachDOMEvent(this.options.ownerDocument.body, 'focus', this.handleBodyFocus.bind(this), true);
this.listeners[name] = true;
break;
case 'blur':
// Detecting when focus is lost
this.setupListener('externalInteraction');
this.listeners[name] = true;
break;
case 'focus':
// Detecting when focus moves into some part of MediumEditor
this.setupListener('externalInteraction');
this.listeners[name] = true;
break;
case 'editableInput':
// setup cache for knowing when the content has changed
this.contentCache = [];
this.base.elements.forEach(function (element) {
this.contentCache[element.getAttribute('medium-editor-index')] = element.innerHTML;
// Attach to the 'oninput' event, handled correctly by most browsers
if (this.InputEventOnContenteditableSupported) {
this.attachDOMEvent(element, 'input', this.handleInput.bind(this));
// Attach to the 'oninput' event, handled correctly by most browsers
if (this.InputEventOnContenteditableSupported) {
this.attachDOMEvent(element, 'input', this.handleInput.bind(this));
}
}.bind(this));
// For browsers which don't support the input event on contenteditable (IE)
// we'll attach to 'selectionchange' on the document and 'keypress' on the editables
if (!this.InputEventOnContenteditableSupported) {
this.setupListener('editableKeypress');
this.keypressUpdateInput = true;
this.attachDOMEvent(document, 'selectionchange', this.handleDocumentSelectionChange.bind(this));
// Listen to calls to execCommand
this.attachToExecCommand();
}
}.bind(this));
// For browsers which don't support the input event on contenteditable (IE)
// we'll attach to 'selectionchange' on the document and 'keypress' on the editables
if (!this.InputEventOnContenteditableSupported) {
this.setupListener('editableKeypress');
this.keypressUpdateInput = true;
this.attachDOMEvent(document, 'selectionchange', this.handleDocumentSelectionChange.bind(this));
// Listen to calls to execCommand
this.attachToExecCommand();
}
this.listeners[name] = true;
break;
case 'editableClick':
// Detecting click in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'click', this.handleClick.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableBlur':
// Detecting blur in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'blur', this.handleBlur.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeypress':
// Detecting keypress in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keypress', this.handleKeypress.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeyup':
// Detecting keyup in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keyup', this.handleKeyup.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeydown':
// Detecting keydown on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keydown', this.handleKeydown.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeydownEnter':
// Detecting keydown for ENTER on the contenteditables
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableKeydownTab':
// Detecting keydown for TAB on the contenteditable
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableKeydownDelete':
// Detecting keydown for DELETE/BACKSPACE on the contenteditables
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableMouseover':
// Detecting mouseover on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'mouseover', this.handleMouseover.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editableDrag':
// Detecting dragover and dragleave on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'dragover', this.handleDragging.bind(this));
this.attachDOMEvent(element, 'dragleave', this.handleDragging.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editableDrop':
// Detecting drop on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'drop', this.handleDrop.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editablePaste':
// Detecting paste on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'paste', this.handlePaste.bind(this));
}, this);
this.listeners[name] = true;
break;
this.listeners[name] = true;
break;
case 'editableClick':
// Detecting click in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'click', this.handleClick.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableBlur':
// Detecting blur in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'blur', this.handleBlur.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeypress':
// Detecting keypress in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keypress', this.handleKeypress.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeyup':
// Detecting keyup in the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keyup', this.handleKeyup.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeydown':
// Detecting keydown on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'keydown', this.handleKeydown.bind(this));
}.bind(this));
this.listeners[name] = true;
break;
case 'editableKeydownEnter':
// Detecting keydown for ENTER on the contenteditables
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableKeydownTab':
// Detecting keydown for TAB on the contenteditable
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableKeydownDelete':
// Detecting keydown for DELETE/BACKSPACE on the contenteditables
this.setupListener('editableKeydown');
this.listeners[name] = true;
break;
case 'editableMouseover':
// Detecting mouseover on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'mouseover', this.handleMouseover.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editableDrag':
// Detecting dragover and dragleave on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'dragover', this.handleDragging.bind(this));
this.attachDOMEvent(element, 'dragleave', this.handleDragging.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editableDrop':
// Detecting drop on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'drop', this.handleDrop.bind(this));
}, this);
this.listeners[name] = true;
break;
case 'editablePaste':
// Detecting paste on the contenteditables
this.base.elements.forEach(function (element) {
this.attachDOMEvent(element, 'paste', this.handlePaste.bind(this));
}, this);
this.listeners[name] = true;
break;
}

@@ -506,12 +509,12 @@ },

switch (event.which) {
case Util.keyCode.ENTER:
this.triggerCustomEvent('editableKeydownEnter', event, event.currentTarget);
break;
case Util.keyCode.TAB:
this.triggerCustomEvent('editableKeydownTab', event, event.currentTarget);
break;
case Util.keyCode.DELETE:
case Util.keyCode.BACKSPACE:
this.triggerCustomEvent('editableKeydownDelete', event, event.currentTarget);
break;
case Util.keyCode.ENTER:
this.triggerCustomEvent('editableKeydownEnter', event, event.currentTarget);
break;
case Util.keyCode.TAB:
this.triggerCustomEvent('editableKeydownTab', event, event.currentTarget);
break;
case Util.keyCode.DELETE:
case Util.keyCode.BACKSPACE:
this.triggerCustomEvent('editableKeydownDelete', event, event.currentTarget);
break;
}

@@ -518,0 +521,0 @@ }

@@ -1,8 +0,7 @@

/* global Util */
var Extension;
(function () {
'use strict';
/* global Util */
Extension = function (options) {

@@ -73,25 +72,17 @@ Util.extend(this, options);

Extension.prototype = {
init: function (/* instance */) {
// called when properly decorated and used.
// has a .base value pointing to the editor
// owning us. has been given a .name if no
// name present
},
/* parent: [boolean]
/* init: [function]
*
* Setting this to false will prevent MediumEditor
* from setting the .base property.
* If left as true, the .base property of the extension
* will be assigned a reference to the
* MediumEditor instance that is using the extension
* Called by MediumEditor during initialization.
* The .base property will already have been set to
* current instance of MediumEditor when this is called.
* All helper methods will exist as well
*/
parent: true,
init: function () {},
/* base: [MediumEditor instance]
*
* If .parent is set to true, this will be set to the
* current MediumEditor instance before init() is called
* If not overriden, this will be set to the current instance
* of MediumEditor, before the init method is called
*/
base: null,
base: undefined,

@@ -105,3 +96,3 @@ /* name: [string]

*/
name: null,
name: undefined,

@@ -119,3 +110,3 @@ /* checkState: [function (node)]

*/
checkState: null,
checkState: undefined,

@@ -138,3 +129,3 @@ /* As alternatives to checkState, these functions provide a more structured

*/
queryCommandState: null,
queryCommandState: undefined,

@@ -149,3 +140,3 @@ /* isActive: [function ()]

*/
isActive: null,
isActive: undefined,

@@ -163,3 +154,3 @@ /* isAlreadyApplied: [function (node)]

*/
isAlreadyApplied: null,
isAlreadyApplied: undefined,

@@ -174,3 +165,3 @@ /* setActive: [function ()]

*/
setActive: null,
setActive: undefined,

@@ -187,11 +178,29 @@ /* setInactive: [function ()]

*/
setInactive: null,
setInactive: undefined,
/* onHide: [function ()]
/************************ Helpers ************************
* The following are helpers that are either set by MediumEditor
* during initialization, or are helper methods which either
* route calls to the MediumEditor instance or provide common
* functionality for all extensions
*********************************************************/
/* window: [Window]
*
* If implemented, this function is called each time the
* toolbar is hidden
* If not overriden, this will be set to the window object
* to be used by MediumEditor and its extensions. This is
* passed via the 'contentWindow' option to MediumEditor
* and is the global 'window' object by default
*/
onHide: null
'window': undefined,
/* document: [Document]
*
* If not overriden, this will be set to the document object
* to be used by MediumEditor and its extensions. This is
* passed via the 'ownerDocument' optin to MediumEditor
* and is the global 'document' object by default
*/
'document': undefined
};
})();
})();

@@ -9,3 +9,2 @@ var AnchorPreview;

name: 'anchor-preview',
parent: true,

@@ -12,0 +11,0 @@ // Anchor Preview Options

@@ -17,3 +17,2 @@ /*global Extension, Util */

AutoLink = Extension.extend({
parent: true,

@@ -25,3 +24,3 @@ init: function () {

// MS IE has it's own auto-URL detect feature but ours is better in some ways. Be consistent.
this.base.options.ownerDocument.execCommand('AutoUrlDetect', false, false);
this.document.execCommand('AutoUrlDetect', false, false);
},

@@ -135,3 +134,3 @@

findOrCreateMatchingTextNodes: function (element, match) {
var treeWalker = this.base.options.ownerDocument.createTreeWalker(element, NodeFilter.SHOW_TEXT,
var treeWalker = this.document.createTreeWalker(element, NodeFilter.SHOW_TEXT,
null, false),

@@ -186,4 +185,4 @@ matchedNodes = [],

var anchor = document.createElement('a'),
span = document.createElement('span');
var anchor = this.document.createElement('a'),
span = this.document.createElement('span');
Util.moveTextRangeIntoElement(textNodes[0], textNodes[textNodes.length - 1], span);

@@ -190,0 +189,0 @@ span.setAttribute('data-auto-link', 'true');

@@ -37,3 +37,3 @@ var Button;

createButton: function () {
var button = this.base.options.ownerDocument.createElement('button'),
var button = this.document.createElement('button'),
content = this.contentDefault,

@@ -116,3 +116,3 @@ ariaLabel = this.getAria();

styleVals = this.style.value.split('|');
computedStyle = this.base.options.contentWindow.getComputedStyle(node, null).getPropertyValue(this.style.prop);
computedStyle = this.window.getComputedStyle(node, null).getPropertyValue(this.style.prop);
styleVals.forEach(function (val) {

@@ -119,0 +119,0 @@ if (!this.knownState) {

@@ -23,3 +23,3 @@ var FontSizeForm;

// Get fontsize of current selection (convert to string since IE returns this as number)
var fontSize = this.base.options.ownerDocument.queryCommandValue('fontSize') + '';
var fontSize = this.document.queryCommandValue('fontSize') + '';
this.showForm(fontSize);

@@ -90,3 +90,3 @@ }

createForm: function () {
var doc = this.base.options.ownerDocument,
var doc = this.document,
form = doc.createElement('div'),

@@ -144,3 +144,3 @@ input = doc.createElement('input'),

clearFontSize: function () {
Selection.getSelectedElements(this.base.options.ownerDocument).forEach(function (el) {
Selection.getSelectedElements(this.document).forEach(function (el) {
if (el.tagName === 'FONT' && el.hasAttribute('size')) {

@@ -147,0 +147,0 @@ el.removeAttribute('size');

@@ -8,4 +8,2 @@ /*global Util, Extension */

ImageDragging = Extension.extend({
// Need a reference to MediumEditor (this.base)
parent: true,

@@ -46,6 +44,6 @@ init: function () {

id = 'medium-img-' + (+new Date());
Util.insertHTMLCommand(this.base.options.ownerDocument, '<img class="medium-image-loading" id="' + id + '" />');
Util.insertHTMLCommand(this.document, '<img class="medium-image-loading" id="' + id + '" />');
fileReader.onload = function () {
var img = this.base.options.ownerDocument.getElementById(id);
var img = this.document.getElementById(id);
if (img) {

@@ -52,0 +50,0 @@ img.removeAttribute('id');

@@ -88,5 +88,2 @@ /*global Util, Selection, Extension */

// Need a reference to MediumEditor (this.base)
parent: true,
init: function () {

@@ -93,0 +90,0 @@ if (this.forcePlainText || this.cleanPastedHTML) {

@@ -10,3 +10,2 @@ var Placeholder;

name: 'placeholder',
parent: true,

@@ -20,2 +19,7 @@ /* Placeholder Options */

/* hideOnClick: [boolean]
* Should we hide the placeholder on click (true) or when user starts typing (false)
*/
hideOnClick: true,
init: function () {

@@ -63,4 +67,10 @@ this.initPlaceholders();

// if we don't want the placeholder to be removed on click but when user start typing
if (this.hideOnClick) {
this.base.subscribe('editableClick', this.handleHidePlaceholderEvent.bind(this));
} else {
this.base.subscribe('editableKeyup', this.handleBlur.bind(this));
}
// Events where we always hide the placeholder
this.base.subscribe('editableClick', this.handleHidePlaceholderEvent.bind(this));
this.base.subscribe('editableKeypress', this.handleHidePlaceholderEvent.bind(this));

@@ -67,0 +77,0 @@ this.base.subscribe('editablePaste', this.handleHidePlaceholderEvent.bind(this));

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

/*global Util, Selection */
/*global Util, Selection*/

@@ -11,2 +11,3 @@ var Toolbar;

this.options = instance.options;
this.initThrottledMethods();

@@ -196,3 +197,6 @@ };

this.getToolbarElement().classList.add('medium-editor-toolbar-active');
this.base.trigger('showToolbar', {}, this.base.getFocusedElement());
if (typeof this.options.onShowToolbar === 'function') {
Util.deprecated('onShowToolbar', 'the showToolbar custom event', 'v5.0.0');
this.options.onShowToolbar();

@@ -205,4 +209,8 @@ }

if (this.isDisplayed()) {
this.getToolbarElement().classList.remove('medium-editor-toolbar-active');
this.base.trigger('hideToolbar', {}, this.base.getFocusedElement());
this.base.commands.forEach(function (extension) {
if (typeof extension.onHide === 'function') {
Util.deprecated('onHide', 'the hideToolbar custom event', 'v5.0.0');
extension.onHide();

@@ -212,4 +220,4 @@ }

this.getToolbarElement().classList.remove('medium-editor-toolbar-active');
if (typeof this.options.onHideToolbar === 'function') {
Util.deprecated('onHideToolbar', 'the hideToolbar custom event', 'v5.0.0');
this.options.onHideToolbar();

@@ -310,3 +318,3 @@ }

// hide toolbar
if (!this.getFocusedElement() ||
if (!this.base.getFocusedElement() ||
Selection.selectionInContentEditableFalse(this.options.contentWindow)) {

@@ -346,9 +354,5 @@ this.hideToolbar();

// leaving here backward compatibility / statics
getFocusedElement: function () {
for (var i = 0; i < this.base.elements.length; i += 1) {
if (this.base.elements[i].getAttribute('data-medium-focused')) {
return this.base.elements[i];
}
}
return null;
return this.base.getFocusedElement();
},

@@ -437,3 +441,3 @@

setToolbarPosition: function () {
var container = this.getFocusedElement(),
var container = this.base.getFocusedElement(),
selection = this.options.contentWindow.getSelection(),

@@ -440,0 +444,0 @@ anchorPreview;

@@ -567,3 +567,3 @@ /*global NodeFilter, console, Selection*/

var afterLast = lastChild.nextSibling,
fragment = document.createDocumentFragment();
fragment = rootNode.ownerDocument.createDocumentFragment();

@@ -570,0 +570,0 @@ // build up fragment on startNode side of tree

@@ -14,3 +14,3 @@ /*global MediumEditor */

// grunt-bump looks for this:
'version': '4.10.2'
'version': '4.11.0'
}).version.split('.'));

Sorry, the diff of this file is not supported yet

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