From ff92ea793083a6510fae4ea574978da6ad245794 Mon Sep 17 00:00:00 2001 From: Stanislas Rolland Date: Wed, 8 Oct 2008 22:41:24 +0000 Subject: [PATCH] Added feature #9521: htmlArea RTE: factor out some functions dealing with inline elements git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@4299 709f56b5-9817-0410-a4d7-c38de5d9e867 --- ChangeLog | 1 + typo3/sysext/rtehtmlarea/ChangeLog | 1 + .../rtehtmlarea/htmlarea/htmlarea-gecko.js | 36 +++- .../rtehtmlarea/htmlarea/htmlarea-ie.js | 86 +++++++++- typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js | 59 +++++++ .../plugins/InlineElements/inline-elements.js | 155 ++++-------------- .../htmlarea/plugins/TextStyle/text-style.js | 141 +++------------- 7 files changed, 236 insertions(+), 243 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5caee0eadde7..3603001ad030 100755 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2008-10-08 Stanislas Rolland * Fixed bug #9516: htmlARea RTE: Move link tags to head + * Added feature #9521: htmlArea RTE: factor out some functions dealing with inline elements 2008-10-05 Stanislas Rolland diff --git a/typo3/sysext/rtehtmlarea/ChangeLog b/typo3/sysext/rtehtmlarea/ChangeLog index 983f13e9e838..33725780612d 100644 --- a/typo3/sysext/rtehtmlarea/ChangeLog +++ b/typo3/sysext/rtehtmlarea/ChangeLog @@ -1,6 +1,7 @@ 2008-10-08 Stanislas Rolland * Fixed bug #9516: htmlARea RTE: Move link tags to head + * Added feature #9521: htmlArea RTE: factor out some functions dealing with inline elements 2008-10-05 Stanislas Rolland diff --git a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js index bae7822e97ac..164185bc00fb 100644 --- a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js +++ b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js @@ -3,7 +3,7 @@ * * (c) 2002-2004, interactivetools.com, inc. * (c) 2003-2004 dynarch.com -* (c) 2004-2008 Stanislas Rolland +* (c) 2004-2008 Stanislas Rolland * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is @@ -445,6 +445,40 @@ HTMLArea.prototype.insertHTML = function(html) { this.insertNodeAtSelection(fragment); }; +/* + * Wrap the range with an inline element + * + * @param string element: the node that will wrap the range + * @param object selection: the selection object + * @param object range: the range to be wrapped + * + * @return void + */ +HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) { + // Sometimes Opera raises a bad boundary points error + if (HTMLArea.is_opera) { + try { + range.surroundContents(element); + } catch(e) { + element.appendChild(range.extractContents()); + range.insertNode(element); + } + } else { + range.surroundContents(element); + element.normalize(); + } + // Sometimes Firefox inserts empty elements just outside the boundaries of the range + var neighbour = element.previousSibling; + if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { + HTMLArea.removeFromParent(neighbour); + } + neighbour = element.nextSibling; + if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { + HTMLArea.removeFromParent(neighbour); + } + this.selectNodeContents(element, false); +}; + /*************************************************** * EVENTS HANDLERS ***************************************************/ diff --git a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js index 05173a6f357e..90a75d59bc6e 100644 --- a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js +++ b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js @@ -119,10 +119,12 @@ HTMLArea.prototype.getSelectedHTMLContents = function() { /* * Get the deepest node that contains both endpoints of the current selection. */ -HTMLArea.prototype.getParentElement = function(sel) { - if(!sel) var sel = this._getSelection(); - var range = this._createRange(sel); - switch (sel.type) { +HTMLArea.prototype.getParentElement = function(selection, range) { + if (!selection) var selection = this._getSelection(); + if (typeof(range) === "undefined") { + var range = this._createRange(selection); + } + switch (selection.type) { case "Text": case "None": var el = range.parentElement(); @@ -218,6 +220,82 @@ HTMLArea.prototype.insertHTML = function(html) { range.pasteHTML(html); }; +/* + * Wrap the range with an inline element + * + * @param string element: the node that will wrap the range + * @param object selection: the selection object + * @param object range: the range to be wrapped + * + * @return void + */ +HTMLArea.prototype.wrapWithInlineElement = function(element, selection, range) { + var nodeName = element.nodeName; + var parent = this.getParentElement(selection, range); + var bookmark = this.getBookmark(range); + if (selection.type !== "Control") { + var rangeStart = range.duplicate(); + rangeStart.collapse(true); + var parentStart = rangeStart.parentElement(); + var rangeEnd = range.duplicate(); + rangeEnd.collapse(true); + var newRange = this._createRange(); + + var parentEnd = rangeEnd.parentElement(); + var upperParentStart = parentStart; + if (parentStart !== parent) { + while (upperParentStart.parentNode !== parent) { + upperParentStart = upperParentStart.parentNode; + } + } + + element.innerHTML = range.htmlText; + // IE eats spaces on the start boundary + if (range.htmlText.charAt(0) === "\x20") { + element.innerHTML = " " + element.innerHTML; + } + var elementClone = element.cloneNode(true); + range.pasteHTML(element.outerHTML); + // IE inserts the element as the last child of the start container + if (parentStart !== parent + && parentStart.lastChild + && parentStart.lastChild.nodeType === 1 + && parentStart.lastChild.nodeName.toLowerCase() === nodeName) { + parent.insertBefore(elementClone, upperParentStart.nextSibling); + parentStart.removeChild(parentStart.lastChild); + // Sometimes an empty previous sibling was created + if (elementClone.previousSibling + && elementClone.previousSibling.nodeType === 1 + && !elementClone.previousSibling.innerText) { + parent.removeChild(elementClone.previousSibling); + } + // The bookmark will not work anymore + newRange.moveToElementText(elementClone); + newRange.collapse(false); + newRange.select(); + } else { + // Working around IE boookmark bug + if (parentStart != parentEnd) { + var newRange = this._createRange(); + if (newRange.moveToBookmark(bookmark)) { + newRange.collapse(false); + newRange.select(); + } + } else { + range.collapse(false); + } + } + // normalize() is not available in IE5.5 + try { + parent.normalize(); + } catch(e) { } + } else { + element = parent.parentNode.insertBefore(element, parent); + element.appendChild(parent); + this.moveToBookmark(bookmark); + } +}; + /*************************************************** * EVENT HANDLERS ***************************************************/ diff --git a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js index e3dde499c97c..a4484d57caec 100644 --- a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js +++ b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js @@ -1717,6 +1717,49 @@ HTMLArea.getElementObject = function(el,tagName) { return oEl; }; +/* + * This function removes the given markup element + * + * @param object element: the inline element to be removed, content being preserved + * + * @return void + */ +HTMLArea.prototype.removeMarkup = function(element) { + var bookmark = this.getBookmark(this._createRange(this._getSelection())); + var parent = element.parentNode; + while (element.firstChild) { + parent.insertBefore(element.firstChild, element); + } + parent.removeChild(element); + this.selectRange(this.moveToBookmark(bookmark)); +}; + +/* + * This function verifies if the element has any allowed attributes + * + * @param object element: the DOM element + * @param array allowedAttributes: array of allowed attribute names + * + * @return boolean true if the element has one of the allowed attributes + */ +HTMLArea.hasAllowedAttributes = function(element,allowedAttributes) { + var value; + for (var i = allowedAttributes.length; --i >= 0;) { + value = element.getAttribute(allowedAttributes[i]); + if (value) { + // IE returns an object on getAttribute("style"); + if (typeof(value) == "object") { + if (allowedAttributes[i] == "style" && value.cssText) { + return true; + } + } else { + return true; + } + } + } + return false; +}; + /*************************************************** * SELECTIONS AND RANGES ***************************************************/ @@ -1773,6 +1816,22 @@ HTMLArea.prototype.getEndBlocks = function(selection) { }; }; +/* + * This function determines if the end poins of the current selection are within the same block + * + * @return boolean true if the end points of the current selection are inside the same block element + */ +HTMLArea.prototype.endPointsInSameBlock = function() { + var selection = this._getSelection(); + if (this._selectionEmpty(selection)) { + return true; + } else { + var parent = this.getParentElement(selection); + var endBlocks = this.getEndBlocks(selection); + return (endBlocks.start === endBlocks.end && !/^(table|thead|tbody|tfoot|tr)$/i.test(parent.nodeName)); + } +}; + /* * Get the deepest ancestor of the selection that is of the specified type * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/ diff --git a/typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js b/typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js index 78bcf024b870..8dc0040a793b 100644 --- a/typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js +++ b/typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js @@ -44,9 +44,14 @@ InlineElements = HTMLArea.Plugin.extend({ * This function gets called by the base constructor */ configurePlugin : function (editor) { - - this.allowedAttributes = new Array("id", "title", "lang", "xml:lang", "dir", (HTMLArea.is_gecko?"class":"className")); - + + // Setting the array of allowed attributes on inline elements + if (this.editor.plugins.TextStyle && this.editor.plugins.TextStyle.instance) { + this.allowedAttributes = this.editor.plugins.TextStyle.instance.allowedAttributes; + } else { + this.allowedAttributes = new Array("id", "title", "lang", "xml:lang", "dir", (HTMLArea.is_gecko?"class":"className")); + } + // Getting tags configuration for inline elements if (this.editorConfiguration.buttons.textstyle) { this.tags = this.editorConfiguration.buttons.textstyle.tags; } @@ -167,6 +172,17 @@ InlineElements = HTMLArea.Plugin.extend({ return el && (el.nodeType === 1) && this.REInlineElements.test(el.nodeName.toLowerCase()); }, + /* + * This function adds an attribute to the array of allowed attributes on inline elements + * + * @param string attribute: the name of the attribute to be added to the array + * + * @return void + */ + addAllowedAttribute : function (attribute) { + this.allowedAttributes.push(attribute); + }, + /* * This function gets called when some inline element button was pressed. */ @@ -205,7 +221,7 @@ InlineElements = HTMLArea.Plugin.extend({ var elementIsAncestor = false; var selectionEmpty = editor._selectionEmpty(selection); if (HTMLArea.is_ie) { - var bookmark = range.getBookmark(); + var bookmark = editor.getBookmark(range); } // Check if the chosen element is among the ancestors for (var i = 0; i < ancestors.length; ++i) { @@ -218,7 +234,7 @@ InlineElements = HTMLArea.Plugin.extend({ if (!selectionEmpty) { // The selection is not empty. for (var i = 0; i < ancestors.length; ++i) { - fullNodeSelected = (HTMLArea.is_ie && ((editor._statusBarTree.selected === ancestors[i] && ancestors[i].innerText === range.text) || (!editor._statusBarTree.selected && ancestors[i].innerText === range.text))) + fullNodeSelected = (HTMLArea.is_ie && ((selection.type !== "Control" && ancestors[i].innerText === range.text) || (selection.type === "Control" && ancestors[i].innerText === range.item(0).text))) || (HTMLArea.is_gecko && ((editor._statusBarTree.selected === ancestors[i] && ancestors[i].textContent === range.toString()) || (!editor._statusBarTree.selected && ancestors[i].textContent === range.toString()))); if (fullNodeSelected) { if (!HTMLArea.isBlockElement(ancestors[i])) { @@ -240,43 +256,23 @@ InlineElements = HTMLArea.Plugin.extend({ } if (element !== "none" && !(fullNodeSelected && elementIsAncestor)) { // Add markup + var newElement = editor._doc.createElement(element); + if (element === "bdo") { + newElement.setAttribute("dir", "rtl"); + } if (HTMLArea.is_gecko) { if (fullNodeSelected && editor._statusBarTree.selected) { if (HTMLArea.is_safari) { - this.editor.selectNode(parent); - range = this.editor._createRange(this.editor._getSelection()); + editor.selectNode(parent); + selection = editor._getSelection(); + range = editor._createRange(selection); } else { range.selectNode(parent); } } - var newElement = this.editor._doc.createElement(element); - if (element === "bdo") { - newElement.setAttribute("dir", "rtl"); - } - // Sometimes Opera 9.25 raises a bad boundary points error - if (HTMLArea.is_opera) { - try { - range.surroundContents(newElement); - } catch(e) { - newElement.appendChild(range.extractContents()); - range.insertNode(newElement); - } - } else { - range.surroundContents(newElement); - } - // Sometimes Firefox inserts empty elements just outside the boundaries of the range - var neighbour = newElement.previousSibling; - if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { - HTMLArea.removeFromParent(neighbour); - } - neighbour = newElement.nextSibling; - if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { - HTMLArea.removeFromParent(neighbour); - } + editor.wrapWithInlineElement(newElement, selection, range); if (fullNodeSelected && editor._statusBarTree.selected && !HTMLArea.is_safari) { - this.editor.selectNodeContents(newElement.lastChild, false); - } else { - this.editor.selectNodeContents(newElement, false); + editor.selectNodeContents(newElement.lastChild, false); } range.detach(); } else { @@ -296,61 +292,7 @@ InlineElements = HTMLArea.Plugin.extend({ editor.selectNodeContents(newElement, false); } } else { - var rangeStart = range.duplicate(); - rangeStart.collapse(true); - var parentStart = rangeStart.parentElement(); - var rangeEnd = range.duplicate(); - rangeEnd.collapse(true); - var newRange = editor._createRange(); - - var parentEnd = rangeEnd.parentElement(); - var upperParentStart = parentStart; - if (parentStart !== parent) { - while (upperParentStart.parentNode !== parent) { - upperParentStart = upperParentStart.parentNode; - } - } - - var newElement = editor._doc.createElement(element); - newElement.innerHTML = range.htmlText; - // IE eats spaces on the start boundary - if (range.htmlText.charAt(0) === "\x20") { - newElement.innerHTML = " " + newElement.innerHTML; - } - var newElementClone = newElement.cloneNode(true); - range.pasteHTML(newElement.outerHTML); - // IE inserts the element as the last child of the start container - if (parentStart !== parent - && parentStart.lastChild - && parentStart.lastChild.nodeType === 1 - && parentStart.lastChild.nodeName.toLowerCase() === element) { - parent.insertBefore(newElementClone, upperParentStart.nextSibling); - parentStart.removeChild(parentStart.lastChild); - // Sometimes an empty previous sibling was created - if (newElementClone.previousSibling - && newElementClone.previousSibling.nodeType === 1 - && !newElementClone.previousSibling.innerText) { - parent.removeChild(newElementClone.previousSibling); - } - // The bookmark will not work anymore - newRange.moveToElementText(newElementClone); - newRange.collapse(false); - newRange.select(); - } else { - // Working around IE boookmark bug - if (parentStart != parentEnd) { - var newRange = editor._createRange(); - if (newRange.moveToBookmark(bookmark)) { - newRange.collapse(false); - newRange.select(); - } - } else { - range.collapse(false); - } - } - try { // normalize() is not available in IE5.5 - parent.normalize(); - } catch(e) { } + editor.wrapWithInlineElement(newElement, selection, range); } } } else { @@ -359,7 +301,7 @@ InlineElements = HTMLArea.Plugin.extend({ if (elementIsAncestor) { parent = ancestors[elementAncestorIndex]; } - this.removeMarkup(parent); + editor.removeMarkup(parent); } } } else { @@ -369,7 +311,7 @@ InlineElements = HTMLArea.Plugin.extend({ if (elementIsAncestor) { parent = ancestors[elementAncestorIndex]; } - this.removeMarkup(parent); + editor.removeMarkup(parent); } else { var bookmark = this.editor.getBookmark(range); var newElement = this.remapMarkup(parent, element); @@ -408,19 +350,6 @@ InlineElements = HTMLArea.Plugin.extend({ return newElement; }, - /* - * This function removes the given markup element - */ - removeMarkup : function(element) { - var bookmark = this.editor.getBookmark(this.editor._createRange(this.editor._getSelection())); - var parent = element.parentNode; - while (element.firstChild) { - parent.insertBefore(element.firstChild, element); - } - parent.removeChild(element); - this.editor.selectRange(this.editor.moveToBookmark(bookmark)); - }, - /* * This function gets called when the toolbar is updated */ @@ -440,7 +369,7 @@ InlineElements = HTMLArea.Plugin.extend({ var ancestors = editor.getAllAncestors(); for (var i = 0; i < ancestors.length; ++i) { fullNodeSelected = (editor._statusBarTree.selected === ancestors[i]) - && ((HTMLArea.is_gecko && ancestors[i].textContent === range.toString()) || (HTMLArea.is_ie && ancestors[i].innerText === range.text)); + && ((HTMLArea.is_gecko && ancestors[i].textContent === range.toString()) || (HTMLArea.is_ie && ((sel.type !== "Control" && ancestors[i].innerText === range.text) || (sel.type === "Control" && ancestors[i].innerText === range.item(0).text)))); if (fullNodeSelected) { if (!HTMLArea.isBlockElement(ancestors[i])) { tagName = ancestors[i].nodeName.toLowerCase(); @@ -455,7 +384,7 @@ InlineElements = HTMLArea.Plugin.extend({ } } var selectionInInlineElement = tagName && this.REInlineElements.test(tagName); - var disabled = !this.endPointsInSameBlock() || (fullNodeSelected && !tagName) || (selectionEmpty && !selectionInInlineElement); + var disabled = !editor.endPointsInSameBlock() || (fullNodeSelected && !tagName) || (selectionEmpty && !selectionInInlineElement); var obj = editor.config.customSelects["FormatText"]; if ((typeof(obj) !== "undefined") && (typeof(editor._toolbarObjects[obj.id]) !== "undefined")) { @@ -484,20 +413,6 @@ InlineElements = HTMLArea.Plugin.extend({ } }, - /* - * This function determines if the end poins of the current selection are within the same block - */ - endPointsInSameBlock : function() { - var selection = this.editor._getSelection(); - if (this.editor._selectionEmpty(selection)) { - return true; - } else { - var parent = this.editor.getParentElement(selection); - var endBlocks = this.editor.getEndBlocks(selection); - return (endBlocks.start === endBlocks.end && !/^(table|thead|tbody|tfoot|tr)$/i.test(parent.nodeName)); - } - }, - /* * This function updates the drop-down list of inline elemenents */ diff --git a/typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js b/typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js index 7ecf8e46204f..5a9fc86315ba 100644 --- a/typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js +++ b/typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js @@ -89,6 +89,9 @@ TextStyle = HTMLArea.Plugin.extend({ */ this.REInlineTags = /^(abbr|acronym|b|bdo|big|cite|code|del|dfn|em|i|ins|kbd|q|samp|small|span|strike|strong|sub|sup|tt|u|var)$/; + // Allowed attributes on inline elements + this.allowedAttributes = new Array("id", "title", "lang", "xml:lang", "dir", (HTMLArea.is_gecko?"class":"className")); + /* * Registering plugin "About" information */ @@ -124,7 +127,18 @@ TextStyle = HTMLArea.Plugin.extend({ isInlineElement : function (el) { return el && (el.nodeType === 1) && this.REInlineTags.test(el.nodeName.toLowerCase()); }, - + + /* + * This function adds an attribute to the array of allowed attributes on inline elements + * + * @param string attribute: the name of the attribute to be added to the array + * + * @return void + */ + addAllowedAttribute : function (attribute) { + this.allowedAttributes.push(attribute); + }, + /* * This function gets called when some style in the drop-down list applies it to the highlighted textt */ @@ -166,80 +180,11 @@ TextStyle = HTMLArea.Plugin.extend({ // The selection is not empty, nor full element if (className !== "none") { // Add span element with class attribute + var newElement = editor._doc.createElement("span"); + HTMLArea._addClass(newElement, className); + editor.wrapWithInlineElement(newElement, selection, range); if (HTMLArea.is_gecko) { - var newElement = this.editor._doc.createElement("span"); - HTMLArea._addClass(newElement, className); - range.surroundContents(newElement); - newElement.normalize(); - parent.normalize(); - // Firefox sometimes inserts empty elements just outside the boundaries of the range - var neighbour = newElement.previousSibling; - if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { - HTMLArea.removeFromParent(neighbour); - } - neighbour = newElement.nextSibling; - if (neighbour && (neighbour.nodeType != 3) && !/\S/.test(neighbour.textContent)) { - HTMLArea.removeFromParent(neighbour); - } - this.editor.selectNodeContents(newElement, false); range.detach(); - } else { - var rangeStart = range.duplicate(); - rangeStart.collapse(true); - var parentStart = rangeStart.parentElement(); - var rangeEnd = range.duplicate(); - rangeEnd.collapse(true); - var parentEnd = rangeEnd.parentElement(); - var newRange = editor._createRange(); - - var upperParentStart = parentStart; - if (parentStart !== parent) { - while (upperParentStart.parentNode !== parent) { - upperParentStart = upperParentStart.parentNode; - } - } - - var newElement = editor._doc.createElement("span"); - HTMLArea._addClass(newElement, className); - newElement.innerHTML = range.htmlText; - // IE eats spaces on the start boundary - if (range.htmlText.charAt(0) === "\x20") { - newElement.innerHTML = " " + newElement.innerHTML; - } - var newElementClone = newElement.cloneNode(true); - range.pasteHTML(newElement.outerHTML); - // IE inserts the element as the last child of the start container - if (parentStart !== parent - && parentStart.lastChild - && parentStart.lastChild.nodeType === 1 - && parentStart.lastChild.nodeName.toLowerCase() === "span") { - parent.insertBefore(newElementClone, upperParentStart.nextSibling); - parentStart.removeChild(parentStart.lastChild); - // Sometimes an empty previous sibling was created - if (newElementClone.previousSibling - && newElementClone.previousSibling.nodeType === 1 - && !newElementClone.previousSibling.innerText) { - parent.removeChild(newElementClone.previousSibling); - } - // The bookmark will not work anymore - newRange.moveToElementText(newElementClone); - newRange.collapse(false); - newRange.select(); - } else { - // Working around IE boookmark bug - if (parentStart != parentEnd) { - var newRange = editor._createRange(); - if (newRange.moveToBookmark(bookmark)) { - newRange.collapse(false); - newRange.select(); - } - } else { - range.collapse(false); - } - } - try { // normalize() not available in IE5.5 - parent.normalize(); - } catch(e) { } } } } else { @@ -253,39 +198,13 @@ TextStyle = HTMLArea.Plugin.extend({ HTMLArea._addClass(parent, className); } // Remove the span tag if it has no more attribute - if ((parent.nodeName.toLowerCase() === "span") && !this.hasAllowedAttributes(parent)) { - this.removeMarkup(parent); + if ((parent.nodeName.toLowerCase() === "span") && !HTMLArea.hasAllowedAttributes(parent, this.allowedAttributes)) { + editor.removeMarkup(parent); } } } }, - - /* - * This function verifies if the element has any of the allowed attributes - */ - hasAllowedAttributes : function(element) { - var allowedAttributes = new Array("id", "title", "lang", "xml:lang", "dir", "class", "className"); - for (var i = 0; i < allowedAttributes.length; ++i) { - if (element.getAttribute(allowedAttributes[i])) { - return true; - } - } - return false; - }, - - /* - * This function removes the given markup element - */ - removeMarkup : function(element) { - var bookmark = this.editor.getBookmark(this.editor._createRange(this.editor._getSelection())); - var parent = element.parentNode; - while (element.firstChild) { - parent.insertBefore(element.firstChild, element); - } - parent.removeChild(element); - this.editor.selectRange(this.editor.moveToBookmark(bookmark)); - }, - + /* * This function gets called when the plugin is generated * Get the classes configuration and initiate the parsing of the style sheets @@ -512,7 +431,7 @@ TextStyle = HTMLArea.Plugin.extend({ } } var selectionInInlineElement = tagName && this.REInlineTags.test(tagName); - var disabled = !this.endPointsInSameBlock() || (fullNodeSelected && !tagName) || (selectionEmpty && !selectionInInlineElement); + var disabled = !editor.endPointsInSameBlock() || (fullNodeSelected && !tagName) || (selectionEmpty && !selectionInInlineElement); if (!disabled && !tagName) { tagName = "span"; } @@ -520,21 +439,7 @@ TextStyle = HTMLArea.Plugin.extend({ this.updateValue(dropDownId, tagName, classNames, selectionEmpty, fullNodeSelected, disabled); } }, - - /* - * This function determines if the end poins of the current selection are within the same block - */ - endPointsInSameBlock : function() { - var selection = this.editor._getSelection(); - if (this.editor._selectionEmpty(selection)) { - return true; - } else { - var parent = this.editor.getParentElement(selection); - var endBlocks = this.editor.getEndBlocks(selection); - return (endBlocks.start === endBlocks.end && !/^(body|table|thead|tbody|tfoot|tr)$/i.test(parent.nodeName)); - } - }, - + updateValue : function(dropDownId, tagName, classNames, selectionEmpty, fullNodeSelected, disabled) { var editor = this.editor; var select = document.getElementById(editor._toolbarObjects[dropDownId]["elementId"]); -- 2.20.1