summaryrefslogtreecommitdiff
path: root/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js
diff options
context:
space:
mode:
Diffstat (limited to 'rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js')
-rw-r--r--rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js497
1 files changed, 497 insertions, 0 deletions
diff --git a/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js
new file mode 100644
index 0000000..e36f9ad
--- /dev/null
+++ b/rt/share/html/NoAuth/RichText/FCKeditor/editor/_source/internals/fck_gecko.js
@@ -0,0 +1,497 @@
+/*
+ * 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 ==
+ *
+ * Creation and initialization of the "FCK" object. This is the main
+ * object that represents an editor instance.
+ * (Gecko specific implementations)
+ */
+
+FCK.Description = "FCKeditor for Gecko Browsers" ;
+
+FCK.InitializeBehaviors = function()
+{
+ // When calling "SetData", the editing area IFRAME gets a fixed height. So we must recalculate it.
+ if ( window.onresize ) // Not for Safari/Opera.
+ window.onresize() ;
+
+ FCKFocusManager.AddWindow( this.EditorWindow ) ;
+
+ this.ExecOnSelectionChange = function()
+ {
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+ }
+
+ this._ExecDrop = function( evt )
+ {
+ if ( FCK.MouseDownFlag )
+ {
+ FCK.MouseDownFlag = false ;
+ return ;
+ }
+
+ if ( FCKConfig.ForcePasteAsPlainText )
+ {
+ if ( evt.dataTransfer )
+ {
+ var text = evt.dataTransfer.getData( 'Text' ) ;
+ text = FCKTools.HTMLEncode( text ) ;
+ text = FCKTools.ProcessLineBreaks( window, FCKConfig, text ) ;
+ FCK.InsertHtml( text ) ;
+ }
+ else if ( FCKConfig.ShowDropDialog )
+ FCK.PasteAsPlainText() ;
+
+ evt.preventDefault() ;
+ evt.stopPropagation() ;
+ }
+ }
+
+ this._ExecCheckCaret = function( evt )
+ {
+ if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
+ return ;
+
+ if ( evt.type == 'keypress' )
+ {
+ var keyCode = evt.keyCode ;
+ // ignore if positioning key is not pressed.
+ // left or up arrow keys need to be processed as well, since <a> links can be expanded in Gecko's editor
+ // when the caret moved left or up from another block element below.
+ if ( keyCode < 33 || keyCode > 40 )
+ return ;
+ }
+
+ var blockEmptyStop = function( node )
+ {
+ if ( node.nodeType != 1 )
+ return false ;
+ var tag = node.tagName.toLowerCase() ;
+ return ( FCKListsLib.BlockElements[tag] || FCKListsLib.EmptyElements[tag] ) ;
+ }
+
+ var moveCursor = function()
+ {
+ var selection = FCKSelection.GetSelection() ;
+ var range = selection.getRangeAt(0) ;
+ if ( ! range || ! range.collapsed )
+ return ;
+
+ var node = range.endContainer ;
+
+ // only perform the patched behavior if we're at the end of a text node.
+ if ( node.nodeType != 3 )
+ return ;
+
+ if ( node.nodeValue.length != range.endOffset )
+ return ;
+
+ // only perform the patched behavior if we're in an <a> tag, or the End key is pressed.
+ var parentTag = node.parentNode.tagName.toLowerCase() ;
+ if ( ! ( parentTag == 'a' || ( !FCKBrowserInfo.IsOpera && String(node.parentNode.contentEditable) == 'false' ) ||
+ ( ! ( FCKListsLib.BlockElements[parentTag] || FCKListsLib.NonEmptyBlockElements[parentTag] )
+ && keyCode == 35 ) ) )
+ return ;
+
+ // our caret has moved to just after the last character of a text node under an unknown tag, how to proceed?
+ // first, see if there are other text nodes by DFS walking from this text node.
+ // - if the DFS has scanned all nodes under my parent, then go the next step.
+ // - if there is a text node after me but still under my parent, then do nothing and return.
+ var nextTextNode = FCKTools.GetNextTextNode( node, node.parentNode, blockEmptyStop ) ;
+ if ( nextTextNode )
+ return ;
+
+ // we're pretty sure we need to move the caret forcefully from here.
+ range = FCK.EditorDocument.createRange() ;
+
+ nextTextNode = FCKTools.GetNextTextNode( node, node.parentNode.parentNode, blockEmptyStop ) ;
+ if ( nextTextNode )
+ {
+ // Opera thinks the dummy empty text node we append beyond the end of <a> nodes occupies a caret
+ // position. So if the user presses the left key and we reset the caret position here, the user
+ // wouldn't be able to go back.
+ if ( FCKBrowserInfo.IsOpera && keyCode == 37 )
+ return ;
+
+ // now we want to get out of our current parent node, adopt the next parent, and move the caret to
+ // the appropriate text node under our new parent.
+ // our new parent might be our current parent's siblings if we are lucky.
+ range.setStart( nextTextNode, 0 ) ;
+ range.setEnd( nextTextNode, 0 ) ;
+ }
+ else
+ {
+ // no suitable next siblings under our grandparent! what to do next?
+ while ( node.parentNode
+ && node.parentNode != FCK.EditorDocument.body
+ && node.parentNode != FCK.EditorDocument.documentElement
+ && node == node.parentNode.lastChild
+ && ( ! FCKListsLib.BlockElements[node.parentNode.tagName.toLowerCase()]
+ && ! FCKListsLib.NonEmptyBlockElements[node.parentNode.tagName.toLowerCase()] ) )
+ node = node.parentNode ;
+
+
+ if ( FCKListsLib.BlockElements[ parentTag ]
+ || FCKListsLib.EmptyElements[ parentTag ]
+ || node == FCK.EditorDocument.body )
+ {
+ // if our parent is a block node, move to the end of our parent.
+ range.setStart( node, node.childNodes.length ) ;
+ range.setEnd( node, node.childNodes.length ) ;
+ }
+ else
+ {
+ // things are a little bit more interesting if our parent is not a block node
+ // due to the weired ways how Gecko's caret acts...
+ var stopNode = node.nextSibling ;
+
+ // find out the next block/empty element at our grandparent, we'll
+ // move the caret just before it.
+ while ( stopNode )
+ {
+ if ( stopNode.nodeType != 1 )
+ {
+ stopNode = stopNode.nextSibling ;
+ continue ;
+ }
+
+ var stopTag = stopNode.tagName.toLowerCase() ;
+ if ( FCKListsLib.BlockElements[stopTag] || FCKListsLib.EmptyElements[stopTag]
+ || FCKListsLib.NonEmptyBlockElements[stopTag] )
+ break ;
+ stopNode = stopNode.nextSibling ;
+ }
+
+ // note that the dummy marker below is NEEDED, otherwise the caret's behavior will
+ // be broken in Gecko.
+ var marker = FCK.EditorDocument.createTextNode( '' ) ;
+ if ( stopNode )
+ node.parentNode.insertBefore( marker, stopNode ) ;
+ else
+ node.parentNode.appendChild( marker ) ;
+ range.setStart( marker, 0 ) ;
+ range.setEnd( marker, 0 ) ;
+ }
+ }
+
+ selection.removeAllRanges() ;
+ selection.addRange( range ) ;
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+ }
+
+ setTimeout( moveCursor, 1 ) ;
+ }
+
+ this.ExecOnSelectionChangeTimer = function()
+ {
+ if ( FCK.LastOnChangeTimer )
+ window.clearTimeout( FCK.LastOnChangeTimer ) ;
+
+ FCK.LastOnChangeTimer = window.setTimeout( FCK.ExecOnSelectionChange, 100 ) ;
+ }
+
+ this.EditorDocument.addEventListener( 'mouseup', this.ExecOnSelectionChange, false ) ;
+
+ // On Gecko, firing the "OnSelectionChange" event on every key press started to be too much
+ // slow. So, a timer has been implemented to solve performance issues when typing to quickly.
+ this.EditorDocument.addEventListener( 'keyup', this.ExecOnSelectionChangeTimer, false ) ;
+
+ this._DblClickListener = function( e )
+ {
+ FCK.OnDoubleClick( e.target ) ;
+ e.stopPropagation() ;
+ }
+ this.EditorDocument.addEventListener( 'dblclick', this._DblClickListener, true ) ;
+
+ // Record changes for the undo system when there are key down events.
+ this.EditorDocument.addEventListener( 'keydown', this._KeyDownListener, false ) ;
+
+ // Hooks for data object drops
+ if ( FCKBrowserInfo.IsGecko )
+ {
+ this.EditorWindow.addEventListener( 'dragdrop', this._ExecDrop, true ) ;
+ }
+ else if ( FCKBrowserInfo.IsSafari )
+ {
+ this.EditorDocument.addEventListener( 'dragover', function ( evt )
+ { if ( !FCK.MouseDownFlag && FCK.Config.ForcePasteAsPlainText ) evt.returnValue = false ; }, true ) ;
+ this.EditorDocument.addEventListener( 'drop', this._ExecDrop, true ) ;
+ this.EditorDocument.addEventListener( 'mousedown',
+ function( ev )
+ {
+ var element = ev.srcElement ;
+
+ if ( element.nodeName.IEquals( 'IMG', 'HR', 'INPUT', 'TEXTAREA', 'SELECT' ) )
+ {
+ FCKSelection.SelectNode( element ) ;
+ }
+ }, true ) ;
+
+ this.EditorDocument.addEventListener( 'mouseup',
+ function( ev )
+ {
+ if ( ev.srcElement.nodeName.IEquals( 'INPUT', 'TEXTAREA', 'SELECT' ) )
+ ev.preventDefault()
+ }, true ) ;
+
+ this.EditorDocument.addEventListener( 'click',
+ function( ev )
+ {
+ if ( ev.srcElement.nodeName.IEquals( 'INPUT', 'TEXTAREA', 'SELECT' ) )
+ ev.preventDefault()
+ }, true ) ;
+ }
+
+ // Kludge for buggy Gecko caret positioning logic (Bug #393 and #1056)
+ if ( FCKBrowserInfo.IsGecko || FCKBrowserInfo.IsOpera )
+ {
+ this.EditorDocument.addEventListener( 'keypress', this._ExecCheckCaret, false ) ;
+ this.EditorDocument.addEventListener( 'click', this._ExecCheckCaret, false ) ;
+ }
+
+ // Reset the context menu.
+ FCK.ContextMenu._InnerContextMenu.SetMouseClickWindow( FCK.EditorWindow ) ;
+ FCK.ContextMenu._InnerContextMenu.AttachToElement( FCK.EditorDocument ) ;
+}
+
+FCK.MakeEditable = function()
+{
+ this.EditingArea.MakeEditable() ;
+}
+
+// Disable the context menu in the editor (outside the editing area).
+function Document_OnContextMenu( e )
+{
+ if ( !e.target._FCKShowContextMenu )
+ e.preventDefault() ;
+}
+document.oncontextmenu = Document_OnContextMenu ;
+
+// GetNamedCommandState overload for Gecko.
+FCK._BaseGetNamedCommandState = FCK.GetNamedCommandState ;
+FCK.GetNamedCommandState = function( commandName )
+{
+ switch ( commandName )
+ {
+ case 'Unlink' :
+ return FCKSelection.HasAncestorNode('A') ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+ default :
+ return FCK._BaseGetNamedCommandState( commandName ) ;
+ }
+}
+
+// Named commands to be handled by this browsers specific implementation.
+FCK.RedirectNamedCommands =
+{
+ Print : true,
+ Paste : true
+} ;
+
+// ExecuteNamedCommand overload for Gecko.
+FCK.ExecuteRedirectedNamedCommand = function( commandName, commandParameter )
+{
+ switch ( commandName )
+ {
+ case 'Print' :
+ FCK.EditorWindow.print() ;
+ break ;
+ case 'Paste' :
+ try
+ {
+ // Force the paste dialog for Safari (#50).
+ if ( FCKBrowserInfo.IsSafari )
+ throw '' ;
+
+ if ( FCK.Paste() )
+ FCK.ExecuteNamedCommand( 'Paste', null, true ) ;
+ }
+ catch (e) {
+ if ( FCKConfig.ForcePasteAsPlainText )
+ FCK.PasteAsPlainText() ;
+ else
+ FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security' ) ;
+ }
+ break ;
+ default :
+ FCK.ExecuteNamedCommand( commandName, commandParameter ) ;
+ }
+}
+
+FCK._ExecPaste = function()
+{
+ // Save a snapshot for undo before actually paste the text
+ FCKUndo.SaveUndoStep() ;
+
+ if ( FCKConfig.ForcePasteAsPlainText )
+ {
+ FCK.PasteAsPlainText() ;
+ return false ;
+ }
+
+ /* For now, the AutoDetectPasteFromWord feature is IE only. */
+ return true ;
+}
+
+//**
+// FCK.InsertHtml: Inserts HTML at the current cursor location. Deletes the
+// selected content if any.
+FCK.InsertHtml = function( html )
+{
+ var doc = FCK.EditorDocument,
+ range;
+
+ html = FCKConfig.ProtectedSource.Protect( html ) ;
+ html = FCK.ProtectEvents( html ) ;
+ html = FCK.ProtectUrls( html ) ;
+ html = FCK.ProtectTags( html ) ;
+
+ // Save an undo snapshot first.
+ FCKUndo.SaveUndoStep() ;
+
+ if ( FCKBrowserInfo.IsGecko )
+ {
+ html = html.replace( /&nbsp;$/, '$&<span _fcktemp="1"/>' ) ;
+
+ var docFrag = new FCKDocumentFragment( this.EditorDocument ) ;
+ docFrag.AppendHtml( html ) ;
+
+ var lastNode = docFrag.RootNode.lastChild ;
+
+ range = new FCKDomRange( this.EditorWindow ) ;
+ range.MoveToSelection() ;
+ range.DeleteContents() ;
+ range.InsertNode( docFrag.RootNode ) ;
+
+ range.MoveToPosition( lastNode, 4 ) ;
+ }
+ else
+ doc.execCommand( 'inserthtml', false, html ) ;
+
+ this.Focus() ;
+
+ // Save the caret position before calling document processor.
+ if ( !range )
+ {
+ range = new FCKDomRange( this.EditorWindow ) ;
+ range.MoveToSelection() ;
+ }
+ var bookmark = range.CreateBookmark() ;
+
+ FCKDocumentProcessor.Process( doc ) ;
+
+ // Restore caret position, ignore any errors in case the document
+ // processor removed the bookmark <span>s for some reason.
+ try
+ {
+ range.MoveToBookmark( bookmark ) ;
+ range.Select() ;
+ }
+ catch ( e ) {}
+
+ // For some strange reason the SaveUndoStep() call doesn't activate the undo button at the first InsertHtml() call.
+ this.Events.FireEvent( "OnSelectionChange" ) ;
+}
+
+FCK.PasteAsPlainText = function()
+{
+ // TODO: Implement the "Paste as Plain Text" code.
+
+ // If the function is called immediately Firefox 2 does automatically paste the contents as soon as the new dialog is created
+ // so we run it in a Timeout and the paste event can be cancelled
+ FCKTools.RunFunction( FCKDialog.OpenDialog, FCKDialog, ['FCKDialog_Paste', FCKLang.PasteAsText, 'dialog/fck_paste.html', 400, 330, 'PlainText'] ) ;
+
+/*
+ var sText = FCKTools.HTMLEncode( clipboardData.getData("Text") ) ;
+ sText = sText.replace( /\n/g, '<BR>' ) ;
+ this.InsertHtml( sText ) ;
+*/
+}
+/*
+FCK.PasteFromWord = function()
+{
+ // TODO: Implement the "Paste as Plain Text" code.
+
+ FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteFromWord, 'dialog/fck_paste.html', 400, 330, 'Word' ) ;
+
+// FCK.CleanAndPaste( FCK.GetClipboardHTML() ) ;
+}
+*/
+FCK.GetClipboardHTML = function()
+{
+ return '' ;
+}
+
+FCK.CreateLink = function( url, noUndo )
+{
+ // Creates the array that will be returned. It contains one or more created links (see #220).
+ var aCreatedLinks = new Array() ;
+
+ // Only for Safari, a collapsed selection may create a link. All other
+ // browser will have no links created. So, we check it here and return
+ // immediatelly, having the same cross browser behavior.
+ if ( FCKSelection.GetSelection().isCollapsed )
+ return aCreatedLinks ;
+
+ FCK.ExecuteNamedCommand( 'Unlink', null, false, !!noUndo ) ;
+
+ if ( url.length > 0 )
+ {
+ // Generate a temporary name for the link.
+ var sTempUrl = 'javascript:void(0);/*' + ( new Date().getTime() ) + '*/' ;
+
+ // Use the internal "CreateLink" command to create the link.
+ FCK.ExecuteNamedCommand( 'CreateLink', sTempUrl, false, !!noUndo ) ;
+
+ // Retrieve the just created links using XPath.
+ var oLinksInteractor = this.EditorDocument.evaluate("//a[@href='" + sTempUrl + "']", this.EditorDocument.body, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null) ;
+
+ // Add all links to the returning array.
+ for ( var i = 0 ; i < oLinksInteractor.snapshotLength ; i++ )
+ {
+ var oLink = oLinksInteractor.snapshotItem( i ) ;
+ oLink.href = url ;
+
+ aCreatedLinks.push( oLink ) ;
+ }
+ }
+
+ return aCreatedLinks ;
+}
+
+FCK._FillEmptyBlock = function( emptyBlockNode )
+{
+ if ( ! emptyBlockNode || emptyBlockNode.nodeType != 1 )
+ return ;
+ var nodeTag = emptyBlockNode.tagName.toLowerCase() ;
+ if ( nodeTag != 'p' && nodeTag != 'div' )
+ return ;
+ if ( emptyBlockNode.firstChild )
+ return ;
+ FCKTools.AppendBogusBr( emptyBlockNode ) ;
+}
+
+FCK._ExecCheckEmptyBlock = function()
+{
+ FCK._FillEmptyBlock( FCK.EditorDocument.body.firstChild ) ;
+ var sel = FCKSelection.GetSelection() ;
+ if ( !sel || sel.rangeCount < 1 )
+ return ;
+ var range = sel.getRangeAt( 0 );
+ FCK._FillEmptyBlock( range.startContainer ) ;
+}