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

medium-editor

Package Overview
Dependencies
Maintainers
3
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.1 to 4.10.2

src/js/extensions/placeholder.js

2

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

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

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

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

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

@@ -34,4 +34,4 @@ /*global module, require, process*/

'src/js/extensions/paste.js',
'src/js/extensions/placeholder.js',
'src/js/toolbar.js',
'src/js/placeholders.js',
'src/js/defaults/options.js',

@@ -38,0 +38,0 @@ 'src/js/defaults/extensions.js',

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

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

@@ -76,12 +76,8 @@ # MediumEditor

* __delay__: time in milliseconds to show the toolbar or anchor tag preview. Default: 0
* __autoLink__: enables/disables the auto-link feature, which automatically turns URLs entered into the text field into HTML anchor tags (similar to the functionality of Markdown). Default: false
* __disableReturn__: enables/disables the use of the return-key. You can also set specific element behavior by using setting a data-disable-return attribute. Default: false
* __disableDoubleReturn__: allows/disallows two (or more) empty new lines. You can also set specific element behavior by using setting a data-disable-double-return attribute. Default: false
* __disableEditing__: enables/disables adding the contenteditable behavior. Useful for using the toolbar with customized buttons/actions. You can also set specific element behavior by using setting a data-disable-editing attribute. Default: false
* __disablePlaceholders__: enables/disables support for __placeholder__, including DOM element creation and attaching event handlers. When disabled, medium-editor will ignore the __placeholder__ option and not show placeholder text. Default: false
* __elementsContainer__: specifies a DOM node to contain MediumEditor's toolbar and anchor preview elements. Default: document.body
* __extensions__: extension to use (see [Custom Buttons and Extensions](https://github.com/daviferreira/medium-editor/wiki/Custom-Buttons-and-Extensions)) for more. Default: {}
* __firstHeader__: HTML tag to be used as first header. Default: h3
* __imageDragging__: Allows image drag and drop into the editor. Default: true
* __placeholder__: Defines the default placeholder for empty contenteditables when __disablePlaceholders__ is not set to true. You can overwrite it by setting a data-placeholder attribute on your elements. Default: 'Type your text'
* __secondHeader__: HTML tag to be used as second header. Default: h4

@@ -117,3 +113,4 @@ * __spellcheck__: Enable/disable native contentEditable automatic spellcheck. Default: true

anchorPreview: {
// These are the default options for anchor form, if nothing is passed this is what it used
/* These are the default options for anchor preview,
if nothing is passed this is what it used */
hideDelay: 500,

@@ -139,2 +136,27 @@ previewValueSelector: 'a'

### Placeholder Options
The placeholder handler is a built-in extension which displays placeholder text when the editor is empty.
Options for placeholder are passed as an object that is a member of the outer options object. Example:
```javascript
var editor = new MediumEditor('.editable', {
buttons: ['bold', 'italic', 'quote'],
placeholder: {
/* This example includes the default options for placeholder,
if nothing is passed this is what it used */
text: 'Type your text'
}
});
```
* __text__: Defines the default placeholder for empty contenteditables when __placeholder__ is not set to false. You can overwrite it by setting a `data-placeholder` attribute on the editor elements. Default: 'Type your text'
To disable the placeholder, set the value of the `placeholder` option to `false`:
```javascript
var editor = new MediumEditor('.editable', {
placeholder: false
});
```
### Anchor Form options

@@ -149,3 +171,4 @@

anchor: {
// These are the default options for anchor form, if nothing is passed this is what it used
/* These are the default options for anchor form,
if nothing is passed this is what it used */
customClassOption: null,

@@ -178,3 +201,4 @@ customClassOptionText: 'Button',

paste: {
// This example includes the default options for paste, if nothing is passed this is what it used
/* This example includes the default options for paste,
if nothing is passed this is what it used */
forcePlainText: true,

@@ -195,2 +219,25 @@ cleanPastedHTML: false,

### Auto Link Options
The auto-link handler is a built-in extension which automatically turns URLs entered into the text field into HTML anchor tags (similar to the functionality of Markdown). This feature is OFF by default.
To enable built-in auto-link support, set the value of the `autoLink` option to `true':
```javascript
var editor = new MediumEditor('.editable', {
autoLink: true
});
```
### Image Dragging Options
The image dragging handler is a built-in extenson for handling dragging & dropping images into the contenteditable. This feature is ON by default.
To disable built-in image dragging, set the value of the `imageDragging` option to `false`:
```javascript
var editor = new MediumEditor('.editable', {
imageDragging: false
});
```
### Options Example:

@@ -219,4 +266,6 @@

hideDelay: 300
},
placeholder: {
text: 'Click to edit'
}
}
});

@@ -223,0 +272,0 @@ ```

@@ -29,5 +29,7 @@ /*global describe, it, expect, beforeEach, afterEach,

'http://www.royal.gov.uk',
'http://www.bbc.co.uk',
'http://mountaindew.com',
'http://coca-cola.com',
'http://example.com',
'http://wwww.example.com', // with more "w"s it's still a valid subdomain
'http://www.example.com',

@@ -39,2 +41,8 @@ 'http://www.example.com/foo/bar',

'http://www.example.com/#buzz'
],
notLinks = [
'http:google.com',
'http:/example.com',
'app.can',
'sadasda.sdfasf.sdfas'
];

@@ -65,2 +73,3 @@

expect('Text content: ' + anchors[0].textContent).toBe('Text content: ' + link);
expect(anchors[0].firstChild.getAttribute('data-auto-link')).toBe('true');
};

@@ -81,2 +90,22 @@ }

function generateNotLinkTest(link) {
return function () {
var selection = window.getSelection(),
newRange = document.createRange();
this.el.innerHTML = '<p>' + link + ' </p>';
selection.removeAllRanges();
newRange.setStart(this.el.firstChild.childNodes[0], link.length + 1);
newRange.setEnd(this.el.firstChild.childNodes[0], link.length + 1);
selection.addRange(newRange);
triggerAutolinking(this.el);
var anchors = this.el.getElementsByTagName('a');
expect(anchors.length).toBe(0);
};
}
notLinks.forEach(function (link) {
it('should not auto-link "' + link + '" when typed in', generateNotLinkTest(link));
});
it('should auto-link text on its own', function () {

@@ -87,3 +116,7 @@ this.el.innerHTML = 'http://www.example.com';

triggerAutolinking(this.el);
expect(this.el.innerHTML).toBe('<a href="http://www.example.com">http://www.example.com</a>');
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
expect(links[0].textContent).toBe('http://www.example.com');
});

@@ -96,3 +129,8 @@

triggerAutolinking(this.el);
expect(this.el.innerHTML).toBe('Text with <a href="http://www.example.com">http://www.example.com</a> inside!');
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].getAttribute('href')).toBe(links[0].textContent);
expect(this.el.childNodes[0].nodeValue).toBe('Text with ');
expect(this.el.childNodes[this.el.childNodes.length - 1].nodeValue).toBe(' inside!');
});

@@ -105,3 +143,10 @@

triggerAutolinking(this.el);
expect(this.el.innerHTML).toBe('<span>Text with <a href="http://www.example.com">http://www.example.com</a> inside!</span>');
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(this.el.firstChild.tagName.toLowerCase()).toBe('span');
expect(this.el.firstChild.textContent).toBe('Text with http://www.example.com inside!');
expect(this.el.firstChild.getElementsByTagName('a').length).toBe(1);
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].textContent).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
});

@@ -120,4 +165,11 @@

expect(this.el.innerHTML).toBe('<p><span class="a"><b>Here is the link: </b></span>' +
'<a href="http://www.example.com"><span class="a"><b>http://www.</b>exa</span>mple.com</a> </p>');
expect(this.el.innerHTML.indexOf('<p><span class="a"><b>Here is the link: </b></span>')).toBe(0);
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].innerHTML).toBe('<span data-auto-link="true">' +
'<span class="a"><b>http://www.</b>exa</span>mple.com</span>');
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
expect(this.el.firstChild.lastChild.nodeValue).toBe(' ');
});

@@ -136,4 +188,10 @@

expect(this.el.innerHTML).toBe('<p><b>Here is the link: </b>' +
'<a href="http://www.example.com"><b>http://www.</b>exampl<b>e</b>.com</a> </p>');
expect(this.el.innerHTML.indexOf('<p><b>Here is the link: </b>')).toBe(0);
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].innerHTML).toBe('<span data-auto-link="true">' +
'<b>http://www.</b>exampl<b>e</b>.com</span>');
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
expect(this.el.firstChild.lastChild.nodeValue).toBe(' ');
});

@@ -160,2 +218,6 @@

var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
var expectedOutput = '' +

@@ -166,13 +228,15 @@ '<span>' +

'<a href="http://www.google.com/wow">' +
'<span>' +
'<b>http</b>' +
'<i>://</i>' +
'<span data-auto-link="true">' +
'<span>' +
'<b>http</b>' +
'<i>://</i>' +
'</span>' +
'<span>' +
'<b>www</b>' +
'<u>.google.com</u>' +
'</span>' +
'<span>' +
'<b>/wow</b>' +
'</span>' +
'</span>' +
'<span>' +
'<b>www</b>' +
'<u>.google.com</u>' +
'</span>' +
'<span>' +
'<b>/wow</b>' +
'</span>' +
'</a>' +

@@ -193,8 +257,32 @@ '<span>' +

triggerAutolinking(this.el);
expect(this.el.innerHTML).toBe('Click this <a href="http://www.example.com">http://www.example.com</a> link');
var links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
triggerAutolinking(this.el);
expect(this.el.innerHTML).toBe('Click this <a href="http://www.example.com">http://www.example.com</a> link');
links = this.el.getElementsByTagName('a');
expect(links.length).toBe(1);
expect(links[0].getAttribute('href')).toBe('http://www.example.com');
expect(links[0].firstChild.getAttribute('data-auto-link')).toBe('true');
});
it('should not auto-link text inside a span with data-auto-link=true', function () {
this.el.innerHTML = 'Click this <span data-auto-link="true">http://www.example.com</span> link';
selectElementContentsAndFire(this.el.firstChild);
triggerAutolinking(this.el);
expect(this.el.getElementsByTagName('a').length).toBe(0, 'should not create a link');
});
it('should not auto-link text containing a span with data-auto-link=true', function () {
this.el.innerHTML = 'Click this <span data-auto-link="true">http://www.example.com</span>foo/bar/baz link';
selectElementContentsAndFire(this.el.firstChild);
triggerAutolinking(this.el);
expect(this.el.getElementsByTagName('a').length).toBe(0, 'should not create a link');
});
it('should stop attempting to auto-link on keypress if an error is encountered', function () {

@@ -201,0 +289,0 @@ var spy = spyOn(MediumEditor.extensions.autoLink.prototype, 'performLinking').and.throwError('DOM ERROR');

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

disableToolbar: false,
disablePlaceholders: false,
autoLink: false,

@@ -111,3 +110,2 @@ toolbarAlign: 'center',

allowMultiParagraphSelection: true,
placeholder: 'Type your text',
secondHeader: 'h4',

@@ -114,0 +112,0 @@ buttons: ['bold', 'italic', 'underline', 'anchor', 'header1', 'header2', 'quote'],

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

@@ -96,5 +97,5 @@ describe('Placeholder TestCase', function () {

// In firefox, getComputedStyle().getPropertyValue('content') can return attr() instead of what attr() evaluates to
expect(match[1]).toEqual('data-placeholder');
expect(match[1]).toBe('data-placeholder');
} else {
expect(placeholder).toEqual('\'' + expectedValue + '\'');
expect(placeholder).toBe('\'' + expectedValue + '\'');
}

@@ -106,3 +107,3 @@ }

var editor = this.newMediumEditor('.editor');
validatePlaceholderContent(editor.elements[0], editor.options.placeholder);
validatePlaceholderContent(editor.elements[0], Placeholder.prototype.text);
});

@@ -118,3 +119,21 @@

it('should not set placeholder for empty elements when disablePlaceholders is set to true', function () {
it('should use custom placeholder text when passed as a deprecated option', function () {
var placeholderText = 'Custom placeholder',
editor = this.newMediumEditor('.editor', {
placeholder: placeholderText
});
validatePlaceholderContent(editor.elements[0], placeholderText);
});
it('should use custom placeholder text when passed as the placeholder.text option', function () {
var placeholderText = 'Custom placeholder',
editor = this.newMediumEditor('.editor', {
placeholder: {
text: placeholderText
}
});
validatePlaceholderContent(editor.elements[0], placeholderText);
});
it('should not set placeholder for empty elements when deprecated disablePlaceholders is set to true', function () {
var editor = this.newMediumEditor('.editor', {

@@ -126,6 +145,13 @@ disablePlaceholders: true

it('should not add a placeholder to empty elements on blur when disablePlaceholders is set to true', function () {
it('should not set placeholder for empty elements when placeholder is set to false', function () {
var editor = this.newMediumEditor('.editor', {
placeholder: false
});
expect(editor.elements[0].className).not.toContain('medium-editor-placeholder');
});
it('should not add a placeholder to empty elements on blur when placeholder is set to false', function () {
this.el.innerHTML = 'some text';
var editor = this.newMediumEditor('.editor', {
disablePlaceholders: true
placeholder: false
});

@@ -132,0 +158,0 @@ expect(editor.elements[0].className).not.toContain('medium-editor-placeholder');

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

@@ -43,2 +43,25 @@ describe('Selection TestCase', function () {

it('should import an exported selection outside any anchor tag', function () {
this.el.innerHTML = '<p id=1>Hello world: <a href="#">http://www.example.com</a></p><p id=2><br></p>';
var editor = this.newMediumEditor('.editor', {
buttons: ['italic', 'underline', 'strikethrough']
}),
link = editor.elements[0].getElementsByTagName('a')[0];
placeCursorInsideElement(link.childNodes[0], link.childNodes[0].nodeValue.length);
var exportedSelection = editor.exportSelection();
editor.importSelection(exportedSelection, true);
var range = window.getSelection().getRangeAt(0),
node = range.startContainer;
// Even though we set the range to use the P tag as the start container, Safari normalizes the range
// down to the text node. Setting the range to use the P tag for the start is necessary to support
// MSIE, where it removes the link when the cursor is placed at the end of the text node in the anchor.
while (node.nodeName.toLowerCase() !== 'p') {
node = node.parentNode;
}
expect(node.nodeName.toLowerCase()).toBe('p');
expect(node.getAttribute('id')).toBe('1');
});
it('should have an index in the exported selection when it is in the second contenteditable', function () {

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

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

@@ -235,2 +234,15 @@

function shouldAddDefaultPlaceholder() {
if (this.options.extensions['placeholder']) {
return false;
}
// TODO: deprecated
if (this.options.disablePlaceholders) {
return false;
}
return this.options.placeholder !== false;
}
function shouldAddDefaultAutoLink() {

@@ -241,3 +253,3 @@ if (this.options.extensions['auto-link']) {

return !!this.options.autoLink;
return this.options.autoLink !== false;
}

@@ -250,3 +262,3 @@

return !!this.options.imageDragging;
return this.options.imageDragging !== false;
}

@@ -293,5 +305,2 @@

}
if (!element.getAttribute('data-placeholder')) {
element.setAttribute('data-placeholder', this.options.placeholder);
}
element.setAttribute('data-medium-element', true);

@@ -362,2 +371,15 @@ element.setAttribute('role', 'textbox');

function initPlaceholder(options) {
// Backwards compatability
var defaultsBC = {
text: (typeof this.options.placeholder === 'string') ? this.options.placeholder : undefined, // deprecated
'window': this.options.contentWindow,
'document': this.options.ownerDocument
};
return new MediumEditor.extensions.placeholder(
Util.extend({}, options, defaultsBC)
);
}
function initAnchorPreview(options) {

@@ -459,2 +481,7 @@ // Backwards compatability

}
if (shouldAddDefaultPlaceholder.call(this)) {
var placeholderOpts = (typeof this.options.placeholder === 'string') ? {} : this.options.placeholder;
this.commands.push(initExtension(initPlaceholder.call(this, placeholderOpts), 'placeholder', this));
}
}

@@ -473,3 +500,4 @@

['anchorPreviewHideDelay', 'anchorPreview.hideDelay'],
['disableAnchorPreview', 'anchorPreview: false']
['disableAnchorPreview', 'anchorPreview: false'],
['disablePlaceholders', 'placeholder: false']
];

@@ -483,2 +511,6 @@ // warn about using deprecated properties

});
if (options.hasOwnProperty('placeholder') && typeof options.placeholder === 'string') {
Util.deprecated('placeholder', 'placeholder.text', 'v5.0.0');
}
}

@@ -572,6 +604,2 @@ return Util.defaults({}, options, defaults);

attachHandlers.call(this);
if (!this.options.disablePlaceholders) {
this.placeholders = new Placeholders(this);
}
},

@@ -878,3 +906,9 @@

// TODO: move to selection.js and clean up old methods there
importSelection: function (inSelectionState) {
//
// {object} inSelectionState - the selection to import
// {boolean} [favorLaterSelectionAnchor] - defaults to false. If true, import the cursor immediately
// subsequent to an anchor tag if it would otherwise be placed right at the trailing edge inside the
// anchor. This cursor positioning, even though visually equivalent to the user, can affect behavior
// in MS IE.
importSelection: function (inSelectionState, favorLaterSelectionAnchor) {
if (!inSelectionState) {

@@ -930,2 +964,7 @@ return;

// If the selection is right at the ending edge of a link, put it outside the anchor tag instead of inside.
if (favorLaterSelectionAnchor) {
range = Selection.importSelectionMoveCursorPastAnchor(selectionState, range);
}
sel = this.options.contentWindow.getSelection();

@@ -932,0 +971,0 @@ sel.removeAllRanges();

/*global Button, FormExtension,
AnchorForm, AnchorPreview, AutoLink,
FontSizeForm, ImageDragging, PasteHandler */
FontSizeForm, ImageDragging, PasteHandler,
Placeholder */

@@ -18,4 +19,5 @@ var extensionDefaults;

imageDragging: ImageDragging,
paste: PasteHandler
paste: PasteHandler,
placeholder: Placeholder
};
})();

@@ -18,3 +18,2 @@ var editorDefaults;

disableEditing: false,
disablePlaceholders: false,
autoLink: false,

@@ -28,3 +27,2 @@ toolbarAlign: 'center',

firstHeader: 'h3',
placeholder: 'Type your text',
secondHeader: 'h4',

@@ -31,0 +29,0 @@ targetBlank: false,

@@ -9,5 +9,5 @@ /*global Extension, Util */

// Version of Gruber URL Regexp optimized for JS: http://stackoverflow.com/a/17733640
'((?:[a-z][\\w-]+:(?:\\\/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\\/)\\S+(?:[^\\s`!\\[\\]{};:\'\".,?\u00AB\u00BB\u201C\u201D\u2018\u2019]))' +
// Addition to above Regexp to support bare domains with common non-i18n TLDs and without www prefix:
')|([a-z0-9\\-]+\\.(com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj| Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))';
'((?:(https?://|ftps?://|nntp://)|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}\\\/)\\S+(?:[^\\s`!\\[\\]{};:\'\".,?\u00AB\u00BB\u201C\u201D\u2018\u2019]))' +
// Addition to above Regexp to support bare domains/one level subdomains with common non-i18n TLDs and without www prefix:
')|(([a-z0-9\\-]+\\.)?[a-z0-9\\-]+\\.(com|net|org|edu|gov|mil|aero|asia|biz|cat|coop|info|int|jobs|mobi|museum|name|post|pro|tel|travel|xxx|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj| Ja|sk|sl|sm|sn|so|sr|ss|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw))';

@@ -23,2 +23,3 @@ (function () {

this.base.subscribe('editableKeypress', this.onKeypress.bind(this));
this.base.subscribe('editableBlur', this.onBlur.bind(this));
// MS IE has it's own auto-URL detect feature but ours is better in some ways. Be consistent.

@@ -28,2 +29,6 @@ this.base.options.ownerDocument.execCommand('AutoUrlDetect', false, false);

onBlur: function (blurEvent, editable) {
this.performLinking(editable);
},
onKeypress: function (keyPressEvent) {

@@ -43,3 +48,5 @@ if (this.disableEventHandling) {

if (this.performLinking(keyPressEvent.target)) {
this.base.importSelection(sel);
// pass true for favorLaterSelectionAnchor - this is needed for links at the end of a
// paragraph in MS IE, or MS IE causes the link to be deleted right after adding it.
this.base.importSelection(sel, true);
}

@@ -108,2 +115,4 @@ } catch (e) {

var linkRegExp = new RegExp(LINK_REGEXP_TEXT, 'gi'),
whitespaceChars = [' ', '\t', '\n', '\r', '\u00A0', '\u2000', '\u2001', '\u2002', '\u2003',
'\u2028', '\u2029'],
textContent = contenteditable.textContent,

@@ -114,7 +123,12 @@ match = null,

while ((match = linkRegExp.exec(textContent)) !== null) {
matches.push({
href: match[0],
start: match.index,
end: match.index + match[0].length
});
var matchEnd = match.index + match[0].length;
// If the regexp detected something as a link that has text immediately preceding/following it, bail out.
if ((match.index === 0 || whitespaceChars.indexOf(textContent[match.index - 1]) !== -1) &&
(matchEnd === textContent.length || whitespaceChars.indexOf(textContent[matchEnd]) !== -1)) {
matches.push({
href: match[0],
start: match.index,
end: matchEnd
});
}
}

@@ -163,12 +177,21 @@ return matches;

createLink: function (textNodes, href) {
var alreadyLinked = Util.traverseUp(textNodes[0], function (node) {
return node.nodeName.toLowerCase() === 'a';
});
if (alreadyLinked) {
var shouldNotLink = false;
for (var i = 0; i < textNodes.length && shouldNotLink === false; i++) {
// Do not link if the text node is either inside an anchor or inside span[data-auto-link]
shouldNotLink = !!Util.traverseUp(textNodes[i], function (node) {
return node.nodeName.toLowerCase() === 'a' ||
(node.getAttribute && node.getAttribute('data-auto-link') === 'true');
});
}
if (shouldNotLink) {
return false;
}
var anchor = document.createElement('a');
Util.moveTextRangeIntoElement(textNodes[0], textNodes[textNodes.length - 1], anchor);
var anchor = document.createElement('a'),
span = document.createElement('span');
Util.moveTextRangeIntoElement(textNodes[0], textNodes[textNodes.length - 1], span);
span.setAttribute('data-auto-link', 'true');
anchor.setAttribute('href', Util.ensureUrlHasProtocol(href));
span.parentNode.insertBefore(anchor, span);
anchor.appendChild(span);
return true;

@@ -175,0 +198,0 @@ }

@@ -29,2 +29,35 @@ /*global Util */

// Utility method called from importSelection only
importSelectionMoveCursorPastAnchor: function (selectionState, range) {
var nodeInsideAnchorTagFunction = function (node) {
return node.nodeName.toLowerCase() === 'a';
};
if (selectionState.start === selectionState.end &&
range.startContainer.nodeType === 3 &&
range.startOffset === range.startContainer.nodeValue.length &&
Util.traverseUp(range.startContainer, nodeInsideAnchorTagFunction)) {
var prevNode = range.startContainer,
currentNode = range.startContainer.parentNode;
while (currentNode !== null && currentNode.nodeName.toLowerCase() !== 'a') {
if (currentNode.childNodes[currentNode.childNodes.length - 1] !== prevNode) {
currentNode = null;
} else {
prevNode = currentNode;
currentNode = currentNode.parentNode;
}
}
if (currentNode !== null && currentNode.nodeName.toLowerCase() === 'a') {
var currentNodeIndex = null;
for (var i = 0; currentNodeIndex === null && i < currentNode.parentNode.childNodes.length; i++) {
if (currentNode.parentNode.childNodes[i] === currentNode) {
currentNodeIndex = i;
}
}
range.setStart(currentNode.parentNode, currentNodeIndex + 1);
range.collapse(true);
}
}
return range;
},
selectionInContentEditableFalse: function (contentWindow) {

@@ -31,0 +64,0 @@ // determine if the current selection is exclusively inside

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

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

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