summaryrefslogtreecommitdiff
path: root/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes
diff options
context:
space:
mode:
Diffstat (limited to 'rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes')
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckcontextmenu.js223
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdataprocessor.js119
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_gecko.js53
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_ie.js58
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange.js935
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_gecko.js104
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_ie.js199
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrangeiterator.js327
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckeditingarea.js368
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckelementpath.js89
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckenterkey.js708
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckevents.js71
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckhtmliterator.js142
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckicon.js103
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckiecleanup.js68
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckimagepreloader.js64
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckkeystrokehandler.js141
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublock.js153
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublockpanel.js54
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenuitem.js161
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckpanel.js463
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckplugin.js56
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckspecialcombo.js376
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckstyle.js1500
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbar.js103
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_gecko.js36
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_ie.js38
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbutton.js81
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbuttonui.js198
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontformatcombo.js139
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontscombo.js98
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontsizecombo.js76
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarpanelbutton.js103
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarspecialcombo.js146
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarstylecombo.js200
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckw3crange.js451
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml.js108
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_gecko.js106
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_ie.js93
39 files changed, 8511 insertions, 0 deletions
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckcontextmenu.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckcontextmenu.js
new file mode 100644
index 0000000..56027dc
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckcontextmenu.js
@@ -0,0 +1,223 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKContextMenu Class: renders an control a context menu.
+ */
+
+var FCKContextMenu = function( parentWindow, langDir )
+{
+ this.CtrlDisable = false ;
+
+ var oPanel = this._Panel = new FCKPanel( parentWindow ) ;
+ oPanel.AppendStyleSheet( FCKConfig.SkinEditorCSS ) ;
+ oPanel.IsContextMenu = true ;
+
+ // The FCKTools.DisableSelection doesn't seems to work to avoid dragging of the icons in Mozilla
+ // so we stop the start of the dragging
+ if ( FCKBrowserInfo.IsGecko )
+ oPanel.Document.addEventListener( 'draggesture', function(e) {e.preventDefault(); return false;}, true ) ;
+
+ var oMenuBlock = this._MenuBlock = new FCKMenuBlock() ;
+ oMenuBlock.Panel = oPanel ;
+ oMenuBlock.OnClick = FCKTools.CreateEventListener( FCKContextMenu_MenuBlock_OnClick, this ) ;
+
+ this._Redraw = true ;
+}
+
+
+FCKContextMenu.prototype.SetMouseClickWindow = function( mouseClickWindow )
+{
+ if ( !FCKBrowserInfo.IsIE )
+ {
+ this._Document = mouseClickWindow.document ;
+ if ( FCKBrowserInfo.IsOpera && !( 'oncontextmenu' in document.createElement('foo') ) )
+ {
+ this._Document.addEventListener( 'mousedown', FCKContextMenu_Document_OnMouseDown, false ) ;
+ this._Document.addEventListener( 'mouseup', FCKContextMenu_Document_OnMouseUp, false ) ;
+ }
+ this._Document.addEventListener( 'contextmenu', FCKContextMenu_Document_OnContextMenu, false ) ;
+ }
+}
+
+/**
+ The customData parameter is just a value that will be send to the command that is executed,
+ so it's possible to reuse the same command for several items just by assigning different data for each one.
+*/
+FCKContextMenu.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
+{
+ var oItem = this._MenuBlock.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
+ this._Redraw = true ;
+ return oItem ;
+}
+
+FCKContextMenu.prototype.AddSeparator = function()
+{
+ this._MenuBlock.AddSeparator() ;
+ this._Redraw = true ;
+}
+
+FCKContextMenu.prototype.RemoveAllItems = function()
+{
+ this._MenuBlock.RemoveAllItems() ;
+ this._Redraw = true ;
+}
+
+FCKContextMenu.prototype.AttachToElement = function( element )
+{
+ if ( FCKBrowserInfo.IsIE )
+ FCKTools.AddEventListenerEx( element, 'contextmenu', FCKContextMenu_AttachedElement_OnContextMenu, this ) ;
+ else
+ element._FCKContextMenu = this ;
+}
+
+function FCKContextMenu_Document_OnContextMenu( e )
+{
+ if ( FCKConfig.BrowserContextMenu )
+ return true ;
+
+ var el = e.target ;
+
+ while ( el )
+ {
+ if ( el._FCKContextMenu )
+ {
+ if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
+ return true ;
+
+ FCKTools.CancelEvent( e ) ;
+ FCKContextMenu_AttachedElement_OnContextMenu( e, el._FCKContextMenu, el ) ;
+ return false ;
+ }
+ el = el.parentNode ;
+ }
+ return true ;
+}
+
+var FCKContextMenu_OverrideButton ;
+
+function FCKContextMenu_Document_OnMouseDown( e )
+{
+ if( !e || e.button != 2 )
+ return false ;
+
+ if ( FCKConfig.BrowserContextMenu )
+ return true ;
+
+ var el = e.target ;
+
+ while ( el )
+ {
+ if ( el._FCKContextMenu )
+ {
+ if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
+ return true ;
+
+ var overrideButton = FCKContextMenu_OverrideButton ;
+ if( !overrideButton )
+ {
+ var doc = FCKTools.GetElementDocument( e.target ) ;
+ overrideButton = FCKContextMenu_OverrideButton = doc.createElement('input') ;
+ overrideButton.type = 'button' ;
+ var buttonHolder = doc.createElement('p') ;
+ doc.body.appendChild( buttonHolder ) ;
+ buttonHolder.appendChild( overrideButton ) ;
+ }
+
+ overrideButton.style.cssText = 'position:absolute;top:' + ( e.clientY - 2 ) +
+ 'px;left:' + ( e.clientX - 2 ) +
+ 'px;width:5px;height:5px;opacity:0.01' ;
+ }
+ el = el.parentNode ;
+ }
+ return false ;
+}
+
+function FCKContextMenu_Document_OnMouseUp( e )
+{
+ if ( FCKConfig.BrowserContextMenu )
+ return true ;
+
+ var overrideButton = FCKContextMenu_OverrideButton ;
+
+ if ( overrideButton )
+ {
+ var parent = overrideButton.parentNode ;
+ parent.parentNode.removeChild( parent ) ;
+ FCKContextMenu_OverrideButton = undefined ;
+
+ if( e && e.button == 2 )
+ {
+ FCKContextMenu_Document_OnContextMenu( e ) ;
+ return false ;
+ }
+ }
+ return true ;
+}
+
+function FCKContextMenu_AttachedElement_OnContextMenu( ev, fckContextMenu, el )
+{
+ if ( ( fckContextMenu.CtrlDisable && ( ev.ctrlKey || ev.metaKey ) ) || FCKConfig.BrowserContextMenu )
+ return true ;
+
+ var eTarget = el || this ;
+
+ if ( fckContextMenu.OnBeforeOpen )
+ fckContextMenu.OnBeforeOpen.call( fckContextMenu, eTarget ) ;
+
+ if ( fckContextMenu._MenuBlock.Count() == 0 )
+ return false ;
+
+ if ( fckContextMenu._Redraw )
+ {
+ fckContextMenu._MenuBlock.Create( fckContextMenu._Panel.MainNode ) ;
+ fckContextMenu._Redraw = false ;
+ }
+
+ // This will avoid that the content of the context menu can be dragged in IE
+ // as the content of the panel is recreated we need to do it every time
+ FCKTools.DisableSelection( fckContextMenu._Panel.Document.body ) ;
+
+ var x = 0 ;
+ var y = 0 ;
+ if ( FCKBrowserInfo.IsIE )
+ {
+ x = ev.screenX ;
+ y = ev.screenY ;
+ }
+ else if ( FCKBrowserInfo.IsSafari )
+ {
+ x = ev.clientX ;
+ y = ev.clientY ;
+ }
+ else
+ {
+ x = ev.pageX ;
+ y = ev.pageY ;
+ }
+ fckContextMenu._Panel.Show( x, y, ev.currentTarget || null ) ;
+
+ return false ;
+}
+
+function FCKContextMenu_MenuBlock_OnClick( menuItem, contextMenu )
+{
+ contextMenu._Panel.Hide() ;
+ FCKTools.RunFunction( contextMenu.OnItemClick, contextMenu, menuItem ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdataprocessor.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdataprocessor.js
new file mode 100644
index 0000000..f0ac79d
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdataprocessor.js
@@ -0,0 +1,119 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * The Data Processor is responsible for transforming the input and output data
+ * in the editor. For more info:
+ * http://dev.fckeditor.net/wiki/Components/DataProcessor
+ *
+ * The default implementation offers the base XHTML compatibility features of
+ * FCKeditor. Further Data Processors may be implemented for other purposes.
+ *
+ */
+
+var FCKDataProcessor = function()
+{}
+
+FCKDataProcessor.prototype =
+{
+ /*
+ * Returns a string representing the HTML format of "data". The returned
+ * value will be loaded in the editor.
+ * The HTML must be from <html> to </html>, including <head>, <body> and
+ * eventually the DOCTYPE.
+ * Note: HTML comments may already be part of the data because of the
+ * pre-processing made with ProtectedSource.
+ * @param {String} data The data to be converted in the
+ * DataProcessor specific format.
+ */
+ ConvertToHtml : function( data )
+ {
+ // The default data processor must handle two different cases depending
+ // on the FullPage setting. Custom Data Processors will not be
+ // compatible with FullPage, much probably.
+ if ( FCKConfig.FullPage )
+ {
+ // Save the DOCTYPE.
+ FCK.DocTypeDeclaration = data.match( FCKRegexLib.DocTypeTag ) ;
+
+ // Check if the <body> tag is available.
+ if ( !FCKRegexLib.HasBodyTag.test( data ) )
+ data = '<body>' + data + '</body>' ;
+
+ // Check if the <html> tag is available.
+ if ( !FCKRegexLib.HtmlOpener.test( data ) )
+ data = '<html dir="' + FCKConfig.ContentLangDirection + '">' + data + '</html>' ;
+
+ // Check if the <head> tag is available.
+ if ( !FCKRegexLib.HeadOpener.test( data ) )
+ data = data.replace( FCKRegexLib.HtmlOpener, '$&<head><title></title></head>' ) ;
+
+ return data ;
+ }
+ else
+ {
+ var html =
+ FCKConfig.DocType +
+ '<html dir="' + FCKConfig.ContentLangDirection + '"' ;
+
+ // On IE, if you are using a DOCTYPE different of HTML 4 (like
+ // XHTML), you must force the vertical scroll to show, otherwise
+ // the horizontal one may appear when the page needs vertical scrolling.
+ // TODO : Check it with IE7 and make it IE6- if it is the case.
+ if ( FCKBrowserInfo.IsIE && FCKConfig.DocType.length > 0 && !FCKRegexLib.Html4DocType.test( FCKConfig.DocType ) )
+ html += ' style="overflow-y: scroll"' ;
+
+ html += '><head><title></title></head>' +
+ '<body' + FCKConfig.GetBodyAttributes() + '>' +
+ data +
+ '</body></html>' ;
+
+ return html ;
+ }
+ },
+
+ /*
+ * Converts a DOM (sub-)tree to a string in the data format.
+ * @param {Object} rootNode The node that contains the DOM tree to be
+ * converted to the data format.
+ * @param {Boolean} excludeRoot Indicates that the root node must not
+ * be included in the conversion, only its children.
+ * @param {Boolean} format Indicates that the data must be formatted
+ * for human reading. Not all Data Processors may provide it.
+ */
+ ConvertToDataFormat : function( rootNode, excludeRoot, ignoreIfEmptyParagraph, format )
+ {
+ var data = FCKXHtml.GetXHTML( rootNode, !excludeRoot, format ) ;
+
+ if ( ignoreIfEmptyParagraph && FCKRegexLib.EmptyOutParagraph.test( data ) )
+ return '' ;
+
+ return data ;
+ },
+
+ /*
+ * Makes any necessary changes to a piece of HTML for insertion in the
+ * editor selection position.
+ * @param {String} html The HTML to be fixed.
+ */
+ FixHtml : function( html )
+ {
+ return html ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_gecko.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_gecko.js
new file mode 100644
index 0000000..04a3099
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_gecko.js
@@ -0,0 +1,53 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This is a generic Document Fragment object. It is not intended to provide
+ * the W3C implementation, but is a way to fix the missing of a real Document
+ * Fragment in IE (where document.createDocumentFragment() returns a normal
+ * document instead), giving a standard interface for it.
+ * (IE Implementation)
+ */
+
+var FCKDocumentFragment = function( parentDocument, baseDocFrag )
+{
+ this.RootNode = baseDocFrag || parentDocument.createDocumentFragment() ;
+}
+
+FCKDocumentFragment.prototype =
+{
+
+ // Append the contents of this Document Fragment to another element.
+ AppendTo : function( targetNode )
+ {
+ targetNode.appendChild( this.RootNode ) ;
+ },
+
+ AppendHtml : function( html )
+ {
+ var eTmpDiv = this.RootNode.ownerDocument.createElement( 'div' ) ;
+ eTmpDiv.innerHTML = html ;
+ FCKDomTools.MoveChildren( eTmpDiv, this.RootNode ) ;
+ },
+
+ InsertAfterNode : function( existingNode )
+ {
+ FCKDomTools.InsertAfterNode( existingNode, this.RootNode ) ;
+ }
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_ie.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_ie.js
new file mode 100644
index 0000000..d9e4b3d
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdocumentfragment_ie.js
@@ -0,0 +1,58 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This is a generic Document Fragment object. It is not intended to provide
+ * the W3C implementation, but is a way to fix the missing of a real Document
+ * Fragment in IE (where document.createDocumentFragment() returns a normal
+ * document instead), giving a standard interface for it.
+ * (IE Implementation)
+ */
+
+var FCKDocumentFragment = function( parentDocument )
+{
+ this._Document = parentDocument ;
+ this.RootNode = parentDocument.createElement( 'div' ) ;
+}
+
+// Append the contents of this Document Fragment to another node.
+FCKDocumentFragment.prototype =
+{
+
+ AppendTo : function( targetNode )
+ {
+ FCKDomTools.MoveChildren( this.RootNode, targetNode ) ;
+ },
+
+ AppendHtml : function( html )
+ {
+ var eTmpDiv = this._Document.createElement( 'div' ) ;
+ eTmpDiv.innerHTML = html ;
+ FCKDomTools.MoveChildren( eTmpDiv, this.RootNode ) ;
+ },
+
+ InsertAfterNode : function( existingNode )
+ {
+ var eRoot = this.RootNode ;
+ var eLast ;
+
+ while( ( eLast = eRoot.lastChild ) )
+ FCKDomTools.InsertAfterNode( existingNode, eRoot.removeChild( eLast ) ) ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange.js
new file mode 100644
index 0000000..b0912eb
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange.js
@@ -0,0 +1,935 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Class for working with a selection range, much like the W3C DOM Range, but
+ * it is not intended to be an implementation of the W3C interface.
+ */
+
+var FCKDomRange = function( sourceWindow )
+{
+ this.Window = sourceWindow ;
+ this._Cache = {} ;
+}
+
+FCKDomRange.prototype =
+{
+
+ _UpdateElementInfo : function()
+ {
+ var innerRange = this._Range ;
+
+ if ( !innerRange )
+ this.Release( true ) ;
+ else
+ {
+ // For text nodes, the node itself is the StartNode.
+ var eStart = innerRange.startContainer ;
+
+ var oElementPath = new FCKElementPath( eStart ) ;
+ this.StartNode = eStart.nodeType == 3 ? eStart : eStart.childNodes[ innerRange.startOffset ] ;
+ this.StartContainer = eStart ;
+ this.StartBlock = oElementPath.Block ;
+ this.StartBlockLimit = oElementPath.BlockLimit ;
+
+ if ( innerRange.collapsed )
+ {
+ this.EndNode = this.StartNode ;
+ this.EndContainer = this.StartContainer ;
+ this.EndBlock = this.StartBlock ;
+ this.EndBlockLimit = this.StartBlockLimit ;
+ }
+ else
+ {
+ var eEnd = innerRange.endContainer ;
+
+ if ( eStart != eEnd )
+ oElementPath = new FCKElementPath( eEnd ) ;
+
+ // The innerRange.endContainer[ innerRange.endOffset ] is not
+ // usually part of the range, but the marker for the range end. So,
+ // let's get the previous available node as the real end.
+ var eEndNode = eEnd ;
+ if ( innerRange.endOffset == 0 )
+ {
+ while ( eEndNode && !eEndNode.previousSibling )
+ eEndNode = eEndNode.parentNode ;
+
+ if ( eEndNode )
+ eEndNode = eEndNode.previousSibling ;
+ }
+ else if ( eEndNode.nodeType == 1 )
+ eEndNode = eEndNode.childNodes[ innerRange.endOffset - 1 ] ;
+
+ this.EndNode = eEndNode ;
+ this.EndContainer = eEnd ;
+ this.EndBlock = oElementPath.Block ;
+ this.EndBlockLimit = oElementPath.BlockLimit ;
+ }
+ }
+
+ this._Cache = {} ;
+ },
+
+ CreateRange : function()
+ {
+ return new FCKW3CRange( this.Window.document ) ;
+ },
+
+ DeleteContents : function()
+ {
+ if ( this._Range )
+ {
+ this._Range.deleteContents() ;
+ this._UpdateElementInfo() ;
+ }
+ },
+
+ ExtractContents : function()
+ {
+ if ( this._Range )
+ {
+ var docFrag = this._Range.extractContents() ;
+ this._UpdateElementInfo() ;
+ return docFrag ;
+ }
+ return null ;
+ },
+
+ CheckIsCollapsed : function()
+ {
+ if ( this._Range )
+ return this._Range.collapsed ;
+
+ return false ;
+ },
+
+ Collapse : function( toStart )
+ {
+ if ( this._Range )
+ this._Range.collapse( toStart ) ;
+
+ this._UpdateElementInfo() ;
+ },
+
+ Clone : function()
+ {
+ var oClone = FCKTools.CloneObject( this ) ;
+
+ if ( this._Range )
+ oClone._Range = this._Range.cloneRange() ;
+
+ return oClone ;
+ },
+
+ MoveToNodeContents : function( targetNode )
+ {
+ if ( !this._Range )
+ this._Range = this.CreateRange() ;
+
+ this._Range.selectNodeContents( targetNode ) ;
+
+ this._UpdateElementInfo() ;
+ },
+
+ MoveToElementStart : function( targetElement )
+ {
+ this.SetStart(targetElement,1) ;
+ this.SetEnd(targetElement,1) ;
+ },
+
+ // Moves to the first editing point inside a element. For example, in a
+ // element tree like "<p><b><i></i></b> Text</p>", the start editing point
+ // is "<p><b><i>^</i></b> Text</p>" (inside <i>).
+ MoveToElementEditStart : function( targetElement )
+ {
+ var editableElement ;
+
+ while ( targetElement && targetElement.nodeType == 1 )
+ {
+ if ( FCKDomTools.CheckIsEditable( targetElement ) )
+ editableElement = targetElement ;
+ else if ( editableElement )
+ break ; // If we already found an editable element, stop the loop.
+
+ targetElement = targetElement.firstChild ;
+ }
+
+ if ( editableElement )
+ this.MoveToElementStart( editableElement ) ;
+ },
+
+ InsertNode : function( node )
+ {
+ if ( this._Range )
+ this._Range.insertNode( node ) ;
+ },
+
+ CheckIsEmpty : function()
+ {
+ if ( this.CheckIsCollapsed() )
+ return true ;
+
+ // Inserts the contents of the range in a div tag.
+ var eToolDiv = this.Window.document.createElement( 'div' ) ;
+ this._Range.cloneContents().AppendTo( eToolDiv ) ;
+
+ FCKDomTools.TrimNode( eToolDiv ) ;
+
+ return ( eToolDiv.innerHTML.length == 0 ) ;
+ },
+
+ /**
+ * Checks if the start boundary of the current range is "visually" (like a
+ * selection caret) at the beginning of the block. It means that some
+ * things could be brefore the range, like spaces or empty inline elements,
+ * but it would still be considered at the beginning of the block.
+ */
+ CheckStartOfBlock : function()
+ {
+ var cache = this._Cache ;
+ var bIsStartOfBlock = cache.IsStartOfBlock ;
+
+ if ( bIsStartOfBlock != undefined )
+ return bIsStartOfBlock ;
+
+ // Take the block reference.
+ var block = this.StartBlock || this.StartBlockLimit ;
+
+ var container = this._Range.startContainer ;
+ var offset = this._Range.startOffset ;
+ var currentNode ;
+
+ if ( offset > 0 )
+ {
+ // First, check the start container. If it is a text node, get the
+ // substring of the node value before the range offset.
+ if ( container.nodeType == 3 )
+ {
+ var textValue = container.nodeValue.substr( 0, offset ).Trim() ;
+
+ // If we have some text left in the container, we are not at
+ // the end for the block.
+ if ( textValue.length != 0 )
+ return cache.IsStartOfBlock = false ;
+ }
+ else
+ currentNode = container.childNodes[ offset - 1 ] ;
+ }
+
+ // We'll not have a currentNode if the container was a text node, or
+ // the offset is zero.
+ if ( !currentNode )
+ currentNode = FCKDomTools.GetPreviousSourceNode( container, true, null, block ) ;
+
+ while ( currentNode )
+ {
+ switch ( currentNode.nodeType )
+ {
+ case 1 :
+ // It's not an inline element.
+ if ( !FCKListsLib.InlineChildReqElements[ currentNode.nodeName.toLowerCase() ] )
+ return cache.IsStartOfBlock = false ;
+
+ break ;
+
+ case 3 :
+ // It's a text node with real text.
+ if ( currentNode.nodeValue.Trim().length > 0 )
+ return cache.IsStartOfBlock = false ;
+ }
+
+ currentNode = FCKDomTools.GetPreviousSourceNode( currentNode, false, null, block ) ;
+ }
+
+ return cache.IsStartOfBlock = true ;
+ },
+
+ /**
+ * Checks if the end boundary of the current range is "visually" (like a
+ * selection caret) at the end of the block. It means that some things
+ * could be after the range, like spaces, empty inline elements, or a
+ * single <br>, but it would still be considered at the end of the block.
+ */
+ CheckEndOfBlock : function( refreshSelection )
+ {
+ var isEndOfBlock = this._Cache.IsEndOfBlock ;
+
+ if ( isEndOfBlock != undefined )
+ return isEndOfBlock ;
+
+ // Take the block reference.
+ var block = this.EndBlock || this.EndBlockLimit ;
+
+ var container = this._Range.endContainer ;
+ var offset = this._Range.endOffset ;
+ var currentNode ;
+
+ // First, check the end container. If it is a text node, get the
+ // substring of the node value after the range offset.
+ if ( container.nodeType == 3 )
+ {
+ var textValue = container.nodeValue ;
+ if ( offset < textValue.length )
+ {
+ textValue = textValue.substr( offset ) ;
+
+ // If we have some text left in the container, we are not at
+ // the end for the block.
+ if ( textValue.Trim().length != 0 )
+ return this._Cache.IsEndOfBlock = false ;
+ }
+ }
+ else
+ currentNode = container.childNodes[ offset ] ;
+
+ // We'll not have a currentNode if the container was a text node, of
+ // the offset is out the container children limits (after it probably).
+ if ( !currentNode )
+ currentNode = FCKDomTools.GetNextSourceNode( container, true, null, block ) ;
+
+ var hadBr = false ;
+
+ while ( currentNode )
+ {
+ switch ( currentNode.nodeType )
+ {
+ case 1 :
+ var nodeName = currentNode.nodeName.toLowerCase() ;
+
+ // It's an inline element.
+ if ( FCKListsLib.InlineChildReqElements[ nodeName ] )
+ break ;
+
+ // It is the first <br> found.
+ if ( nodeName == 'br' && !hadBr )
+ {
+ hadBr = true ;
+ break ;
+ }
+
+ return this._Cache.IsEndOfBlock = false ;
+
+ case 3 :
+ // It's a text node with real text.
+ if ( currentNode.nodeValue.Trim().length > 0 )
+ return this._Cache.IsEndOfBlock = false ;
+ }
+
+ currentNode = FCKDomTools.GetNextSourceNode( currentNode, false, null, block ) ;
+ }
+
+ if ( refreshSelection )
+ this.Select() ;
+
+ return this._Cache.IsEndOfBlock = true ;
+ },
+
+ // This is an "intrusive" way to create a bookmark. It includes <span> tags
+ // in the range boundaries. The advantage of it is that it is possible to
+ // handle DOM mutations when moving back to the bookmark.
+ // Attention: the inclusion of nodes in the DOM is a design choice and
+ // should not be changed as there are other points in the code that may be
+ // using those nodes to perform operations. See GetBookmarkNode.
+ // For performance, includeNodes=true if intended to SelectBookmark.
+ CreateBookmark : function( includeNodes )
+ {
+ // Create the bookmark info (random IDs).
+ var oBookmark =
+ {
+ StartId : (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'S',
+ EndId : (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'E'
+ } ;
+
+ var oDoc = this.Window.document ;
+ var eStartSpan ;
+ var eEndSpan ;
+ var oClone ;
+
+ // For collapsed ranges, add just the start marker.
+ if ( !this.CheckIsCollapsed() )
+ {
+ eEndSpan = oDoc.createElement( 'span' ) ;
+ eEndSpan.style.display = 'none' ;
+ eEndSpan.id = oBookmark.EndId ;
+ eEndSpan.setAttribute( '_fck_bookmark', true ) ;
+
+ // For IE, it must have something inside, otherwise it may be
+ // removed during DOM operations.
+// if ( FCKBrowserInfo.IsIE )
+ eEndSpan.innerHTML = '&nbsp;' ;
+
+ oClone = this.Clone() ;
+ oClone.Collapse( false ) ;
+ oClone.InsertNode( eEndSpan ) ;
+ }
+
+ eStartSpan = oDoc.createElement( 'span' ) ;
+ eStartSpan.style.display = 'none' ;
+ eStartSpan.id = oBookmark.StartId ;
+ eStartSpan.setAttribute( '_fck_bookmark', true ) ;
+
+ // For IE, it must have something inside, otherwise it may be removed
+ // during DOM operations.
+// if ( FCKBrowserInfo.IsIE )
+ eStartSpan.innerHTML = '&nbsp;' ;
+
+ oClone = this.Clone() ;
+ oClone.Collapse( true ) ;
+ oClone.InsertNode( eStartSpan ) ;
+
+ if ( includeNodes )
+ {
+ oBookmark.StartNode = eStartSpan ;
+ oBookmark.EndNode = eEndSpan ;
+ }
+
+ // Update the range position.
+ if ( eEndSpan )
+ {
+ this.SetStart( eStartSpan, 4 ) ;
+ this.SetEnd( eEndSpan, 3 ) ;
+ }
+ else
+ this.MoveToPosition( eStartSpan, 4 ) ;
+
+ return oBookmark ;
+ },
+
+ // This one should be a part of a hypothetic "bookmark" object.
+ GetBookmarkNode : function( bookmark, start )
+ {
+ var doc = this.Window.document ;
+
+ if ( start )
+ return bookmark.StartNode || doc.getElementById( bookmark.StartId ) ;
+ else
+ return bookmark.EndNode || doc.getElementById( bookmark.EndId ) ;
+ },
+
+ MoveToBookmark : function( bookmark, preserveBookmark )
+ {
+ var eStartSpan = this.GetBookmarkNode( bookmark, true ) ;
+ var eEndSpan = this.GetBookmarkNode( bookmark, false ) ;
+
+ this.SetStart( eStartSpan, 3 ) ;
+
+ if ( !preserveBookmark )
+ FCKDomTools.RemoveNode( eStartSpan ) ;
+
+ // If collapsed, the end span will not be available.
+ if ( eEndSpan )
+ {
+ this.SetEnd( eEndSpan, 3 ) ;
+
+ if ( !preserveBookmark )
+ FCKDomTools.RemoveNode( eEndSpan ) ;
+ }
+ else
+ this.Collapse( true ) ;
+
+ this._UpdateElementInfo() ;
+ },
+
+ // Non-intrusive bookmark algorithm
+ CreateBookmark2 : function()
+ {
+ // If there is no range then get out of here.
+ // It happens on initial load in Safari #962 and if the editor it's hidden also in Firefox
+ if ( ! this._Range )
+ return { "Start" : 0, "End" : 0 } ;
+
+ // First, we record down the offset values
+ var bookmark =
+ {
+ "Start" : [ this._Range.startOffset ],
+ "End" : [ this._Range.endOffset ]
+ } ;
+ // Since we're treating the document tree as normalized, we need to backtrack the text lengths
+ // of previous text nodes into the offset value.
+ var curStart = this._Range.startContainer.previousSibling ;
+ var curEnd = this._Range.endContainer.previousSibling ;
+
+ // Also note that the node that we use for "address base" would change during backtracking.
+ var addrStart = this._Range.startContainer ;
+ var addrEnd = this._Range.endContainer ;
+ while ( curStart && curStart.nodeType == 3 && addrStart.nodeType == 3 )
+ {
+ bookmark.Start[0] += curStart.length ;
+ addrStart = curStart ;
+ curStart = curStart.previousSibling ;
+ }
+ while ( curEnd && curEnd.nodeType == 3 && addrEnd.nodeType == 3 )
+ {
+ bookmark.End[0] += curEnd.length ;
+ addrEnd = curEnd ;
+ curEnd = curEnd.previousSibling ;
+ }
+
+ // If the object pointed to by the startOffset and endOffset are text nodes, we need
+ // to backtrack and add in the text offset to the bookmark addresses.
+ if ( addrStart.nodeType == 1 && addrStart.childNodes[bookmark.Start[0]] && addrStart.childNodes[bookmark.Start[0]].nodeType == 3 )
+ {
+ var curNode = addrStart.childNodes[bookmark.Start[0]] ;
+ var offset = 0 ;
+ while ( curNode.previousSibling && curNode.previousSibling.nodeType == 3 )
+ {
+ curNode = curNode.previousSibling ;
+ offset += curNode.length ;
+ }
+ addrStart = curNode ;
+ bookmark.Start[0] = offset ;
+ }
+ if ( addrEnd.nodeType == 1 && addrEnd.childNodes[bookmark.End[0]] && addrEnd.childNodes[bookmark.End[0]].nodeType == 3 )
+ {
+ var curNode = addrEnd.childNodes[bookmark.End[0]] ;
+ var offset = 0 ;
+ while ( curNode.previousSibling && curNode.previousSibling.nodeType == 3 )
+ {
+ curNode = curNode.previousSibling ;
+ offset += curNode.length ;
+ }
+ addrEnd = curNode ;
+ bookmark.End[0] = offset ;
+ }
+
+ // Then, we record down the precise position of the container nodes
+ // by walking up the DOM tree and counting their childNode index
+ bookmark.Start = FCKDomTools.GetNodeAddress( addrStart, true ).concat( bookmark.Start ) ;
+ bookmark.End = FCKDomTools.GetNodeAddress( addrEnd, true ).concat( bookmark.End ) ;
+ return bookmark;
+ },
+
+ MoveToBookmark2 : function( bookmark )
+ {
+ // Reverse the childNode counting algorithm in CreateBookmark2()
+ var curStart = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.Start.slice( 0, -1 ), true ) ;
+ var curEnd = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.End.slice( 0, -1 ), true ) ;
+
+ // Generate the W3C Range object and update relevant data
+ this.Release( true ) ;
+ this._Range = new FCKW3CRange( this.Window.document ) ;
+ var startOffset = bookmark.Start[ bookmark.Start.length - 1 ] ;
+ var endOffset = bookmark.End[ bookmark.End.length - 1 ] ;
+ while ( curStart.nodeType == 3 && startOffset > curStart.length )
+ {
+ if ( ! curStart.nextSibling || curStart.nextSibling.nodeType != 3 )
+ break ;
+ startOffset -= curStart.length ;
+ curStart = curStart.nextSibling ;
+ }
+ while ( curEnd.nodeType == 3 && endOffset > curEnd.length )
+ {
+ if ( ! curEnd.nextSibling || curEnd.nextSibling.nodeType != 3 )
+ break ;
+ endOffset -= curEnd.length ;
+ curEnd = curEnd.nextSibling ;
+ }
+ this._Range.setStart( curStart, startOffset ) ;
+ this._Range.setEnd( curEnd, endOffset ) ;
+ this._UpdateElementInfo() ;
+ },
+
+ MoveToPosition : function( targetElement, position )
+ {
+ this.SetStart( targetElement, position ) ;
+ this.Collapse( true ) ;
+ },
+
+ /*
+ * Moves the position of the start boundary of the range to a specific position
+ * relatively to a element.
+ * @position:
+ * 1 = After Start <target>^contents</target>
+ * 2 = Before End <target>contents^</target>
+ * 3 = Before Start ^<target>contents</target>
+ * 4 = After End <target>contents</target>^
+ */
+ SetStart : function( targetElement, position, noInfoUpdate )
+ {
+ var oRange = this._Range ;
+ if ( !oRange )
+ oRange = this._Range = this.CreateRange() ;
+
+ switch( position )
+ {
+ case 1 : // After Start <target>^contents</target>
+ oRange.setStart( targetElement, 0 ) ;
+ break ;
+
+ case 2 : // Before End <target>contents^</target>
+ oRange.setStart( targetElement, targetElement.childNodes.length ) ;
+ break ;
+
+ case 3 : // Before Start ^<target>contents</target>
+ oRange.setStartBefore( targetElement ) ;
+ break ;
+
+ case 4 : // After End <target>contents</target>^
+ oRange.setStartAfter( targetElement ) ;
+ }
+
+ if ( !noInfoUpdate )
+ this._UpdateElementInfo() ;
+ },
+
+ /*
+ * Moves the position of the start boundary of the range to a specific position
+ * relatively to a element.
+ * @position:
+ * 1 = After Start <target>^contents</target>
+ * 2 = Before End <target>contents^</target>
+ * 3 = Before Start ^<target>contents</target>
+ * 4 = After End <target>contents</target>^
+ */
+ SetEnd : function( targetElement, position, noInfoUpdate )
+ {
+ var oRange = this._Range ;
+ if ( !oRange )
+ oRange = this._Range = this.CreateRange() ;
+
+ switch( position )
+ {
+ case 1 : // After Start <target>^contents</target>
+ oRange.setEnd( targetElement, 0 ) ;
+ break ;
+
+ case 2 : // Before End <target>contents^</target>
+ oRange.setEnd( targetElement, targetElement.childNodes.length ) ;
+ break ;
+
+ case 3 : // Before Start ^<target>contents</target>
+ oRange.setEndBefore( targetElement ) ;
+ break ;
+
+ case 4 : // After End <target>contents</target>^
+ oRange.setEndAfter( targetElement ) ;
+ }
+
+ if ( !noInfoUpdate )
+ this._UpdateElementInfo() ;
+ },
+
+ Expand : function( unit )
+ {
+ var oNode, oSibling ;
+
+ switch ( unit )
+ {
+ // Expand the range to include all inline parent elements if we are
+ // are in their boundary limits.
+ // For example (where [ ] are the range limits):
+ // Before => Some <b>[<i>Some sample text]</i></b>.
+ // After => Some [<b><i>Some sample text</i></b>].
+ case 'inline_elements' :
+ // Expand the start boundary.
+ if ( this._Range.startOffset == 0 )
+ {
+ oNode = this._Range.startContainer ;
+
+ if ( oNode.nodeType != 1 )
+ oNode = oNode.previousSibling ? null : oNode.parentNode ;
+
+ if ( oNode )
+ {
+ while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
+ {
+ this._Range.setStartBefore( oNode ) ;
+
+ if ( oNode != oNode.parentNode.firstChild )
+ break ;
+
+ oNode = oNode.parentNode ;
+ }
+ }
+ }
+
+ // Expand the end boundary.
+ oNode = this._Range.endContainer ;
+ var offset = this._Range.endOffset ;
+
+ if ( ( oNode.nodeType == 3 && offset >= oNode.nodeValue.length ) || ( oNode.nodeType == 1 && offset >= oNode.childNodes.length ) || ( oNode.nodeType != 1 && oNode.nodeType != 3 ) )
+ {
+ if ( oNode.nodeType != 1 )
+ oNode = oNode.nextSibling ? null : oNode.parentNode ;
+
+ if ( oNode )
+ {
+ while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
+ {
+ this._Range.setEndAfter( oNode ) ;
+
+ if ( oNode != oNode.parentNode.lastChild )
+ break ;
+
+ oNode = oNode.parentNode ;
+ }
+ }
+ }
+
+ break ;
+
+ case 'block_contents' :
+ case 'list_contents' :
+ var boundarySet = FCKListsLib.BlockBoundaries ;
+ if ( unit == 'list_contents' || FCKConfig.EnterMode == 'br' )
+ boundarySet = FCKListsLib.ListBoundaries ;
+
+ if ( this.StartBlock && FCKConfig.EnterMode != 'br' && unit == 'block_contents' )
+ this.SetStart( this.StartBlock, 1 ) ;
+ else
+ {
+ // Get the start node for the current range.
+ oNode = this._Range.startContainer ;
+
+ // If it is an element, get the node right before of it (in source order).
+ if ( oNode.nodeType == 1 )
+ {
+ var lastNode = oNode.childNodes[ this._Range.startOffset ] ;
+ if ( lastNode )
+ oNode = FCKDomTools.GetPreviousSourceNode( lastNode, true ) ;
+ else
+ oNode = oNode.lastChild || oNode ;
+ }
+
+ // We must look for the left boundary, relative to the range
+ // start, which is limited by a block element.
+ while ( oNode
+ && ( oNode.nodeType != 1
+ || ( oNode != this.StartBlockLimit
+ && !boundarySet[ oNode.nodeName.toLowerCase() ] ) ) )
+ {
+ this._Range.setStartBefore( oNode ) ;
+ oNode = oNode.previousSibling || oNode.parentNode ;
+ }
+ }
+
+ if ( this.EndBlock && FCKConfig.EnterMode != 'br' && unit == 'block_contents' && this.EndBlock.nodeName.toLowerCase() != 'li' )
+ this.SetEnd( this.EndBlock, 2 ) ;
+ else
+ {
+ oNode = this._Range.endContainer ;
+ if ( oNode.nodeType == 1 )
+ oNode = oNode.childNodes[ this._Range.endOffset ] || oNode.lastChild ;
+
+ // We must look for the right boundary, relative to the range
+ // end, which is limited by a block element.
+ while ( oNode
+ && ( oNode.nodeType != 1
+ || ( oNode != this.StartBlockLimit
+ && !boundarySet[ oNode.nodeName.toLowerCase() ] ) ) )
+ {
+ this._Range.setEndAfter( oNode ) ;
+ oNode = oNode.nextSibling || oNode.parentNode ;
+ }
+
+ // In EnterMode='br', the end <br> boundary element must
+ // be included in the expanded range.
+ if ( oNode && oNode.nodeName.toLowerCase() == 'br' )
+ this._Range.setEndAfter( oNode ) ;
+ }
+
+ this._UpdateElementInfo() ;
+ }
+ },
+
+ /**
+ * Split the block element for the current range. It deletes the contents
+ * of the range and splits the block in the collapsed position, resulting
+ * in two sucessive blocks. The range is then positioned in the middle of
+ * them.
+ *
+ * It returns and object with the following properties:
+ * - PreviousBlock : a reference to the block element that preceeds
+ * the range after the split.
+ * - NextBlock : a reference to the block element that follows the
+ * range after the split.
+ * - WasStartOfBlock : a boolean indicating that the range was
+ * originaly at the start of the block.
+ * - WasEndOfBlock : a boolean indicating that the range was originaly
+ * at the end of the block.
+ *
+ * If the range was originaly at the start of the block, no split will happen
+ * and the PreviousBlock value will be null. The same is valid for the
+ * NextBlock value if the range was at the end of the block.
+ */
+ SplitBlock : function( forceBlockTag )
+ {
+ var blockTag = forceBlockTag || FCKConfig.EnterMode ;
+
+ if ( !this._Range )
+ this.MoveToSelection() ;
+
+ // The range boundaries must be in the same "block limit" element.
+ if ( this.StartBlockLimit == this.EndBlockLimit )
+ {
+ // Get the current blocks.
+ var eStartBlock = this.StartBlock ;
+ var eEndBlock = this.EndBlock ;
+ var oElementPath = null ;
+
+ if ( blockTag != 'br' )
+ {
+ if ( !eStartBlock )
+ {
+ eStartBlock = this.FixBlock( true, blockTag ) ;
+ eEndBlock = this.EndBlock ; // FixBlock may have fixed the EndBlock too.
+ }
+
+ if ( !eEndBlock )
+ eEndBlock = this.FixBlock( false, blockTag ) ;
+ }
+
+ // Get the range position.
+ var bIsStartOfBlock = ( eStartBlock != null && this.CheckStartOfBlock() ) ;
+ var bIsEndOfBlock = ( eEndBlock != null && this.CheckEndOfBlock() ) ;
+
+ // Delete the current contents.
+ if ( !this.CheckIsEmpty() )
+ this.DeleteContents() ;
+
+ if ( eStartBlock && eEndBlock && eStartBlock == eEndBlock )
+ {
+ if ( bIsEndOfBlock )
+ {
+ oElementPath = new FCKElementPath( this.StartContainer ) ;
+ this.MoveToPosition( eEndBlock, 4 ) ;
+ eEndBlock = null ;
+ }
+ else if ( bIsStartOfBlock )
+ {
+ oElementPath = new FCKElementPath( this.StartContainer ) ;
+ this.MoveToPosition( eStartBlock, 3 ) ;
+ eStartBlock = null ;
+ }
+ else
+ {
+ // Extract the contents of the block from the selection point to the end of its contents.
+ this.SetEnd( eStartBlock, 2 ) ;
+ var eDocFrag = this.ExtractContents() ;
+
+ // Duplicate the block element after it.
+ eEndBlock = eStartBlock.cloneNode( false ) ;
+ eEndBlock.removeAttribute( 'id', false ) ;
+
+ // Place the extracted contents in the duplicated block.
+ eDocFrag.AppendTo( eEndBlock ) ;
+
+ FCKDomTools.InsertAfterNode( eStartBlock, eEndBlock ) ;
+
+ this.MoveToPosition( eStartBlock, 4 ) ;
+
+ // In Gecko, the last child node must be a bogus <br>.
+ // Note: bogus <br> added under <ul> or <ol> would cause lists to be incorrectly rendered.
+ if ( FCKBrowserInfo.IsGecko &&
+ ! eStartBlock.nodeName.IEquals( ['ul', 'ol'] ) )
+ FCKTools.AppendBogusBr( eStartBlock ) ;
+ }
+ }
+
+ return {
+ PreviousBlock : eStartBlock,
+ NextBlock : eEndBlock,
+ WasStartOfBlock : bIsStartOfBlock,
+ WasEndOfBlock : bIsEndOfBlock,
+ ElementPath : oElementPath
+ } ;
+ }
+
+ return null ;
+ },
+
+ // Transform a block without a block tag in a valid block (orphan text in the body or td, usually).
+ FixBlock : function( isStart, blockTag )
+ {
+ // Bookmark the range so we can restore it later.
+ var oBookmark = this.CreateBookmark() ;
+
+ // Collapse the range to the requested ending boundary.
+ this.Collapse( isStart ) ;
+
+ // Expands it to the block contents.
+ this.Expand( 'block_contents' ) ;
+
+ // Create the fixed block.
+ var oFixedBlock = this.Window.document.createElement( blockTag ) ;
+
+ // Move the contents of the temporary range to the fixed block.
+ this.ExtractContents().AppendTo( oFixedBlock ) ;
+ FCKDomTools.TrimNode( oFixedBlock ) ;
+
+ // If the fixed block is empty (not counting bookmark nodes)
+ // Add a <br /> inside to expand it.
+ if ( FCKDomTools.CheckIsEmptyElement(oFixedBlock, function( element ) { return element.getAttribute('_fck_bookmark') != 'true' ; } )
+ && FCKBrowserInfo.IsGeckoLike )
+ FCKTools.AppendBogusBr( oFixedBlock ) ;
+
+ // Insert the fixed block into the DOM.
+ this.InsertNode( oFixedBlock ) ;
+
+ // Move the range back to the bookmarked place.
+ this.MoveToBookmark( oBookmark ) ;
+
+ return oFixedBlock ;
+ },
+
+ Release : function( preserveWindow )
+ {
+ if ( !preserveWindow )
+ this.Window = null ;
+
+ this.StartNode = null ;
+ this.StartContainer = null ;
+ this.StartBlock = null ;
+ this.StartBlockLimit = null ;
+ this.EndNode = null ;
+ this.EndContainer = null ;
+ this.EndBlock = null ;
+ this.EndBlockLimit = null ;
+ this._Range = null ;
+ this._Cache = null ;
+ },
+
+ CheckHasRange : function()
+ {
+ return !!this._Range ;
+ },
+
+ GetTouchedStartNode : function()
+ {
+ var range = this._Range ;
+ var container = range.startContainer ;
+
+ if ( range.collapsed || container.nodeType != 1 )
+ return container ;
+
+ return container.childNodes[ range.startOffset ] || container ;
+ },
+
+ GetTouchedEndNode : function()
+ {
+ var range = this._Range ;
+ var container = range.endContainer ;
+
+ if ( range.collapsed || container.nodeType != 1 )
+ return container ;
+
+ return container.childNodes[ range.endOffset - 1 ] || container ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_gecko.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_gecko.js
new file mode 100644
index 0000000..45d7c1c
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_gecko.js
@@ -0,0 +1,104 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Class for working with a selection range, much like the W3C DOM Range, but
+ * it is not intended to be an implementation of the W3C interface.
+ * (Gecko Implementation)
+ */
+
+FCKDomRange.prototype.MoveToSelection = function()
+{
+ this.Release( true ) ;
+
+ var oSel = this.Window.getSelection() ;
+
+ if ( oSel && oSel.rangeCount > 0 )
+ {
+ this._Range = FCKW3CRange.CreateFromRange( this.Window.document, oSel.getRangeAt(0) ) ;
+ this._UpdateElementInfo() ;
+ }
+ else
+ if ( this.Window.document )
+ this.MoveToElementStart( this.Window.document.body ) ;
+}
+
+FCKDomRange.prototype.Select = function()
+{
+ var oRange = this._Range ;
+ if ( oRange )
+ {
+ var startContainer = oRange.startContainer ;
+
+ // If we have a collapsed range, inside an empty element, we must add
+ // something to it, otherwise the caret will not be visible.
+ if ( oRange.collapsed && startContainer.nodeType == 1 && startContainer.childNodes.length == 0 )
+ startContainer.appendChild( oRange._Document.createTextNode('') ) ;
+
+ var oDocRange = this.Window.document.createRange() ;
+ oDocRange.setStart( startContainer, oRange.startOffset ) ;
+
+ try
+ {
+ oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
+ }
+ catch ( e )
+ {
+ // There is a bug in Firefox implementation (it would be too easy
+ // otherwise). The new start can't be after the end (W3C says it can).
+ // So, let's create a new range and collapse it to the desired point.
+ if ( e.toString().Contains( 'NS_ERROR_ILLEGAL_VALUE' ) )
+ {
+ oRange.collapse( true ) ;
+ oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
+ }
+ else
+ throw( e ) ;
+ }
+
+ var oSel = this.Window.getSelection() ;
+ oSel.removeAllRanges() ;
+
+ // We must add a clone otherwise Firefox will have rendering issues.
+ oSel.addRange( oDocRange ) ;
+ }
+}
+
+// Not compatible with bookmark created with CreateBookmark2.
+// The bookmark nodes will be deleted from the document.
+FCKDomRange.prototype.SelectBookmark = function( bookmark )
+{
+ var domRange = this.Window.document.createRange() ;
+
+ var startNode = this.GetBookmarkNode( bookmark, true ) ;
+ var endNode = this.GetBookmarkNode( bookmark, false ) ;
+
+ domRange.setStart( startNode.parentNode, FCKDomTools.GetIndexOf( startNode ) ) ;
+ FCKDomTools.RemoveNode( startNode ) ;
+
+ if ( endNode )
+ {
+ domRange.setEnd( endNode.parentNode, FCKDomTools.GetIndexOf( endNode ) ) ;
+ FCKDomTools.RemoveNode( endNode ) ;
+ }
+
+ var selection = this.Window.getSelection() ;
+ selection.removeAllRanges() ;
+ selection.addRange( domRange ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_ie.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_ie.js
new file mode 100644
index 0000000..0773afd
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrange_ie.js
@@ -0,0 +1,199 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Class for working with a selection range, much like the W3C DOM Range, but
+ * it is not intended to be an implementation of the W3C interface.
+ * (IE Implementation)
+ */
+
+FCKDomRange.prototype.MoveToSelection = function()
+{
+ this.Release( true ) ;
+
+ this._Range = new FCKW3CRange( this.Window.document ) ;
+
+ var oSel = this.Window.document.selection ;
+
+ if ( oSel.type != 'Control' )
+ {
+ var eMarkerStart = this._GetSelectionMarkerTag( true ) ;
+ var eMarkerEnd = this._GetSelectionMarkerTag( false ) ;
+
+ if ( !eMarkerStart && !eMarkerEnd )
+ {
+ this._Range.setStart( this.Window.document.body, 0 ) ;
+ this._UpdateElementInfo() ;
+ return ;
+ }
+
+ // Set the start boundary.
+ this._Range.setStart( eMarkerStart.parentNode, FCKDomTools.GetIndexOf( eMarkerStart ) ) ;
+ eMarkerStart.parentNode.removeChild( eMarkerStart ) ;
+
+ // Set the end boundary.
+ this._Range.setEnd( eMarkerEnd.parentNode, FCKDomTools.GetIndexOf( eMarkerEnd ) ) ;
+ eMarkerEnd.parentNode.removeChild( eMarkerEnd ) ;
+
+ this._UpdateElementInfo() ;
+ }
+ else
+ {
+ var oControl = oSel.createRange().item(0) ;
+
+ if ( oControl )
+ {
+ this._Range.setStartBefore( oControl ) ;
+ this._Range.setEndAfter( oControl ) ;
+ this._UpdateElementInfo() ;
+ }
+ }
+}
+
+FCKDomRange.prototype.Select = function( forceExpand )
+{
+ if ( this._Range )
+ this.SelectBookmark( this.CreateBookmark( true ), forceExpand ) ;
+}
+
+// Not compatible with bookmark created with CreateBookmark2.
+// The bookmark nodes will be deleted from the document.
+FCKDomRange.prototype.SelectBookmark = function( bookmark, forceExpand )
+{
+ var bIsCollapsed = this.CheckIsCollapsed() ;
+ var bIsStartMakerAlone ;
+ var dummySpan ;
+
+ // Create marker tags for the start and end boundaries.
+ var eStartMarker = this.GetBookmarkNode( bookmark, true ) ;
+
+ if ( !eStartMarker )
+ return ;
+
+ var eEndMarker ;
+ if ( !bIsCollapsed )
+ eEndMarker = this.GetBookmarkNode( bookmark, false ) ;
+
+ // Create the main range which will be used for the selection.
+ var oIERange = this.Window.document.body.createTextRange() ;
+
+ // Position the range at the start boundary.
+ oIERange.moveToElementText( eStartMarker ) ;
+ oIERange.moveStart( 'character', 1 ) ;
+
+ if ( eEndMarker )
+ {
+ // Create a tool range for the end.
+ var oIERangeEnd = this.Window.document.body.createTextRange() ;
+
+ // Position the tool range at the end.
+ oIERangeEnd.moveToElementText( eEndMarker ) ;
+
+ // Move the end boundary of the main range to match the tool range.
+ oIERange.setEndPoint( 'EndToEnd', oIERangeEnd ) ;
+ oIERange.moveEnd( 'character', -1 ) ;
+ }
+ else
+ {
+ bIsStartMakerAlone = ( forceExpand || !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ;
+
+ // Append a temporary <span>&#65279;</span> before the selection.
+ // This is needed to avoid IE destroying selections inside empty
+ // inline elements, like <b></b> (#253).
+ // It is also needed when placing the selection right after an inline
+ // element to avoid the selection moving inside of it.
+ dummySpan = this.Window.document.createElement( 'span' ) ;
+ dummySpan.innerHTML = '&#65279;' ; // Zero Width No-Break Space (U+FEFF). See #1359.
+ eStartMarker.parentNode.insertBefore( dummySpan, eStartMarker ) ;
+
+ if ( bIsStartMakerAlone )
+ {
+ // To expand empty blocks or line spaces after <br>, we need
+ // instead to have any char, which will be later deleted using the
+ // selection.
+ // \ufeff = Zero Width No-Break Space (U+FEFF). See #1359.
+ eStartMarker.parentNode.insertBefore( this.Window.document.createTextNode( '\ufeff' ), eStartMarker ) ;
+ }
+ }
+
+ if ( !this._Range )
+ this._Range = this.CreateRange() ;
+
+ // Remove the markers (reset the position, because of the changes in the DOM tree).
+ this._Range.setStartBefore( eStartMarker ) ;
+ eStartMarker.parentNode.removeChild( eStartMarker ) ;
+
+ if ( bIsCollapsed )
+ {
+ if ( bIsStartMakerAlone )
+ {
+ // Move the selection start to include the temporary &#65279;.
+ oIERange.moveStart( 'character', -1 ) ;
+
+ oIERange.select() ;
+
+ // Remove our temporary stuff.
+ this.Window.document.selection.clear() ;
+ }
+ else
+ oIERange.select() ;
+
+ FCKDomTools.RemoveNode( dummySpan ) ;
+ }
+ else
+ {
+ this._Range.setEndBefore( eEndMarker ) ;
+ eEndMarker.parentNode.removeChild( eEndMarker ) ;
+ oIERange.select() ;
+ }
+}
+
+FCKDomRange.prototype._GetSelectionMarkerTag = function( toStart )
+{
+ var doc = this.Window.document ;
+ var selection = doc.selection ;
+
+ // Get a range for the start boundary.
+ var oRange ;
+
+ // IE may throw an "unspecified error" on some cases (it happened when
+ // loading _samples/default.html), so try/catch.
+ try
+ {
+ oRange = selection.createRange() ;
+ }
+ catch (e)
+ {
+ return null ;
+ }
+
+ // IE might take the range object to the main window instead of inside the editor iframe window.
+ // This is known to happen when the editor window has not been selected before (See #933).
+ // We need to avoid that.
+ if ( oRange.parentElement().document != doc )
+ return null ;
+
+ oRange.collapse( toStart === true ) ;
+
+ // Paste a marker element at the collapsed range and get it from the DOM.
+ var sMarkerId = 'fck_dom_range_temp_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000) ;
+ oRange.pasteHTML( '<span id="' + sMarkerId + '"></span>' ) ;
+
+ return doc.getElementById( sMarkerId ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrangeiterator.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrangeiterator.js
new file mode 100644
index 0000000..962b8b1
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckdomrangeiterator.js
@@ -0,0 +1,327 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class can be used to interate through nodes inside a range.
+ *
+ * During interation, the provided range can become invalid, due to document
+ * mutations, so CreateBookmark() used to restore it after processing, if
+ * needed.
+ */
+
+var FCKDomRangeIterator = function( range )
+{
+ /**
+ * The FCKDomRange object that marks the interation boundaries.
+ */
+ this.Range = range ;
+
+ /**
+ * Indicates that <br> elements must be used as paragraph boundaries.
+ */
+ this.ForceBrBreak = false ;
+
+ /**
+ * Guarantees that the iterator will always return "real" block elements.
+ * If "false", elements like <li>, <th> and <td> are returned. If "true", a
+ * dedicated block element block element will be created inside those
+ * elements to hold the selected content.
+ */
+ this.EnforceRealBlocks = false ;
+}
+
+FCKDomRangeIterator.CreateFromSelection = function( targetWindow )
+{
+ var range = new FCKDomRange( targetWindow ) ;
+ range.MoveToSelection() ;
+ return new FCKDomRangeIterator( range ) ;
+}
+
+FCKDomRangeIterator.prototype =
+{
+ /**
+ * Get the next paragraph element. It automatically breaks the document
+ * when necessary to generate block elements for the paragraphs.
+ */
+ GetNextParagraph : function()
+ {
+ // The block element to be returned.
+ var block ;
+
+ // The range object used to identify the paragraph contents.
+ var range ;
+
+ // Indicated that the current element in the loop is the last one.
+ var isLast ;
+
+ // Instructs to cleanup remaining BRs.
+ var removePreviousBr ;
+ var removeLastBr ;
+
+ var boundarySet = this.ForceBrBreak ? FCKListsLib.ListBoundaries : FCKListsLib.BlockBoundaries ;
+
+ // This is the first iteration. Let's initialize it.
+ if ( !this._LastNode )
+ {
+ var range = this.Range.Clone() ;
+ range.Expand( this.ForceBrBreak ? 'list_contents' : 'block_contents' ) ;
+
+ this._NextNode = range.GetTouchedStartNode() ;
+ this._LastNode = range.GetTouchedEndNode() ;
+
+ // Let's reuse this variable.
+ range = null ;
+ }
+
+ var currentNode = this._NextNode ;
+ var lastNode = this._LastNode ;
+
+ this._NextNode = null ;
+
+ while ( currentNode )
+ {
+ // closeRange indicates that a paragraph boundary has been found,
+ // so the range can be closed.
+ var closeRange = false ;
+
+ // includeNode indicates that the current node is good to be part
+ // of the range. By default, any non-element node is ok for it.
+ var includeNode = ( currentNode.nodeType != 1 ) ;
+
+ var continueFromSibling = false ;
+
+ // If it is an element node, let's check if it can be part of the
+ // range.
+ if ( !includeNode )
+ {
+ var nodeName = currentNode.nodeName.toLowerCase() ;
+
+ if ( boundarySet[ nodeName ] && ( !FCKBrowserInfo.IsIE || currentNode.scopeName == 'HTML' ) )
+ {
+ // <br> boundaries must be part of the range. It will
+ // happen only if ForceBrBreak.
+ if ( nodeName == 'br' )
+ includeNode = true ;
+ else if ( !range && currentNode.childNodes.length == 0 && nodeName != 'hr' )
+ {
+ // If we have found an empty block, and haven't started
+ // the range yet, it means we must return this block.
+ block = currentNode ;
+ isLast = currentNode == lastNode ;
+ break ;
+ }
+
+ // The range must finish right before the boundary,
+ // including possibly skipped empty spaces. (#1603)
+ if ( range )
+ {
+ range.SetEnd( currentNode, 3, true ) ;
+
+ // The found boundary must be set as the next one at this
+ // point. (#1717)
+ if ( nodeName != 'br' )
+ this._NextNode = FCKDomTools.GetNextSourceNode( currentNode, true, null, lastNode ) || currentNode ;
+ }
+
+ closeRange = true ;
+ }
+ else
+ {
+ // If we have child nodes, let's check them.
+ if ( currentNode.firstChild )
+ {
+ // If we don't have a range yet, let's start it.
+ if ( !range )
+ {
+ range = new FCKDomRange( this.Range.Window ) ;
+ range.SetStart( currentNode, 3, true ) ;
+ }
+
+ currentNode = currentNode.firstChild ;
+ continue ;
+ }
+ includeNode = true ;
+ }
+ }
+ else if ( currentNode.nodeType == 3 )
+ {
+ // Ignore normal whitespaces (i.e. not including &nbsp; or
+ // other unicode whitespaces) before/after a block node.
+ if ( /^[\r\n\t ]+$/.test( currentNode.nodeValue ) )
+ includeNode = false ;
+ }
+
+ // The current node is good to be part of the range and we are
+ // starting a new range, initialize it first.
+ if ( includeNode && !range )
+ {
+ range = new FCKDomRange( this.Range.Window ) ;
+ range.SetStart( currentNode, 3, true ) ;
+ }
+
+ // The last node has been found.
+ isLast = ( ( !closeRange || includeNode ) && currentNode == lastNode ) ;
+// isLast = ( currentNode == lastNode && ( currentNode.nodeType != 1 || currentNode.childNodes.length == 0 ) ) ;
+
+ // If we are in an element boundary, let's check if it is time
+ // to close the range, otherwise we include the parent within it.
+ if ( range && !closeRange )
+ {
+ while ( !currentNode.nextSibling && !isLast )
+ {
+ var parentNode = currentNode.parentNode ;
+
+ if ( boundarySet[ parentNode.nodeName.toLowerCase() ] )
+ {
+ closeRange = true ;
+ isLast = isLast || ( parentNode == lastNode ) ;
+ break ;
+ }
+
+ currentNode = parentNode ;
+ includeNode = true ;
+ isLast = ( currentNode == lastNode ) ;
+ continueFromSibling = true ;
+ }
+ }
+
+ // Now finally include the node.
+ if ( includeNode )
+ range.SetEnd( currentNode, 4, true ) ;
+
+ // We have found a block boundary. Let's close the range and move out of the
+ // loop.
+ if ( ( closeRange || isLast ) && range )
+ {
+ range._UpdateElementInfo() ;
+
+ if ( range.StartNode == range.EndNode
+ && range.StartNode.parentNode == range.StartBlockLimit
+ && range.StartNode.getAttribute && range.StartNode.getAttribute( '_fck_bookmark' ) )
+ range = null ;
+ else
+ break ;
+ }
+
+ if ( isLast )
+ break ;
+
+ currentNode = FCKDomTools.GetNextSourceNode( currentNode, continueFromSibling, null, lastNode ) ;
+ }
+
+ // Now, based on the processed range, look for (or create) the block to be returned.
+ if ( !block )
+ {
+ // If no range has been found, this is the end.
+ if ( !range )
+ {
+ this._NextNode = null ;
+ return null ;
+ }
+
+ block = range.StartBlock ;
+
+ if ( !block
+ && !this.EnforceRealBlocks
+ && range.StartBlockLimit.nodeName.IEquals( 'DIV', 'TH', 'TD' )
+ && range.CheckStartOfBlock()
+ && range.CheckEndOfBlock() )
+ {
+ block = range.StartBlockLimit ;
+ }
+ else if ( !block || ( this.EnforceRealBlocks && block.nodeName.toLowerCase() == 'li' ) )
+ {
+ // Create the fixed block.
+ block = this.Range.Window.document.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
+
+ // Move the contents of the temporary range to the fixed block.
+ range.ExtractContents().AppendTo( block ) ;
+ FCKDomTools.TrimNode( block ) ;
+
+ // Insert the fixed block into the DOM.
+ range.InsertNode( block ) ;
+
+ removePreviousBr = true ;
+ removeLastBr = true ;
+ }
+ else if ( block.nodeName.toLowerCase() != 'li' )
+ {
+ // If the range doesn't includes the entire contents of the
+ // block, we must split it, isolating the range in a dedicated
+ // block.
+ if ( !range.CheckStartOfBlock() || !range.CheckEndOfBlock() )
+ {
+ // The resulting block will be a clone of the current one.
+ block = block.cloneNode( false ) ;
+
+ // Extract the range contents, moving it to the new block.
+ range.ExtractContents().AppendTo( block ) ;
+ FCKDomTools.TrimNode( block ) ;
+
+ // Split the block. At this point, the range will be in the
+ // right position for our intents.
+ var splitInfo = range.SplitBlock() ;
+
+ removePreviousBr = !splitInfo.WasStartOfBlock ;
+ removeLastBr = !splitInfo.WasEndOfBlock ;
+
+ // Insert the new block into the DOM.
+ range.InsertNode( block ) ;
+ }
+ }
+ else if ( !isLast )
+ {
+ // LIs are returned as is, with all their children (due to the
+ // nested lists). But, the next node is the node right after
+ // the current range, which could be an <li> child (nested
+ // lists) or the next sibling <li>.
+
+ this._NextNode = block == lastNode ? null : FCKDomTools.GetNextSourceNode( range.EndNode, true, null, lastNode ) ;
+ return block ;
+ }
+ }
+
+ if ( removePreviousBr )
+ {
+ var previousSibling = block.previousSibling ;
+ if ( previousSibling && previousSibling.nodeType == 1 )
+ {
+ if ( previousSibling.nodeName.toLowerCase() == 'br' )
+ previousSibling.parentNode.removeChild( previousSibling ) ;
+ else if ( previousSibling.lastChild && previousSibling.lastChild.nodeName.IEquals( 'br' ) )
+ previousSibling.removeChild( previousSibling.lastChild ) ;
+ }
+ }
+
+ if ( removeLastBr )
+ {
+ var lastChild = block.lastChild ;
+ if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName.toLowerCase() == 'br' )
+ block.removeChild( lastChild ) ;
+ }
+
+ // Get a reference for the next element. This is important because the
+ // above block can be removed or changed, so we can rely on it for the
+ // next interation.
+ if ( !this._NextNode )
+ this._NextNode = ( isLast || block == lastNode ) ? null : FCKDomTools.GetNextSourceNode( block, true, null, lastNode ) ;
+
+ return block ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckeditingarea.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckeditingarea.js
new file mode 100644
index 0000000..4f7044e
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckeditingarea.js
@@ -0,0 +1,368 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKEditingArea Class: renders an editable area.
+ */
+
+/**
+ * @constructor
+ * @param {String} targetElement The element that will hold the editing area. Any child element present in the target will be deleted.
+ */
+var FCKEditingArea = function( targetElement )
+{
+ this.TargetElement = targetElement ;
+ this.Mode = FCK_EDITMODE_WYSIWYG ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKEditingArea_Cleanup ) ;
+}
+
+
+/**
+ * @param {String} html The complete HTML for the page, including DOCTYPE and the <html> tag.
+ */
+FCKEditingArea.prototype.Start = function( html, secondCall )
+{
+ var eTargetElement = this.TargetElement ;
+ var oTargetDocument = FCKTools.GetElementDocument( eTargetElement ) ;
+
+ // Remove all child nodes from the target.
+ while( eTargetElement.firstChild )
+ eTargetElement.removeChild( eTargetElement.firstChild ) ;
+
+ if ( this.Mode == FCK_EDITMODE_WYSIWYG )
+ {
+ // For FF, document.domain must be set only when different, otherwhise
+ // we'll strangely have "Permission denied" issues.
+ if ( FCK_IS_CUSTOM_DOMAIN )
+ html = '<script>document.domain="' + FCK_RUNTIME_DOMAIN + '";</script>' + html ;
+
+ // IE has a bug with the <base> tag... it must have a </base> closer,
+ // otherwise the all successive tags will be set as children nodes of the <base>.
+ if ( FCKBrowserInfo.IsIE )
+ html = html.replace( /(<base[^>]*?)\s*\/?>(?!\s*<\/base>)/gi, '$1></base>' ) ;
+ else if ( !secondCall )
+ {
+ // Gecko moves some tags out of the body to the head, so we must use
+ // innerHTML to set the body contents (SF BUG 1526154).
+
+ // Extract the BODY contents from the html.
+ var oMatchBefore = html.match( FCKRegexLib.BeforeBody ) ;
+ var oMatchAfter = html.match( FCKRegexLib.AfterBody ) ;
+
+ if ( oMatchBefore && oMatchAfter )
+ {
+ var sBody = html.substr( oMatchBefore[1].length,
+ html.length - oMatchBefore[1].length - oMatchAfter[1].length ) ; // This is the BODY tag contents.
+
+ html =
+ oMatchBefore[1] + // This is the HTML until the <body...> tag, inclusive.
+ '&nbsp;' +
+ oMatchAfter[1] ; // This is the HTML from the </body> tag, inclusive.
+
+ // If nothing in the body, place a BOGUS tag so the cursor will appear.
+ if ( FCKBrowserInfo.IsGecko && ( sBody.length == 0 || FCKRegexLib.EmptyParagraph.test( sBody ) ) )
+ sBody = '<br type="_moz">' ;
+
+ this._BodyHTML = sBody ;
+
+ }
+ else
+ this._BodyHTML = html ; // Invalid HTML input.
+ }
+
+ // Create the editing area IFRAME.
+ var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ;
+
+ // IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
+ // See #1055.
+ var sOverrideError = '<script type="text/javascript" _fcktemp="true">window.onerror=function(){return true;};</script>' ;
+
+ oIFrame.frameBorder = 0 ;
+ oIFrame.style.width = oIFrame.style.height = '100%' ;
+
+ if ( FCK_IS_CUSTOM_DOMAIN && FCKBrowserInfo.IsIE )
+ {
+ window._FCKHtmlToLoad = html.replace( /<head>/i, '<head>' + sOverrideError ) ;
+ oIFrame.src = 'javascript:void( (function(){' +
+ 'document.open() ;' +
+ 'document.domain="' + document.domain + '" ;' +
+ 'document.write( window.parent._FCKHtmlToLoad );' +
+ 'document.close() ;' +
+ 'window.parent._FCKHtmlToLoad = null ;' +
+ '})() )' ;
+ }
+ else if ( !FCKBrowserInfo.IsGecko )
+ {
+ // Firefox will render the tables inside the body in Quirks mode if the
+ // source of the iframe is set to javascript. see #515
+ oIFrame.src = 'javascript:void(0)' ;
+ }
+
+ // Append the new IFRAME to the target. For IE, it must be done after
+ // setting the "src", to avoid the "secure/unsecure" message under HTTPS.
+ eTargetElement.appendChild( oIFrame ) ;
+
+ // Get the window and document objects used to interact with the newly created IFRAME.
+ this.Window = oIFrame.contentWindow ;
+
+ // IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
+ // TODO: This error handler is not being fired.
+ // this.Window.onerror = function() { alert( 'Error!' ) ; return true ; }
+
+ if ( !FCK_IS_CUSTOM_DOMAIN || !FCKBrowserInfo.IsIE )
+ {
+ var oDoc = this.Window.document ;
+
+ oDoc.open() ;
+ oDoc.write( html.replace( /<head>/i, '<head>' + sOverrideError ) ) ;
+ oDoc.close() ;
+ }
+
+ if ( FCKBrowserInfo.IsAIR )
+ FCKAdobeAIR.EditingArea_Start( oDoc, html ) ;
+
+ // Firefox 1.0.x is buggy... ohh yes... so let's do it two times and it
+ // will magically work.
+ if ( FCKBrowserInfo.IsGecko10 && !secondCall )
+ {
+ this.Start( html, true ) ;
+ return ;
+ }
+
+ if ( oIFrame.readyState && oIFrame.readyState != 'completed' )
+ {
+ var editArea = this ;
+
+ // Using a IE alternative for DOMContentLoaded, similar to the
+ // solution proposed at http://javascript.nwbox.com/IEContentLoaded/
+ setTimeout( function()
+ {
+ try
+ {
+ editArea.Window.document.documentElement.doScroll("left") ;
+ }
+ catch(e)
+ {
+ setTimeout( arguments.callee, 0 ) ;
+ return ;
+ }
+ editArea.Window._FCKEditingArea = editArea ;
+ FCKEditingArea_CompleteStart.call( editArea.Window ) ;
+ }, 0 ) ;
+ }
+ else
+ {
+ this.Window._FCKEditingArea = this ;
+
+ // FF 1.0.x is buggy... we must wait a lot to enable editing because
+ // sometimes the content simply disappears, for example when pasting
+ // "bla1!<img src='some_url'>!bla2" in the source and then switching
+ // back to design.
+ if ( FCKBrowserInfo.IsGecko10 )
+ this.Window.setTimeout( FCKEditingArea_CompleteStart, 500 ) ;
+ else
+ FCKEditingArea_CompleteStart.call( this.Window ) ;
+ }
+ }
+ else
+ {
+ var eTextarea = this.Textarea = oTargetDocument.createElement( 'textarea' ) ;
+ eTextarea.className = 'SourceField' ;
+ eTextarea.dir = 'ltr' ;
+ FCKDomTools.SetElementStyles( eTextarea,
+ {
+ width : '100%',
+ height : '100%',
+ border : 'none',
+ resize : 'none',
+ outline : 'none'
+ } ) ;
+ eTargetElement.appendChild( eTextarea ) ;
+
+ eTextarea.value = html ;
+
+ // Fire the "OnLoad" event.
+ FCKTools.RunFunction( this.OnLoad ) ;
+ }
+}
+
+// "this" here is FCKEditingArea.Window
+function FCKEditingArea_CompleteStart()
+{
+ // On Firefox, the DOM takes a little to become available. So we must wait for it in a loop.
+ if ( !this.document.body )
+ {
+ this.setTimeout( FCKEditingArea_CompleteStart, 50 ) ;
+ return ;
+ }
+
+ var oEditorArea = this._FCKEditingArea ;
+
+ // Save this reference to be re-used later.
+ oEditorArea.Document = oEditorArea.Window.document ;
+
+ oEditorArea.MakeEditable() ;
+
+ // Fire the "OnLoad" event.
+ FCKTools.RunFunction( oEditorArea.OnLoad ) ;
+}
+
+FCKEditingArea.prototype.MakeEditable = function()
+{
+ var oDoc = this.Document ;
+
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // Kludge for #141 and #523
+ oDoc.body.disabled = true ;
+ oDoc.body.contentEditable = true ;
+ oDoc.body.removeAttribute( "disabled" ) ;
+
+ /* The following commands don't throw errors, but have no effect.
+ oDoc.execCommand( 'AutoDetect', false, false ) ;
+ oDoc.execCommand( 'KeepSelection', false, true ) ;
+ */
+ }
+ else
+ {
+ try
+ {
+ // Disable Firefox 2 Spell Checker.
+ oDoc.body.spellcheck = ( this.FFSpellChecker !== false ) ;
+
+ if ( this._BodyHTML )
+ {
+ oDoc.body.innerHTML = this._BodyHTML ;
+ oDoc.body.offsetLeft ; // Don't remove, this is a hack to fix Opera 9.50, see #2264.
+ this._BodyHTML = null ;
+ }
+
+ oDoc.designMode = 'on' ;
+
+ // Tell Gecko (Firefox 1.5+) to enable or not live resizing of objects (by Alfonso Martinez)
+ oDoc.execCommand( 'enableObjectResizing', false, !FCKConfig.DisableObjectResizing ) ;
+
+ // Disable the standard table editing features of Firefox.
+ oDoc.execCommand( 'enableInlineTableEditing', false, !FCKConfig.DisableFFTableHandles ) ;
+ }
+ catch (e)
+ {
+ // In Firefox if the iframe is initially hidden it can't be set to designMode and it raises an exception
+ // So we set up a DOM Mutation event Listener on the HTML, as it will raise several events when the document is visible again
+ FCKTools.AddEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
+ }
+
+ }
+}
+
+// This function processes the notifications of the DOM Mutation event on the document
+// We use it to know that the document will be ready to be editable again (or we hope so)
+function FCKEditingArea_Document_AttributeNodeModified( evt )
+{
+ var editingArea = evt.currentTarget.contentWindow._FCKEditingArea ;
+
+ // We want to run our function after the events no longer fire, so we can know that it's a stable situation
+ if ( editingArea._timer )
+ window.clearTimeout( editingArea._timer ) ;
+
+ editingArea._timer = FCKTools.SetTimeout( FCKEditingArea_MakeEditableByMutation, 1000, editingArea ) ;
+}
+
+// This function ideally should be called after the document is visible, it does clean up of the
+// mutation tracking and tries again to make the area editable.
+function FCKEditingArea_MakeEditableByMutation()
+{
+ // Clean up
+ delete this._timer ;
+ // Now we don't want to keep on getting this event
+ FCKTools.RemoveEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
+ // Let's try now to set the editing area editable
+ // If it fails it will set up the Mutation Listener again automatically
+ this.MakeEditable() ;
+}
+
+FCKEditingArea.prototype.Focus = function()
+{
+ try
+ {
+ if ( this.Mode == FCK_EDITMODE_WYSIWYG )
+ {
+ if ( FCKBrowserInfo.IsIE )
+ this._FocusIE() ;
+ else
+ this.Window.focus() ;
+ }
+ else
+ {
+ var oDoc = FCKTools.GetElementDocument( this.Textarea ) ;
+ if ( (!oDoc.hasFocus || oDoc.hasFocus() ) && oDoc.activeElement == this.Textarea )
+ return ;
+
+ this.Textarea.focus() ;
+ }
+ }
+ catch(e) {}
+}
+
+FCKEditingArea.prototype._FocusIE = function()
+{
+ // In IE it can happen that the document is in theory focused but the
+ // active element is outside of it.
+ this.Document.body.setActive() ;
+
+ this.Window.focus() ;
+
+ // Kludge for #141... yet more code to workaround IE bugs
+ var range = this.Document.selection.createRange() ;
+
+ var parentNode = range.parentElement() ;
+ var parentTag = parentNode.nodeName.toLowerCase() ;
+
+ // Only apply the fix when in a block, and the block is empty.
+ if ( parentNode.childNodes.length > 0 ||
+ !( FCKListsLib.BlockElements[parentTag] ||
+ FCKListsLib.NonEmptyBlockElements[parentTag] ) )
+ {
+ return ;
+ }
+
+ // Force the selection to happen, in this way we guarantee the focus will
+ // be there.
+ range = new FCKDomRange( this.Window ) ;
+ range.MoveToElementEditStart( parentNode ) ;
+ range.Select() ;
+}
+
+function FCKEditingArea_Cleanup()
+{
+ if ( this.Document )
+ this.Document.body.innerHTML = "" ;
+ this.TargetElement = null ;
+ this.IFrame = null ;
+ this.Document = null ;
+ this.Textarea = null ;
+
+ if ( this.Window )
+ {
+ this.Window._FCKEditingArea = null ;
+ this.Window = null ;
+ }
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckelementpath.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckelementpath.js
new file mode 100644
index 0000000..488b19f
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckelementpath.js
@@ -0,0 +1,89 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Manages the DOM ascensors element list of a specific DOM node
+ * (limited to body, inclusive).
+ */
+
+var FCKElementPath = function( lastNode )
+{
+ var eBlock = null ;
+ var eBlockLimit = null ;
+
+ var aElements = new Array() ;
+
+ var e = lastNode ;
+ while ( e )
+ {
+ if ( e.nodeType == 1 )
+ {
+ if ( !this.LastElement )
+ this.LastElement = e ;
+
+ var sElementName = e.nodeName.toLowerCase() ;
+ if ( FCKBrowserInfo.IsIE && e.scopeName != 'HTML' )
+ sElementName = e.scopeName.toLowerCase() + ':' + sElementName ;
+
+ if ( !eBlockLimit )
+ {
+ if ( !eBlock && FCKListsLib.PathBlockElements[ sElementName ] != null )
+ eBlock = e ;
+
+ if ( FCKListsLib.PathBlockLimitElements[ sElementName ] != null )
+ {
+ // DIV is considered the Block, if no block is available (#525)
+ // and if it doesn't contain other blocks.
+ if ( !eBlock && sElementName == 'div' && !FCKElementPath._CheckHasBlock( e ) )
+ eBlock = e ;
+ else
+ eBlockLimit = e ;
+ }
+ }
+
+ aElements.push( e ) ;
+
+ if ( sElementName == 'body' )
+ break ;
+ }
+ e = e.parentNode ;
+ }
+
+ this.Block = eBlock ;
+ this.BlockLimit = eBlockLimit ;
+ this.Elements = aElements ;
+}
+
+/**
+ * Check if an element contains any block element.
+ */
+FCKElementPath._CheckHasBlock = function( element )
+{
+ var childNodes = element.childNodes ;
+
+ for ( var i = 0, count = childNodes.length ; i < count ; i++ )
+ {
+ var child = childNodes[i] ;
+
+ if ( child.nodeType == 1 && FCKListsLib.BlockElements[ child.nodeName.toLowerCase() ] )
+ return true ;
+ }
+
+ return false ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckenterkey.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckenterkey.js
new file mode 100644
index 0000000..8819a19
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckenterkey.js
@@ -0,0 +1,708 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Controls the [Enter] keystroke behavior in a document.
+ */
+
+/*
+ * Constructor.
+ * @targetDocument : the target document.
+ * @enterMode : the behavior for the <Enter> keystroke.
+ * May be "p", "div", "br". Default is "p".
+ * @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke.
+ * May be "p", "div", "br". Defaults to "br".
+ */
+var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode, tabSpaces )
+{
+ this.Window = targetWindow ;
+ this.EnterMode = enterMode || 'p' ;
+ this.ShiftEnterMode = shiftEnterMode || 'br' ;
+
+ // Setup the Keystroke Handler.
+ var oKeystrokeHandler = new FCKKeystrokeHandler( false ) ;
+ oKeystrokeHandler._EnterKey = this ;
+ oKeystrokeHandler.OnKeystroke = FCKEnterKey_OnKeystroke ;
+
+ oKeystrokeHandler.SetKeystrokes( [
+ [ 13 , 'Enter' ],
+ [ SHIFT + 13, 'ShiftEnter' ],
+ [ 8 , 'Backspace' ],
+ [ CTRL + 8 , 'CtrlBackspace' ],
+ [ 46 , 'Delete' ]
+ ] ) ;
+
+ this.TabText = '' ;
+
+ // Safari by default inserts 4 spaces on TAB, while others make the editor
+ // loose focus. So, we need to handle it here to not include those spaces.
+ if ( tabSpaces > 0 || FCKBrowserInfo.IsSafari )
+ {
+ while ( tabSpaces-- )
+ this.TabText += '\xa0' ;
+
+ oKeystrokeHandler.SetKeystrokes( [ 9, 'Tab' ] );
+ }
+
+ oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
+}
+
+
+function FCKEnterKey_OnKeystroke( keyCombination, keystrokeValue )
+{
+ var oEnterKey = this._EnterKey ;
+
+ try
+ {
+ switch ( keystrokeValue )
+ {
+ case 'Enter' :
+ return oEnterKey.DoEnter() ;
+ break ;
+ case 'ShiftEnter' :
+ return oEnterKey.DoShiftEnter() ;
+ break ;
+ case 'Backspace' :
+ return oEnterKey.DoBackspace() ;
+ break ;
+ case 'Delete' :
+ return oEnterKey.DoDelete() ;
+ break ;
+ case 'Tab' :
+ return oEnterKey.DoTab() ;
+ break ;
+ case 'CtrlBackspace' :
+ return oEnterKey.DoCtrlBackspace() ;
+ break ;
+ }
+ }
+ catch (e)
+ {
+ // If for any reason we are not able to handle it, go
+ // ahead with the browser default behavior.
+ }
+
+ return false ;
+}
+
+/*
+ * Executes the <Enter> key behavior.
+ */
+FCKEnterKey.prototype.DoEnter = function( mode, hasShift )
+{
+ // Save an undo snapshot before doing anything
+ FCKUndo.SaveUndoStep() ;
+
+ this._HasShift = ( hasShift === true ) ;
+
+ var parentElement = FCKSelection.GetParentElement() ;
+ var parentPath = new FCKElementPath( parentElement ) ;
+ var sMode = mode || this.EnterMode ;
+
+ if ( sMode == 'br' || parentPath.Block && parentPath.Block.tagName.toLowerCase() == 'pre' )
+ return this._ExecuteEnterBr() ;
+ else
+ return this._ExecuteEnterBlock( sMode ) ;
+}
+
+/*
+ * Executes the <Shift>+<Enter> key behavior.
+ */
+FCKEnterKey.prototype.DoShiftEnter = function()
+{
+ return this.DoEnter( this.ShiftEnterMode, true ) ;
+}
+
+/*
+ * Executes the <Backspace> key behavior.
+ */
+FCKEnterKey.prototype.DoBackspace = function()
+{
+ var bCustom = false ;
+
+ // Get the current selection.
+ var oRange = new FCKDomRange( this.Window ) ;
+ oRange.MoveToSelection() ;
+
+ // Kludge for #247
+ if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
+ {
+ this._FixIESelectAllBug( oRange ) ;
+ return true ;
+ }
+
+ var isCollapsed = oRange.CheckIsCollapsed() ;
+
+ if ( !isCollapsed )
+ {
+ // Bug #327, Backspace with an img selection would activate the default action in IE.
+ // Let's override that with our logic here.
+ if ( FCKBrowserInfo.IsIE && this.Window.document.selection.type.toLowerCase() == "control" )
+ {
+ var controls = this.Window.document.selection.createRange() ;
+ for ( var i = controls.length - 1 ; i >= 0 ; i-- )
+ {
+ var el = controls.item( i ) ;
+ el.parentNode.removeChild( el ) ;
+ }
+ return true ;
+ }
+
+ return false ;
+ }
+
+ // On IE, it is better for us handle the deletion if the caret is preceeded
+ // by a <br> (#1383).
+ if ( FCKBrowserInfo.IsIE )
+ {
+ var previousElement = FCKDomTools.GetPreviousSourceElement( oRange.StartNode, true ) ;
+
+ if ( previousElement && previousElement.nodeName.toLowerCase() == 'br' )
+ {
+ // Create a range that starts after the <br> and ends at the
+ // current range position.
+ var testRange = oRange.Clone() ;
+ testRange.SetStart( previousElement, 4 ) ;
+
+ // If that range is empty, we can proceed cleaning that <br> manually.
+ if ( testRange.CheckIsEmpty() )
+ {
+ previousElement.parentNode.removeChild( previousElement ) ;
+ return true ;
+ }
+ }
+ }
+
+ var oStartBlock = oRange.StartBlock ;
+ var oEndBlock = oRange.EndBlock ;
+
+ // The selection boundaries must be in the same "block limit" element
+ if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock )
+ {
+ if ( !isCollapsed )
+ {
+ var bEndOfBlock = oRange.CheckEndOfBlock() ;
+
+ oRange.DeleteContents() ;
+
+ if ( oStartBlock != oEndBlock )
+ {
+ oRange.SetStart(oEndBlock,1) ;
+ oRange.SetEnd(oEndBlock,1) ;
+
+// if ( bEndOfBlock )
+// oEndBlock.parentNode.removeChild( oEndBlock ) ;
+ }
+
+ oRange.Select() ;
+
+ bCustom = ( oStartBlock == oEndBlock ) ;
+ }
+
+ if ( oRange.CheckStartOfBlock() )
+ {
+ var oCurrentBlock = oRange.StartBlock ;
+
+ var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
+
+ bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ;
+ }
+ else if ( FCKBrowserInfo.IsGeckoLike )
+ {
+ // Firefox and Opera (#1095) loose the selection when executing
+ // CheckStartOfBlock, so we must reselect.
+ oRange.Select() ;
+ }
+ }
+
+ oRange.Release() ;
+ return bCustom ;
+}
+
+FCKEnterKey.prototype.DoCtrlBackspace = function()
+{
+ FCKUndo.SaveUndoStep() ;
+ var oRange = new FCKDomRange( this.Window ) ;
+ oRange.MoveToSelection() ;
+ if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
+ {
+ this._FixIESelectAllBug( oRange ) ;
+ return true ;
+ }
+ return false ;
+}
+
+FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock )
+{
+ var bCustom = false ;
+
+ // We could be in a nested LI.
+ if ( !previous && currentBlock && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) )
+ {
+ this._OutdentWithSelection( currentBlock, range ) ;
+ return true ;
+ }
+
+ if ( previous && previous.nodeName.IEquals( 'LI' ) )
+ {
+ var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
+
+ while ( oNestedList )
+ {
+ previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ;
+ oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
+ }
+ }
+
+ if ( previous && currentBlock )
+ {
+ // If we are in a LI, and the previous block is not an LI, we must outdent it.
+ if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) )
+ {
+ this._OutdentWithSelection( currentBlock, range ) ;
+ return true ;
+ }
+
+ // Take a reference to the parent for post processing cleanup.
+ var oCurrentParent = currentBlock.parentNode ;
+
+ var sPreviousName = previous.nodeName.toLowerCase() ;
+ if ( FCKListsLib.EmptyElements[ sPreviousName ] != null || sPreviousName == 'table' )
+ {
+ FCKDomTools.RemoveNode( previous ) ;
+ bCustom = true ;
+ }
+ else
+ {
+ // Remove the current block.
+ FCKDomTools.RemoveNode( currentBlock ) ;
+
+ // Remove any empty tag left by the block removal.
+ while ( oCurrentParent.innerHTML.Trim().length == 0 )
+ {
+ var oParent = oCurrentParent.parentNode ;
+ oParent.removeChild( oCurrentParent ) ;
+ oCurrentParent = oParent ;
+ }
+
+ // Cleanup the previous and the current elements.
+ FCKDomTools.LTrimNode( currentBlock ) ;
+ FCKDomTools.RTrimNode( previous ) ;
+
+ // Append a space to the previous.
+ // Maybe it is not always desirable...
+ // previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ;
+
+ // Set the range to the end of the previous element and bookmark it.
+ range.SetStart( previous, 2, true ) ;
+ range.Collapse( true ) ;
+ var oBookmark = range.CreateBookmark( true ) ;
+
+ // Move the contents of the block to the previous element and delete it.
+ // But for some block types (e.g. table), moving the children to the previous block makes no sense.
+ // So a check is needed. (See #1081)
+ if ( ! currentBlock.tagName.IEquals( [ 'TABLE' ] ) )
+ FCKDomTools.MoveChildren( currentBlock, previous ) ;
+
+ // Place the selection at the bookmark.
+ range.SelectBookmark( oBookmark ) ;
+
+ bCustom = true ;
+ }
+ }
+
+ return bCustom ;
+}
+
+/*
+ * Executes the <Delete> key behavior.
+ */
+FCKEnterKey.prototype.DoDelete = function()
+{
+ // Save an undo snapshot before doing anything
+ // This is to conform with the behavior seen in MS Word
+ FCKUndo.SaveUndoStep() ;
+
+ // The <Delete> has the same effect as the <Backspace>, so we have the same
+ // results if we just move to the next block and apply the same <Backspace> logic.
+
+ var bCustom = false ;
+
+ // Get the current selection.
+ var oRange = new FCKDomRange( this.Window ) ;
+ oRange.MoveToSelection() ;
+
+ // Kludge for #247
+ if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
+ {
+ this._FixIESelectAllBug( oRange ) ;
+ return true ;
+ }
+
+ // There is just one special case for collapsed selections at the end of a block.
+ if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGeckoLike ) )
+ {
+ var oCurrentBlock = oRange.StartBlock ;
+ var eCurrentCell = FCKTools.GetElementAscensor( oCurrentBlock, 'td' );
+
+ var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ],
+ ['UL','OL','TR'], true ) ;
+
+ // Bug #1323 : if we're in a table cell, and the next node belongs to a different cell, then don't
+ // delete anything.
+ if ( eCurrentCell )
+ {
+ var eNextCell = FCKTools.GetElementAscensor( eNext, 'td' );
+ if ( eNextCell != eCurrentCell )
+ return true ;
+ }
+
+ bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ;
+ }
+
+ oRange.Release() ;
+ return bCustom ;
+}
+
+/*
+ * Executes the <Tab> key behavior.
+ */
+FCKEnterKey.prototype.DoTab = function()
+{
+ var oRange = new FCKDomRange( this.Window );
+ oRange.MoveToSelection() ;
+
+ // If the user pressed <tab> inside a table, we should give him the default behavior ( moving between cells )
+ // instead of giving him more non-breaking spaces. (Bug #973)
+ var node = oRange._Range.startContainer ;
+ while ( node )
+ {
+ if ( node.nodeType == 1 )
+ {
+ var tagName = node.tagName.toLowerCase() ;
+ if ( tagName == "tr" || tagName == "td" || tagName == "th" || tagName == "tbody" || tagName == "table" )
+ return false ;
+ else
+ break ;
+ }
+ node = node.parentNode ;
+ }
+
+ if ( this.TabText )
+ {
+ oRange.DeleteContents() ;
+ oRange.InsertNode( this.Window.document.createTextNode( this.TabText ) ) ;
+ oRange.Collapse( false ) ;
+ oRange.Select() ;
+ }
+ return true ;
+}
+
+FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range )
+{
+ // Get the current selection.
+ var oRange = range || new FCKDomRange( this.Window ) ;
+
+ var oSplitInfo = oRange.SplitBlock( blockTag ) ;
+
+ if ( oSplitInfo )
+ {
+ // Get the current blocks.
+ var ePreviousBlock = oSplitInfo.PreviousBlock ;
+ var eNextBlock = oSplitInfo.NextBlock ;
+
+ var bIsStartOfBlock = oSplitInfo.WasStartOfBlock ;
+ var bIsEndOfBlock = oSplitInfo.WasEndOfBlock ;
+
+ // If there is one block under a list item, modify the split so that the list item gets split as well. (Bug #1647)
+ if ( eNextBlock )
+ {
+ if ( eNextBlock.parentNode.nodeName.IEquals( 'li' ) )
+ {
+ FCKDomTools.BreakParent( eNextBlock, eNextBlock.parentNode ) ;
+ FCKDomTools.MoveNode( eNextBlock, eNextBlock.nextSibling, true ) ;
+ }
+ }
+ else if ( ePreviousBlock && ePreviousBlock.parentNode.nodeName.IEquals( 'li' ) )
+ {
+ FCKDomTools.BreakParent( ePreviousBlock, ePreviousBlock.parentNode ) ;
+ oRange.MoveToElementEditStart( ePreviousBlock.nextSibling );
+ FCKDomTools.MoveNode( ePreviousBlock, ePreviousBlock.previousSibling ) ;
+ }
+
+ // If we have both the previous and next blocks, it means that the
+ // boundaries were on separated blocks, or none of them where on the
+ // block limits (start/end).
+ if ( !bIsStartOfBlock && !bIsEndOfBlock )
+ {
+ // If the next block is an <li> with another list tree as the first child
+ // We'll need to append a placeholder or the list item wouldn't be editable. (Bug #1420)
+ if ( eNextBlock.nodeName.IEquals( 'li' ) && eNextBlock.firstChild
+ && eNextBlock.firstChild.nodeName.IEquals( ['ul', 'ol'] ) )
+ eNextBlock.insertBefore( FCKTools.GetElementDocument( eNextBlock ).createTextNode( '\xa0' ), eNextBlock.firstChild ) ;
+ // Move the selection to the end block.
+ if ( eNextBlock )
+ oRange.MoveToElementEditStart( eNextBlock ) ;
+ }
+ else
+ {
+ if ( bIsStartOfBlock && bIsEndOfBlock && ePreviousBlock.tagName.toUpperCase() == 'LI' )
+ {
+ oRange.MoveToElementStart( ePreviousBlock ) ;
+ this._OutdentWithSelection( ePreviousBlock, oRange ) ;
+ oRange.Release() ;
+ return true ;
+ }
+
+ var eNewBlock ;
+
+ if ( ePreviousBlock )
+ {
+ var sPreviousBlockTag = ePreviousBlock.tagName.toUpperCase() ;
+
+ // If is a header tag, or we are in a Shift+Enter (#77),
+ // create a new block element (later in the code).
+ if ( !this._HasShift && !(/^H[1-6]$/).test( sPreviousBlockTag ) )
+ {
+ // Otherwise, duplicate the previous block.
+ eNewBlock = FCKDomTools.CloneElement( ePreviousBlock ) ;
+ }
+ }
+ else if ( eNextBlock )
+ eNewBlock = FCKDomTools.CloneElement( eNextBlock ) ;
+
+ if ( !eNewBlock )
+ eNewBlock = this.Window.document.createElement( blockTag ) ;
+
+ // Recreate the inline elements tree, which was available
+ // before the hitting enter, so the same styles will be
+ // available in the new block.
+ var elementPath = oSplitInfo.ElementPath ;
+ if ( elementPath )
+ {
+ for ( var i = 0, len = elementPath.Elements.length ; i < len ; i++ )
+ {
+ var element = elementPath.Elements[i] ;
+
+ if ( element == elementPath.Block || element == elementPath.BlockLimit )
+ break ;
+
+ if ( FCKListsLib.InlineChildReqElements[ element.nodeName.toLowerCase() ] )
+ {
+ element = FCKDomTools.CloneElement( element ) ;
+ FCKDomTools.MoveChildren( eNewBlock, element ) ;
+ eNewBlock.appendChild( element ) ;
+ }
+ }
+ }
+
+ if ( FCKBrowserInfo.IsGeckoLike )
+ FCKTools.AppendBogusBr( eNewBlock ) ;
+
+ oRange.InsertNode( eNewBlock ) ;
+
+ // This is tricky, but to make the new block visible correctly
+ // we must select it.
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // Move the selection to the new block.
+ oRange.MoveToElementEditStart( eNewBlock ) ;
+ oRange.Select() ;
+ }
+
+ // Move the selection to the new block.
+ oRange.MoveToElementEditStart( bIsStartOfBlock && !bIsEndOfBlock ? eNextBlock : eNewBlock ) ;
+ }
+
+ if ( FCKBrowserInfo.IsGeckoLike )
+ {
+ if ( eNextBlock )
+ {
+ // If we have split the block, adds a temporary span at the
+ // range position and scroll relatively to it.
+ var tmpNode = this.Window.document.createElement( 'span' ) ;
+
+ // We need some content for Safari.
+ tmpNode.innerHTML = '&nbsp;';
+
+ oRange.InsertNode( tmpNode ) ;
+ FCKDomTools.ScrollIntoView( tmpNode, false ) ;
+ oRange.DeleteContents() ;
+ }
+ else
+ {
+ // We may use the above scroll logic for the new block case
+ // too, but it gives some weird result with Opera.
+ FCKDomTools.ScrollIntoView( eNextBlock || eNewBlock, false ) ;
+ }
+ }
+
+ oRange.Select() ;
+ }
+
+ // Release the resources used by the range.
+ oRange.Release() ;
+
+ return true ;
+}
+
+FCKEnterKey.prototype._ExecuteEnterBr = function( blockTag )
+{
+ // Get the current selection.
+ var oRange = new FCKDomRange( this.Window ) ;
+ oRange.MoveToSelection() ;
+
+ // The selection boundaries must be in the same "block limit" element.
+ if ( oRange.StartBlockLimit == oRange.EndBlockLimit )
+ {
+ oRange.DeleteContents() ;
+
+ // Get the new selection (it is collapsed at this point).
+ oRange.MoveToSelection() ;
+
+ var bIsStartOfBlock = oRange.CheckStartOfBlock() ;
+ var bIsEndOfBlock = oRange.CheckEndOfBlock() ;
+
+ var sStartBlockTag = oRange.StartBlock ? oRange.StartBlock.tagName.toUpperCase() : '' ;
+
+ var bHasShift = this._HasShift ;
+ var bIsPre = false ;
+
+ if ( !bHasShift && sStartBlockTag == 'LI' )
+ return this._ExecuteEnterBlock( null, oRange ) ;
+
+ // If we are at the end of a header block.
+ if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) )
+ {
+ // Insert a BR after the current paragraph.
+ FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ;
+
+ // The space is required by Gecko only to make the cursor blink.
+ if ( FCKBrowserInfo.IsGecko )
+ FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ;
+
+ // IE and Gecko have different behaviors regarding the position.
+ oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ;
+ }
+ else
+ {
+ var eLineBreak ;
+ bIsPre = sStartBlockTag.IEquals( 'pre' ) ;
+ if ( bIsPre )
+ eLineBreak = this.Window.document.createTextNode( FCKBrowserInfo.IsIE ? '\r' : '\n' ) ;
+ else
+ eLineBreak = this.Window.document.createElement( 'br' ) ;
+
+ oRange.InsertNode( eLineBreak ) ;
+
+ // The space is required by Gecko only to make the cursor blink.
+ if ( FCKBrowserInfo.IsGecko )
+ FCKDomTools.InsertAfterNode( eLineBreak, this.Window.document.createTextNode( '' ) ) ;
+
+ // If we are at the end of a block, we must be sure the bogus node is available in that block.
+ if ( bIsEndOfBlock && FCKBrowserInfo.IsGeckoLike )
+ FCKTools.AppendBogusBr( eLineBreak.parentNode ) ;
+
+ if ( FCKBrowserInfo.IsIE )
+ oRange.SetStart( eLineBreak, 4 ) ;
+ else
+ oRange.SetStart( eLineBreak.nextSibling, 1 ) ;
+
+ if ( ! FCKBrowserInfo.IsIE )
+ {
+ var dummy = null ;
+ if ( FCKBrowserInfo.IsOpera )
+ dummy = this.Window.document.createElement( 'span' ) ;
+ else
+ dummy = this.Window.document.createElement( 'br' ) ;
+
+ eLineBreak.parentNode.insertBefore( dummy, eLineBreak.nextSibling ) ;
+
+ FCKDomTools.ScrollIntoView( dummy, false ) ;
+
+ dummy.parentNode.removeChild( dummy ) ;
+ }
+ }
+
+ // This collapse guarantees the cursor will be blinking.
+ oRange.Collapse( true ) ;
+
+ oRange.Select( bIsPre ) ;
+ }
+
+ // Release the resources used by the range.
+ oRange.Release() ;
+
+ return true ;
+}
+
+// Outdents a LI, maintaining the selection defined on a range.
+FCKEnterKey.prototype._OutdentWithSelection = function( li, range )
+{
+ var oBookmark = range.CreateBookmark() ;
+
+ FCKListHandler.OutdentListItem( li ) ;
+
+ range.MoveToBookmark( oBookmark ) ;
+ range.Select() ;
+}
+
+// Is all the contents under a node included by a range?
+FCKEnterKey.prototype._CheckIsAllContentsIncluded = function( range, node )
+{
+ var startOk = false ;
+ var endOk = false ;
+
+ /*
+ FCKDebug.Output( 'sc='+range.StartContainer.nodeName+
+ ',so='+range._Range.startOffset+
+ ',ec='+range.EndContainer.nodeName+
+ ',eo='+range._Range.endOffset ) ;
+ */
+ if ( range.StartContainer == node || range.StartContainer == node.firstChild )
+ startOk = ( range._Range.startOffset == 0 ) ;
+
+ if ( range.EndContainer == node || range.EndContainer == node.lastChild )
+ {
+ var nodeLength = range.EndContainer.nodeType == 3 ? range.EndContainer.length : range.EndContainer.childNodes.length ;
+ endOk = ( range._Range.endOffset == nodeLength ) ;
+ }
+
+ return startOk && endOk ;
+}
+
+// Kludge for #247
+FCKEnterKey.prototype._FixIESelectAllBug = function( range )
+{
+ var doc = this.Window.document ;
+ doc.body.innerHTML = '' ;
+ var editBlock ;
+ if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) )
+ {
+ editBlock = doc.createElement( FCKConfig.EnterMode ) ;
+ doc.body.appendChild( editBlock ) ;
+ }
+ else
+ editBlock = doc.body ;
+
+ range.MoveToNodeContents( editBlock ) ;
+ range.Collapse( true ) ;
+ range.Select() ;
+ range.Release() ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckevents.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckevents.js
new file mode 100644
index 0000000..0bae94d
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckevents.js
@@ -0,0 +1,71 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKEvents Class: used to handle events is a advanced way.
+ */
+
+var FCKEvents = function( eventsOwner )
+{
+ this.Owner = eventsOwner ;
+ this._RegisteredEvents = new Object() ;
+}
+
+FCKEvents.prototype.AttachEvent = function( eventName, functionPointer )
+{
+ var aTargets ;
+
+ if ( !( aTargets = this._RegisteredEvents[ eventName ] ) )
+ this._RegisteredEvents[ eventName ] = [ functionPointer ] ;
+ else
+ {
+ // Check that the event handler isn't already registered with the same listener
+ // It doesn't detect function pointers belonging to an object (at least in Gecko)
+ if ( aTargets.IndexOf( functionPointer ) == -1 )
+ aTargets.push( functionPointer ) ;
+ }
+}
+
+FCKEvents.prototype.FireEvent = function( eventName, params )
+{
+ var bReturnValue = true ;
+
+ var oCalls = this._RegisteredEvents[ eventName ] ;
+
+ if ( oCalls )
+ {
+ for ( var i = 0 ; i < oCalls.length ; i++ )
+ {
+ try
+ {
+ bReturnValue = ( oCalls[ i ]( this.Owner, params ) && bReturnValue ) ;
+ }
+ catch(e)
+ {
+ // Ignore the following error. It may happen if pointing to a
+ // script not anymore available (#934):
+ // -2146823277 = Can't execute code from a freed script
+ if ( e.number != -2146823277 )
+ throw e ;
+ }
+ }
+ }
+
+ return bReturnValue ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckhtmliterator.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckhtmliterator.js
new file mode 100644
index 0000000..2fb3a90
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckhtmliterator.js
@@ -0,0 +1,142 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class can be used to interate through nodes inside a range.
+ *
+ * During interation, the provided range can become invalid, due to document
+ * mutations, so CreateBookmark() used to restore it after processing, if
+ * needed.
+ */
+
+var FCKHtmlIterator = function( source )
+{
+ this._sourceHtml = source ;
+}
+FCKHtmlIterator.prototype =
+{
+ Next : function()
+ {
+ var sourceHtml = this._sourceHtml ;
+ if ( sourceHtml == null )
+ return null ;
+
+ var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ;
+ var isTag = false ;
+ var value = "" ;
+ if ( match )
+ {
+ if ( match.index > 0 )
+ {
+ value = sourceHtml.substr( 0, match.index ) ;
+ this._sourceHtml = sourceHtml.substr( match.index ) ;
+ }
+ else
+ {
+ isTag = true ;
+ value = match[0] ;
+ this._sourceHtml = sourceHtml.substr( match[0].length ) ;
+ }
+ }
+ else
+ {
+ value = sourceHtml ;
+ this._sourceHtml = null ;
+ }
+ return { 'isTag' : isTag, 'value' : value } ;
+ },
+
+ Each : function( func )
+ {
+ var chunk ;
+ while ( ( chunk = this.Next() ) )
+ func( chunk.isTag, chunk.value ) ;
+ }
+} ;
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class can be used to interate through nodes inside a range.
+ *
+ * During interation, the provided range can become invalid, due to document
+ * mutations, so CreateBookmark() used to restore it after processing, if
+ * needed.
+ */
+
+var FCKHtmlIterator = function( source )
+{
+ this._sourceHtml = source ;
+}
+FCKHtmlIterator.prototype =
+{
+ Next : function()
+ {
+ var sourceHtml = this._sourceHtml ;
+ if ( sourceHtml == null )
+ return null ;
+
+ var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ;
+ var isTag = false ;
+ var value = "" ;
+ if ( match )
+ {
+ if ( match.index > 0 )
+ {
+ value = sourceHtml.substr( 0, match.index ) ;
+ this._sourceHtml = sourceHtml.substr( match.index ) ;
+ }
+ else
+ {
+ isTag = true ;
+ value = match[0] ;
+ this._sourceHtml = sourceHtml.substr( match[0].length ) ;
+ }
+ }
+ else
+ {
+ value = sourceHtml ;
+ this._sourceHtml = null ;
+ }
+ return { 'isTag' : isTag, 'value' : value } ;
+ },
+
+ Each : function( func )
+ {
+ var chunk ;
+ while ( ( chunk = this.Next() ) )
+ func( chunk.isTag, chunk.value ) ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckicon.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckicon.js
new file mode 100644
index 0000000..be1bde0
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckicon.js
@@ -0,0 +1,103 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKIcon Class: renders an icon from a single image, a strip or even a
+ * spacer.
+ */
+
+var FCKIcon = function( iconPathOrStripInfoArray )
+{
+ var sTypeOf = iconPathOrStripInfoArray ? typeof( iconPathOrStripInfoArray ) : 'undefined' ;
+ switch ( sTypeOf )
+ {
+ case 'number' :
+ this.Path = FCKConfig.SkinPath + 'fck_strip.gif' ;
+ this.Size = 16 ;
+ this.Position = iconPathOrStripInfoArray ;
+ break ;
+
+ case 'undefined' :
+ this.Path = FCK_SPACER_PATH ;
+ break ;
+
+ case 'string' :
+ this.Path = iconPathOrStripInfoArray ;
+ break ;
+
+ default :
+ // It is an array in the format [ StripFilePath, IconSize, IconPosition ]
+ this.Path = iconPathOrStripInfoArray[0] ;
+ this.Size = iconPathOrStripInfoArray[1] ;
+ this.Position = iconPathOrStripInfoArray[2] ;
+ }
+}
+
+FCKIcon.prototype.CreateIconElement = function( document )
+{
+ var eIcon, eIconImage ;
+
+ if ( this.Position ) // It is using an icons strip image.
+ {
+ var sPos = '-' + ( ( this.Position - 1 ) * this.Size ) + 'px' ;
+
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // <div class="TB_Button_Image"><img src="strip.gif" style="top:-16px"></div>
+
+ eIcon = document.createElement( 'DIV' ) ;
+
+ eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
+ eIconImage.src = this.Path ;
+ eIconImage.style.top = sPos ;
+ }
+ else
+ {
+ // <img class="TB_Button_Image" src="spacer.gif" style="background-position: 0px -16px;background-image: url(strip.gif);">
+
+ eIcon = document.createElement( 'IMG' ) ;
+ eIcon.src = FCK_SPACER_PATH ;
+ eIcon.style.backgroundPosition = '0px ' + sPos ;
+ eIcon.style.backgroundImage = 'url("' + this.Path + '")' ;
+ }
+ }
+ else // It is using a single icon image.
+ {
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // IE makes the button 1px higher if using the <img> directly, so we
+ // are changing to the <div> system to clip the image correctly.
+ eIcon = document.createElement( 'DIV' ) ;
+
+ eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
+ eIconImage.src = this.Path ? this.Path : FCK_SPACER_PATH ;
+ }
+ else
+ {
+ // This is not working well with IE. See notes above.
+ // <img class="TB_Button_Image" src="smiley.gif">
+ eIcon = document.createElement( 'IMG' ) ;
+ eIcon.src = this.Path ? this.Path : FCK_SPACER_PATH ;
+ }
+ }
+
+ eIcon.className = 'TB_Button_Image' ;
+
+ return eIcon ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckiecleanup.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckiecleanup.js
new file mode 100644
index 0000000..e25d648
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckiecleanup.js
@@ -0,0 +1,68 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKIECleanup Class: a generic class used as a tool to remove IE leaks.
+ */
+
+var FCKIECleanup = function( attachWindow )
+{
+ // If the attachWindow already have a cleanup object, just use that one.
+ if ( attachWindow._FCKCleanupObj )
+ this.Items = attachWindow._FCKCleanupObj.Items ;
+ else
+ {
+ this.Items = new Array() ;
+
+ attachWindow._FCKCleanupObj = this ;
+ FCKTools.AddEventListenerEx( attachWindow, 'unload', FCKIECleanup_Cleanup ) ;
+// attachWindow.attachEvent( 'onunload', FCKIECleanup_Cleanup ) ;
+ }
+}
+
+FCKIECleanup.prototype.AddItem = function( dirtyItem, cleanupFunction )
+{
+ this.Items.push( [ dirtyItem, cleanupFunction ] ) ;
+}
+
+function FCKIECleanup_Cleanup()
+{
+ if ( !this._FCKCleanupObj || ( FCKConfig.MsWebBrowserControlCompat && !window.FCKUnloadFlag ) )
+ return ;
+
+ var aItems = this._FCKCleanupObj.Items ;
+
+ while ( aItems.length > 0 )
+ {
+
+ // It is important to remove from the end to the beginning (pop()),
+ // because of the order things get created in the editor. In the code,
+ // elements in deeper position in the DOM are placed at the end of the
+ // cleanup function, so we must cleanup then first, otherwise IE could
+ // throw some crazy memory errors (IE bug).
+ var oItem = aItems.pop() ;
+ if ( oItem )
+ oItem[1].call( oItem[0] ) ;
+ }
+
+ this._FCKCleanupObj = null ;
+
+ if ( CollectGarbage )
+ CollectGarbage() ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckimagepreloader.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckimagepreloader.js
new file mode 100644
index 0000000..b5f0a47
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckimagepreloader.js
@@ -0,0 +1,64 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Preload a list of images, firing an event when complete.
+ */
+
+var FCKImagePreloader = function()
+{
+ this._Images = new Array() ;
+}
+
+FCKImagePreloader.prototype =
+{
+ AddImages : function( images )
+ {
+ if ( typeof( images ) == 'string' )
+ images = images.split( ';' ) ;
+
+ this._Images = this._Images.concat( images ) ;
+ },
+
+ Start : function()
+ {
+ var aImages = this._Images ;
+ this._PreloadCount = aImages.length ;
+
+ for ( var i = 0 ; i < aImages.length ; i++ )
+ {
+ var eImg = document.createElement( 'img' ) ;
+ FCKTools.AddEventListenerEx( eImg, 'load', _FCKImagePreloader_OnImage, this ) ;
+ FCKTools.AddEventListenerEx( eImg, 'error', _FCKImagePreloader_OnImage, this ) ;
+ eImg.src = aImages[i] ;
+
+ _FCKImagePreloader_ImageCache.push( eImg ) ;
+ }
+ }
+};
+
+// All preloaded images must be placed in a global array, otherwise the preload
+// magic will not happen.
+var _FCKImagePreloader_ImageCache = new Array() ;
+
+function _FCKImagePreloader_OnImage( ev, imagePreloader )
+{
+ if ( (--imagePreloader._PreloadCount) == 0 && imagePreloader.OnComplete )
+ imagePreloader.OnComplete() ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckkeystrokehandler.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckkeystrokehandler.js
new file mode 100644
index 0000000..dadd05a
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckkeystrokehandler.js
@@ -0,0 +1,141 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Control keyboard keystroke combinations.
+ */
+
+var FCKKeystrokeHandler = function( cancelCtrlDefaults )
+{
+ this.Keystrokes = new Object() ;
+ this.CancelCtrlDefaults = ( cancelCtrlDefaults !== false ) ;
+}
+
+/*
+ * Listen to keystroke events in an element or DOM document object.
+ * @target: The element or document to listen to keystroke events.
+ */
+FCKKeystrokeHandler.prototype.AttachToElement = function( target )
+{
+ // For newer browsers, it is enough to listen to the keydown event only.
+ // Some browsers instead, don't cancel key events in the keydown, but in the
+ // keypress. So we must do a longer trip in those cases.
+ FCKTools.AddEventListenerEx( target, 'keydown', _FCKKeystrokeHandler_OnKeyDown, this ) ;
+ if ( FCKBrowserInfo.IsGecko10 || FCKBrowserInfo.IsOpera || ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac ) )
+ FCKTools.AddEventListenerEx( target, 'keypress', _FCKKeystrokeHandler_OnKeyPress, this ) ;
+}
+
+/*
+ * Sets a list of keystrokes. It can receive either a single array or "n"
+ * arguments, each one being an array of 1 or 2 elemenst. The first element
+ * is the keystroke combination, and the second is the value to assign to it.
+ * If the second element is missing, the keystroke definition is removed.
+ */
+FCKKeystrokeHandler.prototype.SetKeystrokes = function()
+{
+ // Look through the arguments.
+ for ( var i = 0 ; i < arguments.length ; i++ )
+ {
+ var keyDef = arguments[i] ;
+
+ // If the configuration for the keystrokes is missing some element or has any extra comma
+ // this item won't be valid, so skip it and keep on processing.
+ if ( !keyDef )
+ continue ;
+
+ if ( typeof( keyDef[0] ) == 'object' ) // It is an array with arrays defining the keystrokes.
+ this.SetKeystrokes.apply( this, keyDef ) ;
+ else
+ {
+ if ( keyDef.length == 1 ) // If it has only one element, remove the keystroke.
+ delete this.Keystrokes[ keyDef[0] ] ;
+ else // Otherwise add it.
+ this.Keystrokes[ keyDef[0] ] = keyDef[1] === true ? true : keyDef ;
+ }
+ }
+}
+
+function _FCKKeystrokeHandler_OnKeyDown( ev, keystrokeHandler )
+{
+ // Get the key code.
+ var keystroke = ev.keyCode || ev.which ;
+
+ // Combine it with the CTRL, SHIFT and ALT states.
+ var keyModifiers = 0 ;
+
+ if ( ev.ctrlKey || ev.metaKey )
+ keyModifiers += CTRL ;
+
+ if ( ev.shiftKey )
+ keyModifiers += SHIFT ;
+
+ if ( ev.altKey )
+ keyModifiers += ALT ;
+
+ var keyCombination = keystroke + keyModifiers ;
+
+ var cancelIt = keystrokeHandler._CancelIt = false ;
+
+ // Look for its definition availability.
+ var keystrokeValue = keystrokeHandler.Keystrokes[ keyCombination ] ;
+
+// FCKDebug.Output( 'KeyDown: ' + keyCombination + ' - Value: ' + keystrokeValue ) ;
+
+ // If the keystroke is defined
+ if ( keystrokeValue )
+ {
+ // If the keystroke has been explicitly set to "true" OR calling the
+ // "OnKeystroke" event, it doesn't return "true", the default behavior
+ // must be preserved.
+ if ( keystrokeValue === true || !( keystrokeHandler.OnKeystroke && keystrokeHandler.OnKeystroke.apply( keystrokeHandler, keystrokeValue ) ) )
+ return true ;
+
+ cancelIt = true ;
+ }
+
+ // By default, it will cancel all combinations with the CTRL key only (except positioning keys).
+ if ( cancelIt || ( keystrokeHandler.CancelCtrlDefaults && keyModifiers == CTRL && ( keystroke < 33 || keystroke > 40 ) ) )
+ {
+ keystrokeHandler._CancelIt = true ;
+
+ if ( ev.preventDefault )
+ return ev.preventDefault() ;
+
+ ev.returnValue = false ;
+ ev.cancelBubble = true ;
+ return false ;
+ }
+
+ return true ;
+}
+
+function _FCKKeystrokeHandler_OnKeyPress( ev, keystrokeHandler )
+{
+ if ( keystrokeHandler._CancelIt )
+ {
+// FCKDebug.Output( 'KeyPress Cancel', 'Red') ;
+
+ if ( ev.preventDefault )
+ return ev.preventDefault() ;
+
+ return false ;
+ }
+
+ return true ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublock.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublock.js
new file mode 100644
index 0000000..e26858a
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublock.js
@@ -0,0 +1,153 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Renders a list of menu items.
+ */
+
+var FCKMenuBlock = function()
+{
+ this._Items = new Array() ;
+}
+
+
+FCKMenuBlock.prototype.Count = function()
+{
+ return this._Items.length ;
+}
+
+FCKMenuBlock.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
+{
+ var oItem = new FCKMenuItem( this, name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
+
+ oItem.OnClick = FCKTools.CreateEventListener( FCKMenuBlock_Item_OnClick, this ) ;
+ oItem.OnActivate = FCKTools.CreateEventListener( FCKMenuBlock_Item_OnActivate, this ) ;
+
+ this._Items.push( oItem ) ;
+
+ return oItem ;
+}
+
+FCKMenuBlock.prototype.AddSeparator = function()
+{
+ this._Items.push( new FCKMenuSeparator() ) ;
+}
+
+FCKMenuBlock.prototype.RemoveAllItems = function()
+{
+ this._Items = new Array() ;
+
+ var eItemsTable = this._ItemsTable ;
+ if ( eItemsTable )
+ {
+ while ( eItemsTable.rows.length > 0 )
+ eItemsTable.deleteRow( 0 ) ;
+ }
+}
+
+FCKMenuBlock.prototype.Create = function( parentElement )
+{
+ if ( !this._ItemsTable )
+ {
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKMenuBlock_Cleanup ) ;
+
+ this._Window = FCKTools.GetElementWindow( parentElement ) ;
+
+ var oDoc = FCKTools.GetElementDocument( parentElement ) ;
+
+ var eTable = parentElement.appendChild( oDoc.createElement( 'table' ) ) ;
+ eTable.cellPadding = 0 ;
+ eTable.cellSpacing = 0 ;
+
+ FCKTools.DisableSelection( eTable ) ;
+
+ var oMainElement = eTable.insertRow(-1).insertCell(-1) ;
+ oMainElement.className = 'MN_Menu' ;
+
+ var eItemsTable = this._ItemsTable = oMainElement.appendChild( oDoc.createElement( 'table' ) ) ;
+ eItemsTable.cellPadding = 0 ;
+ eItemsTable.cellSpacing = 0 ;
+ }
+
+ for ( var i = 0 ; i < this._Items.length ; i++ )
+ this._Items[i].Create( this._ItemsTable ) ;
+}
+
+/* Events */
+
+function FCKMenuBlock_Item_OnClick( clickedItem, menuBlock )
+{
+ if ( menuBlock.Hide )
+ menuBlock.Hide() ;
+
+ FCKTools.RunFunction( menuBlock.OnClick, menuBlock, [ clickedItem ] ) ;
+}
+
+function FCKMenuBlock_Item_OnActivate( menuBlock )
+{
+ var oActiveItem = menuBlock._ActiveItem ;
+
+ if ( oActiveItem && oActiveItem != this )
+ {
+ // Set the focus to this menu block window (to fire OnBlur on opened panels).
+ if ( !FCKBrowserInfo.IsIE && oActiveItem.HasSubMenu && !this.HasSubMenu )
+ {
+ menuBlock._Window.focus() ;
+
+ // Due to the event model provided by Opera, we need to set
+ // HasFocus here as the above focus() call will not fire the focus
+ // event in the panel immediately (#1200).
+ menuBlock.Panel.HasFocus = true ;
+ }
+
+ oActiveItem.Deactivate() ;
+ }
+
+ menuBlock._ActiveItem = this ;
+}
+
+function FCKMenuBlock_Cleanup()
+{
+ this._Window = null ;
+ this._ItemsTable = null ;
+}
+
+// ################# //
+
+var FCKMenuSeparator = function()
+{}
+
+FCKMenuSeparator.prototype.Create = function( parentTable )
+{
+ var oDoc = FCKTools.GetElementDocument( parentTable ) ;
+
+ var r = parentTable.insertRow(-1) ;
+
+ var eCell = r.insertCell(-1) ;
+ eCell.className = 'MN_Separator MN_Icon' ;
+
+ eCell = r.insertCell(-1) ;
+ eCell.className = 'MN_Separator' ;
+ eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
+
+ eCell = r.insertCell(-1) ;
+ eCell.className = 'MN_Separator' ;
+ eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublockpanel.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublockpanel.js
new file mode 100644
index 0000000..86e4c58
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenublockpanel.js
@@ -0,0 +1,54 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class is a menu block that behaves like a panel. It's a mix of the
+ * FCKMenuBlock and FCKPanel classes.
+ */
+
+var FCKMenuBlockPanel = function()
+{
+ // Call the "base" constructor.
+ FCKMenuBlock.call( this ) ;
+}
+
+FCKMenuBlockPanel.prototype = new FCKMenuBlock() ;
+
+
+// Override the create method.
+FCKMenuBlockPanel.prototype.Create = function()
+{
+ var oPanel = this.Panel = ( this.Parent && this.Parent.Panel ? this.Parent.Panel.CreateChildPanel() : new FCKPanel() ) ;
+ oPanel.AppendStyleSheet( FCKConfig.SkinEditorCSS ) ;
+
+ // Call the "base" implementation.
+ FCKMenuBlock.prototype.Create.call( this, oPanel.MainNode ) ;
+}
+
+FCKMenuBlockPanel.prototype.Show = function( x, y, relElement )
+{
+ if ( !this.Panel.CheckIsOpened() )
+ this.Panel.Show( x, y, relElement ) ;
+}
+
+FCKMenuBlockPanel.prototype.Hide = function()
+{
+ if ( this.Panel.CheckIsOpened() )
+ this.Panel.Hide() ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenuitem.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenuitem.js
new file mode 100644
index 0000000..3db1291
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckmenuitem.js
@@ -0,0 +1,161 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Defines and renders a menu items in a menu block.
+ */
+
+var FCKMenuItem = function( parentMenuBlock, name, label, iconPathOrStripInfoArray, isDisabled, customData )
+{
+ this.Name = name ;
+ this.Label = label || name ;
+ this.IsDisabled = isDisabled ;
+
+ this.Icon = new FCKIcon( iconPathOrStripInfoArray ) ;
+
+ this.SubMenu = new FCKMenuBlockPanel() ;
+ this.SubMenu.Parent = parentMenuBlock ;
+ this.SubMenu.OnClick = FCKTools.CreateEventListener( FCKMenuItem_SubMenu_OnClick, this ) ;
+ this.CustomData = customData ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKMenuItem_Cleanup ) ;
+}
+
+
+FCKMenuItem.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
+{
+ this.HasSubMenu = true ;
+ return this.SubMenu.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
+}
+
+FCKMenuItem.prototype.AddSeparator = function()
+{
+ this.SubMenu.AddSeparator() ;
+}
+
+FCKMenuItem.prototype.Create = function( parentTable )
+{
+ var bHasSubMenu = this.HasSubMenu ;
+
+ var oDoc = FCKTools.GetElementDocument( parentTable ) ;
+
+ // Add a row in the table to hold the menu item.
+ var r = this.MainElement = parentTable.insertRow(-1) ;
+ r.className = this.IsDisabled ? 'MN_Item_Disabled' : 'MN_Item' ;
+
+ // Set the row behavior.
+ if ( !this.IsDisabled )
+ {
+ FCKTools.AddEventListenerEx( r, 'mouseover', FCKMenuItem_OnMouseOver, [ this ] ) ;
+ FCKTools.AddEventListenerEx( r, 'click', FCKMenuItem_OnClick, [ this ] ) ;
+
+ if ( !bHasSubMenu )
+ FCKTools.AddEventListenerEx( r, 'mouseout', FCKMenuItem_OnMouseOut, [ this ] ) ;
+ }
+
+ // Create the icon cell.
+ var eCell = r.insertCell(-1) ;
+ eCell.className = 'MN_Icon' ;
+ eCell.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
+
+ // Create the label cell.
+ eCell = r.insertCell(-1) ;
+ eCell.className = 'MN_Label' ;
+ eCell.noWrap = true ;
+ eCell.appendChild( oDoc.createTextNode( this.Label ) ) ;
+
+ // Create the arrow cell and setup the sub menu panel (if needed).
+ eCell = r.insertCell(-1) ;
+ if ( bHasSubMenu )
+ {
+ eCell.className = 'MN_Arrow' ;
+
+ // The arrow is a fixed size image.
+ var eArrowImg = eCell.appendChild( oDoc.createElement( 'IMG' ) ) ;
+ eArrowImg.src = FCK_IMAGES_PATH + 'arrow_' + FCKLang.Dir + '.gif' ;
+ eArrowImg.width = 4 ;
+ eArrowImg.height = 7 ;
+
+ this.SubMenu.Create() ;
+ this.SubMenu.Panel.OnHide = FCKTools.CreateEventListener( FCKMenuItem_SubMenu_OnHide, this ) ;
+ }
+}
+
+FCKMenuItem.prototype.Activate = function()
+{
+ this.MainElement.className = 'MN_Item_Over' ;
+
+ if ( this.HasSubMenu )
+ {
+ // Show the child menu block. The ( +2, -2 ) correction is done because
+ // of the padding in the skin. It is not a good solution because one
+ // could change the skin and so the final result would not be accurate.
+ // For now it is ok because we are controlling the skin.
+ this.SubMenu.Show( this.MainElement.offsetWidth + 2, -2, this.MainElement ) ;
+ }
+
+ FCKTools.RunFunction( this.OnActivate, this ) ;
+}
+
+FCKMenuItem.prototype.Deactivate = function()
+{
+ this.MainElement.className = 'MN_Item' ;
+
+ if ( this.HasSubMenu )
+ this.SubMenu.Hide() ;
+}
+
+/* Events */
+
+function FCKMenuItem_SubMenu_OnClick( clickedItem, listeningItem )
+{
+ FCKTools.RunFunction( listeningItem.OnClick, listeningItem, [ clickedItem ] ) ;
+}
+
+function FCKMenuItem_SubMenu_OnHide( menuItem )
+{
+ menuItem.Deactivate() ;
+}
+
+function FCKMenuItem_OnClick( ev, menuItem )
+{
+ if ( menuItem.HasSubMenu )
+ menuItem.Activate() ;
+ else
+ {
+ menuItem.Deactivate() ;
+ FCKTools.RunFunction( menuItem.OnClick, menuItem, [ menuItem ] ) ;
+ }
+}
+
+function FCKMenuItem_OnMouseOver( ev, menuItem )
+{
+ menuItem.Activate() ;
+}
+
+function FCKMenuItem_OnMouseOut( ev, menuItem )
+{
+ menuItem.Deactivate() ;
+}
+
+function FCKMenuItem_Cleanup()
+{
+ this.MainElement = null ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckpanel.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckpanel.js
new file mode 100644
index 0000000..650a264
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckpanel.js
@@ -0,0 +1,463 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * Component that creates floating panels. It is used by many
+ * other components, like the toolbar items, context menu, etc...
+ */
+
+var FCKPanel = function( parentWindow )
+{
+ this.IsRTL = ( FCKLang.Dir == 'rtl' ) ;
+ this.IsContextMenu = false ;
+ this._LockCounter = 0 ;
+
+ this._Window = parentWindow || window ;
+
+ var oDocument ;
+
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // Create the Popup that will hold the panel.
+ // The popup has to be created before playing with domain hacks, see #1666.
+ this._Popup = this._Window.createPopup() ;
+
+ // this._Window cannot be accessed while playing with domain hacks, but local variable is ok.
+ // See #1666.
+ var pDoc = this._Window.document ;
+
+ // This is a trick to IE6 (not IE7). The original domain must be set
+ // before creating the popup, so we are able to take a refence to the
+ // document inside of it, and the set the proper domain for it. (#123)
+ if ( FCK_IS_CUSTOM_DOMAIN && !FCKBrowserInfo.IsIE7 )
+ {
+ pDoc.domain = FCK_ORIGINAL_DOMAIN ;
+ document.domain = FCK_ORIGINAL_DOMAIN ;
+ }
+
+ oDocument = this.Document = this._Popup.document ;
+
+ // Set the proper domain inside the popup.
+ if ( FCK_IS_CUSTOM_DOMAIN )
+ {
+ oDocument.domain = FCK_RUNTIME_DOMAIN ;
+ pDoc.domain = FCK_RUNTIME_DOMAIN ;
+ document.domain = FCK_RUNTIME_DOMAIN ;
+ }
+
+ FCK.IECleanup.AddItem( this, FCKPanel_Cleanup ) ;
+ }
+ else
+ {
+ var oIFrame = this._IFrame = this._Window.document.createElement('iframe') ;
+ FCKTools.ResetStyles( oIFrame );
+ oIFrame.src = 'javascript:void(0)' ;
+ oIFrame.allowTransparency = true ;
+ oIFrame.frameBorder = '0' ;
+ oIFrame.scrolling = 'no' ;
+ oIFrame.style.width = oIFrame.style.height = '0px' ;
+ FCKDomTools.SetElementStyles( oIFrame,
+ {
+ position : 'absolute',
+ zIndex : FCKConfig.FloatingPanelsZIndex
+ } ) ;
+
+ this._Window.document.body.appendChild( oIFrame ) ;
+
+ var oIFrameWindow = oIFrame.contentWindow ;
+
+ oDocument = this.Document = oIFrameWindow.document ;
+
+ // Workaround for Safari 12256. Ticket #63
+ var sBase = '' ;
+ if ( FCKBrowserInfo.IsSafari )
+ sBase = '<base href="' + window.document.location + '">' ;
+
+ // Initialize the IFRAME document body.
+ oDocument.open() ;
+ oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ;
+ oDocument.close() ;
+
+ if( FCKBrowserInfo.IsAIR )
+ FCKAdobeAIR.Panel_Contructor( oDocument, window.document.location ) ;
+
+ FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ;
+ FCKTools.AddEventListenerEx( oIFrameWindow, 'blur', FCKPanel_Window_OnBlur, this ) ;
+ }
+
+ oDocument.dir = FCKLang.Dir ;
+
+ FCKTools.AddEventListener( oDocument, 'contextmenu', FCKTools.CancelEvent ) ;
+
+
+ // Create the main DIV that is used as the panel base.
+ this.MainNode = oDocument.body.appendChild( oDocument.createElement('DIV') ) ;
+
+ // The "float" property must be set so Firefox calculates the size correctly.
+ this.MainNode.style.cssFloat = this.IsRTL ? 'right' : 'left' ;
+}
+
+
+FCKPanel.prototype.AppendStyleSheet = function( styleSheet )
+{
+ FCKTools.AppendStyleSheet( this.Document, styleSheet ) ;
+}
+
+FCKPanel.prototype.Preload = function( x, y, relElement )
+{
+ // The offsetWidth and offsetHeight properties are not available if the
+ // element is not visible. So we must "show" the popup with no size to
+ // be able to use that values in the second call (IE only).
+ if ( this._Popup )
+ this._Popup.show( x, y, 0, 0, relElement ) ;
+}
+
+// Workaround for IE7 problem. See #1982
+// Submenus are restricted to the size of its parent, so we increase it as needed.
+// Returns true if the panel has been repositioned
+FCKPanel.prototype.ResizeForSubpanel = function( panel, width, height )
+{
+ if ( !FCKBrowserInfo.IsIE7 )
+ return false ;
+
+ if ( !this._Popup.isOpen )
+ {
+ this.Subpanel = null ;
+ return false ;
+ }
+
+ // If we are resetting the extra space
+ if ( width == 0 && height == 0 )
+ {
+ // Another subpanel is being shown, so we must not shrink back
+ if (this.Subpanel !== panel)
+ return false ;
+
+ // Reset values.
+ // We leave the IncreasedY untouched to avoid vertical movement of the
+ // menu if the submenu is higher than the main menu.
+ this.Subpanel = null ;
+ this.IncreasedX = 0 ;
+ }
+ else
+ {
+ this.Subpanel = panel ;
+ // If the panel has already been increased enough, get out
+ if ( ( this.IncreasedX >= width ) && ( this.IncreasedY >= height ) )
+ return false ;
+
+ this.IncreasedX = Math.max( this.IncreasedX, width ) ;
+ this.IncreasedY = Math.max( this.IncreasedY, height ) ;
+ }
+
+ var x = this.ShowRect.x ;
+ var w = this.IncreasedX ;
+ if ( this.IsRTL )
+ x = x - w ;
+
+ // Horizontally increase as needed (sum of widths).
+ // Vertically, use only the maximum of this menu or the submenu
+ var finalWidth = this.ShowRect.w + w ;
+ var finalHeight = Math.max( this.ShowRect.h, this.IncreasedY ) ;
+ if ( this.ParentPanel )
+ this.ParentPanel.ResizeForSubpanel( this, finalWidth, finalHeight ) ;
+ this._Popup.show( x, this.ShowRect.y, finalWidth, finalHeight, this.RelativeElement ) ;
+
+ return this.IsRTL ;
+}
+
+FCKPanel.prototype.Show = function( x, y, relElement, width, height )
+{
+ var iMainWidth ;
+ var eMainNode = this.MainNode ;
+
+ if ( this._Popup )
+ {
+ // The offsetWidth and offsetHeight properties are not available if the
+ // element is not visible. So we must "show" the popup with no size to
+ // be able to use that values in the second call.
+ this._Popup.show( x, y, 0, 0, relElement ) ;
+
+ // The following lines must be place after the above "show", otherwise it
+ // doesn't has the desired effect.
+ FCKDomTools.SetElementStyles( eMainNode,
+ {
+ width : width ? width + 'px' : '',
+ height : height ? height + 'px' : ''
+ } ) ;
+
+ iMainWidth = eMainNode.offsetWidth ;
+
+ if ( FCKBrowserInfo.IsIE7 )
+ {
+ if (this.ParentPanel && this.ParentPanel.ResizeForSubpanel(this, iMainWidth, eMainNode.offsetHeight) )
+ {
+ // As the parent has moved, allow the browser to update its internal data, so the new position is correct.
+ FCKTools.RunFunction( this.Show, this, [x, y, relElement] ) ;
+ return ;
+ }
+ }
+
+ if ( this.IsRTL )
+ {
+ if ( this.IsContextMenu )
+ x = x - iMainWidth + 1 ;
+ else if ( relElement )
+ x = ( x * -1 ) + relElement.offsetWidth - iMainWidth ;
+ }
+
+ if ( FCKBrowserInfo.IsIE7 )
+ {
+ // Store the values that will be used by the ResizeForSubpanel function
+ this.ShowRect = {x:x, y:y, w:iMainWidth, h:eMainNode.offsetHeight} ;
+ this.IncreasedX = 0 ;
+ this.IncreasedY = 0 ;
+ this.RelativeElement = relElement ;
+ }
+
+ // Second call: Show the Popup at the specified location, with the correct size.
+ this._Popup.show( x, y, iMainWidth, eMainNode.offsetHeight, relElement ) ;
+
+ if ( this.OnHide )
+ {
+ if ( this._Timer )
+ CheckPopupOnHide.call( this, true ) ;
+
+ this._Timer = FCKTools.SetInterval( CheckPopupOnHide, 100, this ) ;
+ }
+ }
+ else
+ {
+ // Do not fire OnBlur while the panel is opened.
+ if ( typeof( FCK.ToolbarSet.CurrentInstance.FocusManager ) != 'undefined' )
+ FCK.ToolbarSet.CurrentInstance.FocusManager.Lock() ;
+
+ if ( this.ParentPanel )
+ {
+ this.ParentPanel.Lock() ;
+
+ // Due to a bug on FF3, we must ensure that the parent panel will
+ // blur (#1584).
+ FCKPanel_Window_OnBlur( null, this.ParentPanel ) ;
+ }
+
+ // Toggle the iframe scrolling attribute to prevent the panel
+ // scrollbars from disappearing in FF Mac. (#191)
+ if ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac )
+ {
+ this._IFrame.scrolling = '' ;
+ FCKTools.RunFunction( function(){ this._IFrame.scrolling = 'no'; }, this ) ;
+ }
+
+ // Be sure we'll not have more than one Panel opened at the same time.
+ // Do not unlock focus manager here because we're displaying another floating panel
+ // instead of returning the editor to a "no panel" state (Bug #1514).
+ if ( FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel &&
+ FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel != this )
+ FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel.Hide( false, true ) ;
+
+ FCKDomTools.SetElementStyles( eMainNode,
+ {
+ width : width ? width + 'px' : '',
+ height : height ? height + 'px' : ''
+ } ) ;
+
+ iMainWidth = eMainNode.offsetWidth ;
+
+ if ( !width ) this._IFrame.width = 1 ;
+ if ( !height ) this._IFrame.height = 1 ;
+
+ // This is weird... but with Firefox, we must get the offsetWidth before
+ // setting the _IFrame size (which returns "0"), and then after that,
+ // to return the correct width. Remove the first step and it will not
+ // work when the editor is in RTL.
+ //
+ // The "|| eMainNode.firstChild.offsetWidth" part has been added
+ // for Opera compatibility (see #570).
+ iMainWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
+
+ // Base the popup coordinates upon the coordinates of relElement.
+ var oPos = FCKTools.GetDocumentPosition( this._Window,
+ relElement.nodeType == 9 ?
+ ( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :
+ relElement ) ;
+
+ // Minus the offsets provided by any positioned parent element of the panel iframe.
+ var positionedAncestor = FCKDomTools.GetPositionedAncestor( this._IFrame.parentNode ) ;
+ if ( positionedAncestor )
+ {
+ var nPos = FCKTools.GetDocumentPosition( FCKTools.GetElementWindow( positionedAncestor ), positionedAncestor ) ;
+ oPos.x -= nPos.x ;
+ oPos.y -= nPos.y ;
+ }
+
+ if ( this.IsRTL && !this.IsContextMenu )
+ x = ( x * -1 ) ;
+
+ x += oPos.x ;
+ y += oPos.y ;
+
+ if ( this.IsRTL )
+ {
+ if ( this.IsContextMenu )
+ x = x - iMainWidth + 1 ;
+ else if ( relElement )
+ x = x + relElement.offsetWidth - iMainWidth ;
+ }
+ else
+ {
+ var oViewPaneSize = FCKTools.GetViewPaneSize( this._Window ) ;
+ var oScrollPosition = FCKTools.GetScrollPosition( this._Window ) ;
+
+ var iViewPaneHeight = oViewPaneSize.Height + oScrollPosition.Y ;
+ var iViewPaneWidth = oViewPaneSize.Width + oScrollPosition.X ;
+
+ if ( ( x + iMainWidth ) > iViewPaneWidth )
+ x -= x + iMainWidth - iViewPaneWidth ;
+
+ if ( ( y + eMainNode.offsetHeight ) > iViewPaneHeight )
+ y -= y + eMainNode.offsetHeight - iViewPaneHeight ;
+ }
+
+ // Set the context menu DIV in the specified location.
+ FCKDomTools.SetElementStyles( this._IFrame,
+ {
+ left : x + 'px',
+ top : y + 'px'
+ } ) ;
+
+ // Move the focus to the IFRAME so we catch the "onblur".
+ this._IFrame.contentWindow.focus() ;
+ this._IsOpened = true ;
+
+ var me = this ;
+ this._resizeTimer = setTimeout( function()
+ {
+ var iWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
+ var iHeight = eMainNode.offsetHeight ;
+ me._IFrame.style.width = iWidth + 'px' ;
+ me._IFrame.style.height = iHeight + 'px' ;
+
+ }, 0 ) ;
+
+ FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel = this ;
+ }
+
+ FCKTools.RunFunction( this.OnShow, this ) ;
+}
+
+FCKPanel.prototype.Hide = function( ignoreOnHide, ignoreFocusManagerUnlock )
+{
+ if ( this._Popup )
+ this._Popup.hide() ;
+ else
+ {
+ if ( !this._IsOpened || this._LockCounter > 0 )
+ return ;
+
+ // Enable the editor to fire the "OnBlur".
+ if ( typeof( FCKFocusManager ) != 'undefined' && !ignoreFocusManagerUnlock )
+ FCKFocusManager.Unlock() ;
+
+ // It is better to set the sizes to 0, otherwise Firefox would have
+ // rendering problems.
+ this._IFrame.style.width = this._IFrame.style.height = '0px' ;
+
+ this._IsOpened = false ;
+
+ if ( this._resizeTimer )
+ {
+ clearTimeout( this._resizeTimer ) ;
+ this._resizeTimer = null ;
+ }
+
+ if ( this.ParentPanel )
+ this.ParentPanel.Unlock() ;
+
+ if ( !ignoreOnHide )
+ FCKTools.RunFunction( this.OnHide, this ) ;
+ }
+}
+
+FCKPanel.prototype.CheckIsOpened = function()
+{
+ if ( this._Popup )
+ return this._Popup.isOpen ;
+ else
+ return this._IsOpened ;
+}
+
+FCKPanel.prototype.CreateChildPanel = function()
+{
+ var oWindow = this._Popup ? FCKTools.GetDocumentWindow( this.Document ) : this._Window ;
+
+ var oChildPanel = new FCKPanel( oWindow ) ;
+ oChildPanel.ParentPanel = this ;
+
+ return oChildPanel ;
+}
+
+FCKPanel.prototype.Lock = function()
+{
+ this._LockCounter++ ;
+}
+
+FCKPanel.prototype.Unlock = function()
+{
+ if ( --this._LockCounter == 0 && !this.HasFocus )
+ this.Hide() ;
+}
+
+/* Events */
+
+function FCKPanel_Window_OnFocus( e, panel )
+{
+ panel.HasFocus = true ;
+}
+
+function FCKPanel_Window_OnBlur( e, panel )
+{
+ panel.HasFocus = false ;
+
+ if ( panel._LockCounter == 0 )
+ FCKTools.RunFunction( panel.Hide, panel ) ;
+}
+
+function CheckPopupOnHide( forceHide )
+{
+ if ( forceHide || !this._Popup.isOpen )
+ {
+ window.clearInterval( this._Timer ) ;
+ this._Timer = null ;
+
+ if (this._Popup && this.ParentPanel && !forceHide)
+ this.ParentPanel.ResizeForSubpanel(this, 0, 0) ;
+
+ FCKTools.RunFunction( this.OnHide, this ) ;
+ }
+}
+
+function FCKPanel_Cleanup()
+{
+ this._Popup = null ;
+ this._Window = null ;
+ this.Document = null ;
+ this.MainNode = null ;
+ this.RelativeElement = null ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckplugin.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckplugin.js
new file mode 100644
index 0000000..28e54b4
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckplugin.js
@@ -0,0 +1,56 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKPlugin Class: Represents a single plugin.
+ */
+
+var FCKPlugin = function( name, availableLangs, basePath )
+{
+ this.Name = name ;
+ this.BasePath = basePath ? basePath : FCKConfig.PluginsPath ;
+ this.Path = this.BasePath + name + '/' ;
+
+ if ( !availableLangs || availableLangs.length == 0 )
+ this.AvailableLangs = new Array() ;
+ else
+ this.AvailableLangs = availableLangs.split(',') ;
+}
+
+FCKPlugin.prototype.Load = function()
+{
+ // Load the language file, if defined.
+ if ( this.AvailableLangs.length > 0 )
+ {
+ var sLang ;
+
+ // Check if the plugin has the language file for the active language.
+ if ( this.AvailableLangs.IndexOf( FCKLanguageManager.ActiveLanguage.Code ) >= 0 )
+ sLang = FCKLanguageManager.ActiveLanguage.Code ;
+ else
+ // Load the default language file (first one) if the current one is not available.
+ sLang = this.AvailableLangs[0] ;
+
+ // Add the main plugin script.
+ LoadScript( this.Path + 'lang/' + sLang + '.js' ) ;
+ }
+
+ // Add the main plugin script.
+ LoadScript( this.Path + 'fckplugin.js' ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckspecialcombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckspecialcombo.js
new file mode 100644
index 0000000..b31a8f6
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckspecialcombo.js
@@ -0,0 +1,376 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKSpecialCombo Class: represents a special combo.
+ */
+
+var FCKSpecialCombo = function( caption, fieldWidth, panelWidth, panelMaxHeight, parentWindow )
+{
+ // Default properties values.
+ this.FieldWidth = fieldWidth || 100 ;
+ this.PanelWidth = panelWidth || 150 ;
+ this.PanelMaxHeight = panelMaxHeight || 150 ;
+ this.Label = '&nbsp;' ;
+ this.Caption = caption ;
+ this.Tooltip = caption ;
+ this.Style = FCK_TOOLBARITEM_ICONTEXT ;
+
+ this.Enabled = true ;
+
+ this.Items = new Object() ;
+
+ this._Panel = new FCKPanel( parentWindow || window ) ;
+ this._Panel.AppendStyleSheet( FCKConfig.SkinEditorCSS ) ;
+ this._PanelBox = this._Panel.MainNode.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ;
+ this._PanelBox.className = 'SC_Panel' ;
+ this._PanelBox.style.width = this.PanelWidth + 'px' ;
+
+ this._PanelBox.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
+
+ this._ItemsHolderEl = this._PanelBox.getElementsByTagName('TD')[0] ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKSpecialCombo_Cleanup ) ;
+
+// this._Panel.StyleSheet = FCKConfig.SkinPath + 'fck_contextmenu.css' ;
+// this._Panel.Create() ;
+// this._Panel.PanelDiv.className += ' SC_Panel' ;
+// this._Panel.PanelDiv.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
+// this._ItemsHolderEl = this._Panel.PanelDiv.getElementsByTagName('TD')[0] ;
+}
+
+function FCKSpecialCombo_ItemOnMouseOver()
+{
+ this.className += ' SC_ItemOver' ;
+}
+
+function FCKSpecialCombo_ItemOnMouseOut()
+{
+ this.className = this.originalClass ;
+}
+
+function FCKSpecialCombo_ItemOnClick( ev, specialCombo, itemId )
+{
+ this.className = this.originalClass ;
+
+ specialCombo._Panel.Hide() ;
+
+ specialCombo.SetLabel( this.FCKItemLabel ) ;
+
+ if ( typeof( specialCombo.OnSelect ) == 'function' )
+ specialCombo.OnSelect( itemId, this ) ;
+}
+
+FCKSpecialCombo.prototype.ClearItems = function ()
+{
+ if ( this.Items )
+ this.Items = {} ;
+
+ var itemsholder = this._ItemsHolderEl ;
+ while ( itemsholder.firstChild )
+ itemsholder.removeChild( itemsholder.firstChild ) ;
+}
+
+FCKSpecialCombo.prototype.AddItem = function( id, html, label, bgColor )
+{
+ // <div class="SC_Item" onmouseover="this.className='SC_Item SC_ItemOver';" onmouseout="this.className='SC_Item';"><b>Bold 1</b></div>
+ var oDiv = this._ItemsHolderEl.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ;
+ oDiv.className = oDiv.originalClass = 'SC_Item' ;
+ oDiv.innerHTML = html ;
+ oDiv.FCKItemLabel = label || id ;
+ oDiv.Selected = false ;
+
+ // In IE, the width must be set so the borders are shown correctly when the content overflows.
+ if ( FCKBrowserInfo.IsIE )
+ oDiv.style.width = '100%' ;
+
+ if ( bgColor )
+ oDiv.style.backgroundColor = bgColor ;
+
+ FCKTools.AddEventListenerEx( oDiv, 'mouseover', FCKSpecialCombo_ItemOnMouseOver ) ;
+ FCKTools.AddEventListenerEx( oDiv, 'mouseout', FCKSpecialCombo_ItemOnMouseOut ) ;
+ FCKTools.AddEventListenerEx( oDiv, 'click', FCKSpecialCombo_ItemOnClick, [ this, id ] ) ;
+
+ this.Items[ id.toString().toLowerCase() ] = oDiv ;
+
+ return oDiv ;
+}
+
+FCKSpecialCombo.prototype.SelectItem = function( item )
+{
+ if ( typeof item == 'string' )
+ item = this.Items[ item.toString().toLowerCase() ] ;
+
+ if ( item )
+ {
+ item.className = item.originalClass = 'SC_ItemSelected' ;
+ item.Selected = true ;
+ }
+}
+
+FCKSpecialCombo.prototype.SelectItemByLabel = function( itemLabel, setLabel )
+{
+ for ( var id in this.Items )
+ {
+ var oDiv = this.Items[id] ;
+
+ if ( oDiv.FCKItemLabel == itemLabel )
+ {
+ oDiv.className = oDiv.originalClass = 'SC_ItemSelected' ;
+ oDiv.Selected = true ;
+
+ if ( setLabel )
+ this.SetLabel( itemLabel ) ;
+ }
+ }
+}
+
+FCKSpecialCombo.prototype.DeselectAll = function( clearLabel )
+{
+ for ( var i in this.Items )
+ {
+ if ( !this.Items[i] ) continue;
+ this.Items[i].className = this.Items[i].originalClass = 'SC_Item' ;
+ this.Items[i].Selected = false ;
+ }
+
+ if ( clearLabel )
+ this.SetLabel( '' ) ;
+}
+
+FCKSpecialCombo.prototype.SetLabelById = function( id )
+{
+ id = id ? id.toString().toLowerCase() : '' ;
+
+ var oDiv = this.Items[ id ] ;
+ this.SetLabel( oDiv ? oDiv.FCKItemLabel : '' ) ;
+}
+
+FCKSpecialCombo.prototype.SetLabel = function( text )
+{
+ text = ( !text || text.length == 0 ) ? '&nbsp;' : text ;
+
+ if ( text == this.Label )
+ return ;
+
+ this.Label = text ;
+
+ var labelEl = this._LabelEl ;
+ if ( labelEl )
+ {
+ labelEl.innerHTML = text ;
+
+ // It may happen that the label is some HTML, including tags. This
+ // would be a problem because when the user click on those tags, the
+ // combo will get the selection from the editing area. So we must
+ // disable any kind of selection here.
+ FCKTools.DisableSelection( labelEl ) ;
+ }
+}
+
+FCKSpecialCombo.prototype.SetEnabled = function( isEnabled )
+{
+ this.Enabled = isEnabled ;
+
+ // In IE it can happen when the page is reloaded that _OuterTable is null, so check its existence
+ if ( this._OuterTable )
+ this._OuterTable.className = isEnabled ? '' : 'SC_FieldDisabled' ;
+}
+
+FCKSpecialCombo.prototype.Create = function( targetElement )
+{
+ var oDoc = FCKTools.GetElementDocument( targetElement ) ;
+ var eOuterTable = this._OuterTable = targetElement.appendChild( oDoc.createElement( 'TABLE' ) ) ;
+ eOuterTable.cellPadding = 0 ;
+ eOuterTable.cellSpacing = 0 ;
+
+ eOuterTable.insertRow(-1) ;
+
+ var sClass ;
+ var bShowLabel ;
+
+ switch ( this.Style )
+ {
+ case FCK_TOOLBARITEM_ONLYICON :
+ sClass = 'TB_ButtonType_Icon' ;
+ bShowLabel = false;
+ break ;
+ case FCK_TOOLBARITEM_ONLYTEXT :
+ sClass = 'TB_ButtonType_Text' ;
+ bShowLabel = false;
+ break ;
+ case FCK_TOOLBARITEM_ICONTEXT :
+ bShowLabel = true;
+ break ;
+ }
+
+ if ( this.Caption && this.Caption.length > 0 && bShowLabel )
+ {
+ var oCaptionCell = eOuterTable.rows[0].insertCell(-1) ;
+ oCaptionCell.innerHTML = this.Caption ;
+ oCaptionCell.className = 'SC_FieldCaption' ;
+ }
+
+ // Create the main DIV element.
+ var oField = FCKTools.AppendElement( eOuterTable.rows[0].insertCell(-1), 'div' ) ;
+ if ( bShowLabel )
+ {
+ oField.className = 'SC_Field' ;
+ oField.style.width = this.FieldWidth + 'px' ;
+ oField.innerHTML = '<table width="100%" cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldLabel"><label>&nbsp;</label></td><td class="SC_FieldButton">&nbsp;</td></tr></tbody></table>' ;
+
+ this._LabelEl = oField.getElementsByTagName('label')[0] ; // Memory Leak
+ this._LabelEl.innerHTML = this.Label ;
+ }
+ else
+ {
+ oField.className = 'TB_Button_Off' ;
+ //oField.innerHTML = '<span className="SC_FieldCaption">' + this.Caption + '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
+ //oField.innerHTML = '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
+
+ // Gets the correct CSS class to use for the specified style (param).
+ oField.innerHTML = '<table title="' + this.Tooltip + '" class="' + sClass + '" cellspacing="0" cellpadding="0" border="0">' +
+ '<tr>' +
+ //'<td class="TB_Icon"><img src="' + FCKConfig.SkinPath + 'toolbar/' + this.Command.Name.toLowerCase() + '.gif" width="21" height="21"></td>' +
+ '<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
+ '<td class="TB_Text">' + this.Caption + '</td>' +
+ '<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
+ '<td class="TB_ButtonArrow"><img src="' + FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif" width="5" height="3"></td>' +
+ '<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
+ '</tr>' +
+ '</table>' ;
+ }
+
+
+ // Events Handlers
+
+ FCKTools.AddEventListenerEx( oField, 'mouseover', FCKSpecialCombo_OnMouseOver, this ) ;
+ FCKTools.AddEventListenerEx( oField, 'mouseout', FCKSpecialCombo_OnMouseOut, this ) ;
+ FCKTools.AddEventListenerEx( oField, 'click', FCKSpecialCombo_OnClick, this ) ;
+
+ FCKTools.DisableSelection( this._Panel.Document.body ) ;
+}
+
+function FCKSpecialCombo_Cleanup()
+{
+ this._LabelEl = null ;
+ this._OuterTable = null ;
+ this._ItemsHolderEl = null ;
+ this._PanelBox = null ;
+
+ if ( this.Items )
+ {
+ for ( var key in this.Items )
+ this.Items[key] = null ;
+ }
+}
+
+function FCKSpecialCombo_OnMouseOver( ev, specialCombo )
+{
+ if ( specialCombo.Enabled )
+ {
+ switch ( specialCombo.Style )
+ {
+ case FCK_TOOLBARITEM_ONLYICON :
+ this.className = 'TB_Button_On_Over';
+ break ;
+ case FCK_TOOLBARITEM_ONLYTEXT :
+ this.className = 'TB_Button_On_Over';
+ break ;
+ case FCK_TOOLBARITEM_ICONTEXT :
+ this.className = 'SC_Field SC_FieldOver' ;
+ break ;
+ }
+ }
+}
+
+function FCKSpecialCombo_OnMouseOut( ev, specialCombo )
+{
+ switch ( specialCombo.Style )
+ {
+ case FCK_TOOLBARITEM_ONLYICON :
+ this.className = 'TB_Button_Off';
+ break ;
+ case FCK_TOOLBARITEM_ONLYTEXT :
+ this.className = 'TB_Button_Off';
+ break ;
+ case FCK_TOOLBARITEM_ICONTEXT :
+ this.className='SC_Field' ;
+ break ;
+ }
+}
+
+function FCKSpecialCombo_OnClick( e, specialCombo )
+{
+ // For Mozilla we must stop the event propagation to avoid it hiding
+ // the panel because of a click outside of it.
+// if ( e )
+// {
+// e.stopPropagation() ;
+// FCKPanelEventHandlers.OnDocumentClick( e ) ;
+// }
+
+ if ( specialCombo.Enabled )
+ {
+ var oPanel = specialCombo._Panel ;
+ var oPanelBox = specialCombo._PanelBox ;
+ var oItemsHolder = specialCombo._ItemsHolderEl ;
+ var iMaxHeight = specialCombo.PanelMaxHeight ;
+
+ if ( specialCombo.OnBeforeClick )
+ specialCombo.OnBeforeClick( specialCombo ) ;
+
+ // This is a tricky thing. We must call the "Load" function, otherwise
+ // it will not be possible to retrieve "oItemsHolder.offsetHeight" (IE only).
+ if ( FCKBrowserInfo.IsIE )
+ oPanel.Preload( 0, this.offsetHeight, this ) ;
+
+ if ( oItemsHolder.offsetHeight > iMaxHeight )
+// {
+ oPanelBox.style.height = iMaxHeight + 'px' ;
+
+// if ( FCKBrowserInfo.IsGecko )
+// oPanelBox.style.overflow = '-moz-scrollbars-vertical' ;
+// }
+ else
+ oPanelBox.style.height = '' ;
+
+// oPanel.PanelDiv.style.width = specialCombo.PanelWidth + 'px' ;
+
+ oPanel.Show( 0, this.offsetHeight, this ) ;
+ }
+
+// return false ;
+}
+
+/*
+Sample Combo Field HTML output:
+
+<div class="SC_Field" style="width: 80px;">
+ <table width="100%" cellpadding="0" cellspacing="0" style="table-layout: fixed;">
+ <tbody>
+ <tr>
+ <td class="SC_FieldLabel"><label>&nbsp;</label></td>
+ <td class="SC_FieldButton">&nbsp;</td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+*/
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckstyle.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckstyle.js
new file mode 100644
index 0000000..540f70e
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckstyle.js
@@ -0,0 +1,1500 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKStyle Class: contains a style definition, and all methods to work with
+ * the style in a document.
+ */
+
+/**
+ * @param {Object} styleDesc A "style descriptor" object, containing the raw
+ * style definition in the following format:
+ * '<style name>' : {
+ * Element : '<element name>',
+ * Attributes : {
+ * '<att name>' : '<att value>',
+ * ...
+ * },
+ * Styles : {
+ * '<style name>' : '<style value>',
+ * ...
+ * },
+ * Overrides : '<element name>'|{
+ * Element : '<element name>',
+ * Attributes : {
+ * '<att name>' : '<att value>'|/<att regex>/
+ * },
+ * Styles : {
+ * '<style name>' : '<style value>'|/<style regex>/
+ * },
+ * }
+ * }
+ */
+var FCKStyle = function( styleDesc )
+{
+ this.Element = ( styleDesc.Element || 'span' ).toLowerCase() ;
+ this._StyleDesc = styleDesc ;
+}
+
+FCKStyle.prototype =
+{
+ /**
+ * Get the style type, based on its element name:
+ * - FCK_STYLE_BLOCK (0): Block Style
+ * - FCK_STYLE_INLINE (1): Inline Style
+ * - FCK_STYLE_OBJECT (2): Object Style
+ */
+ GetType : function()
+ {
+ var type = this.GetType_$ ;
+
+ if ( type != undefined )
+ return type ;
+
+ var elementName = this.Element ;
+
+ if ( elementName == '#' || FCKListsLib.StyleBlockElements[ elementName ] )
+ type = FCK_STYLE_BLOCK ;
+ else if ( FCKListsLib.StyleObjectElements[ elementName ] )
+ type = FCK_STYLE_OBJECT ;
+ else
+ type = FCK_STYLE_INLINE ;
+
+ return ( this.GetType_$ = type ) ;
+ },
+
+ /**
+ * Apply the style to the current selection.
+ */
+ ApplyToSelection : function( targetWindow )
+ {
+ // Create a range for the current selection.
+ var range = new FCKDomRange( targetWindow ) ;
+ range.MoveToSelection() ;
+
+ this.ApplyToRange( range, true ) ;
+ },
+
+ /**
+ * Apply the style to a FCKDomRange.
+ */
+ ApplyToRange : function( range, selectIt, updateRange )
+ {
+ // ApplyToRange is not valid for FCK_STYLE_OBJECT types.
+ // Use ApplyToObject instead.
+
+ switch ( this.GetType() )
+ {
+ case FCK_STYLE_BLOCK :
+ this.ApplyToRange = this._ApplyBlockStyle ;
+ break ;
+ case FCK_STYLE_INLINE :
+ this.ApplyToRange = this._ApplyInlineStyle ;
+ break ;
+ default :
+ return ;
+ }
+
+ this.ApplyToRange( range, selectIt, updateRange ) ;
+ },
+
+ /**
+ * Apply the style to an object. Valid for FCK_STYLE_BLOCK types only.
+ */
+ ApplyToObject : function( objectElement )
+ {
+ if ( !objectElement )
+ return ;
+
+ this.BuildElement( null, objectElement ) ;
+ },
+
+ /**
+ * Remove the style from the current selection.
+ */
+ RemoveFromSelection : function( targetWindow )
+ {
+ // Create a range for the current selection.
+ var range = new FCKDomRange( targetWindow ) ;
+ range.MoveToSelection() ;
+
+ this.RemoveFromRange( range, true ) ;
+ },
+
+ /**
+ * Remove the style from a FCKDomRange. Block type styles will have no
+ * effect.
+ */
+ RemoveFromRange : function( range, selectIt, updateRange )
+ {
+ var bookmark ;
+
+ // Create the attribute list to be used later for element comparisons.
+ var styleAttribs = this._GetAttribsForComparison() ;
+ var styleOverrides = this._GetOverridesForComparison() ;
+
+ // If collapsed, we are removing all conflicting styles from the range
+ // parent tree.
+ if ( range.CheckIsCollapsed() )
+ {
+ // Bookmark the range so we can re-select it after processing.
+ var bookmark = range.CreateBookmark( true ) ;
+
+ // Let's start from the bookmark <span> parent.
+ var bookmarkStart = range.GetBookmarkNode( bookmark, true ) ;
+
+ var path = new FCKElementPath( bookmarkStart.parentNode ) ;
+
+ // While looping through the path, we'll be saving references to
+ // parent elements if the range is in one of their boundaries. In
+ // this way, we are able to create a copy of those elements when
+ // removing a style if the range is in a boundary limit (see #1270).
+ var boundaryElements = [] ;
+
+ // Check if the range is in the boundary limits of an element
+ // (related to #1270).
+ var isBoundaryRight = !FCKDomTools.GetNextSibling( bookmarkStart ) ;
+ var isBoundary = isBoundaryRight || !FCKDomTools.GetPreviousSibling( bookmarkStart ) ;
+
+ // This is the last element to be removed in the boundary situation
+ // described at #1270.
+ var lastBoundaryElement ;
+ var boundaryLimitIndex = -1 ;
+
+ for ( var i = 0 ; i < path.Elements.length ; i++ )
+ {
+ var pathElement = path.Elements[i] ;
+ if ( this.CheckElementRemovable( pathElement ) )
+ {
+ if ( isBoundary
+ && !FCKDomTools.CheckIsEmptyElement( pathElement,
+ function( el )
+ {
+ return ( el != bookmarkStart ) ;
+ } )
+ )
+ {
+ lastBoundaryElement = pathElement ;
+
+ // We'll be continuously including elements in the
+ // boundaryElements array, but only those added before
+ // setting lastBoundaryElement must be used later, so
+ // let's mark the current index here.
+ boundaryLimitIndex = boundaryElements.length - 1 ;
+ }
+ else
+ {
+ var pathElementName = pathElement.nodeName.toLowerCase() ;
+
+ if ( pathElementName == this.Element )
+ {
+ // Remove any attribute that conflict with this style, no
+ // matter their values.
+ for ( var att in styleAttribs )
+ {
+ if ( FCKDomTools.HasAttribute( pathElement, att ) )
+ {
+ switch ( att )
+ {
+ case 'style' :
+ this._RemoveStylesFromElement( pathElement ) ;
+ break ;
+
+ case 'class' :
+ // The 'class' element value must match (#1318).
+ if ( FCKDomTools.GetAttributeValue( pathElement, att ) != this.GetFinalAttributeValue( att ) )
+ continue ;
+
+ /*jsl:fallthru*/
+
+ default :
+ FCKDomTools.RemoveAttribute( pathElement, att ) ;
+ }
+ }
+ }
+ }
+
+ // Remove overrides defined to the same element name.
+ this._RemoveOverrides( pathElement, styleOverrides[ pathElementName ] ) ;
+
+ // Remove the element if no more attributes are available and it's an inline style element
+ if ( this.GetType() == FCK_STYLE_INLINE)
+ this._RemoveNoAttribElement( pathElement ) ;
+ }
+ }
+ else if ( isBoundary )
+ boundaryElements.push( pathElement ) ;
+
+ // Check if we are still in a boundary (at the same side).
+ isBoundary = isBoundary && ( ( isBoundaryRight && !FCKDomTools.GetNextSibling( pathElement ) ) || ( !isBoundaryRight && !FCKDomTools.GetPreviousSibling( pathElement ) ) ) ;
+
+ // If we are in an element that is not anymore a boundary, or
+ // we are at the last element, let's move things outside the
+ // boundary (if available).
+ if ( lastBoundaryElement && ( !isBoundary || ( i == path.Elements.length - 1 ) ) )
+ {
+ // Remove the bookmark node from the DOM.
+ var currentElement = FCKDomTools.RemoveNode( bookmarkStart ) ;
+
+ // Build the collapsed group of elements that are not
+ // removed by this style, but share the boundary.
+ // (see comment 1 and 2 at #1270)
+ for ( var j = 0 ; j <= boundaryLimitIndex ; j++ )
+ {
+ var newElement = FCKDomTools.CloneElement( boundaryElements[j] ) ;
+ newElement.appendChild( currentElement ) ;
+ currentElement = newElement ;
+ }
+
+ // Re-insert the bookmark node (and the collapsed elements)
+ // in the DOM, in the new position next to the styled element.
+ if ( isBoundaryRight )
+ FCKDomTools.InsertAfterNode( lastBoundaryElement, currentElement ) ;
+ else
+ lastBoundaryElement.parentNode.insertBefore( currentElement, lastBoundaryElement ) ;
+
+ isBoundary = false ;
+ lastBoundaryElement = null ;
+ }
+ }
+
+ // Re-select the original range.
+ if ( selectIt )
+ range.SelectBookmark( bookmark ) ;
+
+ if ( updateRange )
+ range.MoveToBookmark( bookmark ) ;
+
+ return ;
+ }
+
+ // Expand the range, if inside inline element boundaries.
+ range.Expand( 'inline_elements' ) ;
+
+ // Bookmark the range so we can re-select it after processing.
+ bookmark = range.CreateBookmark( true ) ;
+
+ // The style will be applied within the bookmark boundaries.
+ var startNode = range.GetBookmarkNode( bookmark, true ) ;
+ var endNode = range.GetBookmarkNode( bookmark, false ) ;
+
+ range.Release( true ) ;
+
+ // We need to check the selection boundaries (bookmark spans) to break
+ // the code in a way that we can properly remove partially selected nodes.
+ // For example, removing a <b> style from
+ // <b>This is [some text</b> to show <b>the] problem</b>
+ // ... where [ and ] represent the selection, must result:
+ // <b>This is </b>[some text to show the]<b> problem</b>
+ // The strategy is simple, we just break the partial nodes before the
+ // removal logic, having something that could be represented this way:
+ // <b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
+
+ // Let's start checking the start boundary.
+ var path = new FCKElementPath( startNode ) ;
+ var pathElements = path.Elements ;
+ var pathElement ;
+
+ for ( var i = 1 ; i < pathElements.length ; i++ )
+ {
+ pathElement = pathElements[i] ;
+
+ if ( pathElement == path.Block || pathElement == path.BlockLimit )
+ break ;
+
+ // If this element can be removed (even partially).
+ if ( this.CheckElementRemovable( pathElement ) )
+ FCKDomTools.BreakParent( startNode, pathElement, range ) ;
+ }
+
+ // Now the end boundary.
+ path = new FCKElementPath( endNode ) ;
+ pathElements = path.Elements ;
+
+ for ( var i = 1 ; i < pathElements.length ; i++ )
+ {
+ pathElement = pathElements[i] ;
+
+ if ( pathElement == path.Block || pathElement == path.BlockLimit )
+ break ;
+
+ elementName = pathElement.nodeName.toLowerCase() ;
+
+ // If this element can be removed (even partially).
+ if ( this.CheckElementRemovable( pathElement ) )
+ FCKDomTools.BreakParent( endNode, pathElement, range ) ;
+ }
+
+ // Navigate through all nodes between the bookmarks.
+ var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
+
+ while ( currentNode )
+ {
+ // Cache the next node to be processed. Do it now, because
+ // currentNode may be removed.
+ var nextNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
+
+ // Remove elements nodes that match with this style rules.
+ if ( currentNode.nodeType == 1 )
+ {
+ var elementName = currentNode.nodeName.toLowerCase() ;
+
+ var mayRemove = ( elementName == this.Element ) ;
+ if ( mayRemove )
+ {
+ // Remove any attribute that conflict with this style, no matter
+ // their values.
+ for ( var att in styleAttribs )
+ {
+ if ( FCKDomTools.HasAttribute( currentNode, att ) )
+ {
+ switch ( att )
+ {
+ case 'style' :
+ this._RemoveStylesFromElement( currentNode ) ;
+ break ;
+
+ case 'class' :
+ // The 'class' element value must match (#1318).
+ if ( FCKDomTools.GetAttributeValue( currentNode, att ) != this.GetFinalAttributeValue( att ) )
+ continue ;
+
+ /*jsl:fallthru*/
+
+ default :
+ FCKDomTools.RemoveAttribute( currentNode, att ) ;
+ }
+ }
+ }
+ }
+ else
+ mayRemove = !!styleOverrides[ elementName ] ;
+
+ if ( mayRemove )
+ {
+ // Remove overrides defined to the same element name.
+ this._RemoveOverrides( currentNode, styleOverrides[ elementName ] ) ;
+
+ // Remove the element if no more attributes are available.
+ this._RemoveNoAttribElement( currentNode ) ;
+ }
+ }
+
+ // If we have reached the end of the selection, stop looping.
+ if ( nextNode == endNode )
+ break ;
+
+ currentNode = nextNode ;
+ }
+
+ this._FixBookmarkStart( startNode ) ;
+
+ // Re-select the original range.
+ if ( selectIt )
+ range.SelectBookmark( bookmark ) ;
+
+ if ( updateRange )
+ range.MoveToBookmark( bookmark ) ;
+ },
+
+ /**
+ * Checks if an element, or any of its attributes, is removable by the
+ * current style definition.
+ */
+ CheckElementRemovable : function( element, fullMatch )
+ {
+ if ( !element )
+ return false ;
+
+ var elementName = element.nodeName.toLowerCase() ;
+
+ // If the element name is the same as the style name.
+ if ( elementName == this.Element )
+ {
+ // If no attributes are defined in the element.
+ if ( !fullMatch && !FCKDomTools.HasAttributes( element ) )
+ return true ;
+
+ // If any attribute conflicts with the style attributes.
+ var attribs = this._GetAttribsForComparison() ;
+ var allMatched = ( attribs._length == 0 ) ;
+ for ( var att in attribs )
+ {
+ if ( att == '_length' )
+ continue ;
+
+ if ( this._CompareAttributeValues( att, FCKDomTools.GetAttributeValue( element, att ), ( this.GetFinalAttributeValue( att ) || '' ) ) )
+ {
+ allMatched = true ;
+ if ( !fullMatch )
+ break ;
+ }
+ else
+ {
+ allMatched = false ;
+ if ( fullMatch )
+ return false ;
+ }
+ }
+ if ( allMatched )
+ return true ;
+ }
+
+ // Check if the element can be somehow overriden.
+ var override = this._GetOverridesForComparison()[ elementName ] ;
+ if ( override )
+ {
+ // If no attributes have been defined, remove the element.
+ if ( !( attribs = override.Attributes ) ) // Only one "="
+ return true ;
+
+ for ( var i = 0 ; i < attribs.length ; i++ )
+ {
+ var attName = attribs[i][0] ;
+ if ( FCKDomTools.HasAttribute( element, attName ) )
+ {
+ var attValue = attribs[i][1] ;
+
+ // Remove the attribute if:
+ // - The override definition value is null ;
+ // - The override definition valie is a string that
+ // matches the attribute value exactly.
+ // - The override definition value is a regex that
+ // has matches in the attribute value.
+ if ( attValue == null ||
+ ( typeof attValue == 'string' && FCKDomTools.GetAttributeValue( element, attName ) == attValue ) ||
+ attValue.test( FCKDomTools.GetAttributeValue( element, attName ) ) )
+ return true ;
+ }
+ }
+ }
+
+ return false ;
+ },
+
+ /**
+ * Get the style state for an element path. Returns "true" if the element
+ * is active in the path.
+ */
+ CheckActive : function( elementPath )
+ {
+ switch ( this.GetType() )
+ {
+ case FCK_STYLE_BLOCK :
+ return this.CheckElementRemovable( elementPath.Block || elementPath.BlockLimit, true ) ;
+
+ case FCK_STYLE_INLINE :
+
+ var elements = elementPath.Elements ;
+
+ for ( var i = 0 ; i < elements.length ; i++ )
+ {
+ var element = elements[i] ;
+
+ if ( element == elementPath.Block || element == elementPath.BlockLimit )
+ continue ;
+
+ if ( this.CheckElementRemovable( element, true ) )
+ return true ;
+ }
+ }
+ return false ;
+ },
+
+ /**
+ * Removes an inline style from inside an element tree. The element node
+ * itself is not checked or removed, only the child tree inside of it.
+ */
+ RemoveFromElement : function( element )
+ {
+ var attribs = this._GetAttribsForComparison() ;
+ var overrides = this._GetOverridesForComparison() ;
+
+ // Get all elements with the same name.
+ var innerElements = element.getElementsByTagName( this.Element ) ;
+
+ for ( var i = innerElements.length - 1 ; i >= 0 ; i-- )
+ {
+ var innerElement = innerElements[i] ;
+
+ // Remove any attribute that conflict with this style, no matter
+ // their values.
+ for ( var att in attribs )
+ {
+ if ( FCKDomTools.HasAttribute( innerElement, att ) )
+ {
+ switch ( att )
+ {
+ case 'style' :
+ this._RemoveStylesFromElement( innerElement ) ;
+ break ;
+
+ case 'class' :
+ // The 'class' element value must match (#1318).
+ if ( FCKDomTools.GetAttributeValue( innerElement, att ) != this.GetFinalAttributeValue( att ) )
+ continue ;
+
+ /*jsl:fallthru*/
+
+ default :
+ FCKDomTools.RemoveAttribute( innerElement, att ) ;
+ }
+ }
+ }
+
+ // Remove overrides defined to the same element name.
+ this._RemoveOverrides( innerElement, overrides[ this.Element ] ) ;
+
+ // Remove the element if no more attributes are available.
+ this._RemoveNoAttribElement( innerElement ) ;
+ }
+
+ // Now remove any other element with different name that is
+ // defined to be overriden.
+ for ( var overrideElement in overrides )
+ {
+ if ( overrideElement != this.Element )
+ {
+ // Get all elements.
+ innerElements = element.getElementsByTagName( overrideElement ) ;
+
+ for ( var i = innerElements.length - 1 ; i >= 0 ; i-- )
+ {
+ var innerElement = innerElements[i] ;
+ this._RemoveOverrides( innerElement, overrides[ overrideElement ] ) ;
+ this._RemoveNoAttribElement( innerElement ) ;
+ }
+ }
+ }
+ },
+
+ _RemoveStylesFromElement : function( element )
+ {
+ var elementStyle = element.style.cssText ;
+ var pattern = this.GetFinalStyleValue() ;
+
+ if ( elementStyle.length > 0 && pattern.length == 0 )
+ return ;
+
+ pattern = '(^|;)\\s*(' +
+ pattern.replace( /\s*([^ ]+):.*?(;|$)/g, '$1|' ).replace( /\|$/, '' ) +
+ '):[^;]+' ;
+
+ var regex = new RegExp( pattern, 'gi' ) ;
+
+ elementStyle = elementStyle.replace( regex, '' ).Trim() ;
+
+ if ( elementStyle.length == 0 || elementStyle == ';' )
+ FCKDomTools.RemoveAttribute( element, 'style' ) ;
+ else
+ element.style.cssText = elementStyle.replace( regex, '' ) ;
+ },
+
+ /**
+ * Remove all attributes that are defined to be overriden,
+ */
+ _RemoveOverrides : function( element, override )
+ {
+ var attributes = override && override.Attributes ;
+
+ if ( attributes )
+ {
+ for ( var i = 0 ; i < attributes.length ; i++ )
+ {
+ var attName = attributes[i][0] ;
+
+ if ( FCKDomTools.HasAttribute( element, attName ) )
+ {
+ var attValue = attributes[i][1] ;
+
+ // Remove the attribute if:
+ // - The override definition value is null ;
+ // - The override definition valie is a string that
+ // matches the attribute value exactly.
+ // - The override definition value is a regex that
+ // has matches in the attribute value.
+ if ( attValue == null ||
+ ( attValue.test && attValue.test( FCKDomTools.GetAttributeValue( element, attName ) ) ) ||
+ ( typeof attValue == 'string' && FCKDomTools.GetAttributeValue( element, attName ) == attValue ) )
+ FCKDomTools.RemoveAttribute( element, attName ) ;
+ }
+ }
+ }
+ },
+
+ /**
+ * If the element has no more attributes, remove it.
+ */
+ _RemoveNoAttribElement : function( element )
+ {
+ // If no more attributes remained in the element, remove it,
+ // leaving its children.
+ if ( !FCKDomTools.HasAttributes( element ) )
+ {
+ // Removing elements may open points where merging is possible,
+ // so let's cache the first and last nodes for later checking.
+ var firstChild = element.firstChild ;
+ var lastChild = element.lastChild ;
+
+ FCKDomTools.RemoveNode( element, true ) ;
+
+ // Check the cached nodes for merging.
+ this._MergeSiblings( firstChild ) ;
+
+ if ( firstChild != lastChild )
+ this._MergeSiblings( lastChild ) ;
+ }
+ },
+
+ /**
+ * Creates a DOM element for this style object.
+ */
+ BuildElement : function( targetDoc, element )
+ {
+ // Create the element.
+ var el = element || targetDoc.createElement( this.Element ) ;
+
+ // Assign all defined attributes.
+ var attribs = this._StyleDesc.Attributes ;
+ var attValue ;
+ if ( attribs )
+ {
+ for ( var att in attribs )
+ {
+ attValue = this.GetFinalAttributeValue( att ) ;
+
+ if ( att.toLowerCase() == 'class' )
+ el.className = attValue ;
+ else
+ el.setAttribute( att, attValue ) ;
+ }
+ }
+
+ // Assign the style attribute.
+ if ( this._GetStyleText().length > 0 )
+ el.style.cssText = this.GetFinalStyleValue() ;
+
+ return el ;
+ },
+
+ _CompareAttributeValues : function( attName, valueA, valueB )
+ {
+ if ( attName == 'style' && valueA && valueB )
+ {
+ valueA = valueA.replace( /;$/, '' ).toLowerCase() ;
+ valueB = valueB.replace( /;$/, '' ).toLowerCase() ;
+ }
+
+ // Return true if they match or if valueA is null and valueB is an empty string
+ return ( valueA == valueB || ( ( valueA === null || valueA === '' ) && ( valueB === null || valueB === '' ) ) )
+ },
+
+ GetFinalAttributeValue : function( attName )
+ {
+ var attValue = this._StyleDesc.Attributes ;
+ var attValue = attValue ? attValue[ attName ] : null ;
+
+ if ( !attValue && attName == 'style' )
+ return this.GetFinalStyleValue() ;
+
+ if ( attValue && this._Variables )
+ // Using custom Replace() to guarantee the correct scope.
+ attValue = attValue.Replace( FCKRegexLib.StyleVariableAttName, this._GetVariableReplace, this ) ;
+
+ return attValue ;
+ },
+
+ GetFinalStyleValue : function()
+ {
+ var attValue = this._GetStyleText() ;
+
+ if ( attValue.length > 0 && this._Variables )
+ {
+ // Using custom Replace() to guarantee the correct scope.
+ attValue = attValue.Replace( FCKRegexLib.StyleVariableAttName, this._GetVariableReplace, this ) ;
+ attValue = FCKTools.NormalizeCssText( attValue ) ;
+ }
+
+ return attValue ;
+ },
+
+ _GetVariableReplace : function()
+ {
+ // The second group in the regex is the variable name.
+ return this._Variables[ arguments[2] ] || arguments[0] ;
+ },
+
+ /**
+ * Set the value of a variable attribute or style, to be used when
+ * appliying the style.
+ */
+ SetVariable : function( name, value )
+ {
+ var variables = this._Variables ;
+
+ if ( !variables )
+ variables = this._Variables = {} ;
+
+ this._Variables[ name ] = value ;
+ },
+
+ /**
+ * Converting from a PRE block to a non-PRE block in formatting operations.
+ */
+ _FromPre : function( doc, block, newBlock )
+ {
+ var innerHTML = block.innerHTML ;
+
+ // Trim the first and last linebreaks immediately after and before <pre>, </pre>,
+ // if they exist.
+ // This is done because the linebreaks are not rendered.
+ innerHTML = innerHTML.replace( /(\r\n|\r)/g, '\n' ) ;
+ innerHTML = innerHTML.replace( /^[ \t]*\n/, '' ) ;
+ innerHTML = innerHTML.replace( /\n$/, '' ) ;
+
+ // 1. Convert spaces or tabs at the beginning or at the end to &nbsp;
+ innerHTML = innerHTML.replace( /^[ \t]+|[ \t]+$/g, function( match, offset, s )
+ {
+ if ( match.length == 1 ) // one space, preserve it
+ return '&nbsp;' ;
+ else if ( offset == 0 ) // beginning of block
+ return new Array( match.length ).join( '&nbsp;' ) + ' ' ;
+ else // end of block
+ return ' ' + new Array( match.length ).join( '&nbsp;' ) ;
+ } ) ;
+
+ // 2. Convert \n to <BR>.
+ // 3. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;
+ var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
+ var results = [] ;
+ htmlIterator.Each( function( isTag, value )
+ {
+ if ( !isTag )
+ {
+ value = value.replace( /\n/g, '<br>' ) ;
+ value = value.replace( /[ \t]{2,}/g,
+ function ( match )
+ {
+ return new Array( match.length ).join( '&nbsp;' ) + ' ' ;
+ } ) ;
+ }
+ results.push( value ) ;
+ } ) ;
+ newBlock.innerHTML = results.join( '' ) ;
+ return newBlock ;
+ },
+
+ /**
+ * Converting from a non-PRE block to a PRE block in formatting operations.
+ */
+ _ToPre : function( doc, block, newBlock )
+ {
+ // Handle converting from a regular block to a <pre> block.
+ var innerHTML = block.innerHTML.Trim() ;
+
+ // 1. Delete ANSI whitespaces immediately before and after <BR> because
+ // they are not visible.
+ // 2. Mark down any <BR /> nodes here so they can be turned into \n in
+ // the next step and avoid being compressed.
+ innerHTML = innerHTML.replace( /[ \t\r\n]*(<br[^>]*>)[ \t\r\n]*/gi, '<br />' ) ;
+
+ // 3. Compress other ANSI whitespaces since they're only visible as one
+ // single space previously.
+ // 4. Convert &nbsp; to spaces since &nbsp; is no longer needed in <PRE>.
+ // 5. Convert any <BR /> to \n. This must not be done earlier because
+ // the \n would then get compressed.
+ var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
+ var results = [] ;
+ htmlIterator.Each( function( isTag, value )
+ {
+ if ( !isTag )
+ value = value.replace( /([ \t\n\r]+|&nbsp;)/g, ' ' ) ;
+ else if ( isTag && value == '<br />' )
+ value = '\n' ;
+ results.push( value ) ;
+ } ) ;
+
+ // Assigning innerHTML to <PRE> in IE causes all linebreaks to be
+ // reduced to spaces.
+ // Assigning outerHTML to <PRE> in IE doesn't work if the <PRE> isn't
+ // contained in another node since the node reference is changed after
+ // outerHTML assignment.
+ // So, we need some hacks to workaround IE bugs here.
+ if ( FCKBrowserInfo.IsIE )
+ {
+ var temp = doc.createElement( 'div' ) ;
+ temp.appendChild( newBlock ) ;
+ newBlock.outerHTML = '<pre>\n' + results.join( '' ) + '</pre>' ;
+ newBlock = temp.removeChild( temp.firstChild ) ;
+ }
+ else
+ newBlock.innerHTML = results.join( '' ) ;
+
+ return newBlock ;
+ },
+
+ /**
+ * Merge a <pre> block with a previous <pre> block, if available.
+ */
+ _CheckAndMergePre : function( previousBlock, preBlock )
+ {
+ // Check if the previous block and the current block are next
+ // to each other.
+ if ( previousBlock != FCKDomTools.GetPreviousSourceElement( preBlock, true ) )
+ return ;
+
+ // Merge the previous <pre> block contents into the current <pre>
+ // block.
+ //
+ // Another thing to be careful here is that currentBlock might contain
+ // a '\n' at the beginning, and previousBlock might contain a '\n'
+ // towards the end. These new lines are not normally displayed but they
+ // become visible after merging.
+ var innerHTML = previousBlock.innerHTML.replace( /\n$/, '' ) + '\n\n' +
+ preBlock.innerHTML.replace( /^\n/, '' ) ;
+
+ // Buggy IE normalizes innerHTML from <pre>, breaking whitespaces.
+ if ( FCKBrowserInfo.IsIE )
+ preBlock.outerHTML = '<pre>' + innerHTML + '</pre>' ;
+ else
+ preBlock.innerHTML = innerHTML ;
+
+ // Remove the previous <pre> block.
+ //
+ // The preBlock must not be moved or deleted from the DOM tree. This
+ // guarantees the FCKDomRangeIterator in _ApplyBlockStyle would not
+ // get lost at the next iteration.
+ FCKDomTools.RemoveNode( previousBlock ) ;
+ },
+
+ _CheckAndSplitPre : function( newBlock )
+ {
+ var lastNewBlock ;
+
+ var cursor = newBlock.firstChild ;
+
+ // We are not splitting <br><br> at the beginning of the block, so
+ // we'll start from the second child.
+ cursor = cursor && cursor.nextSibling ;
+
+ while ( cursor )
+ {
+ var next = cursor.nextSibling ;
+
+ // If we have two <BR>s, and they're not at the beginning or the end,
+ // then we'll split up the contents following them into another block.
+ // Stop processing if we are at the last child couple.
+ if ( next && next.nextSibling && cursor.nodeName.IEquals( 'br' ) && next.nodeName.IEquals( 'br' ) )
+ {
+ // Remove the first <br>.
+ FCKDomTools.RemoveNode( cursor ) ;
+
+ // Move to the node after the second <br>.
+ cursor = next.nextSibling ;
+
+ // Remove the second <br>.
+ FCKDomTools.RemoveNode( next ) ;
+
+ // Create the block that will hold the child nodes from now on.
+ lastNewBlock = FCKDomTools.InsertAfterNode( lastNewBlock || newBlock, FCKDomTools.CloneElement( newBlock ) ) ;
+
+ continue ;
+ }
+
+ // If we split it, then start moving the nodes to the new block.
+ if ( lastNewBlock )
+ {
+ cursor = cursor.previousSibling ;
+ FCKDomTools.MoveNode(cursor.nextSibling, lastNewBlock ) ;
+ }
+
+ cursor = cursor.nextSibling ;
+ }
+ },
+
+ /**
+ * Apply an inline style to a FCKDomRange.
+ *
+ * TODO
+ * - Implement the "#" style handling.
+ * - Properly handle block containers like <div> and <blockquote>.
+ */
+ _ApplyBlockStyle : function( range, selectIt, updateRange )
+ {
+ // Bookmark the range so we can re-select it after processing.
+ var bookmark ;
+
+ if ( selectIt )
+ bookmark = range.CreateBookmark() ;
+
+ var iterator = new FCKDomRangeIterator( range ) ;
+ iterator.EnforceRealBlocks = true ;
+
+ var block ;
+ var doc = range.Window.document ;
+ var previousPreBlock ;
+
+ while( ( block = iterator.GetNextParagraph() ) ) // Only one =
+ {
+ // Create the new node right before the current one.
+ var newBlock = this.BuildElement( doc ) ;
+
+ // Check if we are changing from/to <pre>.
+ var newBlockIsPre = newBlock.nodeName.IEquals( 'pre' ) ;
+ var blockIsPre = block.nodeName.IEquals( 'pre' ) ;
+
+ var toPre = newBlockIsPre && !blockIsPre ;
+ var fromPre = !newBlockIsPre && blockIsPre ;
+
+ // Move everything from the current node to the new one.
+ if ( toPre )
+ newBlock = this._ToPre( doc, block, newBlock ) ;
+ else if ( fromPre )
+ newBlock = this._FromPre( doc, block, newBlock ) ;
+ else // Convering from a regular block to another regular block.
+ FCKDomTools.MoveChildren( block, newBlock ) ;
+
+ // Replace the current block.
+ block.parentNode.insertBefore( newBlock, block ) ;
+ FCKDomTools.RemoveNode( block ) ;
+
+ // Complete other tasks after inserting the node in the DOM.
+ if ( newBlockIsPre )
+ {
+ if ( previousPreBlock )
+ this._CheckAndMergePre( previousPreBlock, newBlock ) ; // Merge successive <pre> blocks.
+ previousPreBlock = newBlock ;
+ }
+ else if ( fromPre )
+ this._CheckAndSplitPre( newBlock ) ; // Split <br><br> in successive <pre>s.
+ }
+
+ // Re-select the original range.
+ if ( selectIt )
+ range.SelectBookmark( bookmark ) ;
+
+ if ( updateRange )
+ range.MoveToBookmark( bookmark ) ;
+ },
+
+ /**
+ * Apply an inline style to a FCKDomRange.
+ *
+ * TODO
+ * - Merge elements, when applying styles to similar elements that enclose
+ * the entire selection, outputing:
+ * <span style="color: #ff0000; background-color: #ffffff">XYZ</span>
+ * instead of:
+ * <span style="color: #ff0000;"><span style="background-color: #ffffff">XYZ</span></span>
+ */
+ _ApplyInlineStyle : function( range, selectIt, updateRange )
+ {
+ var doc = range.Window.document ;
+
+ if ( range.CheckIsCollapsed() )
+ {
+ // Create the element to be inserted in the DOM.
+ var collapsedElement = this.BuildElement( doc ) ;
+ range.InsertNode( collapsedElement ) ;
+ range.MoveToPosition( collapsedElement, 2 ) ;
+ range.Select() ;
+
+ return ;
+ }
+
+ // The general idea here is navigating through all nodes inside the
+ // current selection, working on distinct range blocks, defined by the
+ // DTD compatibility between the style element and the nodes inside the
+ // ranges.
+ //
+ // For example, suppose we have the following selection (where [ and ]
+ // are the boundaries), and we apply a <b> style there:
+ //
+ // <p>Here we [have <b>some</b> text.<p>
+ // <p>And some here] here.</p>
+ //
+ // Two different ranges will be detected:
+ //
+ // "have <b>some</b> text."
+ // "And some here"
+ //
+ // Both ranges will be extracted, moved to a <b> element, and
+ // re-inserted, resulting in the following output:
+ //
+ // <p>Here we [<b>have some text.</b><p>
+ // <p><b>And some here</b>] here.</p>
+ //
+ // Note that the <b> element at <b>some</b> is also removed because it
+ // is not needed anymore.
+
+ var elementName = this.Element ;
+
+ // Get the DTD definition for the element. Defaults to "span".
+ var elementDTD = FCK.DTD[ elementName ] || FCK.DTD.span ;
+
+ // Create the attribute list to be used later for element comparisons.
+ var styleAttribs = this._GetAttribsForComparison() ;
+ var styleNode ;
+
+ // Expand the range, if inside inline element boundaries.
+ range.Expand( 'inline_elements' ) ;
+
+ // Bookmark the range so we can re-select it after processing.
+ var bookmark = range.CreateBookmark( true ) ;
+
+ // The style will be applied within the bookmark boundaries.
+ var startNode = range.GetBookmarkNode( bookmark, true ) ;
+ var endNode = range.GetBookmarkNode( bookmark, false ) ;
+
+ // We'll be reusing the range to apply the styles. So, release it here
+ // to indicate that it has not been initialized.
+ range.Release( true ) ;
+
+ // Let's start the nodes lookup from the node right after the bookmark
+ // span.
+ var currentNode = FCKDomTools.GetNextSourceNode( startNode, true ) ;
+
+ while ( currentNode )
+ {
+ var applyStyle = false ;
+
+ var nodeType = currentNode.nodeType ;
+ var nodeName = nodeType == 1 ? currentNode.nodeName.toLowerCase() : null ;
+
+ // Check if the current node can be a child of the style element.
+ if ( !nodeName || elementDTD[ nodeName ] )
+ {
+ // Check if the style element can be a child of the current
+ // node parent or if the element is not defined in the DTD.
+ if ( ( FCK.DTD[ currentNode.parentNode.nodeName.toLowerCase() ] || FCK.DTD.span )[ elementName ] || !FCK.DTD[ elementName ] )
+ {
+ // This node will be part of our range, so if it has not
+ // been started, place its start right before the node.
+ if ( !range.CheckHasRange() )
+ range.SetStart( currentNode, 3 ) ;
+
+ // Non element nodes, or empty elements can be added
+ // completely to the range.
+ if ( nodeType != 1 || currentNode.childNodes.length == 0 )
+ {
+ var includedNode = currentNode ;
+ var parentNode = includedNode.parentNode ;
+
+ // This node is about to be included completelly, but,
+ // if this is the last node in its parent, we must also
+ // check if the parent itself can be added completelly
+ // to the range.
+ while ( includedNode == parentNode.lastChild
+ && elementDTD[ parentNode.nodeName.toLowerCase() ] )
+ {
+ includedNode = parentNode ;
+ }
+
+ range.SetEnd( includedNode, 4 ) ;
+
+ // If the included node is the last node in its parent
+ // and its parent can't be inside the style node, apply
+ // the style immediately.
+ if ( includedNode == includedNode.parentNode.lastChild && !elementDTD[ includedNode.parentNode.nodeName.toLowerCase() ] )
+ applyStyle = true ;
+ }
+ else
+ {
+ // Element nodes will not be added directly. We need to
+ // check their children because the selection could end
+ // inside the node, so let's place the range end right
+ // before the element.
+ range.SetEnd( currentNode, 3 ) ;
+ }
+ }
+ else
+ applyStyle = true ;
+ }
+ else
+ applyStyle = true ;
+
+ // Get the next node to be processed.
+ currentNode = FCKDomTools.GetNextSourceNode( currentNode ) ;
+
+ // If we have reached the end of the selection, just apply the
+ // style ot the range, and stop looping.
+ if ( currentNode == endNode )
+ {
+ currentNode = null ;
+ applyStyle = true ;
+ }
+
+ // Apply the style if we have something to which apply it.
+ if ( applyStyle && range.CheckHasRange() && !range.CheckIsCollapsed() )
+ {
+ // Build the style element, based on the style object definition.
+ styleNode = this.BuildElement( doc ) ;
+
+ // Move the contents of the range to the style element.
+ range.ExtractContents().AppendTo( styleNode ) ;
+
+ // If it is not empty.
+ if ( styleNode.innerHTML.RTrim().length > 0 )
+ {
+ // Insert it in the range position (it is collapsed after
+ // ExtractContents.
+ range.InsertNode( styleNode ) ;
+
+ // Here we do some cleanup, removing all duplicated
+ // elements from the style element.
+ this.RemoveFromElement( styleNode ) ;
+
+ // Let's merge our new style with its neighbors, if possible.
+ this._MergeSiblings( styleNode, this._GetAttribsForComparison() ) ;
+
+ // As the style system breaks text nodes constantly, let's normalize
+ // things for performance.
+ // With IE, some paragraphs get broken when calling normalize()
+ // repeatedly. Also, for IE, we must normalize body, not documentElement.
+ // IE is also known for having a "crash effect" with normalize().
+ // We should try to normalize with IE too in some way, somewhere.
+ if ( !FCKBrowserInfo.IsIE )
+ styleNode.normalize() ;
+ }
+
+ // Style applied, let's release the range, so it gets marked to
+ // re-initialization in the next loop.
+ range.Release( true ) ;
+ }
+ }
+
+ this._FixBookmarkStart( startNode ) ;
+
+ // Re-select the original range.
+ if ( selectIt )
+ range.SelectBookmark( bookmark ) ;
+
+ if ( updateRange )
+ range.MoveToBookmark( bookmark ) ;
+ },
+
+ _FixBookmarkStart : function( startNode )
+ {
+ // After appliying or removing an inline style, the start boundary of
+ // the selection must be placed inside all inline elements it is
+ // bordering.
+ var startSibling ;
+ while ( ( startSibling = startNode.nextSibling ) ) // Only one "=".
+ {
+ if ( startSibling.nodeType == 1
+ && FCKListsLib.InlineNonEmptyElements[ startSibling.nodeName.toLowerCase() ] )
+ {
+ // If it is an empty inline element, we can safely remove it.
+ if ( !startSibling.firstChild )
+ FCKDomTools.RemoveNode( startSibling ) ;
+ else
+ FCKDomTools.MoveNode( startNode, startSibling, true ) ;
+ continue ;
+ }
+
+ // Empty text nodes can be safely removed to not disturb.
+ if ( startSibling.nodeType == 3 && startSibling.length == 0 )
+ {
+ FCKDomTools.RemoveNode( startSibling ) ;
+ continue ;
+ }
+
+ break ;
+ }
+ },
+
+ /**
+ * Merge an element with its similar siblings.
+ * "attribs" is and object computed with _CreateAttribsForComparison.
+ */
+ _MergeSiblings : function( element, attribs )
+ {
+ if ( !element || element.nodeType != 1 || !FCKListsLib.InlineNonEmptyElements[ element.nodeName.toLowerCase() ] )
+ return ;
+
+ this._MergeNextSibling( element, attribs ) ;
+ this._MergePreviousSibling( element, attribs ) ;
+ },
+
+ /**
+ * Merge an element with its similar siblings after it.
+ * "attribs" is and object computed with _CreateAttribsForComparison.
+ */
+ _MergeNextSibling : function( element, attribs )
+ {
+ // Check the next sibling.
+ var sibling = element.nextSibling ;
+
+ // Check if the next sibling is a bookmark element. In this case, jump it.
+ var hasBookmark = ( sibling && sibling.nodeType == 1 && sibling.getAttribute( '_fck_bookmark' ) ) ;
+ if ( hasBookmark )
+ sibling = sibling.nextSibling ;
+
+ if ( sibling && sibling.nodeType == 1 && sibling.nodeName == element.nodeName )
+ {
+ if ( !attribs )
+ attribs = this._CreateElementAttribsForComparison( element ) ;
+
+ if ( this._CheckAttributesMatch( sibling, attribs ) )
+ {
+ // Save the last child to be checked too (to merge things like <b><i></i></b><b><i></i></b>).
+ var innerSibling = element.lastChild ;
+
+ if ( hasBookmark )
+ FCKDomTools.MoveNode( element.nextSibling, element ) ;
+
+ // Move contents from the sibling.
+ FCKDomTools.MoveChildren( sibling, element ) ;
+ FCKDomTools.RemoveNode( sibling ) ;
+
+ // Now check the last inner child (see two comments above).
+ if ( innerSibling )
+ this._MergeNextSibling( innerSibling ) ;
+ }
+ }
+ },
+
+ /**
+ * Merge an element with its similar siblings before it.
+ * "attribs" is and object computed with _CreateAttribsForComparison.
+ */
+ _MergePreviousSibling : function( element, attribs )
+ {
+ // Check the previous sibling.
+ var sibling = element.previousSibling ;
+
+ // Check if the previous sibling is a bookmark element. In this case, jump it.
+ var hasBookmark = ( sibling && sibling.nodeType == 1 && sibling.getAttribute( '_fck_bookmark' ) ) ;
+ if ( hasBookmark )
+ sibling = sibling.previousSibling ;
+
+ if ( sibling && sibling.nodeType == 1 && sibling.nodeName == element.nodeName )
+ {
+ if ( !attribs )
+ attribs = this._CreateElementAttribsForComparison( element ) ;
+
+ if ( this._CheckAttributesMatch( sibling, attribs ) )
+ {
+ // Save the first child to be checked too (to merge things like <b><i></i></b><b><i></i></b>).
+ var innerSibling = element.firstChild ;
+
+ if ( hasBookmark )
+ FCKDomTools.MoveNode( element.previousSibling, element, true ) ;
+
+ // Move contents to the sibling.
+ FCKDomTools.MoveChildren( sibling, element, true ) ;
+ FCKDomTools.RemoveNode( sibling ) ;
+
+ // Now check the first inner child (see two comments above).
+ if ( innerSibling )
+ this._MergePreviousSibling( innerSibling ) ;
+ }
+ }
+ },
+
+ /**
+ * Build the cssText based on the styles definition.
+ */
+ _GetStyleText : function()
+ {
+ var stylesDef = this._StyleDesc.Styles ;
+
+ // Builds the StyleText.
+ var stylesText = ( this._StyleDesc.Attributes ? this._StyleDesc.Attributes['style'] || '' : '' ) ;
+
+ if ( stylesText.length > 0 )
+ stylesText += ';' ;
+
+ for ( var style in stylesDef )
+ stylesText += style + ':' + stylesDef[style] + ';' ;
+
+ // Browsers make some changes to the style when applying them. So, here
+ // we normalize it to the browser format. We'll not do that if there
+ // are variables inside the style.
+ if ( stylesText.length > 0 && !( /#\(/.test( stylesText ) ) )
+ {
+ stylesText = FCKTools.NormalizeCssText( stylesText ) ;
+ }
+
+ return (this._GetStyleText = function() { return stylesText ; })() ;
+ },
+
+ /**
+ * Get the the collection used to compare the attributes defined in this
+ * style with attributes in an element. All information in it is lowercased.
+ */
+ _GetAttribsForComparison : function()
+ {
+ // If we have already computed it, just return it.
+ var attribs = this._GetAttribsForComparison_$ ;
+ if ( attribs )
+ return attribs ;
+
+ attribs = new Object() ;
+
+ // Loop through all defined attributes.
+ var styleAttribs = this._StyleDesc.Attributes ;
+ if ( styleAttribs )
+ {
+ for ( var styleAtt in styleAttribs )
+ {
+ attribs[ styleAtt.toLowerCase() ] = styleAttribs[ styleAtt ].toLowerCase() ;
+ }
+ }
+
+ // Includes the style definitions.
+ if ( this._GetStyleText().length > 0 )
+ {
+ attribs['style'] = this._GetStyleText().toLowerCase() ;
+ }
+
+ // Appends the "length" information to the object.
+ FCKTools.AppendLengthProperty( attribs, '_length' ) ;
+
+ // Return it, saving it to the next request.
+ return ( this._GetAttribsForComparison_$ = attribs ) ;
+ },
+
+ /**
+ * Get the the collection used to compare the elements and attributes,
+ * defined in this style overrides, with other element. All information in
+ * it is lowercased.
+ */
+ _GetOverridesForComparison : function()
+ {
+ // If we have already computed it, just return it.
+ var overrides = this._GetOverridesForComparison_$ ;
+ if ( overrides )
+ return overrides ;
+
+ overrides = new Object() ;
+
+ var overridesDesc = this._StyleDesc.Overrides ;
+
+ if ( overridesDesc )
+ {
+ // The override description can be a string, object or array.
+ // Internally, well handle arrays only, so transform it if needed.
+ if ( !FCKTools.IsArray( overridesDesc ) )
+ overridesDesc = [ overridesDesc ] ;
+
+ // Loop through all override definitions.
+ for ( var i = 0 ; i < overridesDesc.length ; i++ )
+ {
+ var override = overridesDesc[i] ;
+ var elementName ;
+ var overrideEl ;
+ var attrs ;
+
+ // If can be a string with the element name.
+ if ( typeof override == 'string' )
+ elementName = override.toLowerCase() ;
+ // Or an object.
+ else
+ {
+ elementName = override.Element ? override.Element.toLowerCase() : this.Element ;
+ attrs = override.Attributes ;
+ }
+
+ // We can have more than one override definition for the same
+ // element name, so we attempt to simply append information to
+ // it if it already exists.
+ overrideEl = overrides[ elementName ] || ( overrides[ elementName ] = {} ) ;
+
+ if ( attrs )
+ {
+ // The returning attributes list is an array, because we
+ // could have different override definitions for the same
+ // attribute name.
+ var overrideAttrs = ( overrideEl.Attributes = overrideEl.Attributes || new Array() ) ;
+ for ( var attName in attrs )
+ {
+ // Each item in the attributes array is also an array,
+ // where [0] is the attribute name and [1] is the
+ // override value.
+ overrideAttrs.push( [ attName.toLowerCase(), attrs[ attName ] ] ) ;
+ }
+ }
+ }
+ }
+
+ return ( this._GetOverridesForComparison_$ = overrides ) ;
+ },
+
+ /*
+ * Create and object containing all attributes specified in an element,
+ * added by a "_length" property. All values are lowercased.
+ */
+ _CreateElementAttribsForComparison : function( element )
+ {
+ var attribs = new Object() ;
+ var attribsCount = 0 ;
+
+ for ( var i = 0 ; i < element.attributes.length ; i++ )
+ {
+ var att = element.attributes[i] ;
+
+ if ( att.specified )
+ {
+ attribs[ att.nodeName.toLowerCase() ] = FCKDomTools.GetAttributeValue( element, att ).toLowerCase() ;
+ attribsCount++ ;
+ }
+ }
+
+ attribs._length = attribsCount ;
+
+ return attribs ;
+ },
+
+ /**
+ * Checks is the element attributes have a perfect match with the style
+ * attributes.
+ */
+ _CheckAttributesMatch : function( element, styleAttribs )
+ {
+ // Loop through all specified attributes. The same number of
+ // attributes must be found and their values must match to
+ // declare them as equal.
+
+ var elementAttrbs = element.attributes ;
+ var matchCount = 0 ;
+
+ for ( var i = 0 ; i < elementAttrbs.length ; i++ )
+ {
+ var att = elementAttrbs[i] ;
+ if ( att.specified )
+ {
+ var attName = att.nodeName.toLowerCase() ;
+ var styleAtt = styleAttribs[ attName ] ;
+
+ // The attribute is not defined in the style.
+ if ( !styleAtt )
+ break ;
+
+ // The values are different.
+ if ( styleAtt != FCKDomTools.GetAttributeValue( element, att ).toLowerCase() )
+ break ;
+
+ matchCount++ ;
+ }
+ }
+
+ return ( matchCount == styleAttribs._length ) ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbar.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbar.js
new file mode 100644
index 0000000..73114a1
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbar.js
@@ -0,0 +1,103 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbar Class: represents a toolbar in the toolbarset. It is a group of
+ * toolbar items.
+ */
+
+var FCKToolbar = function()
+{
+ this.Items = new Array() ;
+}
+
+FCKToolbar.prototype.AddItem = function( item )
+{
+ return this.Items[ this.Items.length ] = item ;
+}
+
+FCKToolbar.prototype.AddButton = function( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state )
+{
+ if ( typeof( iconPathOrStripInfoArrayOrIndex ) == 'number' )
+ iconPathOrStripInfoArrayOrIndex = [ this.DefaultIconsStrip, this.DefaultIconSize, iconPathOrStripInfoArrayOrIndex ] ;
+
+ var oButton = new FCKToolbarButtonUI( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state ) ;
+ oButton._FCKToolbar = this ;
+ oButton.OnClick = FCKToolbar_OnItemClick ;
+
+ return this.AddItem( oButton ) ;
+}
+
+function FCKToolbar_OnItemClick( item )
+{
+ var oToolbar = item._FCKToolbar ;
+
+ if ( oToolbar.OnItemClick )
+ oToolbar.OnItemClick( oToolbar, item ) ;
+}
+
+FCKToolbar.prototype.AddSeparator = function()
+{
+ this.AddItem( new FCKToolbarSeparator() ) ;
+}
+
+FCKToolbar.prototype.Create = function( parentElement )
+{
+ var oDoc = FCKTools.GetElementDocument( parentElement ) ;
+
+ var e = oDoc.createElement( 'table' ) ;
+ e.className = 'TB_Toolbar' ;
+ e.style.styleFloat = e.style.cssFloat = ( FCKLang.Dir == 'ltr' ? 'left' : 'right' ) ;
+ e.dir = FCKLang.Dir ;
+ e.cellPadding = 0 ;
+ e.cellSpacing = 0 ;
+
+ var targetRow = e.insertRow(-1) ;
+
+ // Insert the start cell.
+ var eCell ;
+
+ if ( !this.HideStart )
+ {
+ eCell = targetRow.insertCell(-1) ;
+ eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_Start' ;
+ }
+
+ for ( var i = 0 ; i < this.Items.length ; i++ )
+ {
+ this.Items[i].Create( targetRow.insertCell(-1) ) ;
+ }
+
+ // Insert the ending cell.
+ if ( !this.HideEnd )
+ {
+ eCell = targetRow.insertCell(-1) ;
+ eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_End' ;
+ }
+
+ parentElement.appendChild( e ) ;
+}
+
+var FCKToolbarSeparator = function()
+{}
+
+FCKToolbarSeparator.prototype.Create = function( parentElement )
+{
+ FCKTools.AppendElement( parentElement, 'div' ).className = 'TB_Separator' ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_gecko.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_gecko.js
new file mode 100644
index 0000000..f738455
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_gecko.js
@@ -0,0 +1,36 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarBreak Class: breaks the toolbars.
+ * It makes it possible to force the toolbar to break to a new line.
+ * This is the Gecko specific implementation.
+ */
+
+var FCKToolbarBreak = function()
+{}
+
+FCKToolbarBreak.prototype.Create = function( targetElement )
+{
+ var oBreakDiv = targetElement.ownerDocument.createElement( 'div' ) ;
+
+ oBreakDiv.style.clear = oBreakDiv.style.cssFloat = FCKLang.Dir == 'rtl' ? 'right' : 'left' ;
+
+ targetElement.appendChild( oBreakDiv ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_ie.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_ie.js
new file mode 100644
index 0000000..787bbbf
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbreak_ie.js
@@ -0,0 +1,38 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarBreak Class: breaks the toolbars.
+ * It makes it possible to force the toolbar to break to a new line.
+ * This is the IE specific implementation.
+ */
+
+var FCKToolbarBreak = function()
+{}
+
+FCKToolbarBreak.prototype.Create = function( targetElement )
+{
+ var oBreakDiv = FCKTools.GetElementDocument( targetElement ).createElement( 'div' ) ;
+
+ oBreakDiv.className = 'TB_Break' ;
+
+ oBreakDiv.style.clear = FCKLang.Dir == 'rtl' ? 'left' : 'right' ;
+
+ targetElement.appendChild( oBreakDiv ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbutton.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbutton.js
new file mode 100644
index 0000000..6e7de60
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbutton.js
@@ -0,0 +1,81 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarButton Class: represents a button in the toolbar.
+ */
+
+var FCKToolbarButton = function( commandName, label, tooltip, style, sourceView, contextSensitive, icon )
+{
+ this.CommandName = commandName ;
+ this.Label = label ;
+ this.Tooltip = tooltip ;
+ this.Style = style ;
+ this.SourceView = sourceView ? true : false ;
+ this.ContextSensitive = contextSensitive ? true : false ;
+
+ if ( icon == null )
+ this.IconPath = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
+ else if ( typeof( icon ) == 'number' )
+ this.IconPath = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
+ else
+ this.IconPath = icon ;
+}
+
+FCKToolbarButton.prototype.Create = function( targetElement )
+{
+ this._UIButton = new FCKToolbarButtonUI( this.CommandName, this.Label, this.Tooltip, this.IconPath, this.Style ) ;
+ this._UIButton.OnClick = this.Click ;
+ this._UIButton._ToolbarButton = this ;
+ this._UIButton.Create( targetElement ) ;
+}
+
+FCKToolbarButton.prototype.RefreshState = function()
+{
+ var uiButton = this._UIButton ;
+
+ if ( !uiButton )
+ return ;
+
+ // Gets the actual state.
+ var eState = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
+
+ // If there are no state changes than do nothing and return.
+ if ( eState == uiButton.State ) return ;
+
+ // Sets the actual state.
+ uiButton.ChangeState( eState ) ;
+}
+
+FCKToolbarButton.prototype.Click = function()
+{
+ var oToolbarButton = this._ToolbarButton || this ;
+ FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oToolbarButton.CommandName ).Execute() ;
+}
+
+FCKToolbarButton.prototype.Enable = function()
+{
+ this.RefreshState() ;
+}
+
+FCKToolbarButton.prototype.Disable = function()
+{
+ // Sets the actual state.
+ this._UIButton.ChangeState( FCK_TRISTATE_DISABLED ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbuttonui.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbuttonui.js
new file mode 100644
index 0000000..08598a1
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarbuttonui.js
@@ -0,0 +1,198 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarButtonUI Class: interface representation of a toolbar button.
+ */
+
+var FCKToolbarButtonUI = function( name, label, tooltip, iconPathOrStripInfoArray, style, state )
+{
+ this.Name = name ;
+ this.Label = label || name ;
+ this.Tooltip = tooltip || this.Label ;
+ this.Style = style || FCK_TOOLBARITEM_ONLYICON ;
+ this.State = state || FCK_TRISTATE_OFF ;
+
+ this.Icon = new FCKIcon( iconPathOrStripInfoArray ) ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKToolbarButtonUI_Cleanup ) ;
+}
+
+
+FCKToolbarButtonUI.prototype._CreatePaddingElement = function( document )
+{
+ var oImg = document.createElement( 'IMG' ) ;
+ oImg.className = 'TB_Button_Padding' ;
+ oImg.src = FCK_SPACER_PATH ;
+ return oImg ;
+}
+
+FCKToolbarButtonUI.prototype.Create = function( parentElement )
+{
+ var oDoc = FCKTools.GetElementDocument( parentElement ) ;
+
+ // Create the Main Element.
+ var oMainElement = this.MainElement = oDoc.createElement( 'DIV' ) ;
+ oMainElement.title = this.Tooltip ;
+
+ // The following will prevent the button from catching the focus.
+ if ( FCKBrowserInfo.IsGecko )
+ oMainElement.onmousedown = FCKTools.CancelEvent ;
+
+ FCKTools.AddEventListenerEx( oMainElement, 'mouseover', FCKToolbarButtonUI_OnMouseOver, this ) ;
+ FCKTools.AddEventListenerEx( oMainElement, 'mouseout', FCKToolbarButtonUI_OnMouseOut, this ) ;
+ FCKTools.AddEventListenerEx( oMainElement, 'click', FCKToolbarButtonUI_OnClick, this ) ;
+
+ this.ChangeState( this.State, true ) ;
+
+ if ( this.Style == FCK_TOOLBARITEM_ONLYICON && !this.ShowArrow )
+ {
+ // <td><div class="TB_Button_On" title="Smiley">{Image}</div></td>
+
+ oMainElement.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
+ }
+ else
+ {
+ // <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td>{Image}</td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
+ // <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td><img class="TB_Button_Padding"></td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
+
+ var oTable = oMainElement.appendChild( oDoc.createElement( 'TABLE' ) ) ;
+ oTable.cellPadding = 0 ;
+ oTable.cellSpacing = 0 ;
+
+ var oRow = oTable.insertRow(-1) ;
+
+ // The Image cell (icon or padding).
+ var oCell = oRow.insertCell(-1) ;
+
+ if ( this.Style == FCK_TOOLBARITEM_ONLYICON || this.Style == FCK_TOOLBARITEM_ICONTEXT )
+ oCell.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
+ else
+ oCell.appendChild( this._CreatePaddingElement( oDoc ) ) ;
+
+ if ( this.Style == FCK_TOOLBARITEM_ONLYTEXT || this.Style == FCK_TOOLBARITEM_ICONTEXT )
+ {
+ // The Text cell.
+ oCell = oRow.insertCell(-1) ;
+ oCell.className = 'TB_Button_Text' ;
+ oCell.noWrap = true ;
+ oCell.appendChild( oDoc.createTextNode( this.Label ) ) ;
+ }
+
+ if ( this.ShowArrow )
+ {
+ if ( this.Style != FCK_TOOLBARITEM_ONLYICON )
+ {
+ // A padding cell.
+ oRow.insertCell(-1).appendChild( this._CreatePaddingElement( oDoc ) ) ;
+ }
+
+ oCell = oRow.insertCell(-1) ;
+ var eImg = oCell.appendChild( oDoc.createElement( 'IMG' ) ) ;
+ eImg.src = FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif' ;
+ eImg.width = 5 ;
+ eImg.height = 3 ;
+ }
+
+ // The last padding cell.
+ oCell = oRow.insertCell(-1) ;
+ oCell.appendChild( this._CreatePaddingElement( oDoc ) ) ;
+ }
+
+ parentElement.appendChild( oMainElement ) ;
+}
+
+FCKToolbarButtonUI.prototype.ChangeState = function( newState, force )
+{
+ if ( !force && this.State == newState )
+ return ;
+
+ var e = this.MainElement ;
+
+ // In IE it can happen when the page is reloaded that MainElement is null, so exit here
+ if ( !e )
+ return ;
+
+ switch ( parseInt( newState, 10 ) )
+ {
+ case FCK_TRISTATE_OFF :
+ e.className = 'TB_Button_Off' ;
+ break ;
+
+ case FCK_TRISTATE_ON :
+ e.className = 'TB_Button_On' ;
+ break ;
+
+ case FCK_TRISTATE_DISABLED :
+ e.className = 'TB_Button_Disabled' ;
+ break ;
+ }
+
+ this.State = newState ;
+}
+
+function FCKToolbarButtonUI_OnMouseOver( ev, button )
+{
+ if ( button.State == FCK_TRISTATE_OFF )
+ this.className = 'TB_Button_Off_Over' ;
+ else if ( button.State == FCK_TRISTATE_ON )
+ this.className = 'TB_Button_On_Over' ;
+}
+
+function FCKToolbarButtonUI_OnMouseOut( ev, button )
+{
+ if ( button.State == FCK_TRISTATE_OFF )
+ this.className = 'TB_Button_Off' ;
+ else if ( button.State == FCK_TRISTATE_ON )
+ this.className = 'TB_Button_On' ;
+}
+
+function FCKToolbarButtonUI_OnClick( ev, button )
+{
+ if ( button.OnClick && button.State != FCK_TRISTATE_DISABLED )
+ button.OnClick( button ) ;
+}
+
+function FCKToolbarButtonUI_Cleanup()
+{
+ // This one should not cause memory leak, but just for safety, let's clean
+ // it up.
+ this.MainElement = null ;
+}
+
+/*
+ Sample outputs:
+
+ This is the base structure. The variation is the image that is marked as {Image}:
+ <td><div class="TB_Button_On" title="Smiley">{Image}</div></td>
+ <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td>{Image}</td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
+ <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td><img class="TB_Button_Padding"></td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
+
+ These are samples of possible {Image} values:
+
+ Strip - IE version:
+ <div class="TB_Button_Image"><img src="strip.gif" style="top:-16px"></div>
+
+ Strip : Firefox, Safari and Opera version
+ <img class="TB_Button_Image" style="background-position: 0px -16px;background-image: url(strip.gif);">
+
+ No-Strip : Browser independent:
+ <img class="TB_Button_Image" src="smiley.gif">
+*/
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontformatcombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontformatcombo.js
new file mode 100644
index 0000000..6c8b7de
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontformatcombo.js
@@ -0,0 +1,139 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarPanelButton Class: Handles the Fonts combo selector.
+ */
+
+var FCKToolbarFontFormatCombo = function( tooltip, style )
+{
+ if ( tooltip === false )
+ return ;
+
+ this.CommandName = 'FontFormat' ;
+ this.Label = this.GetLabel() ;
+ this.Tooltip = tooltip ? tooltip : this.Label ;
+ this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
+
+ this.NormalLabel = 'Normal' ;
+
+ this.PanelWidth = 190 ;
+
+ this.DefaultLabel = FCKConfig.DefaultFontFormatLabel || '' ;
+}
+
+// Inherit from FCKToolbarSpecialCombo.
+FCKToolbarFontFormatCombo.prototype = new FCKToolbarStyleCombo( false ) ;
+
+FCKToolbarFontFormatCombo.prototype.GetLabel = function()
+{
+ return FCKLang.FontFormat ;
+}
+
+FCKToolbarFontFormatCombo.prototype.GetStyles = function()
+{
+ var styles = {} ;
+
+ // Get the format names from the language file.
+ var aNames = FCKLang['FontFormats'].split(';') ;
+ var oNames = {
+ p : aNames[0],
+ pre : aNames[1],
+ address : aNames[2],
+ h1 : aNames[3],
+ h2 : aNames[4],
+ h3 : aNames[5],
+ h4 : aNames[6],
+ h5 : aNames[7],
+ h6 : aNames[8],
+ div : aNames[9] || ( aNames[0] + ' (DIV)')
+ } ;
+
+ // Get the available formats from the configuration file.
+ var elements = FCKConfig.FontFormats.split(';') ;
+
+ for ( var i = 0 ; i < elements.length ; i++ )
+ {
+ var elementName = elements[ i ] ;
+ var style = FCKStyles.GetStyle( '_FCK_' + elementName ) ;
+ if ( style )
+ {
+ style.Label = oNames[ elementName ] ;
+ styles[ '_FCK_' + elementName ] = style ;
+ }
+ else
+ alert( "The FCKConfig.CoreStyles['" + elementName + "'] setting was not found. Please check the fckconfig.js file" ) ;
+ }
+
+ return styles ;
+}
+
+FCKToolbarFontFormatCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
+{
+ var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
+
+ if ( startElement )
+ {
+ var path = new FCKElementPath( startElement ) ;
+ var blockElement = path.Block ;
+
+ if ( blockElement )
+ {
+ for ( var i in targetSpecialCombo.Items )
+ {
+ var item = targetSpecialCombo.Items[i] ;
+ var style = item.Style ;
+
+ if ( style.CheckElementRemovable( blockElement ) )
+ {
+ targetSpecialCombo.SetLabel( style.Label ) ;
+ return ;
+ }
+ }
+ }
+ }
+
+ targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
+}
+
+FCKToolbarFontFormatCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
+{
+ // Clear the current selection.
+ targetSpecialCombo.DeselectAll() ;
+
+ var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
+
+ if ( startElement )
+ {
+ var path = new FCKElementPath( startElement ) ;
+ var blockElement = path.Block ;
+
+ for ( var i in targetSpecialCombo.Items )
+ {
+ var item = targetSpecialCombo.Items[i] ;
+ var style = item.Style ;
+
+ if ( style.CheckElementRemovable( blockElement ) )
+ {
+ targetSpecialCombo.SelectItem( item ) ;
+ return ;
+ }
+ }
+ }
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontscombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontscombo.js
new file mode 100644
index 0000000..47322a9
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontscombo.js
@@ -0,0 +1,98 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarPanelButton Class: Handles the Fonts combo selector.
+ */
+
+var FCKToolbarFontsCombo = function( tooltip, style )
+{
+ this.CommandName = 'FontName' ;
+ this.Label = this.GetLabel() ;
+ this.Tooltip = tooltip ? tooltip : this.Label ;
+ this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
+
+ this.DefaultLabel = FCKConfig.DefaultFontLabel || '' ;
+}
+
+// Inherit from FCKToolbarSpecialCombo.
+FCKToolbarFontsCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
+
+FCKToolbarFontsCombo.prototype.GetLabel = function()
+{
+ return FCKLang.Font ;
+}
+
+FCKToolbarFontsCombo.prototype.GetStyles = function()
+{
+ var baseStyle = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
+
+ if ( !baseStyle )
+ {
+ alert( "The FCKConfig.CoreStyles['Size'] setting was not found. Please check the fckconfig.js file" ) ;
+ return {} ;
+ }
+
+ var styles = {} ;
+
+ var fonts = FCKConfig.FontNames.split(';') ;
+
+ for ( var i = 0 ; i < fonts.length ; i++ )
+ {
+ var fontParts = fonts[i].split('/') ;
+ var font = fontParts[0] ;
+ var caption = fontParts[1] || font ;
+
+ var style = FCKTools.CloneObject( baseStyle ) ;
+
+ style.SetVariable( 'Font', font ) ;
+ style.Label = caption ;
+
+ styles[ caption ] = style ;
+ }
+
+ return styles ;
+}
+
+FCKToolbarFontsCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
+
+FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
+{
+ // Clear the current selection.
+ targetSpecialCombo.DeselectAll() ;
+
+ var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
+
+ if ( startElement )
+ {
+ var path = new FCKElementPath( startElement ) ;
+
+ for ( var i in targetSpecialCombo.Items )
+ {
+ var item = targetSpecialCombo.Items[i] ;
+ var style = item.Style ;
+
+ if ( style.CheckActive( path ) )
+ {
+ targetSpecialCombo.SelectItem( item ) ;
+ return ;
+ }
+ }
+ }
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontsizecombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontsizecombo.js
new file mode 100644
index 0000000..4a4386d
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarfontsizecombo.js
@@ -0,0 +1,76 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarPanelButton Class: Handles the Fonts combo selector.
+ */
+
+var FCKToolbarFontSizeCombo = function( tooltip, style )
+{
+ this.CommandName = 'FontSize' ;
+ this.Label = this.GetLabel() ;
+ this.Tooltip = tooltip ? tooltip : this.Label ;
+ this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
+
+ this.DefaultLabel = FCKConfig.DefaultFontSizeLabel || '' ;
+
+ this.FieldWidth = 70 ;
+}
+
+// Inherit from FCKToolbarSpecialCombo.
+FCKToolbarFontSizeCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
+
+FCKToolbarFontSizeCombo.prototype.GetLabel = function()
+{
+ return FCKLang.FontSize ;
+}
+
+FCKToolbarFontSizeCombo.prototype.GetStyles = function()
+{
+ var baseStyle = FCKStyles.GetStyle( '_FCK_Size' ) ;
+
+ if ( !baseStyle )
+ {
+ alert( "The FCKConfig.CoreStyles['FontFace'] setting was not found. Please check the fckconfig.js file" ) ;
+ return {} ;
+ }
+
+ var styles = {} ;
+
+ var fonts = FCKConfig.FontSizes.split(';') ;
+
+ for ( var i = 0 ; i < fonts.length ; i++ )
+ {
+ var fontParts = fonts[i].split('/') ;
+ var font = fontParts[0] ;
+ var caption = fontParts[1] || font ;
+
+ var style = FCKTools.CloneObject( baseStyle ) ;
+ style.SetVariable( 'Size', font ) ;
+ style.Label = caption ;
+
+ styles[ caption ] = style ;
+ }
+
+ return styles ;
+}
+
+FCKToolbarFontSizeCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
+
+FCKToolbarFontSizeCombo.prototype.StyleCombo_OnBeforeClick = FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarpanelbutton.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarpanelbutton.js
new file mode 100644
index 0000000..a507696
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarpanelbutton.js
@@ -0,0 +1,103 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarPanelButton Class: represents a special button in the toolbar
+ * that shows a panel when pressed.
+ */
+
+var FCKToolbarPanelButton = function( commandName, label, tooltip, style, icon )
+{
+ this.CommandName = commandName ;
+
+ var oIcon ;
+
+ if ( icon == null )
+ oIcon = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
+ else if ( typeof( icon ) == 'number' )
+ oIcon = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
+
+ var oUIButton = this._UIButton = new FCKToolbarButtonUI( commandName, label, tooltip, oIcon, style ) ;
+ oUIButton._FCKToolbarPanelButton = this ;
+ oUIButton.ShowArrow = true ;
+ oUIButton.OnClick = FCKToolbarPanelButton_OnButtonClick ;
+}
+
+FCKToolbarPanelButton.prototype.TypeName = 'FCKToolbarPanelButton' ;
+
+FCKToolbarPanelButton.prototype.Create = function( parentElement )
+{
+ parentElement.className += 'Menu' ;
+
+ this._UIButton.Create( parentElement ) ;
+
+ var oPanel = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName )._Panel ;
+ this.RegisterPanel( oPanel ) ;
+}
+
+FCKToolbarPanelButton.prototype.RegisterPanel = function( oPanel )
+{
+ if ( oPanel._FCKToolbarPanelButton )
+ return ;
+
+ oPanel._FCKToolbarPanelButton = this ;
+
+ var eLineDiv = oPanel.Document.body.appendChild( oPanel.Document.createElement( 'div' ) ) ;
+ eLineDiv.style.position = 'absolute' ;
+ eLineDiv.style.top = '0px' ;
+
+ var eLine = oPanel._FCKToolbarPanelButtonLineDiv = eLineDiv.appendChild( oPanel.Document.createElement( 'IMG' ) ) ;
+ eLine.className = 'TB_ConnectionLine' ;
+ eLine.style.position = 'absolute' ;
+// eLine.style.backgroundColor = 'Red' ;
+ eLine.src = FCK_SPACER_PATH ;
+
+ oPanel.OnHide = FCKToolbarPanelButton_OnPanelHide ;
+}
+
+/*
+ Events
+*/
+
+function FCKToolbarPanelButton_OnButtonClick( toolbarButton )
+{
+ var oButton = this._FCKToolbarPanelButton ;
+ var e = oButton._UIButton.MainElement ;
+
+ oButton._UIButton.ChangeState( FCK_TRISTATE_ON ) ;
+
+ // oButton.LineImg.style.width = ( e.offsetWidth - 2 ) + 'px' ;
+
+ var oCommand = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oButton.CommandName ) ;
+ var oPanel = oCommand._Panel ;
+ oPanel._FCKToolbarPanelButtonLineDiv.style.width = ( e.offsetWidth - 2 ) + 'px' ;
+ oCommand.Execute( 0, e.offsetHeight - 1, e ) ; // -1 to be over the border
+}
+
+function FCKToolbarPanelButton_OnPanelHide()
+{
+ var oMenuButton = this._FCKToolbarPanelButton ;
+ oMenuButton._UIButton.ChangeState( FCK_TRISTATE_OFF ) ;
+}
+
+// The Panel Button works like a normal button so the refresh state functions
+// defined for the normal button can be reused here.
+FCKToolbarPanelButton.prototype.RefreshState = FCKToolbarButton.prototype.RefreshState ;
+FCKToolbarPanelButton.prototype.Enable = FCKToolbarButton.prototype.Enable ;
+FCKToolbarPanelButton.prototype.Disable = FCKToolbarButton.prototype.Disable ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarspecialcombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarspecialcombo.js
new file mode 100644
index 0000000..c5ea580
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarspecialcombo.js
@@ -0,0 +1,146 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarSpecialCombo Class: This is a "abstract" base class to be used
+ * by the special combo toolbar elements like font name, font size, paragraph format, etc...
+ *
+ * The following properties and methods must be implemented when inheriting from
+ * this class:
+ * - Property: CommandName [ The command name to be executed ]
+ * - Method: GetLabel() [ Returns the label ]
+ * - CreateItems( targetSpecialCombo ) [ Add all items in the special combo ]
+ */
+
+var FCKToolbarSpecialCombo = function()
+{
+ this.SourceView = false ;
+ this.ContextSensitive = true ;
+ this.FieldWidth = null ;
+ this.PanelWidth = null ;
+ this.PanelMaxHeight = null ;
+ //this._LastValue = null ;
+}
+
+
+FCKToolbarSpecialCombo.prototype.DefaultLabel = '' ;
+
+function FCKToolbarSpecialCombo_OnSelect( itemId, item )
+{
+ FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).Execute( itemId, item ) ;
+}
+
+FCKToolbarSpecialCombo.prototype.Create = function( targetElement )
+{
+ this._Combo = new FCKSpecialCombo( this.GetLabel(), this.FieldWidth, this.PanelWidth, this.PanelMaxHeight, FCKBrowserInfo.IsIE ? window : FCKTools.GetElementWindow( targetElement ).parent ) ;
+
+ /*
+ this._Combo.FieldWidth = this.FieldWidth != null ? this.FieldWidth : 100 ;
+ this._Combo.PanelWidth = this.PanelWidth != null ? this.PanelWidth : 150 ;
+ this._Combo.PanelMaxHeight = this.PanelMaxHeight != null ? this.PanelMaxHeight : 150 ;
+ */
+
+ //this._Combo.Command.Name = this.Command.Name;
+// this._Combo.Label = this.Label ;
+ this._Combo.Tooltip = this.Tooltip ;
+ this._Combo.Style = this.Style ;
+
+ this.CreateItems( this._Combo ) ;
+
+ this._Combo.Create( targetElement ) ;
+
+ this._Combo.CommandName = this.CommandName ;
+
+ this._Combo.OnSelect = FCKToolbarSpecialCombo_OnSelect ;
+}
+
+function FCKToolbarSpecialCombo_RefreshActiveItems( combo, value )
+{
+ combo.DeselectAll() ;
+ combo.SelectItem( value ) ;
+ combo.SetLabelById( value ) ;
+}
+
+FCKToolbarSpecialCombo.prototype.RefreshState = function()
+{
+ // Gets the actual state.
+ var eState ;
+
+// if ( FCK.EditMode == FCK_EDITMODE_SOURCE && ! this.SourceView )
+// eState = FCK_TRISTATE_DISABLED ;
+// else
+// {
+ var sValue = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
+
+// FCKDebug.Output( 'RefreshState of Special Combo "' + this.TypeOf + '" - State: ' + sValue ) ;
+
+ if ( sValue != FCK_TRISTATE_DISABLED )
+ {
+ eState = FCK_TRISTATE_ON ;
+
+ if ( this.RefreshActiveItems )
+ this.RefreshActiveItems( this._Combo, sValue ) ;
+ else
+ {
+ if ( this._LastValue !== sValue)
+ {
+ this._LastValue = sValue ;
+
+ if ( !sValue || sValue.length == 0 )
+ {
+ this._Combo.DeselectAll() ;
+ this._Combo.SetLabel( this.DefaultLabel ) ;
+ }
+ else
+ FCKToolbarSpecialCombo_RefreshActiveItems( this._Combo, sValue ) ;
+ }
+ }
+ }
+ else
+ eState = FCK_TRISTATE_DISABLED ;
+// }
+
+ // If there are no state changes then do nothing and return.
+ if ( eState == this.State ) return ;
+
+ if ( eState == FCK_TRISTATE_DISABLED )
+ {
+ this._Combo.DeselectAll() ;
+ this._Combo.SetLabel( '' ) ;
+ }
+
+ // Sets the actual state.
+ this.State = eState ;
+
+ // Updates the graphical state.
+ this._Combo.SetEnabled( eState != FCK_TRISTATE_DISABLED ) ;
+}
+
+FCKToolbarSpecialCombo.prototype.Enable = function()
+{
+ this.RefreshState() ;
+}
+
+FCKToolbarSpecialCombo.prototype.Disable = function()
+{
+ this.State = FCK_TRISTATE_DISABLED ;
+ this._Combo.DeselectAll() ;
+ this._Combo.SetLabel( '' ) ;
+ this._Combo.SetEnabled( false ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarstylecombo.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarstylecombo.js
new file mode 100644
index 0000000..341b2d9
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fcktoolbarstylecombo.js
@@ -0,0 +1,200 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKToolbarPanelButton Class: Handles the Fonts combo selector.
+ */
+
+var FCKToolbarStyleCombo = function( tooltip, style )
+{
+ if ( tooltip === false )
+ return ;
+
+ this.CommandName = 'Style' ;
+ this.Label = this.GetLabel() ;
+ this.Tooltip = tooltip ? tooltip : this.Label ;
+ this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
+
+ this.DefaultLabel = FCKConfig.DefaultStyleLabel || '' ;
+}
+
+// Inherit from FCKToolbarSpecialCombo.
+FCKToolbarStyleCombo.prototype = new FCKToolbarSpecialCombo ;
+
+FCKToolbarStyleCombo.prototype.GetLabel = function()
+{
+ return FCKLang.Style ;
+}
+
+FCKToolbarStyleCombo.prototype.GetStyles = function()
+{
+ var styles = {} ;
+ var allStyles = FCK.ToolbarSet.CurrentInstance.Styles.GetStyles() ;
+
+ for ( var styleName in allStyles )
+ {
+ var style = allStyles[ styleName ] ;
+ if ( !style.IsCore )
+ styles[ styleName ] = style ;
+ }
+ return styles ;
+}
+
+FCKToolbarStyleCombo.prototype.CreateItems = function( targetSpecialCombo )
+{
+ var targetDoc = targetSpecialCombo._Panel.Document ;
+
+ // Add the Editor Area CSS to the panel so the style classes are previewed correctly.
+ FCKTools.AppendStyleSheet( targetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
+ FCKTools.AppendStyleString( targetDoc, FCKConfig.EditorAreaStyles ) ;
+ targetDoc.body.className += ' ForceBaseFont' ;
+
+ // Add ID and Class to the body.
+ FCKConfig.ApplyBodyAttributes( targetDoc.body ) ;
+
+ // Get the styles list.
+ var styles = this.GetStyles() ;
+
+ for ( var styleName in styles )
+ {
+ var style = styles[ styleName ] ;
+
+ // Object type styles have no preview.
+ var caption = style.GetType() == FCK_STYLE_OBJECT ?
+ styleName :
+ FCKToolbarStyleCombo_BuildPreview( style, style.Label || styleName ) ;
+
+ var item = targetSpecialCombo.AddItem( styleName, caption ) ;
+
+ item.Style = style ;
+ }
+
+ // We must prepare the list before showing it.
+ targetSpecialCombo.OnBeforeClick = this.StyleCombo_OnBeforeClick ;
+}
+
+FCKToolbarStyleCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
+{
+ var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
+
+ if ( startElement )
+ {
+ var path = new FCKElementPath( startElement ) ;
+ var elements = path.Elements ;
+
+ for ( var e = 0 ; e < elements.length ; e++ )
+ {
+ for ( var i in targetSpecialCombo.Items )
+ {
+ var item = targetSpecialCombo.Items[i] ;
+ var style = item.Style ;
+
+ if ( style.CheckElementRemovable( elements[ e ], true ) )
+ {
+ targetSpecialCombo.SetLabel( style.Label || style.Name ) ;
+ return ;
+ }
+ }
+ }
+ }
+
+ targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
+}
+
+FCKToolbarStyleCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
+{
+ // Two things are done here:
+ // - In a control selection, get the element name, so we'll display styles
+ // for that element only.
+ // - Select the styles that are active for the current selection.
+
+ // Clear the current selection.
+ targetSpecialCombo.DeselectAll() ;
+
+ var startElement ;
+ var path ;
+ var tagName ;
+
+ var selection = FCK.ToolbarSet.CurrentInstance.Selection ;
+
+ if ( selection.GetType() == 'Control' )
+ {
+ startElement = selection.GetSelectedElement() ;
+ tagName = startElement.nodeName.toLowerCase() ;
+ }
+ else
+ {
+ startElement = selection.GetBoundaryParentElement( true ) ;
+ path = new FCKElementPath( startElement ) ;
+ }
+
+ for ( var i in targetSpecialCombo.Items )
+ {
+ var item = targetSpecialCombo.Items[i] ;
+ var style = item.Style ;
+
+ if ( ( tagName && style.Element == tagName ) || ( !tagName && style.GetType() != FCK_STYLE_OBJECT ) )
+ {
+ item.style.display = '' ;
+
+ if ( ( path && style.CheckActive( path ) ) || ( !path && style.CheckElementRemovable( startElement, true ) ) )
+ targetSpecialCombo.SelectItem( style.Name ) ;
+ }
+ else
+ item.style.display = 'none' ;
+ }
+}
+
+function FCKToolbarStyleCombo_BuildPreview( style, caption )
+{
+ var styleType = style.GetType() ;
+ var html = [] ;
+
+ if ( styleType == FCK_STYLE_BLOCK )
+ html.push( '<div class="BaseFont">' ) ;
+
+ var elementName = style.Element ;
+
+ // Avoid <bdo> in the preview.
+ if ( elementName == 'bdo' )
+ elementName = 'span' ;
+
+ html = [ '<', elementName ] ;
+
+ // Assign all defined attributes.
+ var attribs = style._StyleDesc.Attributes ;
+ if ( attribs )
+ {
+ for ( var att in attribs )
+ {
+ html.push( ' ', att, '="', style.GetFinalAttributeValue( att ), '"' ) ;
+ }
+ }
+
+ // Assign the style attribute.
+ if ( style._GetStyleText().length > 0 )
+ html.push( ' style="', style.GetFinalStyleValue(), '"' ) ;
+
+ html.push( '>', caption, '</', elementName, '>' ) ;
+
+ if ( styleType == FCK_STYLE_BLOCK )
+ html.push( '</div>' ) ;
+
+ return html.join( '' ) ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckw3crange.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckw3crange.js
new file mode 100644
index 0000000..ae6ab8a
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckw3crange.js
@@ -0,0 +1,451 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class partially implements the W3C DOM Range for browser that don't
+ * support the standards (like IE):
+ * http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
+ */
+
+var FCKW3CRange = function( parentDocument )
+{
+ this._Document = parentDocument ;
+
+ this.startContainer = null ;
+ this.startOffset = null ;
+ this.endContainer = null ;
+ this.endOffset = null ;
+ this.collapsed = true ;
+}
+
+FCKW3CRange.CreateRange = function( parentDocument )
+{
+ // We could opt to use the Range implementation of the browsers. The problem
+ // is that every browser have different bugs on their implementations,
+ // mostly related to different interpretations of the W3C specifications.
+ // So, for now, let's use our implementation and pray for browsers fixings
+ // soon. Otherwise will go crazy on trying to find out workarounds.
+ /*
+ // Get the browser implementation of the range, if available.
+ if ( parentDocument.createRange )
+ {
+ var range = parentDocument.createRange() ;
+ if ( typeof( range.startContainer ) != 'undefined' )
+ return range ;
+ }
+ */
+ return new FCKW3CRange( parentDocument ) ;
+}
+
+FCKW3CRange.CreateFromRange = function( parentDocument, sourceRange )
+{
+ var range = FCKW3CRange.CreateRange( parentDocument ) ;
+ range.setStart( sourceRange.startContainer, sourceRange.startOffset ) ;
+ range.setEnd( sourceRange.endContainer, sourceRange.endOffset ) ;
+ return range ;
+}
+
+FCKW3CRange.prototype =
+{
+
+ _UpdateCollapsed : function()
+ {
+ this.collapsed = ( this.startContainer == this.endContainer && this.startOffset == this.endOffset ) ;
+ },
+
+ // W3C requires a check for the new position. If it is after the end
+ // boundary, the range should be collapsed to the new start. It seams we
+ // will not need this check for our use of this class so we can ignore it for now.
+ setStart : function( refNode, offset )
+ {
+ this.startContainer = refNode ;
+ this.startOffset = offset ;
+
+ if ( !this.endContainer )
+ {
+ this.endContainer = refNode ;
+ this.endOffset = offset ;
+ }
+
+ this._UpdateCollapsed() ;
+ },
+
+ // W3C requires a check for the new position. If it is before the start
+ // boundary, the range should be collapsed to the new end. It seams we
+ // will not need this check for our use of this class so we can ignore it for now.
+ setEnd : function( refNode, offset )
+ {
+ this.endContainer = refNode ;
+ this.endOffset = offset ;
+
+ if ( !this.startContainer )
+ {
+ this.startContainer = refNode ;
+ this.startOffset = offset ;
+ }
+
+ this._UpdateCollapsed() ;
+ },
+
+ setStartAfter : function( refNode )
+ {
+ this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
+ },
+
+ setStartBefore : function( refNode )
+ {
+ this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
+ },
+
+ setEndAfter : function( refNode )
+ {
+ this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
+ },
+
+ setEndBefore : function( refNode )
+ {
+ this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
+ },
+
+ collapse : function( toStart )
+ {
+ if ( toStart )
+ {
+ this.endContainer = this.startContainer ;
+ this.endOffset = this.startOffset ;
+ }
+ else
+ {
+ this.startContainer = this.endContainer ;
+ this.startOffset = this.endOffset ;
+ }
+
+ this.collapsed = true ;
+ },
+
+ selectNodeContents : function( refNode )
+ {
+ this.setStart( refNode, 0 ) ;
+ this.setEnd( refNode, refNode.nodeType == 3 ? refNode.data.length : refNode.childNodes.length ) ;
+ },
+
+ insertNode : function( newNode )
+ {
+ var startContainer = this.startContainer ;
+ var startOffset = this.startOffset ;
+
+ // If we are in a text node.
+ if ( startContainer.nodeType == 3 )
+ {
+ startContainer.splitText( startOffset ) ;
+
+ // Check if it is necessary to update the end boundary.
+ if ( startContainer == this.endContainer )
+ this.setEnd( startContainer.nextSibling, this.endOffset - this.startOffset ) ;
+
+ // Insert the new node it after the text node.
+ FCKDomTools.InsertAfterNode( startContainer, newNode ) ;
+
+ return ;
+ }
+ else
+ {
+ // Simply insert the new node before the current start node.
+ startContainer.insertBefore( newNode, startContainer.childNodes[ startOffset ] || null ) ;
+
+ // Check if it is necessary to update the end boundary.
+ if ( startContainer == this.endContainer )
+ {
+ this.endOffset++ ;
+ this.collapsed = false ;
+ }
+ }
+ },
+
+ deleteContents : function()
+ {
+ if ( this.collapsed )
+ return ;
+
+ this._ExecContentsAction( 0 ) ;
+ },
+
+ extractContents : function()
+ {
+ var docFrag = new FCKDocumentFragment( this._Document ) ;
+
+ if ( !this.collapsed )
+ this._ExecContentsAction( 1, docFrag ) ;
+
+ return docFrag ;
+ },
+
+ // The selection may be lost when cloning (due to the splitText() call).
+ cloneContents : function()
+ {
+ var docFrag = new FCKDocumentFragment( this._Document ) ;
+
+ if ( !this.collapsed )
+ this._ExecContentsAction( 2, docFrag ) ;
+
+ return docFrag ;
+ },
+
+ _ExecContentsAction : function( action, docFrag )
+ {
+ var startNode = this.startContainer ;
+ var endNode = this.endContainer ;
+
+ var startOffset = this.startOffset ;
+ var endOffset = this.endOffset ;
+
+ var removeStartNode = false ;
+ var removeEndNode = false ;
+
+ // Check the start and end nodes and make the necessary removals or changes.
+
+ // Start from the end, otherwise DOM mutations (splitText) made in the
+ // start boundary may interfere on the results here.
+
+ // For text containers, we must simply split the node and point to the
+ // second part. The removal will be handled by the rest of the code .
+ if ( endNode.nodeType == 3 )
+ endNode = endNode.splitText( endOffset ) ;
+ else
+ {
+ // If the end container has children and the offset is pointing
+ // to a child, then we should start from it.
+ if ( endNode.childNodes.length > 0 )
+ {
+ // If the offset points after the last node.
+ if ( endOffset > endNode.childNodes.length - 1 )
+ {
+ // Let's create a temporary node and mark it for removal.
+ endNode = FCKDomTools.InsertAfterNode( endNode.lastChild, this._Document.createTextNode('') ) ;
+ removeEndNode = true ;
+ }
+ else
+ endNode = endNode.childNodes[ endOffset ] ;
+ }
+ }
+
+ // For text containers, we must simply split the node. The removal will
+ // be handled by the rest of the code .
+ if ( startNode.nodeType == 3 )
+ {
+ startNode.splitText( startOffset ) ;
+
+ // In cases the end node is the same as the start node, the above
+ // splitting will also split the end, so me must move the end to
+ // the second part of the split.
+ if ( startNode == endNode )
+ endNode = startNode.nextSibling ;
+ }
+ else
+ {
+ // If the start container has children and the offset is pointing
+ // to a child, then we should start from its previous sibling.
+
+ // If the offset points to the first node, we don't have a
+ // sibling, so let's use the first one, but mark it for removal.
+ if ( startOffset == 0 )
+ {
+ // Let's create a temporary node and mark it for removal.
+ startNode = startNode.insertBefore( this._Document.createTextNode(''), startNode.firstChild ) ;
+ removeStartNode = true ;
+ }
+ else if ( startOffset > startNode.childNodes.length - 1 )
+ {
+ // Let's create a temporary node and mark it for removal.
+ startNode = startNode.appendChild( this._Document.createTextNode('') ) ;
+ removeStartNode = true ;
+ }
+ else
+ startNode = startNode.childNodes[ startOffset ].previousSibling ;
+ }
+
+ // Get the parent nodes tree for the start and end boundaries.
+ var startParents = FCKDomTools.GetParents( startNode ) ;
+ var endParents = FCKDomTools.GetParents( endNode ) ;
+
+ // Compare them, to find the top most siblings.
+ var i, topStart, topEnd ;
+
+ for ( i = 0 ; i < startParents.length ; i++ )
+ {
+ topStart = startParents[i] ;
+ topEnd = endParents[i] ;
+
+ // The compared nodes will match until we find the top most
+ // siblings (different nodes that have the same parent).
+ // "i" will hold the index in the parents array for the top
+ // most element.
+ if ( topStart != topEnd )
+ break ;
+ }
+
+ var clone, levelStartNode, levelClone, currentNode, currentSibling ;
+
+ if ( docFrag )
+ clone = docFrag.RootNode ;
+
+ // Remove all successive sibling nodes for every node in the
+ // startParents tree.
+ for ( var j = i ; j < startParents.length ; j++ )
+ {
+ levelStartNode = startParents[j] ;
+
+ // For Extract and Clone, we must clone this level.
+ if ( clone && levelStartNode != startNode ) // action = 0 = Delete
+ levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == startNode ) ) ;
+
+ currentNode = levelStartNode.nextSibling ;
+
+ while( currentNode )
+ {
+ // Stop processing when the current node matches a node in the
+ // endParents tree or if it is the endNode.
+ if ( currentNode == endParents[j] || currentNode == endNode )
+ break ;
+
+ // Cache the next sibling.
+ currentSibling = currentNode.nextSibling ;
+
+ // If cloning, just clone it.
+ if ( action == 2 ) // 2 = Clone
+ clone.appendChild( currentNode.cloneNode( true ) ) ;
+ else
+ {
+ // Both Delete and Extract will remove the node.
+ currentNode.parentNode.removeChild( currentNode ) ;
+
+ // When Extracting, move the removed node to the docFrag.
+ if ( action == 1 ) // 1 = Extract
+ clone.appendChild( currentNode ) ;
+ }
+
+ currentNode = currentSibling ;
+ }
+
+ if ( clone )
+ clone = levelClone ;
+ }
+
+ if ( docFrag )
+ clone = docFrag.RootNode ;
+
+ // Remove all previous sibling nodes for every node in the
+ // endParents tree.
+ for ( var k = i ; k < endParents.length ; k++ )
+ {
+ levelStartNode = endParents[k] ;
+
+ // For Extract and Clone, we must clone this level.
+ if ( action > 0 && levelStartNode != endNode ) // action = 0 = Delete
+ levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == endNode ) ) ;
+
+ // The processing of siblings may have already been done by the parent.
+ if ( !startParents[k] || levelStartNode.parentNode != startParents[k].parentNode )
+ {
+ currentNode = levelStartNode.previousSibling ;
+
+ while( currentNode )
+ {
+ // Stop processing when the current node matches a node in the
+ // startParents tree or if it is the startNode.
+ if ( currentNode == startParents[k] || currentNode == startNode )
+ break ;
+
+ // Cache the next sibling.
+ currentSibling = currentNode.previousSibling ;
+
+ // If cloning, just clone it.
+ if ( action == 2 ) // 2 = Clone
+ clone.insertBefore( currentNode.cloneNode( true ), clone.firstChild ) ;
+ else
+ {
+ // Both Delete and Extract will remove the node.
+ currentNode.parentNode.removeChild( currentNode ) ;
+
+ // When Extracting, mode the removed node to the docFrag.
+ if ( action == 1 ) // 1 = Extract
+ clone.insertBefore( currentNode, clone.firstChild ) ;
+ }
+
+ currentNode = currentSibling ;
+ }
+ }
+
+ if ( clone )
+ clone = levelClone ;
+ }
+
+ if ( action == 2 ) // 2 = Clone.
+ {
+ // No changes in the DOM should be done, so fix the split text (if any).
+
+ var startTextNode = this.startContainer ;
+ if ( startTextNode.nodeType == 3 )
+ {
+ startTextNode.data += startTextNode.nextSibling.data ;
+ startTextNode.parentNode.removeChild( startTextNode.nextSibling ) ;
+ }
+
+ var endTextNode = this.endContainer ;
+ if ( endTextNode.nodeType == 3 && endTextNode.nextSibling )
+ {
+ endTextNode.data += endTextNode.nextSibling.data ;
+ endTextNode.parentNode.removeChild( endTextNode.nextSibling ) ;
+ }
+ }
+ else
+ {
+ // Collapse the range.
+
+ // If a node has been partially selected, collapse the range between
+ // topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
+ if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
+ {
+ var endIndex = FCKDomTools.GetIndexOf( topEnd ) ;
+
+ // If the start node is to be removed, we must correct the
+ // index to reflect the removal.
+ if ( removeStartNode && topEnd.parentNode == startNode.parentNode )
+ endIndex-- ;
+
+ this.setStart( topEnd.parentNode, endIndex ) ;
+ }
+
+ // Collapse it to the start.
+ this.collapse( true ) ;
+ }
+
+ // Cleanup any marked node.
+ if( removeStartNode )
+ startNode.parentNode.removeChild( startNode ) ;
+
+ if( removeEndNode && endNode.parentNode )
+ endNode.parentNode.removeChild( endNode ) ;
+ },
+
+ cloneRange : function()
+ {
+ return FCKW3CRange.CreateFromRange( this._Document, this ) ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml.js
new file mode 100644
index 0000000..930ab30
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml.js
@@ -0,0 +1,108 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKXml Class: class to load and manipulate XML files.
+ * (IE specific implementation)
+ */
+
+var FCKXml = function()
+{
+ this.Error = false ;
+}
+
+FCKXml.GetAttribute = function( node, attName, defaultValue )
+{
+ var attNode = node.attributes.getNamedItem( attName ) ;
+ return attNode ? attNode.value : defaultValue ;
+}
+
+/**
+ * Transforms a XML element node in a JavaScript object. Attributes defined for
+ * the element will be available as properties, as long as child element
+ * nodes, but the later will generate arrays with property names prefixed with "$".
+ *
+ * For example, the following XML element:
+ *
+ * <SomeNode name="Test" key="2">
+ * <MyChild id="10">
+ * <OtherLevel name="Level 3" />
+ * </MyChild>
+ * <MyChild id="25" />
+ * <AnotherChild price="499" />
+ * </SomeNode>
+ *
+ * ... results in the following object:
+ *
+ * {
+ * name : "Test",
+ * key : "2",
+ * $MyChild :
+ * [
+ * {
+ * id : "10",
+ * $OtherLevel :
+ * {
+ * name : "Level 3"
+ * }
+ * },
+ * {
+ * id : "25"
+ * }
+ * ],
+ * $AnotherChild :
+ * [
+ * {
+ * price : "499"
+ * }
+ * ]
+ * }
+ */
+FCKXml.TransformToObject = function( element )
+{
+ if ( !element )
+ return null ;
+
+ var obj = {} ;
+
+ var attributes = element.attributes ;
+ for ( var i = 0 ; i < attributes.length ; i++ )
+ {
+ var att = attributes[i] ;
+ obj[ att.name ] = att.value ;
+ }
+
+ var childNodes = element.childNodes ;
+ for ( i = 0 ; i < childNodes.length ; i++ )
+ {
+ var child = childNodes[i] ;
+
+ if ( child.nodeType == 1 )
+ {
+ var childName = '$' + child.nodeName ;
+ var childList = obj[ childName ] ;
+ if ( !childList )
+ childList = obj[ childName ] = [] ;
+
+ childList.push( this.TransformToObject( child ) ) ;
+ }
+ }
+
+ return obj ;
+}
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_gecko.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_gecko.js
new file mode 100644
index 0000000..03f287f
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_gecko.js
@@ -0,0 +1,106 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKXml Class: class to load and manipulate XML files.
+ */
+
+FCKXml.prototype =
+{
+ LoadUrl : function( urlToCall )
+ {
+ this.Error = false ;
+
+ var oXml ;
+ var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
+ oXmlHttp.open( 'GET', urlToCall, false ) ;
+ oXmlHttp.send( null ) ;
+
+ if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 || ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 ) )
+ {
+ oXml = oXmlHttp.responseXML ;
+ // #1426: Fallback if responseXML isn't set for some
+ // reason (e.g. improperly configured web server)
+ if ( !oXml )
+ oXml = (new DOMParser()).parseFromString( oXmlHttp.responseText, 'text/xml' ) ;
+ }
+ else
+ oXml = null ;
+
+ if ( oXml )
+ {
+ // Try to access something on it.
+ try
+ {
+ var test = oXml.firstChild ;
+ }
+ catch (e)
+ {
+ // If document.domain has been changed (#123), we'll have a security
+ // error at this point. The workaround here is parsing the responseText:
+ // http://alexander.kirk.at/2006/07/27/firefox-15-xmlhttprequest-reqresponsexml-and-documentdomain/
+ oXml = (new DOMParser()).parseFromString( oXmlHttp.responseText, 'text/xml' ) ;
+ }
+ }
+
+ if ( !oXml || !oXml.firstChild )
+ {
+ this.Error = true ;
+ if ( window.confirm( 'Error loading "' + urlToCall + '" (HTTP Status: ' + oXmlHttp.status + ').\r\nDo you want to see the server response dump?' ) )
+ alert( oXmlHttp.responseText ) ;
+ }
+
+ this.DOMDocument = oXml ;
+ },
+
+ SelectNodes : function( xpath, contextNode )
+ {
+ if ( this.Error )
+ return new Array() ;
+
+ var aNodeArray = new Array();
+
+ var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
+ this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ;
+ if ( xPathResult )
+ {
+ var oNode = xPathResult.iterateNext() ;
+ while( oNode )
+ {
+ aNodeArray[aNodeArray.length] = oNode ;
+ oNode = xPathResult.iterateNext();
+ }
+ }
+ return aNodeArray ;
+ },
+
+ SelectSingleNode : function( xpath, contextNode )
+ {
+ if ( this.Error )
+ return null ;
+
+ var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
+ this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), 9, null);
+
+ if ( xPathResult && xPathResult.singleNodeValue )
+ return xPathResult.singleNodeValue ;
+ else
+ return null ;
+ }
+} ;
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_ie.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_ie.js
new file mode 100644
index 0000000..0a18f45
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/classes/fckxml_ie.js
@@ -0,0 +1,93 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2009 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ * - GNU General Public License Version 2 or later (the "GPL")
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * - Mozilla Public License Version 1.1 or later (the "MPL")
+ * http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * FCKXml Class: class to load and manipulate XML files.
+ * (IE specific implementation)
+ */
+
+FCKXml.prototype =
+{
+ LoadUrl : function( urlToCall )
+ {
+ this.Error = false ;
+
+ var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
+
+ if ( !oXmlHttp )
+ {
+ this.Error = true ;
+ return ;
+ }
+
+ oXmlHttp.open( "GET", urlToCall, false ) ;
+
+ oXmlHttp.send( null ) ;
+
+ if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 || ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 ) )
+ {
+ this.DOMDocument = oXmlHttp.responseXML ;
+
+ // #1426: Fallback if responseXML isn't set for some
+ // reason (e.g. improperly configured web server)
+ if ( !this.DOMDocument || this.DOMDocument.firstChild == null )
+ {
+ this.DOMDocument = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
+ this.DOMDocument.async = false ;
+ this.DOMDocument.resolveExternals = false ;
+ this.DOMDocument.loadXML( oXmlHttp.responseText ) ;
+ }
+ }
+ else
+ {
+ this.DOMDocument = null ;
+ }
+
+ if ( this.DOMDocument == null || this.DOMDocument.firstChild == null )
+ {
+ this.Error = true ;
+ if (window.confirm( 'Error loading "' + urlToCall + '"\r\nDo you want to see more info?' ) )
+ alert( 'URL requested: "' + urlToCall + '"\r\n' +
+ 'Server response:\r\nStatus: ' + oXmlHttp.status + '\r\n' +
+ 'Response text:\r\n' + oXmlHttp.responseText ) ;
+ }
+ },
+
+ SelectNodes : function( xpath, contextNode )
+ {
+ if ( this.Error )
+ return new Array() ;
+
+ if ( contextNode )
+ return contextNode.selectNodes( xpath ) ;
+ else
+ return this.DOMDocument.selectNodes( xpath ) ;
+ },
+
+ SelectSingleNode : function( xpath, contextNode )
+ {
+ if ( this.Error )
+ return null ;
+
+ if ( contextNode )
+ return contextNode.selectSingleNode( xpath ) ;
+ else
+ return this.DOMDocument.selectSingleNode( xpath ) ;
+ }
+} ;