Project

General

Profile

Feature #19439 ยป rtehtmlarea_feature_9521.patch

Administrator Admin, 2008-10-09 00:17

View differences:

typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js (copie de travail)
*
* (c) 2002-2004, interactivetools.com, inc.
* (c) 2003-2004 dynarch.com
* (c) 2004-2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
* (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
......
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
***************************************************/
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js (copie de travail)
/*
* 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();
......
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 = "&nbsp;" + 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
***************************************************/
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js (copie de travail)
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
***************************************************/
......
};
/*
* 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/
*/
typo3/sysext/rtehtmlarea/htmlarea/plugins/InlineElements/inline-elements.js (copie de travail)
* 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;
}
......
},
/*
* 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.
*/
onButtonPress : function (editor, id) {
......
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) {
......
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])) {
......
}
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 {
......
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 = "&nbsp;" + 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 {
......
if (elementIsAncestor) {
parent = ancestors[elementAncestorIndex];
}
this.removeMarkup(parent);
editor.removeMarkup(parent);
}
}
} else {
......
if (elementIsAncestor) {
parent = ancestors[elementAncestorIndex];
}
this.removeMarkup(parent);
editor.removeMarkup(parent);
} else {
var bookmark = this.editor.getBookmark(range);
var newElement = this.remapMarkup(parent, element);
......
},
/*
* 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
*/
onUpdateToolbar : function () {
......
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();
......
}
}
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")) {
......
},
/*
* 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
*/
updateValue : function (editor, obj, tagName, selectionEmpty, fullNodeSelected, disabled) {
typo3/sysext/rtehtmlarea/htmlarea/plugins/TextStyle/text-style.js (copie de travail)
*/
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
*/
......
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
*/
onChange : function (editor, buttonId) {
......
// 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 = "&nbsp;" + 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 {
......
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
*/
......
}
}
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";
}
......
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"]);
    (1-1/1)