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 = 'Some text
link text more text
';
+ 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 wasn't removed, and the 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 container when adding a link inside a top-level
with a single text-node child', function () {
spyOn(MediumEditor.prototype, 'createLink').and.callThrough();
this.el.innerHTML = '
Some text
link text more text
';
var editor = this.newMediumEditor('.editor'),
diff --git a/spec/selection.spec.js b/spec/selection.spec.js
index d1dabfc23..3ef1d7aa2 100644
--- a/spec/selection.spec.js
+++ b/spec/selection.spec.js
@@ -106,6 +106,16 @@ describe('Selection TestCase', function () {
expect(exportedSelection.emptyBlocksIndex).toEqual(undefined);
});
+ it('should export a position indicating the cursor is at the beginning of a paragraph', function () {
+ this.el.innerHTML = 'www.google.com
Whatever
';
+ var editor = this.newMediumEditor('.editor', {
+ buttons: ['italic', 'underline', 'strikethrough']
+ });
+ placeCursorInsideElement(editor.elements[0].querySelector('b'), 0); // beginning of 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 () {
this.el.innerHTML = 'www.google.com
' +
'Whatever
';
diff --git a/src/js/core.js b/src/js/core.js
index 3c0bd5b89..b6368ef55 100644
--- a/src/js/core.js
+++ b/src/js/core.js
@@ -924,7 +924,7 @@ function MediumEditor(elements, options) {
this.elements[editableElementIndex],
range.startContainer,
range.startOffset);
- if (emptyBlocksIndex !== 0) {
+ if (emptyBlocksIndex !== -1) {
selectionState.emptyBlocksIndex = emptyBlocksIndex;
}
}
@@ -1002,11 +1002,11 @@ function MediumEditor(elements, options) {
}
}
- if (inSelectionState.emptyBlocksIndex) {
+ if (typeof inSelectionState.emptyBlocksIndex !== 'undefined') {
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) {
+ while ((index === 0 || index < inSelectionState.emptyBlocksIndex) && targetNode.nextSibling) {
targetNode = targetNode.nextSibling;
index++;
// If we find a non-empty block, ignore the emptyBlocksIndex and just put selection here
diff --git a/src/js/selection.js b/src/js/selection.js
index ec34a60c6..cd796d02f 100644
--- a/src/js/selection.js
+++ b/src/js/selection.js
@@ -67,23 +67,24 @@ var Selection;
return range;
},
- // 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.
+ // 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;
}
// Check if the block that contains the cursor has any other text in front of the cursor
var node = cursorContainer;
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;
}
// Walk over block elements, counting number of empty blocks between last piece of text