medium-editor
Advanced tools
Comparing version 5.0.0 to 5.1.0
@@ -33,3 +33,3 @@ { | ||
"package.json", | ||
"src/js", | ||
"src", | ||
"README.md", | ||
@@ -36,0 +36,0 @@ "CHANGES.md" |
@@ -0,1 +1,10 @@ | ||
5.1.0 / 2015-06-18 | ||
================== | ||
* Add showToolbarDefaultAction helper method to form extension | ||
* Ensure elements generated for textareas have a unique id | ||
* Ensure all added attributes are removed during destroy | ||
* Cleanup divs generated by Chrome during justify actions | ||
* Add parameter to anchorPreview.positionPreview for reusability | ||
5.0.0 / 2015-06-18 | ||
@@ -2,0 +11,0 @@ ================== |
{ | ||
"name": "medium-editor", | ||
"version": "5.0.0", | ||
"version": "5.1.0", | ||
"author": "Davi Ferreira <hi@daviferreira.com>", | ||
@@ -5,0 +5,0 @@ "contributors": [ |
@@ -292,3 +292,3 @@ /*global describe, it, expect, spyOn, | ||
describe('when deleting and empty first list item via backspace', function () { | ||
describe('when deleting an empty first list item via backspace', function () { | ||
it('should insert a paragraph before the list if it is the first element in the editor', function () { | ||
@@ -331,2 +331,48 @@ this.el.innerHTML = '<ul><li></li><li>lorem ipsum</li></ul>'; | ||
}); | ||
describe('justify actions', function () { | ||
it('should not replace line breaks inside header elements with div elements', function () { | ||
this.el.innerHTML = '<h2>lorem ipsum<br />lorem ipsum<br />lorem ipsum<br /></h2><ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
h2 = this.el.querySelector('h2'); | ||
selectElementContentsAndFire(h2.firstChild); | ||
editor.execAction('justifyRight'); | ||
h2 = this.el.querySelector('h2'); | ||
expect(h2.querySelectorAll('br').length).toBe(3, 'Some of the <br> elements have been removed from the <h2>'); | ||
expect(h2.querySelectorAll('div').length).toBe(0, 'Some <br> elements were replaced with <div> elements within the <h2>'); | ||
}); | ||
it('should not replace line breaks inside blockquote elements with div elements', function () { | ||
this.el.innerHTML = '<ul><li>item 1</li><li>item 2</li></ul><blockquote>lorem ipsum<br />lorem ipsum<br />lorem ipsum<br /></blockquote><ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
blockquote = this.el.querySelector('blockquote'); | ||
selectElementContentsAndFire(blockquote); | ||
editor.execAction('justifyCenter'); | ||
blockquote = this.el.querySelector('blockquote'); | ||
expect(blockquote.querySelectorAll('br').length).toBe(3, 'Some of the <br> elements have been removed from the <blockquote>'); | ||
expect(blockquote.querySelectorAll('div').length).toBe(0, 'Some <br> elements were replaced with <div> elements within the <blckquote>'); | ||
}); | ||
it('should not replace line breaks inside pre elements with div elements', function () { | ||
this.el.innerHTML = '<ul><li>item 1</li><li>item 2</li></ul><pre>lorem ipsum<br />lorem ipsum<br />lorem ipsum<br /></pre><ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
pre = this.el.querySelector('pre'); | ||
selectElementContentsAndFire(pre); | ||
editor.execAction('justifyCenter'); | ||
pre = this.el.querySelector('pre'); | ||
expect(pre.querySelectorAll('br').length).toBe(3, 'Some of the <br> elements have been removed from the <pre>'); | ||
expect(pre.querySelectorAll('div').length).toBe(0, 'Some <br> elements were replaced with <div> elements within the <pre>'); | ||
}); | ||
it('should not replace line breaks inside p elements with div elements', function () { | ||
this.el.innerHTML = '<ul><li>item 1</li><li>item 2</li></ul><p>lorem ipsum<br />lorem ipsum<br />lorem ipsum<br /></p><ul><li>item 1</li><li>item 2</li><li>item 3</li></ul>'; | ||
var editor = this.newMediumEditor('.editor'), | ||
para = this.el.querySelector('p'); | ||
selectElementContentsAndFire(para); | ||
editor.execAction('justifyCenter'); | ||
para = this.el.querySelector('p'); | ||
expect(para.querySelectorAll('br').length).toBe(3, 'Some of the <br> elements have been removed from the <p>'); | ||
expect(para.querySelectorAll('div').length).toBe(0, 'Some <br> elements were replaced with <div> elements within the <p>'); | ||
}); | ||
}); | ||
}); |
@@ -34,2 +34,8 @@ /*global MediumEditor, describe, it, expect, spyOn, jasmine, | ||
expect(editor.setup).toHaveBeenCalled(); | ||
expect(document.querySelector('[data-medium-editor-element]')).toBeTruthy(); | ||
expect(document.querySelector('[aria-multiline]')).toBeTruthy(); | ||
expect(document.querySelector('[medium-editor-index]')).toBeTruthy(); | ||
expect(document.querySelector('[role]')).toBeTruthy(); | ||
expect(document.querySelector('[spellcheck]')).toBeTruthy(); | ||
expect(document.querySelector('[contenteditable]')).toBeTruthy(); | ||
}); | ||
@@ -48,2 +54,6 @@ | ||
expect(document.querySelector('.medium-editor-toolbar')).toBeFalsy(); | ||
// ensure only initial attributes are here: the editor class | ||
expect(this.el.getAttribute('class')).toBe('editor'); | ||
expect(this.el.attributes.length).toBe(1); | ||
}); | ||
@@ -50,0 +60,0 @@ |
@@ -57,2 +57,21 @@ /*global describe, it, beforeEach, afterEach, expect, | ||
it('should create unique div ids for multiple textareas', function () { | ||
var tas = []; | ||
for (var i = 0; i < 12; i++) { | ||
var ta = document.createElement('textarea'); | ||
ta.className = 'editor'; | ||
ta.value = 'test content'; | ||
document.body.appendChild(ta); | ||
tas.push(ta); | ||
} | ||
var editor = this.newMediumEditor('.editor'); | ||
editor.elements.forEach(function (el) { | ||
expect(document.querySelectorAll('div#' + el.id).length).toEqual(1); | ||
}); | ||
editor.destroy(); | ||
tas.forEach(function (el) { | ||
document.body.removeChild(el); | ||
}); | ||
}); | ||
it('should cleanup after destroy', function () { | ||
@@ -59,0 +78,0 @@ var editor = this.newMediumEditor('.editor'); |
@@ -19,2 +19,3 @@ /*global MediumEditor, describe, it, expect */ | ||
expect(MediumEditor.version.revision).toBeDefined(); | ||
expect(MediumEditor.version.preRelease).toBeDefined(); | ||
}); | ||
@@ -41,2 +42,3 @@ | ||
expect(info.preRelease).toBe(''); | ||
expect(info.toString()).toBe('1.2.3'); | ||
}); | ||
@@ -51,2 +53,3 @@ | ||
expect(info.preRelease).toBe('alpha.1'); | ||
expect(info.toString()).toBe('5.0.0-alpha.1'); | ||
}); | ||
@@ -53,0 +56,0 @@ }); |
@@ -209,5 +209,5 @@ /*global Util, Selection, Extension, | ||
this.elements = []; | ||
elements.forEach(function (element) { | ||
elements.forEach(function (element, index) { | ||
if (element.nodeName.toLowerCase() === 'textarea') { | ||
this.elements.push(createContentEditable.call(this, element)); | ||
this.elements.push(createContentEditable.call(this, element, index)); | ||
} else { | ||
@@ -287,5 +287,5 @@ this.elements.push(element); | ||
function createContentEditable(textarea) { | ||
function createContentEditable(textarea, id) { | ||
var div = this.options.ownerDocument.createElement('div'), | ||
id = (+new Date()), | ||
uniqueId = 'medium-editor-' + Date.now() + '-' + id, | ||
attributesToClone = [ | ||
@@ -302,3 +302,3 @@ 'data-disable-editing', | ||
div.className = textarea.className; | ||
div.id = id; | ||
div.id = uniqueId; | ||
div.innerHTML = textarea.value; | ||
@@ -439,2 +439,3 @@ div.setAttribute('medium-editor-textarea-id', id); | ||
var appendAction = /^append-(.+)$/gi, | ||
justifyAction = /justify([A-Za-z]*)$/g, /* Detecting if is justifyCenter|Right|Left */ | ||
match; | ||
@@ -462,5 +463,62 @@ /*jslint regexp: false*/ | ||
/* Issue: https://github.com/yabwe/medium-editor/issues/595 | ||
* If the action is to justify the text */ | ||
if (justifyAction.exec(action)) { | ||
var result = this.options.ownerDocument.execCommand(action, false, null), | ||
parentNode = Selection.getSelectedParentElement(Selection.getSelectionRange(this.options.ownerDocument)); | ||
if (parentNode) { | ||
cleanupJustifyDivFragments.call(this, Util.getTopBlockContainer(parentNode)); | ||
} | ||
return result; | ||
} | ||
return this.options.ownerDocument.execCommand(action, false, null); | ||
} | ||
/* If we've just justified text within a container block | ||
* Chrome may have removed <br> elements and instead wrapped lines in <div> elements | ||
* with a text-align property. If so, we want to fix this | ||
*/ | ||
function cleanupJustifyDivFragments(blockContainer) { | ||
if (!blockContainer) { | ||
return; | ||
} | ||
var textAlign, | ||
childDivs = Array.prototype.slice.call(blockContainer.childNodes).filter(function (element) { | ||
var isDiv = element.nodeName.toLowerCase() === 'div'; | ||
if (isDiv && !textAlign) { | ||
textAlign = element.style.textAlign; | ||
} | ||
return isDiv; | ||
}); | ||
/* If we found child <div> elements with text-align style attributes | ||
* we should fix this by: | ||
* | ||
* 1) Unwrapping each <div> which has a text-align style | ||
* 2) Insert a <br> element after each set of 'unwrapped' div children | ||
* 3) Set the text-align style of the parent block element | ||
*/ | ||
if (childDivs.length) { | ||
// Since we're mucking with the HTML, preserve selection | ||
this.saveSelection(); | ||
childDivs.forEach(function (div) { | ||
if (div.style.textAlign === textAlign) { | ||
var lastChild = div.lastChild; | ||
if (lastChild) { | ||
// Instead of a div, extract the child elements and add a <br> | ||
Util.unwrap(div, this.options.ownerDocument); | ||
var br = this.options.ownerDocument.createElement('BR'); | ||
lastChild.parentNode.insertBefore(br, lastChild.nextSibling); | ||
} | ||
} | ||
}, this); | ||
blockContainer.style.textAlign = textAlign; | ||
// We're done, so restore selection | ||
this.restoreSelection(); | ||
} | ||
} | ||
MediumEditor.Extension = Extension; | ||
@@ -528,5 +586,10 @@ | ||
// cleanup extra added attributes | ||
element.removeAttribute('contentEditable'); | ||
element.removeAttribute('spellcheck'); | ||
element.removeAttribute('data-medium-focused'); | ||
element.removeAttribute('data-medium-editor-element'); | ||
element.removeAttribute('role'); | ||
element.removeAttribute('aria-multiline'); | ||
element.removeAttribute('medium-editor-index'); | ||
@@ -533,0 +596,0 @@ // Remove any elements created for textareas |
@@ -92,5 +92,6 @@ var AnchorPreview; | ||
positionPreview: function () { | ||
positionPreview: function (activeAnchor) { | ||
activeAnchor = activeAnchor || this.activeAnchor; | ||
var buttonHeight = this.anchorPreview.offsetHeight, | ||
boundary = this.activeAnchor.getBoundingClientRect(), | ||
boundary = activeAnchor.getBoundingClientRect(), | ||
middleBoundary = (boundary.left + boundary.right) / 2, | ||
@@ -97,0 +98,0 @@ diffLeft = this.diffLeft, |
@@ -60,2 +60,14 @@ var FormExtension; | ||
/* showToolbarDefaultActions: [function ()] | ||
* | ||
* Helper method which will turn back the toolbar after canceling | ||
* the customized form | ||
*/ | ||
showToolbarDefaultActions: function () { | ||
var toolbar = this.base.getExtensionByName('toolbar'); | ||
if (toolbar) { | ||
toolbar.showToolbarDefaultActions(); | ||
} | ||
}, | ||
/* hideToolbarDefaultActions: [function ()] | ||
@@ -62,0 +74,0 @@ * |
@@ -13,3 +13,3 @@ /*global MediumEditor */ | ||
toString: function () { | ||
return [[version[0], version[1], version[2]].join('.'), preRelease].join('-'); | ||
return [version[0], version[1], version[2]].join('.') + (preRelease ? '-' + preRelease : ''); | ||
} | ||
@@ -21,3 +21,3 @@ }; | ||
// grunt-bump looks for this: | ||
'version': '5.0.0' | ||
'version': '5.1.0' | ||
}).version); |
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
1355301
114
17516