From b6f3d9f8869082fd32cf9f9c94139b5b7aad3172 Mon Sep 17 00:00:00 2001
From: Stanislas Rolland <typo3@sjbr.ca>
Date: Tue, 20 Nov 2007 22:48:36 +0000
Subject: [PATCH] * Feature #6769 continued: Further adjustments and
 workarounds to enable htmlArea RTE in Safari

git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2742 709f56b5-9817-0410-a4d7-c38de5d9e867
---
 ChangeLog                                     |  4 +
 typo3/sysext/rtehtmlarea/ChangeLog            |  4 +
 .../rtehtmlarea/htmlarea/htmlarea-gecko.js    | 97 ++++++++++---------
 typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js | 15 ++-
 .../pi2/class.tx_rtehtmlarea_pi2.php          |  2 +-
 5 files changed, 65 insertions(+), 57 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e9dcc5cfba58..5b01eab66339 100755
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2007-11-20  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
+
+	* Feature #6769 continued: Further adjustments and workarounds to enable htmlArea RTE in Safari
+
 2007-11-20  Dmitry Dulepov  <dmitry@typo3.org>
 
 	* Restored typo3/sysext/lang/locallang_mod_doc.xml because it was zero length and broke translations
diff --git a/typo3/sysext/rtehtmlarea/ChangeLog b/typo3/sysext/rtehtmlarea/ChangeLog
index 49159f0d8850..f4e127bb4746 100644
--- a/typo3/sysext/rtehtmlarea/ChangeLog
+++ b/typo3/sysext/rtehtmlarea/ChangeLog
@@ -1,3 +1,7 @@
+2007-11-20  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
+
+	* Feature #6769 continued: Further adjustments and workarounds to enable htmlArea RTE in Safari
+
 2007-11-19  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
 
 	* Feature #6769: Enable htmlArea RTE in Safari
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
index 3095b6af6f02..4db2f57a12b0 100644
--- a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
+++ b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
@@ -95,6 +95,28 @@ HTMLArea.prototype._getSelection = function() {
 	return this._iframe.contentWindow.getSelection();
 };
 
+/*
+ * Empty the selection object
+ */
+HTMLArea.prototype.emptySelection = function(sel) {
+	if (HTMLArea.is_safari) {
+		sel.empty();
+	} else {
+		sel.removeAllRanges();
+	}
+};
+
+/*
+ * Add a range to the selection
+ */
+HTMLArea.prototype.addRangeToSelection = function(sel, range) {
+	if (HTMLArea.is_safari) {
+		sel.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
+	} else {
+		sel.addRange(range);
+	}
+};
+
 /*
  * Create a range for the current selection
  */
