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.1 to 5.5.2

9

CHANGES.md

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

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

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

2

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

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

@@ -17,3 +17,5 @@ /*global describe, it, expect, spyOn, AnchorForm,

'<a id="test-markup-link" href="http://test.com"><b>ipsum</b></a> ' +
'<a id="test-symbol-link" href="http://[{~#custom#~}].com"></a>');
'<a id="test-symbol-link" href="http://[{~#custom#~}].com"></a> ' +
'<a id="text-target-blank-link" target="_blank" href="http://test.com">ipsum</a> ' +
'<a id="text-custom-class-link" class="custom-class" href="http://test.com">ipsum</a>');
});

@@ -120,3 +122,10 @@

it('should display the anchor form in the toolbar when clicked', function () {
var editor = this.newMediumEditor('.editor'),
var editor = this.newMediumEditor('.editor', {
anchor: {
targetCheckbox: true,
targetCheckboxText: 'Open in new window',
customClassOption: 'custom-class',
customClassOptionText: 'Custom Class'
}
}),
anchorPreview = editor.getExtensionByName('anchor-preview'),

@@ -136,4 +145,66 @@ anchor = editor.getExtensionByName('anchor'),

expect(anchor.isDisplayed()).toBe(true);
// the checkboxes should be unchecked
expect(anchor.getAnchorTargetCheckbox().checked).toBe(false);
expect(anchor.getAnchorButtonCheckbox().checked).toBe(false);
});
it('should display the anchor form with target checkbox checked in the toolbar when clicked', function () {
var editor = this.newMediumEditor('.editor', {
anchor: {
targetCheckbox: true,
targetCheckboxText: 'Open in new window',
customClassOption: 'custom-class',
customClassOptionText: 'Custom Class'
}
}),
anchorPreview = editor.getExtensionByName('anchor-preview'),
anchor = editor.getExtensionByName('anchor'),
toolbar = editor.getExtensionByName('toolbar');
// show preview
fireEvent(document.getElementById('text-target-blank-link'), 'mouseover');
// load into editor
jasmine.clock().tick(1);
fireEvent(anchorPreview.getPreviewElement(), 'click');
jasmine.clock().tick(200);
expect(toolbar.isDisplayed()).toBe(true);
expect(anchor.isDisplayed()).toBe(true);
// the checkboxes should be unchecked
expect(anchor.getAnchorTargetCheckbox().checked).toBe(true);
expect(anchor.getAnchorButtonCheckbox().checked).toBe(false);
});
it('should display the anchor form with custom class checkbox checked in the toolbar when clicked', function () {
var editor = this.newMediumEditor('.editor', {
anchor: {
targetCheckbox: true,
targetCheckboxText: 'Open in new window',
customClassOption: 'custom-class',
customClassOptionText: 'Custom Class'
}
}),
anchorPreview = editor.getExtensionByName('anchor-preview'),
anchor = editor.getExtensionByName('anchor'),
toolbar = editor.getExtensionByName('toolbar');
// show preview
fireEvent(document.getElementById('text-custom-class-link'), 'mouseover');
// load into editor
jasmine.clock().tick(1);
fireEvent(anchorPreview.getPreviewElement(), 'click');
jasmine.clock().tick(200);
expect(toolbar.isDisplayed()).toBe(true);
expect(anchor.isDisplayed()).toBe(true);
// the checkboxes should be unchecked
expect(anchor.getAnchorTargetCheckbox().checked).toBe(false);
expect(anchor.getAnchorButtonCheckbox().checked).toBe(true);
});
it('should NOT be displayed when the hovered link is empty', function () {

@@ -140,0 +211,0 @@ var editor = this.newMediumEditor('.editor', {

/*global MediumEditor, describe, it, expect, spyOn,
afterEach, beforeEach, selectElementContents,
jasmine, fireEvent, Util, setupTestHelpers,
selectElementContentsAndFire, AnchorForm,
Selection */
selectElementContentsAndFire */

