Socket
Socket
Sign inDemoInstall

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 5.5.4 to 5.6.0

dist/css/themes/tim.css

7

CHANGES.md

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

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

@@ -2,0 +9,0 @@ ==================

6

Gruntfile.js

@@ -134,3 +134,4 @@ /*global module, require, process*/

}
}]
}],
files: srcFiles.concat('!src/js/extensions/deprecated/*')
},

@@ -186,3 +187,4 @@ summary: true

'dist/css/themes/mani.css': 'src/sass/themes/mani.scss',
'dist/css/themes/roman.css': 'src/sass/themes/roman.scss'
'dist/css/themes/roman.css': 'src/sass/themes/roman.scss',
'dist/css/themes/tim.css': 'src/sass/themes/tim.scss'
}

@@ -189,0 +191,0 @@ }

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

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

@@ -266,2 +266,45 @@ /*global MediumEditor, describe, it, expect, spyOn,

it('should fire editableInput only once when the user creates a link open to a new window,' +
' and it should fire at the end of the DOM and selection modifications', function () {
spyOn(MediumEditor.prototype, 'createLink').and.callThrough();
this.el.innerHTML = '<p>Lorem ipsum et dolitur sunt.</p>';
var editor = this.newMediumEditor('.editor', {
anchor: {
targetCheckbox: true
}
}),
p = this.el.lastChild,
anchorExtension = editor.getExtensionByName('anchor'),
toolbar = editor.getExtensionByName('toolbar'),
selectionWhenEventsFired = [],
listener = function () {
selectionWhenEventsFired.push(window.getSelection().toString());
};
MediumEditor.selection.select(document, p.firstChild, 'Lorem '.length, p.firstChild, 'Lorem ipsum'.length);
fireEvent(editor.elements[0], 'focus');
jasmine.clock().tick(1);
// Click the 'anchor' button in the toolbar
fireEvent(toolbar.getToolbarElement().querySelector('[data-action="createLink"]'), 'click');
// Input a url and save
var input = anchorExtension.getInput(),
checkbox = anchorExtension.getAnchorTargetCheckbox();
input.value = 'http://www.example.com';
checkbox.checked = true;
editor.subscribe('editableInput', listener);
fireEvent(input, 'keyup', {
keyCode: Util.keyCode.ENTER
});
expect(editor.createLink).toHaveBeenCalledWith({
url: 'http://www.example.com',
target: '_blank'
});
expect(window.getSelection().toString()).toBe('ipsum', 'selected text should remain selected');
expect(selectionWhenEventsFired.length).toBe(1, 'only one editableInput event should have been registered');
expect(selectionWhenEventsFired[0]).toBe('ipsum', 'selected text should have been the same when event fired');
});
it('should not select empty paragraphs when link is created at beginning of paragraph', function () {

@@ -268,0 +311,0 @@ spyOn(MediumEditor.prototype, 'createLink').and.callThrough();

@@ -55,2 +55,16 @@ /*global describe, it, expect, jasmine,

});
it('can be disabled for a temporary period of time on a named basis', function () {
var editor = this.newMediumEditor('.editor'),
spy = jasmine.createSpy('handler'),
tempData = { temp: 'data' };
editor.subscribe('myIncredibleEvent', spy);
expect(spy).not.toHaveBeenCalled();
editor.events.disableCustomEvent('myIncredibleEvent');
editor.trigger('myIncredibleEvent', tempData, editor.elements[0]);
expect(spy).not.toHaveBeenCalled();
editor.events.enableCustomEvent('myIncredibleEvent');
editor.trigger('myIncredibleEvent', tempData, editor.elements[0]);
expect(spy).toHaveBeenCalledWith(tempData, editor.elements[0]);
});
});

@@ -57,0 +71,0 @@

@@ -900,122 +900,129 @@ /*global Util, Selection, Extension,

createLink: function (opts) {
var customEvent, i;
var currentEditor, customEvent, i;
if (opts.url && opts.url.trim().length > 0) {
var currentSelection = this.options.contentWindow.getSelection();
if (currentSelection) {
var currRange = currentSelection.getRangeAt(0),
commonAncestorContainer = currRange.commonAncestorContainer,
exportedSelection,
startContainerParentElement,
endContainerParentElement,
textNodes;
try {
this.events.disableCustomEvent('editableInput');
if (opts.url && opts.url.trim().length > 0) {
var currentSelection = this.options.contentWindow.getSelection();
if (currentSelection) {
var currRange = currentSelection.getRangeAt(0),
commonAncestorContainer = currRange.commonAncestorContainer,
exportedSelection,
startContainerParentElement,
endContainerParentElement,
textNodes;
// If the selection is contained within a single text node
// and the selection starts at the beginning of the text node,
// MSIE still says the startContainer is the parent of the text node.
// If the selection is contained within a single text node, we
// want to just use the default browser 'createLink', so we need
// to account for this case and adjust the commonAncestorContainer accordingly
if (currRange.endContainer.nodeType === 3 &&
currRange.startContainer.nodeType !== 3 &&
currRange.startOffset === 0 &&
currRange.startContainer.firstChild === currRange.endContainer) {
commonAncestorContainer = currRange.endContainer;
}
// If the selection is contained within a single text node
// and the selection starts at the beginning of the text node,
// MSIE still says the startContainer is the parent of the text node.
// If the selection is contained within a single text node, we
// want to just use the default browser 'createLink', so we need
// to account for this case and adjust the commonAncestorContainer accordingly
if (currRange.endContainer.nodeType === 3 &&
currRange.startContainer.nodeType !== 3 &&
currRange.startOffset === 0 &&
currRange.startContainer.firstChild === currRange.endContainer) {
commonAncestorContainer = currRange.endContainer;
}
startContainerParentElement = Util.getClosestBlockContainer(currRange.startContainer);
endContainerParentElement = Util.getClosestBlockContainer(currRange.endContainer);
startContainerParentElement = Util.getClosestBlockContainer(currRange.startContainer);
endContainerParentElement = Util.getClosestBlockContainer(currRange.endContainer);
// If the selection is not contained within a single text node
// but the selection is contained within the same block element
// we want to make sure we create a single link, and not multiple links
// which can happen with the built in browser functionality
if (commonAncestorContainer.nodeType !== 3 && startContainerParentElement === endContainerParentElement) {
// If the selection is not contained within a single text node
// but the selection is contained within the same block element
// we want to make sure we create a single link, and not multiple links
// which can happen with the built in browser functionality
if (commonAncestorContainer.nodeType !== 3 && startContainerParentElement === endContainerParentElement) {
var currentEditor = Selection.getSelectionElement(this.options.contentWindow),
parentElement = (startContainerParentElement || currentEditor),
fragment = this.options.ownerDocument.createDocumentFragment();
currentEditor = Selection.getSelectionElement(this.options.contentWindow);
var parentElement = (startContainerParentElement || currentEditor),
fragment = this.options.ownerDocument.createDocumentFragment();
// since we are going to create a link from an extracted text,
// be sure that if we are updating a link, we won't let an empty link behind (see #754)
// (Workaroung for Chrome)
this.execAction('unlink');
// since we are going to create a link from an extracted text,
// be sure that if we are updating a link, we won't let an empty link behind (see #754)
// (Workaroung for Chrome)
this.execAction('unlink');
exportedSelection = this.exportSelection();
fragment.appendChild(parentElement.cloneNode(true));
exportedSelection = this.exportSelection();
fragment.appendChild(parentElement.cloneNode(true));
if (currentEditor === parentElement) {
// We have to avoid the editor itself being wiped out when it's the only block element,
// as our reference inside this.elements gets detached from the page when insertHTML runs.
// If we just use [parentElement, 0] and [parentElement, parentElement.childNodes.length]
// as the range boundaries, this happens whenever parentElement === currentEditor.
// The tradeoff to this workaround is that a orphaned tag can sometimes be left behind at
// the end of the editor's content.
// In Gecko:
// as an empty <strong></strong> if parentElement.lastChild is a <strong> tag.
// In WebKit:
// an invented <br /> tag at the end in the same situation
Selection.select(
if (currentEditor === parentElement) {
// We have to avoid the editor itself being wiped out when it's the only block element,
// as our reference inside this.elements gets detached from the page when insertHTML runs.
// If we just use [parentElement, 0] and [parentElement, parentElement.childNodes.length]
// as the range boundaries, this happens whenever parentElement === currentEditor.
// The tradeoff to this workaround is that a orphaned tag can sometimes be left behind at
// the end of the editor's content.
// In Gecko:
// as an empty <strong></strong> if parentElement.lastChild is a <strong> tag.
// In WebKit:
// an invented <br /> tag at the end in the same situation
Selection.select(
this.options.ownerDocument,
parentElement.firstChild,
0,
parentElement.lastChild,
parentElement.lastChild.nodeType === 3 ?
parentElement.lastChild.nodeValue.length : parentElement.lastChild.childNodes.length
);
} else {
Selection.select(
this.options.ownerDocument,
parentElement,
0,
parentElement,
parentElement.childNodes.length
);
}
var modifiedExportedSelection = this.exportSelection();
textNodes = Util.findOrCreateMatchingTextNodes(
this.options.ownerDocument,
parentElement.firstChild,
0,
parentElement.lastChild,
parentElement.lastChild.nodeType === 3 ?
parentElement.lastChild.nodeValue.length : parentElement.lastChild.childNodes.length
fragment,
{
start: exportedSelection.start - modifiedExportedSelection.start,
end: exportedSelection.end - modifiedExportedSelection.start,
editableElementIndex: exportedSelection.editableElementIndex
}
);
} else {
Selection.select(
this.options.ownerDocument,
parentElement,
0,
parentElement,
parentElement.childNodes.length
);
}
var modifiedExportedSelection = this.exportSelection();
// Creates the link in the document fragment
Util.createLink(this.options.ownerDocument, textNodes, opts.url.trim());
textNodes = Util.findOrCreateMatchingTextNodes(
this.options.ownerDocument,
fragment,
{
start: exportedSelection.start - modifiedExportedSelection.start,
end: exportedSelection.end - modifiedExportedSelection.start,
editableElementIndex: exportedSelection.editableElementIndex
}
);
// Chrome trims the leading whitespaces when inserting HTML, which messes up restoring the selection.
var leadingWhitespacesCount = (fragment.firstChild.innerHTML.match(/^\s+/) || [''])[0].length;
// Creates the link in the document fragment
Util.createLink(this.options.ownerDocument, textNodes, opts.url.trim());
// Now move the created link back into the original document in a way to preserve undo/redo history
Util.insertHTMLCommand(this.options.ownerDocument, fragment.firstChild.innerHTML.replace(/^\s+/, ''));
exportedSelection.start -= leadingWhitespacesCount;
exportedSelection.end -= leadingWhitespacesCount;
// Chrome trims the leading whitespaces when inserting HTML, which messes up restoring the selection.
var leadingWhitespacesCount = (fragment.firstChild.innerHTML.match(/^\s+/) || [''])[0].length;
this.importSelection(exportedSelection);
} else {
this.options.ownerDocument.execCommand('createLink', false, opts.url);
}
// Now move the created link back into the original document in a way to preserve undo/redo history
Util.insertHTMLCommand(this.options.ownerDocument, fragment.firstChild.innerHTML.replace(/^\s+/, ''));
exportedSelection.start -= leadingWhitespacesCount;
exportedSelection.end -= leadingWhitespacesCount;
if (this.options.targetBlank || opts.target === '_blank') {
Util.setTargetBlank(Selection.getSelectionStart(this.options.ownerDocument), opts.url);
}
this.importSelection(exportedSelection);
} else {
this.options.ownerDocument.execCommand('createLink', false, opts.url);
if (opts.buttonClass) {
Util.addClassToAnchors(Selection.getSelectionStart(this.options.ownerDocument), opts.buttonClass);
}
}
if (this.options.targetBlank || opts.target === '_blank') {
Util.setTargetBlank(Selection.getSelectionStart(this.options.ownerDocument), opts.url);
}
// Fire input event for backwards compatibility if anyone was listening directly to the DOM input event
if (this.options.targetBlank || opts.target === '_blank' || opts.buttonClass) {
customEvent = this.options.ownerDocument.createEvent('HTMLEvents');
customEvent.initEvent('input', true, true, this.options.contentWindow);
for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].dispatchEvent(customEvent);
}
if (opts.buttonClass) {
Util.addClassToAnchors(Selection.getSelectionStart(this.options.ownerDocument), opts.buttonClass);
}
}
} finally {
this.events.enableCustomEvent('editableInput');
}
if (this.options.targetBlank || opts.target === '_blank' || opts.buttonClass) {
customEvent = this.options.ownerDocument.createEvent('HTMLEvents');
customEvent.initEvent('input', true, true, this.options.contentWindow);
for (i = 0; i < this.elements.length; i += 1) {
this.elements[i].dispatchEvent(customEvent);
}
}
// Fire our custom editableInput event
this.events.triggerCustomEvent('editableInput', customEvent, currentEditor);
},

@@ -1022,0 +1029,0 @@

@@ -12,2 +12,3 @@ /*global Util*/