@@ -135,13 +157,8 @@ HTMLArea.prototype.selectNode = function(node,pos) {
 	if (node.nodeType == 1 && node.tagName.toLowerCase() == "body") range.selectNodeContents(node);
 		else range.selectNode(node);
 	if ((typeof(pos) != "undefined")) range.collapse(pos);
-	if (HTMLArea.is_safari) {
-		sel.empty();
-		sel.setBaseAndExtent(range.startContainer,range.startOffset,range.endContainer,range.endOffset);
-	} else {
-		sel.removeAllRanges();
-		sel.addRange(range);
-	}
+	this.emptySelection(sel);
+	this.addRangeToSelection(sel, range);
 };
 
 /*
@@ -153,13 +170,8 @@ HTMLArea.prototype.selectNodeContents = function(node,pos) {
 	var range = this._doc.createRange();
 	range.selectNodeContents(node);
 	if ((typeof(pos) != "undefined")) range.collapse(pos);
-	if (HTMLArea.is_safari) {
-		sel.empty();
-		sel.setBaseAndExtent(range.startContainer,range.startOffset,range.endContainer,range.endOffset);
-	} else {
-		sel.removeAllRanges();
-		sel.addRange(range);
-	}
+	this.emptySelection(sel);
+	this.addRangeToSelection(sel, range);
 };
 
 /*
@@ -192,19 +204,11 @@ HTMLArea.prototype.getParentElement = function(sel,range) {
 	if (typeof(range) === "undefined") {
 		var range = this._createRange(sel);
 	}
-	try {
-		var p = range.commonAncestorContainer;
-		if (!range.collapsed && range.startContainer == range.endContainer &&
-				range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes()) {
-			p = range.startContainer.childNodes[range.startOffset];
-		}
-		while (p.nodeType == 3) {
-			p = p.parentNode;
-		}
-		return p;
-	} catch (e) {
-		return this._doc.body;
+	var p = range.commonAncestorContainer;
+	while (p.nodeType == 3) {
+		p = p.parentNode;
 	}
+	return p;
 };
 
 /*
@@ -246,8 +250,7 @@ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
 		node = range.startContainer,
 		pos = range.startOffset,
 		selnode = toBeInserted;
-	if (HTMLArea.is_safari) sel.empty();
-		else sel.removeAllRanges();
+	this.emptySelection(sel);
 	range.deleteContents();
 	switch (node.nodeType) {
 	    case 3: // Node.TEXT_NODE: we have to split it at the caret position.
@@ -256,8 +259,7 @@ HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
 			range = this._createRange();
 			range.setEnd(node, pos + toBeInserted.length);
 			range.setStart(node, pos + toBeInserted.length);
-			if (HTMLArea.is_safari) sel.setBaseAndExtent(range.startContainer, range.startOffset, range.endContainer, range.endOffset);
-				else sel.addRange(range);
+			this.addRangeToSelection(sel, range);
 		} else {
 			node = node.splitText(pos);
 			if (toBeInserted.nodeType == 11) selnode = selnode.lastChild;
@@ -345,6 +347,7 @@ HTMLArea.statusBarHandler = function (ev) {
 	var editor = target.editor;
 	target.blur();
 	editor.selectNode(target.el);
+	editor._statusBarTree.selected = target.el;
 	editor.updateToolbar(true);
 	switch (ev.type) {
 		case "click" :
@@ -426,13 +429,8 @@ HTMLArea.prototype._checkBackspace = function() {
 			r.setStartBefore(newr);
 			r.setEndAfter(newr);
 			r.extractContents();
-			if(HTMLArea.is_safari) {
-				sel.empty();
-				sel.setBaseAndExtent(r.startContainer,r.startOffset,r.endContainer,r.endOffset);
-			} else {
-				sel.removeAllRanges();
-				sel.addRange(r);
-			}
+			this.emptySelection(sel);
+			this.addRangeToSelection(sel, r);
 			return true;
 		}
 	},10);
@@ -442,7 +440,7 @@ HTMLArea.prototype._checkBackspace = function() {
 /*
  * Enter event handler
  */