@@ -86,3 +85,3 @@ describe('Anchor Button TestCase', function () {

Selection.select(document, this.el.childNodes[0], 'Hello world, '.length,
MediumEditor.selection.select(document, this.el.childNodes[0], 'Hello world, '.length,
this.el.childNodes[1].childNodes[0], 'will become a link'.length);

@@ -116,3 +115,3 @@ button = toolbar.getToolbarElement().querySelector('[data-action="createLink"]');

Selection.select(document, this.el.querySelector('span'), 0,
MediumEditor.selection.select(document, this.el.querySelector('span'), 0,
this.el.querySelector('strong'), 1);

@@ -306,3 +305,3 @@ button = toolbar.getToolbarElement().querySelector('[data-action="createLink"]');

it('should display the anchor form when toolbar is visible', function () {
spyOn(AnchorForm.prototype, 'showForm').and.callThrough();
spyOn(MediumEditor.extensions.anchor.prototype, 'showForm').and.callThrough();
var button,

@@ -335,4 +334,26 @@ editor = this.newMediumEditor('.editor'),

// https://github.com/yabwe/medium-editor/issues/751
it('should allow more than one link creation within a paragraph', function () {
spyOn(MediumEditor.extensions.anchor.prototype, 'showForm').and.callThrough();
this.el.innerHTML = '<p><a href="#">beginning</a> some text middle some text end</p>';
var editor = this.newMediumEditor('.editor'),
anchorExtension = editor.getExtensionByName('anchor'),
toolbar = editor.getExtensionByName('toolbar'),
para = this.el.firstChild;
// Select the text 'middle'
MediumEditor.selection.select(document, para.childNodes[1], 11, para.childNodes[1], 18);
fireEvent(editor.elements[0], 'focus');
jasmine.clock().tick(1);
// Click the 'anchor' button in the toolbar
fireEvent(toolbar.getToolbarElement().querySelector('[data-action="createLink"]'), 'click');
expect(toolbar.getToolbarActionsElement().style.display).toBe('none');
expect(anchorExtension.isDisplayed()).toBe(true);
expect(anchorExtension.showForm).toHaveBeenCalled();
expect(anchorExtension.getInput().value).toBe('');
});
});
});

@@ -71,2 +71,23 @@ /*global MediumEditor, describe, it, expect, spyOn,

// https://github.com/yabwe/medium-editor/issues/738
it('should import an exported non-collapsed selection after an empty paragraph', function () {
this.el.innerHTML = '<p>This is <a href="#">a link</a></p><p><br/></p><p>not a link</p>';
var editor = this.newMediumEditor('.editor'),
lastTextNode = this.el.childNodes[2].firstChild;
MediumEditor.selection.select(document, lastTextNode, 0, lastTextNode, 'not a link'.length);
var exportedSelection = editor.exportSelection();
expect(exportedSelection).toEqual({ start: 14, end: 24, emptyBlocksIndex: 2 });
editor.importSelection(exportedSelection);
var range = window.getSelection().getRangeAt(0);
expect(range.startContainer === lastTextNode || range.startContainer === lastTextNode.parentNode)
.toBe(true, 'The selection is starting at the wrong element');
expect(range.startOffset).toBe(0, 'The start of the selection is not at the beginning of the text node');
expect(range.endContainer === lastTextNode || range.endContainer === lastTextNode.parentNode)
.toBe(true, 'The selection is ending at the wrong element');
expect(range.endOffset).toBe('not a link'.length, 'The end of the selection is not at the end of the text node');
});
it('should have an index in the exported selection when it is in the second contenteditable', function () {

@@ -73,0 +94,0 @@ this.createElement('div', 'editor', 'lorem <i>ipsum</i> dolor');

@@ -18,2 +18,3 @@ /*global describe, it, beforeEach, afterEach, expect,

this.el.setAttribute('spellcheck', true);
this.el.setAttribute('data-imhere', 'ohyeah');
document.body.appendChild(this.el);

@@ -27,3 +28,3 @@ });

it('should accept a textarea element and "convert" it to a div, preserving important attributes', function () {
it('should accept a textarea element and "convert" it to a div, preserving all attributes', function () {
var editor = this.newMediumEditor('.editor'),

@@ -33,3 +34,4 @@ textarea = this.el;

var attributesToPreserve = ['data-disable-editing',
var attributes = [
'data-disable-editing',
'data-disable-toolbar',

@@ -40,4 +42,6 @@ 'data-placeholder',

'data-disable-preview',
'spellcheck'];
attributesToPreserve.forEach(function (attr) {
'spellcheck',
'data-imhere'
];
attributes.forEach(function (attr) {
expect(editor.elements[0].getAttribute(attr)).toBe(textarea.getAttribute(attr));

@@ -44,0 +48,0 @@ });

@@ -296,11 +296,3 @@ /*global Util, Selection, Extension,

uniqueId = 'medium-editor-' + Date.now() + '-' + id,
attributesToClone = [
'data-disable-editing',
'data-disable-toolbar',
'data-placeholder',
'data-disable-return',
'data-disable-double-return',
'data-disable-preview',
'spellcheck'
];
atts = textarea.attributes;

@@ -310,11 +302,14 @@ div.className = textarea.className;

div.innerHTML = textarea.value;
div.setAttribute('medium-editor-textarea-id', id);
attributesToClone.forEach(function (attr) {
if (textarea.hasAttribute(attr)) {
div.setAttribute(attr, textarea.getAttribute(attr));
textarea.setAttribute('medium-editor-textarea-id', id);
// re-create all attributes from the textearea to the new created div
for (var i = 0, n = atts.length; i < n; i++) {
// do not re-create existing attributes
if (!div.hasAttribute(atts[i].nodeName)) {
div.setAttribute(atts[i].nodeName, atts[i].nodeValue);
}
});
}
textarea.classList.add('medium-editor-hidden');
textarea.setAttribute('medium-editor-textarea-id', id);
textarea.parentNode.insertBefore(

@@ -321,0 +316,0 @@ div,

@@ -137,3 +137,8 @@ var AnchorPreview;

if (activeAnchor) {
anchorExtension.showForm(activeAnchor.attributes.href.value);
var opts = {
url: activeAnchor.attributes.href.value,
target: activeAnchor.getAttribute('target'),
buttonClass: activeAnchor.getAttribute('class')
};
anchorExtension.showForm(opts);
activeAnchor = null;

@@ -140,0 +145,0 @@ }

@@ -63,6 +63,7 @@ var AnchorForm;

var selectedParentElement = Selection.getSelectedParentElement(Selection.getSelectionRange(this.document)),
firstTextNode = Util.getFirstTextNode(selectedParentElement);
var range = Selection.getSelectionRange(this.document);
if (Util.getClosestTag(firstTextNode, 'a')) {
if (range.startContainer.nodeName.toLowerCase() === 'a' ||
range.endContainer.nodeName.toLowerCase() === 'a' ||
Util.getClosestTag(Selection.getSelectedParentElement(range), 'a')) {
return this.execAction('unlink');

@@ -151,5 +152,16 @@ }

showForm: function (linkValue) {
var input = this.getInput();
showForm: function (opts) {
var input = this.getInput(),
targetCheckbox = this.getAnchorTargetCheckbox(),
buttonCheckbox = this.getAnchorButtonCheckbox();
opts = opts || { url: '' };
// TODO: This is for backwards compatability
// We don't need to support the 'string' argument in 6.0.0
if (typeof opts === 'string') {
opts = {
url: opts
};
}
this.base.saveSelection();

@@ -160,4 +172,17 @@ this.hideToolbarDefaultActions();

input.value = linkValue || '';
input.value = opts.url;
input.focus();
// If we have a target checkbox, we want it to be checked/unchecked
// based on whether the existing link has target=_blank
if (targetCheckbox) {
targetCheckbox.checked = opts.target === '_blank';
}
// If we have a custom class checkbox, we want it to be checked/unchecked
// based on whether an existing link already has the class
if (buttonCheckbox) {
var classList = opts.buttonClass ? opts.buttonClass.split(' ') : [];
buttonCheckbox.checked = (classList.indexOf(this.customClassOption) !== -1);
}
},

@@ -182,4 +207,4 @@

// no notion of private functions? wanted `_getFormOpts`
var targetCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-target'),
buttonCheckbox = this.getForm().querySelector('.medium-editor-toolbar-anchor-button'),
var targetCheckbox = this.getAnchorTargetCheckbox(),
buttonCheckbox = this.getAnchorButtonCheckbox(),
opts = {

@@ -263,2 +288,10 @@ url: this.getInput().value

getAnchorTargetCheckbox: function () {
return this.getForm().querySelector('.medium-editor-toolbar-anchor-target');
},
getAnchorButtonCheckbox: function () {
return this.getForm().querySelector('.medium-editor-toolbar-anchor-button');
},
handleTextboxKeyup: function (event) {

@@ -265,0 +298,0 @@ // For ENTER -> create the anchor

@@ -76,3 +76,3 @@ var KeyboardCommands;

// command can be false so the shortcurt is just disabled
// command can be false so the shortcut is just disabled
if (false !== data.command) {

@@ -79,0 +79,0 @@ this.execAction(data.command);

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

/*global Util, Selection, Extension */
/*global Util, Extension */
var PasteHandler;

@@ -141,4 +141,3 @@

cleanPaste: function (text) {
var i, elList, workEl,
el = Selection.getSelectionElement(this.window),
var i, elList,
multiline = /<p|<br|<div/.test(text),

@@ -159,27 +158,2 @@ replacements = createReplacements().concat(this.cleanReplacements || []);

this.pasteHTML('<p>' + elList.join('</p><p>') + '</p>');
try {
this.document.execCommand('insertText', false, '\n');
} catch (ignore) { }
// block element cleanup
elList = el.querySelectorAll('a,p,div,br');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
// Microsoft Word replaces some spaces with newlines.
// While newlines between block elements are meaningless, newlines within
// elements are sometimes actually spaces.
workEl.innerHTML = workEl.innerHTML.replace(/\n/gi, ' ');
switch (workEl.nodeName.toLowerCase()) {
case 'p':
case 'div':
this.filterCommonBlocks(workEl);
break;
case 'br':
this.filterLineBreak(workEl);
break;
}
}
},

@@ -203,3 +177,2 @@

elList = fragmentBody.querySelectorAll('*');
for (i = 0; i < elList.length; i += 1) {

@@ -216,2 +189,23 @@ workEl = elList[i];

// block element cleanup
elList = fragmentBody.querySelectorAll('a,p,div,br');
for (i = 0; i < elList.length; i += 1) {
workEl = elList[i];
// Microsoft Word replaces some spaces with newlines.
// While newlines between block elements are meaningless, newlines within
// elements are sometimes actually spaces.
workEl.innerHTML = workEl.innerHTML.replace(/\n/gi, ' ');
switch (workEl.nodeName.toLowerCase()) {
case 'p':
case 'div':
this.filterCommonBlocks(workEl);
break;
case 'br':
this.filterLineBreak(workEl);
break;
}
}
Util.insertHTMLCommand(this.document, fragmentBody.innerHTML.replace(/&nbsp;/g, ' '));

@@ -218,0 +212,0 @@ },

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

range.setStart(Util.getFirstSelectableLeafNode(targetNode), 0);
range.collapse(true);
}

@@ -179,3 +178,2 @@

range.setStart(currentNode.parentNode, currentNodeIndex + 1);
range.collapse(true);
}

@@ -182,0 +180,0 @@ }

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

// grunt-bump looks for this:
'version': '5.5.1'
'version': '5.5.2'
}).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