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