medium-editor
Advanced tools
Comparing version 4.12.7 to 4.12.8
@@ -0,1 +1,7 @@ | ||
4.12.8 / 2015-08-10 | ||
================== | ||
* Fix issue with creating anchors and restoring selection at the beginning of paragraphs | ||
* Fix issue with creating anchors and restoring selection within list items and nested blocks | ||
4.12.7 / 2015-08-04 | ||
@@ -2,0 +8,0 @@ ================== |
{ | ||
"name": "medium-editor", | ||
"version": "4.12.7", | ||
"version": "4.12.8", | ||
"author": "Davi Ferreira <hi@daviferreira.com>", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
@@ -236,2 +236,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'), | ||
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(editor.toolbar.getToolbarElement().querySelector('[data-action="createLink"]'), 'click'); | ||
// Input a url and save | ||
var input = anchorExtension.getInput(), | ||
checkbox = anchorExtension.getForm().querySelector('.medium-editor-toolbar-anchor-target'); | ||
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 create a button when deprecated anchorButton + anchorButtonClass options are used', function () { | ||
@@ -277,3 +320,4 @@ spyOn(MediumEditor.prototype, 'createLink').and.callThrough(); | ||
it('should not select empty paragraphs when link is created at beginning of paragraph', function () { | ||
// https://github.com/yabwe/medium-editor/issues/757 | ||
it('should not select empty paragraphs when link is created at beginning of paragraph after empty paragraphs', function () { | ||
spyOn(MediumEditor.prototype, 'createLink').and.callThrough(); | ||
@@ -305,5 +349,82 @@ this.el.innerHTML = '<p>Some text</p><p><br/></p><p><br/></p><p>link text more text</p>'; | ||
// Make sure the <p> wasn't removed, and the <a> was added to the end | ||
expect(this.el.lastChild).toBe(lastP); | ||
expect(lastP.firstChild.nodeName.toLowerCase()).toBe('a'); | ||
// Make sure selection is only the link | ||
var range = window.getSelection().getRangeAt(0); | ||
expect(MediumEditor.util.isDescendant(lastP, range.startContainer, true)).toBe(true, 'The start of the selection is incorrect'); | ||
expect(range.startOffset).toBe(0); | ||
expect(MediumEditor.util.isDescendant(lastP.firstChild, range.endContainer, true)).toBe(true, 'The end of the selection is not contained within the link'); | ||
}); | ||
// https://github.com/yabwe/medium-editor/issues/757 | ||
it('should not select empty paragraphs when link is created at beginning of paragraph after another paragraph', function () { | ||
spyOn(MediumEditor.prototype, 'createLink').and.callThrough(); | ||
this.el.innerHTML = '<p>Some text</p><p>link text more text</p>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
lastP = this.el.lastChild, | ||
anchorExtension = editor.getExtensionByName('anchor'); | ||
// Select the text 'link text' in the last paragraph | ||
MediumEditor.selection.select(document, lastP.firstChild, 0, lastP.firstChild, 'link text'.length); | ||
fireEvent(editor.elements[0], 'focus'); | ||
jasmine.clock().tick(1); | ||
// Click the 'anchor' button in the toolbar | ||
fireEvent(editor.toolbar.getToolbarElement().querySelector('[data-action="createLink"]'), 'click'); | ||
// Input a url and save | ||
var input = anchorExtension.getInput(); | ||
input.value = 'http://www.example.com'; | ||
fireEvent(input, 'keyup', { | ||
keyCode: Util.keyCode.ENTER | ||
}); | ||
expect(editor.createLink).toHaveBeenCalledWith({ | ||
url: 'http://www.example.com', | ||
target: '_self' | ||
}); | ||
// Make sure the <p> wasn't removed, and the <a> was added to the end | ||
expect(this.el.lastChild).toBe(lastP); | ||
expect(lastP.firstChild.nodeName.toLowerCase()).toBe('a'); | ||
// Make sure selection is only the link | ||
var range = window.getSelection().getRangeAt(0); | ||
expect(MediumEditor.util.isDescendant(lastP, range.startContainer, true)).toBe(true, 'The start of the selection is incorrect'); | ||
expect(range.startOffset).toBe(0); | ||
expect(MediumEditor.util.isDescendant(lastP.firstChild, range.endContainer, true)).toBe(true, 'The end of the selection is not contained within the link'); | ||
}); | ||
it('should not remove the <p> container when adding a link inside a top-level <p> with a single text-node child', function () { | ||
spyOn(MediumEditor.prototype, 'createLink').and.callThrough(); | ||
this.el.innerHTML = '<p>Some text</p><p><br/></p><p><br/></p><p>link text more text</p>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
lastP = this.el.lastChild, | ||
anchorExtension = editor.getExtensionByName('anchor'); | ||
// Select the text 'link text' in the last paragraph | ||
MediumEditor.selection.select(document, lastP.firstChild, 0, lastP.firstChild, 'link text'.length); | ||
fireEvent(editor.elements[0], 'focus'); | ||
jasmine.clock().tick(1); | ||
// Click the 'anchor' button in the toolbar | ||
fireEvent(editor.toolbar.getToolbarElement().querySelector('[data-action="createLink"]'), 'click'); | ||
// Input a url and save | ||
var input = anchorExtension.getInput(); | ||
input.value = 'http://www.example.com'; | ||
fireEvent(input, 'keyup', { | ||
keyCode: Util.keyCode.ENTER | ||
}); | ||
expect(editor.createLink).toHaveBeenCalledWith({ | ||
url: 'http://www.example.com', | ||
target: '_self' | ||
}); | ||
// Make sure selection is only the link | ||
var range = window.getSelection().getRangeAt(0); | ||
expect(MediumEditor.util.isDescendant(lastP, range.startContainer, true)).toBe(true, 'The start of the selection is incorrect'); | ||
expect(MediumEditor.util.isDescendant(lastP, range.endContainer, true)).toBe(true, 'The end of the selection is incorrect'); | ||
@@ -310,0 +431,0 @@ }); |
@@ -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 @@ |
/*global MediumEditor, describe, it, expect, spyOn, | ||
afterEach, beforeEach, fireEvent, Util, | ||
afterEach, beforeEach, fireEvent, | ||
jasmine, selectElementContents, setupTestHelpers, | ||
@@ -109,2 +109,12 @@ selectElementContentsAndFire, Selection, placeCursorInsideElement */ | ||
it('should export a position indicating the cursor is at the beginning of a paragraph', function () { | ||
this.el.innerHTML = '<p><span>www.google.com</span></p><p><b>Whatever</b></p>'; | ||
var editor = this.newMediumEditor('.editor', { | ||
buttons: ['italic', 'underline', 'strikethrough'] | ||
}); | ||
placeCursorInsideElement(editor.elements[0].querySelector('b'), 0); // beginning of <b> tag | ||
var exportedSelection = editor.exportSelection(); | ||
expect(exportedSelection.emptyBlocksIndex).toEqual(0); | ||
}); | ||
it('should not export a position indicating the cursor is after an empty paragraph', function () { | ||
@@ -189,3 +199,3 @@ this.el.innerHTML = '<p><span>www.google.com</span></p><p><br /></p>' + | ||
var startParagraph = Util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
var startParagraph = MediumEditor.util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
expect(startParagraph).toBe(editor.elements[0].getElementsByTagName('p')[1], 'empty paragraph'); | ||
@@ -205,3 +215,3 @@ }); | ||
var startParagraph = Util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
var startParagraph = MediumEditor.util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
expect(startParagraph).toBe(editor.elements[0].getElementsByTagName('p')[2], 'paragraph after empty paragraph'); | ||
@@ -222,3 +232,3 @@ }); | ||
var startParagraph = Util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
var startParagraph = MediumEditor.util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'p'); | ||
expect(startParagraph).toBe(editor.elements[1].getElementsByTagName('p')[2], 'paragraph after empty paragraph'); | ||
@@ -238,3 +248,3 @@ }); | ||
var startParagraph = Util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'h2'); | ||
var startParagraph = MediumEditor.util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'h2'); | ||
expect(startParagraph).toBe(editor.elements[0].querySelector('h2'), 'block element after empty block element'); | ||
@@ -254,3 +264,3 @@ }); | ||
var startParagraph = Util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'h2'); | ||
var startParagraph = MediumEditor.util.getClosestTag(window.getSelection().getRangeAt(0).startContainer, 'h2'); | ||
expect(startParagraph).toBe(editor.elements[0].querySelector('h2'), 'block element after empty block element'); | ||
@@ -271,3 +281,3 @@ }); | ||
var innerElement = window.getSelection().getRangeAt(0).startContainer; | ||
expect(Util.isDescendant(editor.elements[0].querySelector('i'), innerElement, true)).toBe(true, 'nested inline elment inside block element after empty block element'); | ||
expect(MediumEditor.util.isDescendant(editor.elements[0].querySelector('i'), innerElement, true)).toBe(true, 'nested inline elment inside block element after empty block element'); | ||
}); | ||
@@ -310,3 +320,3 @@ | ||
// The behavior varies from browser to browser for this case, some select TH, some #textNode | ||
expect(Util.isDescendant(editor.elements[0].querySelector('th'), innerElement, true)) | ||
expect(MediumEditor.util.isDescendant(editor.elements[0].querySelector('th'), innerElement, true)) | ||
.toBe(true, 'expect selection to be of TH or a descendant'); | ||
@@ -329,5 +339,29 @@ expect(innerElement).toBe(window.getSelection().getRangeAt(0).endContainer); | ||
var innerElement = window.getSelection().getRangeAt(0).startContainer; | ||
expect(Util.isDescendant(editor.elements[0].querySelectorAll('p')[1], innerElement, true)).toBe(false, 'moved selection beyond non-empty block element'); | ||
expect(Util.isDescendant(editor.elements[0].querySelector('h2'), innerElement, true)).toBe(true, 'moved selection to element to incorrect block element'); | ||
expect(MediumEditor.util.isDescendant(editor.elements[0].querySelectorAll('p')[1], innerElement, true)).toBe(false, 'moved selection beyond non-empty block element'); | ||
expect(MediumEditor.util.isDescendant(editor.elements[0].querySelector('h2'), innerElement, true)).toBe(true, 'moved selection to element to incorrect block element'); | ||
}); | ||
// https://github.com/yabwe/medium-editor/issues/732 | ||
it('should support a selection correctly when space + newlines are separating block elements', function () { | ||
this.el.innerHTML = '<ul>\n' + | ||
' <li><a href="#">a link</a></li>\n' + | ||
' <li>a list item</li>\n' + | ||
' <li>target</li>\n' + | ||
'</ul>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
lastLi = this.el.querySelectorAll('ul > li')[2]; | ||
// Select the <li> with 'target' | ||
selectElementContents(lastLi.firstChild); | ||
var selectionData = editor.exportSelection(); | ||
expect(selectionData.emptyBlocksIndex).toBe(0); | ||
editor.importSelection(selectionData); | ||
var range = window.getSelection().getRangeAt(0); | ||
expect(range.toString()).toBe('target', 'The selection is around the wrong element'); | ||
expect(MediumEditor.util.isDescendant(lastLi, range.startContainer, true)).toBe(true, 'The start of the selection is invalid'); | ||
expect(MediumEditor.util.isDescendant(lastLi, range.endContainer, true)).toBe(true, 'The end of the selection is invalid'); | ||
}); | ||
}); | ||
@@ -441,3 +475,3 @@ | ||
it('no selected elements on empty selection', function () { | ||
var elements = Selection.getSelectedElements(document); | ||
var elements = MediumEditor.selection.getSelectedElements(document); | ||
@@ -453,3 +487,3 @@ expect(elements.length).toBe(0); | ||
selectElementContents(editor.elements[0].querySelector('i').firstChild); | ||
elements = Selection.getSelectedElements(document); | ||
elements = MediumEditor.selection.getSelectedElements(document); | ||
@@ -466,3 +500,3 @@ expect(elements.length).toBe(1); | ||
selectElementContents(this.el); | ||
elements = Selection.getSelectedElements(document); | ||
elements = MediumEditor.selection.getSelectedElements(document); | ||
@@ -477,4 +511,4 @@ expect(elements.length).toBe(1); | ||
it('should return null on bad range', function () { | ||
expect(Selection.getSelectedParentElement(null)).toBe(null); | ||
expect(Selection.getSelectedParentElement(false)).toBe(null); | ||
expect(MediumEditor.selection.getSelectedParentElement(null)).toBe(null); | ||
expect(MediumEditor.selection.getSelectedParentElement(false)).toBe(null); | ||
}); | ||
@@ -494,3 +528,3 @@ | ||
element = Selection.getSelectedParentElement(range); | ||
element = MediumEditor.selection.getSelectedParentElement(range); | ||
@@ -497,0 +531,0 @@ expect(element).toBe(document); |
@@ -927,3 +927,3 @@ /*global Util, ButtonsData, Selection, Extension, | ||
range.startOffset); | ||
if (emptyBlocksIndex !== 0) { | ||
if (emptyBlocksIndex !== -1) { | ||
selectionState.emptyBlocksIndex = emptyBlocksIndex; | ||
@@ -1006,18 +1006,4 @@ } | ||
if (inSelectionState.emptyBlocksIndex) { | ||
var targetNode = Util.getBlockContainer(range.startContainer), | ||
index = 0; | ||
// Skip over empty blocks until we hit the block we want the selection to be in | ||
while (index < inSelectionState.emptyBlocksIndex && targetNode.nextSibling) { | ||
targetNode = targetNode.nextSibling; | ||
index++; | ||
// If we find a non-empty block, ignore the emptyBlocksIndex and just put selection here | ||
if (targetNode.textContent.length > 0) { | ||
break; | ||
} | ||
} | ||
// We're selecting a high-level block node, so make sure the cursor gets moved into the deepest | ||
// element at the beginning of the block | ||
range.setStart(Util.getFirstSelectableLeafNode(targetNode), 0); | ||
if (typeof inSelectionState.emptyBlocksIndex !== 'undefined') { | ||
range = Selection.importSelectionMoveCursorPastBlocks(this.options.ownerDocument, editableElement, inSelectionState.emptyBlocksIndex, range); | ||
} | ||
@@ -1042,21 +1028,28 @@ | ||
if (opts.url && opts.url.trim().length > 0) { | ||
this.options.ownerDocument.execCommand('createLink', false, opts.url); | ||
try { | ||
this.events.disableCustomEvent('editableInput'); | ||
if (opts.url && opts.url.trim().length > 0) { | ||
this.options.ownerDocument.execCommand('createLink', false, opts.url); | ||
if (this.options.targetBlank || opts.target === '_blank') { | ||
Util.setTargetBlank(Selection.getSelectionStart(this.options.ownerDocument), opts.url); | ||
} | ||
if (this.options.targetBlank || opts.target === '_blank') { | ||
Util.setTargetBlank(Selection.getSelectionStart(this.options.ownerDocument), opts.url); | ||
} | ||
if (opts.buttonClass) { | ||
Util.addClassToAnchors(Selection.getSelectionStart(this.options.ownerDocument), opts.buttonClass); | ||
if (opts.buttonClass) { | ||
Util.addClassToAnchors(Selection.getSelectionStart(this.options.ownerDocument), opts.buttonClass); | ||
} | ||
} | ||
} | ||
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 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); | ||
} | ||
} | ||
} finally { | ||
this.events.enableCustomEvent('editableInput'); | ||
} | ||
// Fire our custom editableInput event | ||
this.events.triggerCustomEvent('editableInput', customEvent, this.getFocusedElement()); | ||
}, | ||
@@ -1063,0 +1056,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); |
@@ -70,9 +70,59 @@ /*global Util */ | ||
// Returns 0 unless the cursor is within or preceded by empty paragraphs/blocks, | ||
// in which case it returns the count of such preceding paragraphs, including | ||
// the empty paragraph in which the cursor itself may be embedded. | ||
// Uses the emptyBlocksIndex calculated by getIndexRelativeToAdjacentEmptyBlocks | ||
// to move the cursor back to the start of the correct paragraph | ||
importSelectionMoveCursorPastBlocks: function (doc, root, index, range) { | ||
var treeWalker = doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filterOnlyParentElements, false), | ||
startContainer = range.startContainer, | ||
startBlock, | ||
targetNode, | ||
currIndex = 0; | ||
index = index || 1; // If index is 0, we still want to move to the next block | ||
// Chrome counts newlines and spaces that separate block elements as actual elements. | ||
// If the selection is inside one of these text nodes, and it has a previous sibling | ||
// which is a block element, we want the treewalker to start at the previous sibling | ||
// and NOT at the parent of the textnode | ||
if (startContainer.nodeType === 3 && Util.isBlockContainer(startContainer.previousSibling)) { | ||
startBlock = startContainer.previousSibling; | ||
} else { | ||
startBlock = Util.getClosestBlockContainer(startContainer); | ||
} | ||
// Skip over empty blocks until we hit the block we want the selection to be in | ||
while (treeWalker.nextNode()) { | ||
if (!targetNode) { | ||
// Loop through all blocks until we hit the starting block element | ||
if (startBlock === treeWalker.currentNode) { | ||
targetNode = treeWalker.currentNode; | ||
} | ||
} else { | ||
targetNode = treeWalker.currentNode; | ||
currIndex++; | ||
// We hit the target index, bail | ||
if (currIndex === index) { | ||
break; | ||
} | ||
// If we find a non-empty block, ignore the emptyBlocksIndex and just put selection here | ||
if (targetNode.textContent.length > 0) { | ||
break; | ||
} | ||
} | ||
} | ||
// We're selecting a high-level block node, so make sure the cursor gets moved into the deepest | ||
// element at the beginning of the block | ||
range.setStart(Util.getFirstSelectableLeafNode(targetNode), 0); | ||
return range; | ||
}, | ||
// Returns -1 unless the cursor is at the beginning of a paragraph/block | ||
// If the paragraph/block is preceeded by empty paragraphs/block (with no text) | ||
// it will return the number of empty paragraphs before the cursor. | ||
// Otherwise, it will return 0, which indicates the cursor is at the beginning | ||
// of a paragraph/block, and not at the end of the paragraph/block before it | ||
getIndexRelativeToAdjacentEmptyBlocks: function (doc, root, cursorContainer, cursorOffset) { | ||
// If there is text in front of the cursor, that means there isn't only empty blocks before it | ||
if (cursorContainer.nodeType === 3 && cursorOffset > 0) { | ||
return 0; | ||
if (cursorContainer.textContent.length > 0 && cursorOffset > 0) { | ||
return -1; | ||
} | ||
@@ -83,7 +133,6 @@ | ||
if (node.nodeType !== 3) { | ||
//node = cursorContainer.childNodes.length === cursorOffset ? null : cursorContainer.childNodes[cursorOffset]; | ||
node = cursorContainer.childNodes[cursorOffset]; | ||
} | ||
if (node && !Util.isElementAtBeginningOfBlock(node)) { | ||
return 0; | ||
return -1; | ||
} | ||
@@ -93,3 +142,4 @@ | ||
// and the block the cursor is in | ||
var treeWalker = doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filterOnlyParentElements, false), | ||
var closestBlock = Util.getClosestBlockContainer(cursorContainer), | ||
treeWalker = doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, filterOnlyParentElements, false), | ||
emptyBlocksCount = 0; | ||
@@ -101,3 +151,3 @@ while (treeWalker.nextNode()) { | ||
} | ||
if (Util.isDescendant(treeWalker.currentNode, cursorContainer, true)) { | ||
if (treeWalker.currentNode === closestBlock) { | ||
return emptyBlocksCount; | ||
@@ -104,0 +154,0 @@ } |
@@ -109,3 +109,10 @@ /*global NodeFilter, Selection*/ | ||
parentElements: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre'], | ||
parentElements: [ | ||
// elements our editor generates | ||
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'pre', 'ul', 'li', 'ol', | ||
// all other known block elements | ||
'address', 'article', 'aside', 'audio', 'canvas', 'dd', 'dl', 'dt', 'fieldset', | ||
'figcaption', 'figure', 'footer', 'form', 'header', 'hgroup', 'main', 'nav', | ||
'noscript', 'output', 'section', 'table', 'tbody', 'tfoot', 'video' | ||
], | ||
@@ -400,3 +407,3 @@ extend: function extend(/* dest, source1, source2, ...*/) { | ||
tagName = parentNode.tagName.toLowerCase(); | ||
while (!this.isBlockContainer(parentNode) && tagName !== 'div') { | ||
while (tagName === 'li' || (!this.isBlockContainer(parentNode) && tagName !== 'div')) { | ||
if (tagName === 'li') { | ||
@@ -678,2 +685,8 @@ return true; | ||
getClosestBlockContainer: function (node) { | ||
return Util.traverseUp(node, function (node) { | ||
return Util.isBlockContainer(node); | ||
}); | ||
}, | ||
getBlockContainer: function (element) { | ||
@@ -680,0 +693,0 @@ return this.traverseUp(element, function (el) { |
@@ -14,3 +14,3 @@ /*global MediumEditor */ | ||
// grunt-bump looks for this: | ||
'version': '4.12.7' | ||
'version': '4.12.8' | ||
}).version.split('.')); |
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
1412020
18725