-HTMLArea.prototype._checkInsertP = function(ev) {
+HTMLArea.prototype._checkInsertP = function() {
 	var editor = this;
 	this.focusEditor();
 	var i, left, right, rangeClone,
@@ -459,9 +457,10 @@ HTMLArea.prototype._checkInsertP = function(ev) {
 			break;
 		}
 	}
-	if (!range.collapsed) range.deleteContents();
-	if (HTMLArea.is_safari) sel.empty();
-		else sel.removeAllRanges();
+	if (!range.collapsed) {
+		range.deleteContents();
+	}
+	this.emptySelection(sel);
 	if (!block || /^(td|div)$/i.test(block.tagName)) {
 		if (!block) var block = doc.body;
 		if (/\S/.test(HTMLArea.getInnerText(block))) {
@@ -475,8 +474,13 @@ HTMLArea.prototype._checkInsertP = function(ev) {
 				left.appendChild(doc.createElement('br'));
 			}
 			left.normalize();
+			range.setStartAfter(left);
 			range.setEndAfter(block.lastChild);
-			range.surroundContents(right = doc.createElement('p'));
+				// Working around Safari issue: The following gives a range exception
+				// range.surroundContents(right = doc.createElement('p'));
+			right = doc.createElement('p');
+			right.appendChild(range.extractContents());
+			block.appendChild(right);
 				// Remove any element created empty
 			a = right.previousSibling;
 			if (a && !/\S/.test(HTMLArea.getInnerText(a))) HTMLArea.removeFromParent(a);
@@ -490,9 +494,9 @@ HTMLArea.prototype._checkInsertP = function(ev) {
 		} else {
 			range = doc.createRange();
 			var first = block.firstChild;
-			block.removeChild(first);
+			if (first) block.removeChild(first);
 			block.appendChild(right = doc.createElement('p'));
-			right.appendChild(first);
+			if (first) right.appendChild(first);
 		}
 		range.selectNodeContents(right);
 	} else {
@@ -523,10 +527,9 @@ HTMLArea.prototype._checkInsertP = function(ev) {
 		}
 	}
 	range.collapse(true);
-	if (HTMLArea.is_safari) sel.setBaseAndExtent(r.startContainer,r.startOffset,r.endContainer,r.endOffset);
-		else sel.addRange(range);
+	this.emptySelection(sel);
+	this.addRangeToSelection(sel, range);
 	this.scrollToCaret();
-	return true;
 };
 
 /*
diff --git a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
index 66585f20f8cb..bab835f78c6b 100644
--- a/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
+++ b/typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
@@ -2298,13 +2298,8 @@ HTMLArea.prototype.execCommand = function(cmdID, UI, param) {
 				sel = this._getSelection();
 				var r = this._createRange(sel).cloneRange();
 				r.collapse(false);
-				if(HTMLArea.is_safari) {
-					sel.empty();
-					sel.setBaseAndExtent(r.startContainer,r.startOffset,r.endContainer,r.endOffset);
-				} else {
-					sel.removeAllRanges();
-					sel.addRange(r);
-				}
+				this.emptySelection(sel);
+				this.addRangeToSelection(sel, r);
 			}
 		}
 		break;
@@ -2327,7 +2322,7 @@ HTMLArea._editorEvent = function(ev) {
 		while (owner.parentElement) { owner = owner.parentElement; }
 	}
 	var editor = RTEarea[owner._editorNo]["editor"];
-	var keyEvent = ((HTMLArea.is_ie || HTMLArea.is_safari) && ev.type == "keydown") || (!HTMLArea.is_ie && ev.type == "keypress");
+	var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (HTMLArea.is_gecko && ev.type == "keypress");
 	editor.focusEditor();
 
 	if(keyEvent) {
@@ -2428,10 +2423,12 @@ HTMLArea._editorEvent = function(ev) {
 			switch (ev.keyCode) {
 				case 13	: // KEY enter
 					if (HTMLArea.is_gecko && !ev.shiftKey && !editor.config.disableEnterParagraphs) {
-						if (editor._checkInsertP(ev)) HTMLArea._stopEvent(ev);
+						editor._checkInsertP();
+						HTMLArea._stopEvent(ev);
 							// update the toolbar state after some time
 						if (editor._timerToolbar) window.clearTimeout(editor._timerToolbar);
 						editor._timerToolbar = window.setTimeout("HTMLArea.updateToolbar(" + editor._editorNumber + ");", 50);
+						return false;
 					}
 					break;
 				case 8	: // KEY backspace
diff --git a/typo3/sysext/rtehtmlarea/pi2/class.tx_rtehtmlarea_pi2.php b/typo3/sysext/rtehtmlarea/pi2/class.tx_rtehtmlarea_pi2.php
index 18716336c6be..018ac48141d6 100644
--- a/typo3/sysext/rtehtmlarea/pi2/class.tx_rtehtmlarea_pi2.php
+++ b/typo3/sysext/rtehtmlarea/pi2/class.tx_rtehtmlarea_pi2.php
@@ -229,7 +229,7 @@ class tx_rtehtmlarea_pi2 extends tx_rtehtmlarea_base {
 			// Preloading the pageStyle
 		$filename = trim($this->thisConfig['contentCSS']) ? trim($this->thisConfig['contentCSS']) : 'EXT:' . $this->ID . '/htmlarea/plugins/DynamicCSS/dynamiccss.css';
 		$additionalCode_loadCSS = '
-		<link rel="alternate stylesheet" type="text/css" href="' . $this->getFullFileName($filename) . '" />';
+		<link rel="alternate stylesheet" type="text/css" href="' . $this->getFullFileName($filename) . '" title="HTMLArea RTE Content CSS" />';
 
 			// Loading the editor skin
 		$skinFilename = trim($this->thisConfig['skin']) ? trim($this->thisConfig['skin']) : 'EXT:' . $this->ID . '/htmlarea/skins/default/htmlarea.css';
-- 
GitLab