this.events = [];
this.disabledEvents = {};
this.customEvents = {};

@@ -55,2 +56,12 @@ this.listeners = {};

enableCustomEvent: function (event) {
if (this.disabledEvents[event] !== undefined) {
delete this.disabledEvents[event];
}
},
disableCustomEvent: function (event) {
this.disabledEvents[event] = true;
},
// custom events

@@ -87,3 +98,3 @@ attachCustomEvent: function (event, listener) {

triggerCustomEvent: function (name, data, editable) {
if (this.customEvents[name]) {
if (this.customEvents[name] && !this.disabledEvents[name]) {
this.customEvents[name].forEach(function (listener) {

@@ -90,0 +101,0 @@ listener(data, editable);

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

return [
// replace two bogus tags that begin pastes from google docs

@@ -46,3 +45,7 @@ [new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi), ''],

// Microsoft Word makes these odd tags, like <o:p></o:p>
[new RegExp(/<\/?o:[a-z]*>/gi), '']
[new RegExp(/<\/?o:[a-z]*>/gi), ''],
// cleanup comments added by Chrome when pasting html
['<!--EndFragment-->', ''],
['<!--StartFragment-->', '']
];

@@ -49,0 +52,0 @@ }

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

// grunt-bump looks for this:
'version': '5.5.4'
'version': '5.6.0'
}).version);

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc