medium-editor
Advanced tools
Comparing version 4.8.1 to 4.9.0
{ | ||
"name": "medium-editor", | ||
"version": "4.8.1", | ||
"version": "4.9.0", | ||
"homepage": "http://daviferreira.github.io/medium-editor/", | ||
@@ -5,0 +5,0 @@ "authors": [ |
@@ -0,1 +1,9 @@ | ||
4.9.0 / 2015-05-18 | ||
================== | ||
* New auto-link support for detecting urls and converting them to links | ||
* Fix target _blank issue for links in Firefox | ||
* Don't show placeholders for empty lists | ||
* Allow for overriding image drag and drop via extension | ||
4.8.1 / 2015-05-13 | ||
@@ -2,0 +10,0 @@ ================== |
@@ -23,6 +23,8 @@ /*global module, require, process*/ | ||
'src/js/button.js', | ||
'src/js/paste.js', | ||
'src/js/extensions/anchor.js', | ||
'src/js/extensions/anchor-preview.js', | ||
'src/js/extensions/auto-link.js', | ||
'src/js/extensions/image-dragging.js', | ||
'src/js/extensions/fontsize.js', | ||
'src/js/extensions/paste.js', | ||
'src/js/toolbar.js', | ||
@@ -29,0 +31,0 @@ 'src/js/placeholders.js', |
{ | ||
"name": "medium-editor", | ||
"version": "4.8.1", | ||
"version": "4.9.0", | ||
"author": "Davi Ferreira <hi@daviferreira.com>", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
@@ -15,3 +15,3 @@ # MediumEditor | ||
[![NPM info](https://nodei.co/npm/medium-editor.png?downloads=true)](https://nodei.co/npm/medium-editor.png?downloads=true) | ||
[![NPM info](https://nodei.co/npm/medium-editor.png?downloads=true)](https://www.npmjs.com/package/medium-editor) | ||
@@ -78,2 +78,3 @@ [![Travis build status](http://img.shields.io/travis/daviferreira/medium-editor.svg?style=flat-square)](https://travis-ci.org/daviferreira/medium-editor) | ||
* __disableAnchorPreview__: enables/disables the anchor preview element, which appears when hovering links and allows the user to edit the link when clicking. If toolbar is diabled (via __disableToolbar__ or `data-disable-toolbar attribute`) the anchor preview is always disabled so this option will be ignored. Default: false | ||
* __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 | ||
@@ -80,0 +81,0 @@ * __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 |
@@ -1,2 +0,2 @@ | ||
/*global describe, it, expect, afterEach, | ||
/*global describe, it, expect, afterEach, Util, | ||
beforeEach, fireEvent, setupTestHelpers */ | ||
@@ -31,3 +31,5 @@ | ||
// hit return | ||
fireEvent(editor.elements[0], 'keypress', 13); | ||
fireEvent(editor.elements[0], 'keypress', { | ||
keyCode: Util.keyCode.ENTER | ||
}); | ||
@@ -51,3 +53,5 @@ el = document.getElementById('header'); | ||
// hit return | ||
fireEvent(editor.elements[0], 'keypress', 13); | ||
fireEvent(editor.elements[0], 'keypress', { | ||
keyCode: Util.keyCode.ENTER | ||
}); | ||
@@ -72,3 +76,5 @@ el = document.getElementById('header'); | ||
// hit backspace | ||
fireEvent(editor.elements[0].querySelector(el.tagName.toLowerCase()), 'keydown', { keyCode: 8 }); | ||
fireEvent(editor.elements[0].querySelector(el.tagName.toLowerCase()), 'keydown', { | ||
keyCode: Util.keyCode.BACKSPACE | ||
}); | ||
@@ -75,0 +81,0 @@ el = document.getElementById('header'); |
@@ -11,3 +11,5 @@ /*global atob, unescape, Uint8Array, Blob*/ | ||
el.innerHTML = html || ''; | ||
el.className = className; | ||
if (className) { | ||
el.className = className; | ||
} | ||
this.elements.push(el); | ||
@@ -14,0 +16,0 @@ if (!dontAppend) { |
@@ -103,2 +103,3 @@ /*global MediumEditor, describe, it, expect, spyOn, | ||
disablePlaceholders: false, | ||
autoLink: false, | ||
toolbarAlign: 'center', | ||
@@ -105,0 +106,0 @@ elementsContainer: document.body, |
@@ -33,2 +33,14 @@ /*global describe, it, expect, | ||
it('should not set a placeholder for elements with unorderedlist', function () { | ||
this.el.innerHTML = '<ul><li></li></ul>'; | ||
var editor = this.newMediumEditor('.editor'); | ||
expect(editor.elements[0].className).not.toContain('medium-editor-placeholder'); | ||
}); | ||
it('should not set a placeholder for elements with orderedlist', function () { | ||
this.el.innerHTML = '<ol><li></li></ol>'; | ||
var editor = this.newMediumEditor('.editor'); | ||
expect(editor.elements[0].className).not.toContain('medium-editor-placeholder'); | ||
}); | ||
it('should set placeholder for elements with empty children', function () { | ||
@@ -35,0 +47,0 @@ this.el.innerHTML = '<p><br></p><div class="empty"></div>'; |
@@ -1,2 +0,3 @@ | ||
/*global MediumEditor, Util, describe, it, expect, spyOn */ | ||
/*global MediumEditor, Util, describe, it, expect, spyOn, | ||
afterEach, beforeEach, setupTestHelpers */ | ||
@@ -6,2 +7,10 @@ describe('Util', function () { | ||
beforeEach(function () { | ||
setupTestHelpers.call(this); | ||
}); | ||
afterEach(function () { | ||
this.cleanupTest(); | ||
}); | ||
describe('Exposure', function () { | ||
@@ -104,2 +113,26 @@ | ||
describe('settargetblank', function () { | ||
it('sets target blank on a A element from a A element', function () { | ||
var el = this.createElement('a', '', 'lorem ipsum'); | ||
el.attributes.href = 'http://0.0.0.0/bar.html'; | ||
Util.setTargetBlank(el); | ||
expect(el.target).toBe('_blank'); | ||
}); | ||
it('sets target blank on a A element from a DIV element', function () { | ||
var el = this.createElement('div', '', '<a href="http://1.1.1.1/foo.html">foo</a> <a href="http://0.0.0.0/bar.html">bar</a>'); | ||
Util.setTargetBlank(el, 'http://0.0.0.0/bar.html'); | ||
var nodes = el.getElementsByTagName('a'); | ||
expect(nodes[0].target).not.toBe('_blank'); | ||
expect(nodes[1].target).toBe('_blank'); | ||
}); | ||
}); | ||
describe('warn', function () { | ||
@@ -131,2 +164,101 @@ | ||
}); | ||
describe('splitOffDOMTree', function () { | ||
/* start: | ||
* | ||
* <div> | ||
* / | \ | ||
* <span> <span> <span> | ||
* / \ / \ / \ | ||
* 1 2 3 4 5 6 | ||
* | ||
* result: | ||
* | ||
* <div> <div>' | ||
* / \ / \ | ||
* <span> <span> <span>' <span> | ||
* / \ | | / \ | ||
* 1 2 3 4 5 6 | ||
*/ | ||
it('should split a complex tree correctly when splitting off right part of tree', function () { | ||
var el = this.createElement('div', '', | ||
'<span><b>1</b><i>2</i></span><span><b>3</b><u>4</u></span><span><b>5</b><i>6</i></span>'), | ||
splitOn = el.querySelector('u').firstChild, | ||
result = Util.splitOffDOMTree(el, splitOn); | ||
expect(el.outerHTML).toBe('<div><span><b>1</b><i>2</i></span><span><b>3</b></span></div>'); | ||
expect(result.outerHTML).toBe('<div><span><u>4</u></span><span><b>5</b><i>6</i></span></div>'); | ||
}); | ||
/* start: | ||
* | ||
* <div> | ||
* / | \ | ||
* <span> <span> <span> | ||
* / \ / \ / \ | ||
* 1 2 3 4 5 6 | ||
* | ||
* result: | ||
* | ||
* <div>' <div> | ||
* / \ | | ||
* <span> <span> <span> | ||
* /\ /\ /\ | ||
* 1 2 3 4 5 6 | ||
*/ | ||
it('should split a complex tree correctly when splitting off left part of tree', function () { | ||
var el = this.createElement('div', '', | ||
'<span><b>1</b><i>2</i></span><span><b>3</b><u>4</u></span><span><b>5</b><i>6</i></span>'), | ||
splitOn = el.querySelector('u').firstChild, | ||
result = Util.splitOffDOMTree(el, splitOn, true); | ||
expect(el.outerHTML).toBe('<div><span><b>5</b><i>6</i></span></div>'); | ||
expect(result.outerHTML).toBe('<div><span><b>1</b><i>2</i></span><span><b>3</b><u>4</u></span></div>'); | ||
}); | ||
}); | ||
describe('moveTextRangeIntoElement', function () { | ||
it('should return false and bail if no elements are passed', function () { | ||
expect(Util.moveTextRangeIntoElement(null, null)).toBe(false); | ||
}); | ||
it('should return false and bail if elemenets do not share a root', function () { | ||
var el = this.createElement('div', '', 'text'), | ||
elTwo = this.createElement('div', '', 'more text', true), | ||
temp = this.createElement('div', ''); | ||
expect(Util.moveTextRangeIntoElement(el, elTwo, temp)).toBe(false); | ||
expect(temp.innerHTML).toBe(''); | ||
}); | ||
it('should create a parent element that spans multiple root elements', function () { | ||
var el = this.createElement('div', '', | ||
'<span>Link = http</span>' + | ||
'<span>://</span>' + | ||
'<span>www.exam</span>' + | ||
'<span>ple.com</span>' + | ||
'<span>:443/</span>' + | ||
'<span>path/to</span>' + | ||
'<span>somewhere#</span>' + | ||
'<span>index notLink</span>'), | ||
firstText = el.firstChild.firstChild.splitText('Link = '.length), | ||
lastText = el.lastChild.firstChild, | ||
para = this.createElement('p', ''); | ||
lastText.splitText('index'.length); | ||
Util.moveTextRangeIntoElement(firstText, lastText, para); | ||
expect(el.innerHTML).toBe( | ||
'<span>Link = </span>' + | ||
'<p>' + | ||
'<span>http</span>' + | ||
'<span>://</span>' + | ||
'<span>www.exam</span>' + | ||
'<span>ple.com</span>' + | ||
'<span>:443/</span>' + | ||
'<span>path/to</span>' + | ||
'<span>somewhere#</span>' + | ||
'<span>index</span>' + | ||
'</p>' + | ||
'<span> notLink</span>' | ||
); | ||
}); | ||
}); | ||
}); |
@@ -1,4 +0,5 @@ | ||
/*global FileReader, Util, ButtonsData, DefaultButton, | ||
/*global Util, ButtonsData, DefaultButton, | ||
Selection, AnchorExtension, FontSizeExtension, Extension, extensionDefaults, | ||
Toolbar, AnchorPreview, Events, Placeholders, editorDefaults */ | ||
Toolbar, AnchorPreview, AutoLink, ImageDragging, | ||
Events, Placeholders, editorDefaults */ | ||
@@ -142,47 +143,2 @@ function MediumEditor(elements, options) { | ||
function handleDrag(event) { | ||
var className = 'medium-editor-dragover'; | ||
event.preventDefault(); | ||
event.dataTransfer.dropEffect = 'copy'; | ||
if (event.type === 'dragover') { | ||
event.target.classList.add(className); | ||
} else if (event.type === 'dragleave') { | ||
event.target.classList.remove(className); | ||
} | ||
} | ||
function handleDrop(event) { | ||
var className = 'medium-editor-dragover', | ||
files; | ||
event.preventDefault(); | ||
event.stopPropagation(); | ||
// IE9 does not support the File API, so prevent file from opening in a new window | ||
// but also don't try to actually get the file | ||
if (event.dataTransfer.files) { | ||
files = Array.prototype.slice.call(event.dataTransfer.files, 0); | ||
files.some(function (file) { | ||
if (file.type.match('image')) { | ||
var fileReader, id; | ||
fileReader = new FileReader(); | ||
fileReader.readAsDataURL(file); | ||
id = 'medium-img-' + (+new Date()); | ||
Util.insertHTMLCommand(this.options.ownerDocument, '<img class="medium-image-loading" id="' + id + '" />'); | ||
fileReader.onload = function () { | ||
var img = this.options.ownerDocument.getElementById(id); | ||
if (img) { | ||
img.removeAttribute('id'); | ||
img.removeAttribute('class'); | ||
img.src = fileReader.result; | ||
} | ||
}.bind(this); | ||
} | ||
}.bind(this)); | ||
} | ||
event.target.classList.remove(className); | ||
} | ||
function handleKeyup(event) { | ||
@@ -282,2 +238,18 @@ var node = Util.getSelectionStart(this.options.ownerDocument), | ||
function shouldAddDefaultAutoLink() { | ||
if (this.options.extensions['auto-link']) { | ||
return false; | ||
} | ||
return !!this.options.autoLink; | ||
} | ||
function shouldAddDefaultImageDragging() { | ||
if (this.options.extensions['image-dragging']) { | ||
return false; | ||
} | ||
return !!this.options.imageDragging; | ||
} | ||
function createContentEditable(textarea) { | ||
@@ -388,8 +360,2 @@ var div = this.options.ownerDocument.createElement('div'), | ||
} | ||
// drag and drop of images | ||
if (this.options.imageDragging) { | ||
this.subscribe('editableDrag', handleDrag.bind(this)); | ||
this.subscribe('editableDrop', handleDrop.bind(this)); | ||
} | ||
} | ||
@@ -452,2 +418,10 @@ | ||
} | ||
if (shouldAddDefaultAutoLink.call(this)) { | ||
this.commands.push(initExtension(new AutoLink(), 'auto-link', this)); | ||
} | ||
if (shouldAddDefaultImageDragging.call(this)) { | ||
this.commands.push(initExtension(new ImageDragging(), 'image-dragging', this)); | ||
} | ||
} | ||
@@ -937,3 +911,3 @@ | ||
if (this.options.targetBlank || opts.target === '_blank') { | ||
Util.setTargetBlank(Util.getSelectionStart(this.options.ownerDocument)); | ||
Util.setTargetBlank(Util.getSelectionStart(this.options.ownerDocument), opts.url); | ||
} | ||
@@ -940,0 +914,0 @@ |
@@ -1,2 +0,2 @@ | ||
/*global PasteHandler */ | ||
/*global PasteHandler, AutoLink, ImageDragging */ | ||
@@ -8,4 +8,6 @@ var extensionDefaults; | ||
extensionDefaults = { | ||
autoLink: AutoLink, | ||
imageDragging: ImageDragging, | ||
paste: PasteHandler | ||
}; | ||
})(); |
@@ -24,2 +24,3 @@ var editorDefaults; | ||
disablePlaceholders: false, | ||
autoLink: false, | ||
toolbarAlign: 'center', | ||
@@ -26,0 +27,0 @@ elementsContainer: false, |
@@ -25,4 +25,4 @@ /* global Util */ | ||
// | ||
// var thingOne = new Thing(); // foo === bar | ||
// var thingTwo = new ThingTwo(); // foo == baz | ||
// var thingOne = new Thing(); // foo === "bar" | ||
// var thingTwo = new ThingTwo(); // foo === "baz" | ||
// | ||
@@ -111,3 +111,3 @@ // which seems like some simply shallow copy nonsense | ||
* 2) Call checkState on the extension, passing the node as an argument | ||
* 3) Get tha parent node of the previous node | ||
* 3) Get the parent node of the previous node | ||
* 4) Repeat steps #2 and #3 until we move outside the parent contenteditable | ||
@@ -136,3 +136,3 @@ */ | ||
* | ||
* If this function returns a non-null value, the exntesion will | ||
* If this function returns a non-null value, the extension will | ||
* be ignored as the code climbs the dom tree. | ||
@@ -158,3 +158,3 @@ * | ||
* If implemented, this function is similar to checkState() in | ||
* that it will be calle repeatedly as MediumEditor moves up | ||
* that it will be called repeatedly as MediumEditor moves up | ||
* the DOM to update the editor & toolbar after a state change. | ||
@@ -161,0 +161,0 @@ * |
@@ -19,5 +19,4 @@ /*global Util*/ | ||
init: function (instance) { | ||
init: function () { | ||
this.base = instance; | ||
this.anchorPreview = this.createPreview(); | ||
@@ -24,0 +23,0 @@ this.base.options.elementsContainer.appendChild(this.anchorPreview); |
@@ -34,5 +34,4 @@ var Placeholders; | ||
updatePlaceholder: function (el) { | ||
if (!(el.querySelector('img')) && | ||
!(el.querySelector('blockquote')) && | ||
el.textContent.replace(/^\s+|\s+$/g, '') === '') { | ||
// if one of these element ('img, blockquote, ul, ol') are found inside the given element, we won't display the placeholder | ||
if (!(el.querySelector('img, blockquote, ul, ol')) && el.textContent.replace(/^\s+|\s+$/g, '') === '') { | ||
this.showPlaceholder(el); | ||
@@ -39,0 +38,0 @@ } else { |
@@ -338,5 +338,14 @@ /*global NodeFilter, console*/ | ||
// TODO: not sure if this should be here | ||
setTargetBlank: function (el) { | ||
var i; | ||
/** | ||
* Set target to blank on the given el element | ||
* | ||
* TODO: not sure if this should be here | ||
* | ||
* When creating a link (using core -> createLink) the selection returned by Firefox will be the parent of the created link | ||
* instead of the created link itself (as it is for Chrome for example), so we retrieve all "a" children to grab the good one by | ||
* using `anchorUrl` to ensure that we are adding target="_blank" on the good one. | ||
* This isn't a bulletproof solution anyway .. | ||
*/ | ||
setTargetBlank: function (el, anchorUrl) { | ||
var i, url = anchorUrl || false; | ||
if (el.tagName.toLowerCase() === 'a') { | ||
@@ -348,3 +357,5 @@ el.target = '_blank'; | ||
for (i = 0; i < el.length; i += 1) { | ||
el[i].target = '_blank'; | ||
if (false === url || url === el[i].attributes.href.value) { | ||
el[i].target = '_blank'; | ||
} | ||
} | ||
@@ -417,2 +428,226 @@ } | ||
/* splitDOMTree | ||
* | ||
* Given a root element some descendant element, split the root element | ||
* into its own element containing the descendant element and all elements | ||
* on the left or right side of the descendant ('right' is default) | ||
* | ||
* example: | ||
* | ||
* <div> | ||
* / | \ | ||
* <span> <span> <span> | ||
* / \ / \ / \ | ||
* 1 2 3 4 5 6 | ||
* | ||
* If I wanted to split this tree given the <div> as the root and "4" as the leaf | ||
* the result would be (the prime ' marks indicates nodes that are created as clones): | ||
* | ||
* SPLITTING OFF 'RIGHT' TREE SPLITTING OFF 'LEFT' TREE | ||
* | ||
* <div> <div>' <div>' <div> | ||
* / \ / \ / \ | | ||
* <span> <span> <span>' <span> <span> <span> <span> | ||
* / \ | | / \ /\ /\ /\ | ||
* 1 2 3 4 5 6 1 2 3 4 5 6 | ||
* | ||
* The above example represents splitting off the 'right' or 'left' part of a tree, where | ||
* the <div>' would be returned as an element not appended to the DOM, and the <div> | ||
* would remain in place where it was | ||
* | ||
*/ | ||
splitOffDOMTree: function (rootNode, leafNode, splitLeft) { | ||
var splitOnNode = leafNode, | ||
createdNode = null, | ||
splitRight = !splitLeft; | ||
// loop until we hit the root | ||
while (splitOnNode !== rootNode) { | ||
var currParent = splitOnNode.parentNode, | ||
newParent = currParent.cloneNode(false), | ||
targetNode = (splitRight ? splitOnNode : currParent.firstChild), | ||
appendLast; | ||
// Create a new parent element which is a clone of the current parent | ||
if (createdNode) { | ||
if (splitRight) { | ||
// If we're splitting right, add previous created element before siblings | ||
newParent.appendChild(createdNode); | ||
} else { | ||
// If we're splitting left, add previous created element last | ||
appendLast = createdNode; | ||
} | ||
} | ||
createdNode = newParent; | ||
while (targetNode) { | ||
var sibling = targetNode.nextSibling; | ||
// Special handling for the 'splitNode' | ||
if (targetNode === splitOnNode) { | ||
if (!targetNode.hasChildNodes()) { | ||
targetNode.parentNode.removeChild(targetNode); | ||
} else { | ||
// For the node we're splitting on, if it has children, we need to clone it | ||
// and not just move it | ||
targetNode = targetNode.cloneNode(false); | ||
} | ||
// If the resulting split node has content, add it | ||
if (targetNode.textContent) { | ||
createdNode.appendChild(targetNode); | ||
} | ||
targetNode = (splitRight ? sibling : null); | ||
} else { | ||
// For general case, just remove the element and only | ||
// add it to the split tree if it contains something | ||
targetNode.parentNode.removeChild(targetNode); | ||
if (targetNode.hasChildNodes() || targetNode.textContent) { | ||
createdNode.appendChild(targetNode); | ||
} | ||
targetNode = sibling; | ||
} | ||
} | ||
// If we had an element we wanted to append at the end, do that now | ||
if (appendLast) { | ||
createdNode.appendChild(appendLast); | ||
} | ||
splitOnNode = currParent; | ||
} | ||
return createdNode; | ||
}, | ||
moveTextRangeIntoElement: function (startNode, endNode, newElement) { | ||
if (!startNode || !endNode) { | ||
return false; | ||
} | ||
var rootNode = this.findCommonRoot(startNode, endNode); | ||
if (!rootNode) { | ||
return false; | ||
} | ||
if (endNode === startNode) { | ||
var temp = startNode.parentNode, | ||
sibling = startNode.nextSibling; | ||
temp.removeChild(startNode); | ||
newElement.appendChild(startNode); | ||
if (sibling) { | ||
temp.insertBefore(newElement, sibling); | ||
} else { | ||
temp.appendChild(newElement); | ||
} | ||
return newElement.hasChildNodes(); | ||
} | ||
// create rootChildren array which includes all the children | ||
// we care about | ||
var rootChildren = [], | ||
firstChild, | ||
lastChild, | ||
nextNode; | ||
for (var i = 0; i < rootNode.childNodes.length; i++) { | ||
nextNode = rootNode.childNodes[i]; | ||
if (!firstChild) { | ||
if (Util.isDescendant(nextNode, startNode, true)) { | ||
firstChild = nextNode; | ||
} | ||
} else { | ||
if (this.isDescendant(nextNode, endNode, true)) { | ||
lastChild = nextNode; | ||
break; | ||
} else { | ||
rootChildren.push(nextNode); | ||
} | ||
} | ||
} | ||
var afterLast = lastChild.nextSibling, | ||
fragment = document.createDocumentFragment(); | ||
// build up fragment on startNode side of tree | ||
if (firstChild === startNode) { | ||
firstChild.parentNode.removeChild(firstChild); | ||
fragment.appendChild(firstChild); | ||
} else { | ||
fragment.appendChild(this.splitOffDOMTree(firstChild, startNode)); | ||
} | ||
// add any elements between firstChild & lastChild | ||
rootChildren.forEach(function (element) { | ||
element.parentNode.removeChild(element); | ||
fragment.appendChild(element); | ||
}); | ||
// build up fragment on endNode side of the tree | ||
if (lastChild === endNode) { | ||
lastChild.parentNode.removeChild(lastChild); | ||
fragment.appendChild(lastChild); | ||
} else { | ||
fragment.appendChild(this.splitOffDOMTree(lastChild, endNode, true)); | ||
} | ||
// Add fragment into passed in element | ||
newElement.appendChild(fragment); | ||
if (lastChild.parentNode === rootNode) { | ||
// If last child is in the root, insert newElement in front of it | ||
rootNode.insertBefore(newElement, lastChild); | ||
} else if (afterLast) { | ||
// If last child was removed, but it had a sibling, insert in front of it | ||
rootNode.insertBefore(newElement, afterLast); | ||
} else { | ||
// lastChild was removed and was the last actual element just append | ||
rootNode.appendChild(newElement); | ||
} | ||
return newElement.hasChildNodes(); | ||
}, | ||
/* based on http://stackoverflow.com/a/6183069 */ | ||
depthOfNode: function (inNode) { | ||
var theDepth = 0, | ||
node = inNode; | ||
while (node.parentNode !== null) { | ||
node = node.parentNode; | ||
theDepth++; | ||
} | ||
return theDepth; | ||
}, | ||
findCommonRoot: function (inNode1, inNode2) { | ||
var depth1 = this.depthOfNode(inNode1), | ||
depth2 = this.depthOfNode(inNode2), | ||
node1 = inNode1, | ||
node2 = inNode2; | ||
while (depth1 !== depth2) { | ||
if (depth1 > depth2) { | ||
node1 = node1.parentNode; | ||
depth1 -= 1; | ||
} else { | ||
node2 = node2.parentNode; | ||
depth2 -= 1; | ||
} | ||
} | ||
while (node1 !== node2) { | ||
node1 = node1.parentNode; | ||
node2 = node2.parentNode; | ||
} | ||
return node1; | ||
}, | ||
/* END - based on http://stackoverflow.com/a/6183069 */ | ||
ensureUrlHasProtocol: function (url) { | ||
if (url.indexOf('://') === -1) { | ||
return 'http://' + url; | ||
} | ||
return url; | ||
}, | ||
warn: function () { | ||
@@ -419,0 +654,0 @@ if (window.console !== undefined && typeof window.console.warn === 'function') { |
@@ -14,3 +14,3 @@ /*global MediumEditor */ | ||
// grunt-bump looks for this: | ||
'version': '4.8.1' | ||
'version': '4.9.0' | ||
}).version.split('.')); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1178372
103
14671
305