, and 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 ;
+
+ 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 ] )
+ {
+ // 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 ;
+ }
+
+ 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 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 ;
+ 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 child (nested
+ // lists) or the next sibling .
+
+ 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 && previousSibling.nodeName.toLowerCase() == 'br' )
+ previousSibling.parentNode.removeChild( previousSibling ) ;
+ }
+
+ 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.
+ this._NextNode = ( isLast || block == lastNode ) ? null : FCKDomTools.GetNextSourceNode( block, true, null, lastNode ) ;
+
+ return block ;
+ }
+} ;
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckeditingarea.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckeditingarea.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckeditingarea.js (revision 1015)
@@ -0,0 +1,345 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ) ;
+}
+
+FCKEditingArea.prototype.TypeName = 'FCKEditingArea' ; // @Packager.RemoveLine
+
+/**
+ * @param {String} html The complete HTML for the page, including DOCTYPE and the tag.
+ */
+FCKEditingArea.prototype.Start = function( html, secondCall )
+{
+ var eTargetElement = this.TargetElement ;
+ var oTargetDocument = FCKTools.GetElementDocument( eTargetElement ) ;
+
+ // Remove all child nodes from the target.
+ var oChild ;
+ while( ( oChild = eTargetElement.firstChild ) ) // Only one "=".
+ {
+ // Set innerHTML = '' to avoid memory leak.
+ if ( oChild.contentWindow )
+ oChild.contentWindow.document.body.innerHTML = '' ;
+
+ eTargetElement.removeChild( oChild ) ;
+ }
+
+ if ( this.Mode == FCK_EDITMODE_WYSIWYG )
+ {
+ // Create the editing area IFRAME.
+ var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ;
+
+ // Firefox will render the tables inside the body in Quirks mode if the
+ // source of the iframe is set to javascript. see #515
+ if ( !FCKBrowserInfo.IsGecko )
+ oIFrame.src = 'javascript:void(0)' ;
+
+ oIFrame.frameBorder = 0 ;
+ oIFrame.width = oIFrame.height = '100%' ;
+
+ // Append the new IFRAME to the target.
+ eTargetElement.appendChild( oIFrame ) ;
+
+ // IE has a bug with the tag... it must have a closer,
+ // otherwise the all successive tags will be set as children nodes of the .
+ if ( FCKBrowserInfo.IsIE )
+ html = html.replace( /( ]*?)\s*\/?>(?!\s*<\/base>)/gi, '$1>' ) ;
+ 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 tag, inclusive.
+ ' ' +
+ oMatchAfter[1] ; // This is the HTML from the 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 = ' ' ;
+
+ this._BodyHTML = sBody ;
+
+ }
+ else
+ this._BodyHTML = html ; // Invalid HTML input.
+ }
+
+ // 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 ; }
+
+ var oDoc = this.Document = this.Window.document ;
+
+ oDoc.open() ;
+ oDoc.write( html ) ;
+ oDoc.close() ;
+
+ // 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 ;
+ }
+
+ 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! !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 ;
+
+ 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 ;
+ this._BodyHTML = null ;
+ }
+
+ oDoc.designMode = 'on' ;
+
+ // Tell Gecko to use or not the tag for the bold, italic and underline.
+ try
+ {
+ oDoc.execCommand( 'styleWithCSS', false, FCKConfig.GeckoUseSPAN ) ;
+ }
+ catch (e)
+ {
+ // As evidenced here, useCSS is deprecated in favor of styleWithCSS:
+ // http://www.mozilla.org/editor/midas-spec.html
+ oDoc.execCommand( 'useCSS', false, !FCKConfig.GeckoUseSPAN ) ;
+ }
+
+ // Analyzing Firefox 1.5 source code, it seams that there is support for a
+ // "insertBrOnReturn" command. Applying it gives no error, but it doesn't
+ // gives the same behavior that you have with IE. It works only if you are
+ // already inside a paragraph and it doesn't render correctly in the first enter.
+ // oDoc.execCommand( 'insertBrOnReturn', false, false ) ;
+
+ // 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 )
+ {
+ // The following check is important to avoid IE entering in a focus loop. Ref:
+ // http://sourceforge.net/tracker/index.php?func=detail&aid=1567060&group_id=75348&atid=543653
+ if ( FCKBrowserInfo.IsIE && this.Document.hasFocus() )
+ this._EnsureFocusIE() ;
+
+ if ( FCKBrowserInfo.IsSafari )
+ this.IFrame.focus() ;
+ else
+ {
+ this.Window.focus() ;
+
+ // In IE it can happen that the document is in theory focused but the active element is outside it
+ if ( FCKBrowserInfo.IsIE )
+ this._EnsureFocusIE() ;
+ }
+ }
+ else
+ {
+ var oDoc = FCKTools.GetElementDocument( this.Textarea ) ;
+ if ( (!oDoc.hasFocus || oDoc.hasFocus() ) && oDoc.activeElement == this.Textarea )
+ return ;
+
+ this.Textarea.focus() ;
+ }
+ }
+ catch(e) {}
+}
+
+FCKEditingArea.prototype._EnsureFocusIE = function()
+{
+ // In IE it can happen that the document is in theory focused but the active element is outside it
+ this.Document.body.setActive() ;
+
+ // Kludge for #141... yet more code to workaround IE bugs
+ var range = this.Document.selection.createRange() ;
+
+ // Only apply the fix when in a block and the block is empty.
+ var parentNode = range.parentElement() ;
+
+ if ( ! ( parentNode.childNodes.length == 0 && (
+ FCKListsLib.BlockElements[parentNode.nodeName.toLowerCase()] ||
+ FCKListsLib.NonEmptyBlockElements[parentNode.nodeName.toLowerCase()] ) ) )
+ return ;
+
+ var oldLength = range.text.length ;
+ range.moveEnd( "character", 1 ) ;
+ range.select() ;
+ if ( range.text.length > oldLength )
+ {
+ range.moveEnd( "character", -1 ) ;
+ 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 ;
+ }
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckelementpath.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckelementpath.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckelementpath.js (revision 1015)
@@ -0,0 +1,70 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ( !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).
+ if ( !eBlock && sElementName == 'div' )
+ eBlock = e ;
+ else
+ eBlockLimit = e ;
+ }
+ }
+
+ aElements.push( e ) ;
+
+ if ( sElementName == 'body' )
+ break ;
+ }
+ e = e.parentNode ;
+ }
+
+ this.Block = eBlock ;
+ this.BlockLimit = eBlockLimit ;
+ this.Elements = aElements ;
+}
+
+
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckenterkey.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckenterkey.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckenterkey.js (revision 1015)
@@ -0,0 +1,634 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 keystroke.
+ * May be "p", "div", "br". Default is "p".
+ * @shiftEnterMode : the behavior for the + 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' ],
+ [ 9 , 'Tab' ],
+ [ 8 , 'Backspace' ],
+ [ CTRL + 8 , 'CtrlBackspace' ],
+ [ 46 , 'Delete' ]
+ ] ) ;
+
+ if ( tabSpaces > 0 )
+ {
+ this.TabText = '' ;
+ while ( tabSpaces-- > 0 )
+ this.TabText += '\xa0' ;
+ }
+
+ oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
+}
+
+FCKEnterKey.prototype.TypeName = 'FCKEnterKey' ; // @Packager.RemoveLine
+
+function FCKEnterKey_OnKeystroke( keyCombination, keystrokeValue )
+{
+ var oEnterKey = this._EnterKey ;
+
+ /* @Packager.RemoveLine
+ try
+ {
+ @Packager.RemoveLine */
+ 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 ;
+ }
+ /* @Packager.RemoveLine
+ }
+ catch (e)
+ {
+ // If for any reason we are not able to handle it, go
+ // ahead with the browser default behavior.
+ }
+ @Packager.RemoveLine */
+
+ return false ;
+}
+
+/*
+ * Executes the 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 + key behavior.
+ */
+FCKEnterKey.prototype.DoShiftEnter = function()
+{
+ return this.DoEnter( this.ShiftEnterMode, true ) ;
+}
+
+/*
+ * Executes the 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 ;
+ }
+
+ 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() ;
+
+ // 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.MoveToBookmark( oBookmark ) ;
+ range.Select() ;
+
+ bCustom = true ;
+ }
+ }
+
+ return bCustom ;
+}
+
+/*
+ * Executes the 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 has the same effect as the , so we have the same
+ // results if we just move to the next block and apply the same 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'] ) ;
+
+ // 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 key behavior.
+ */
+FCKEnterKey.prototype.DoTab = function()
+{
+ var oRange = new FCKDomRange( this.Window );
+ oRange.MoveToSelection() ;
+
+ // If the user pressed 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() ;
+
+ if ( oSplitInfo )
+ {
+ // Get the current blocks.
+ var ePreviousBlock = oSplitInfo.PreviousBlock ;
+ var eNextBlock = oSplitInfo.NextBlock ;
+
+ var bIsStartOfBlock = oSplitInfo.WasStartOfBlock ;
+ var bIsEndOfBlock = oSplitInfo.WasEndOfBlock ;
+
+ // 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 ( !oSplitInfo.WasStartOfBlock && !oSplitInfo.WasEndOfBlock )
+ {
+ // 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.
+ if ( this._HasShift || (/^H[1-6]$/).test( sPreviousBlockTag ) )
+ eNewBlock = this.Window.document.createElement( blockTag ) ;
+ else
+ {
+ // Otherwise, duplicate the previous block.
+ eNewBlock = FCKDomTools.CloneElement( ePreviousBlock ) ;
+
+ this._RecreateEndingTree( ePreviousBlock, eNewBlock ) ;
+ }
+ }
+ else if ( eNextBlock )
+ {
+ eNewBlock = FCKDomTools.CloneElement( eNextBlock ) ;
+ }
+ else
+ eNewBlock = this.Window.document.createElement( blockTag ) ;
+
+ 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.MoveToNodeContents( eNewBlock ) ;
+ oRange.Select() ;
+ }
+
+ oRange.MoveToElementEditStart( bIsStartOfBlock && !bIsEndOfBlock ? eNextBlock : eNewBlock ) ;
+
+ if ( FCKBrowserInfo.IsGeckoLike )
+ eNewBlock.scrollIntoView( 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 ;
+
+ 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 = null ;
+ if ( sStartBlockTag.IEquals( 'pre' ) )
+ 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 ) ;
+ dummy.scrollIntoView( false ) ;
+ dummy.parentNode.removeChild( dummy ) ;
+ }
+ }
+
+ // This collapse guarantees the cursor will be blinking.
+ oRange.Collapse( true ) ;
+
+ oRange.Select() ;
+ }
+
+ // Release the resources used by the range.
+ oRange.Release() ;
+
+ return true ;
+}
+
+// Recreate the elements tree at the end of the source block, at the beginning
+// of the target block. Eg.:
+// If source = Some sample text
then target =
+// If source = Some sample text
then target =
+FCKEnterKey.prototype._RecreateEndingTree = function( source, target )
+{
+ while ( ( source = source.lastChild ) && source.nodeType == 1 && FCKListsLib.InlineChildReqElements[ source.nodeName.toLowerCase() ] != null )
+ target = target.insertBefore( FCKDomTools.CloneElement( source ), target.firstChild ) ;
+}
+
+// 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() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckevents.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckevents.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckevents.js (revision 1015)
@@ -0,0 +1,66 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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
+ 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 ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckicon.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckicon.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckicon.js (revision 1015)
@@ -0,0 +1,103 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 )
+ {
+ //
+
+ eIcon = document.createElement( 'DIV' ) ;
+
+ eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
+ eIconImage.src = this.Path ;
+ eIconImage.style.top = sPos ;
+ }
+ else
+ {
+ //
+
+ 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 directly, so we
+ // are changing to the 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.
+ //
+ eIcon = document.createElement( 'IMG' ) ;
+ eIcon.src = this.Path ? this.Path : FCK_SPACER_PATH ;
+ }
+ }
+
+ eIcon.className = 'TB_Button_Image' ;
+
+ return eIcon ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckiecleanup.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckiecleanup.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckiecleanup.js (revision 1015)
@@ -0,0 +1,68 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 || !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() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckimagepreloader.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckimagepreloader.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckimagepreloader.js (revision 1015)
@@ -0,0 +1,64 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckkeystrokehandler.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckkeystrokehandler.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckkeystrokehandler.js (revision 1015)
@@ -0,0 +1,141 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublock.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublock.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublock.js (revision 1015)
@@ -0,0 +1,151 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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.TypeName = 'FCKMenuBlock' ; // @Packager.RemoveLine
+
+FCKMenuBlock.prototype.Count = function()
+{
+ return this._Items.length ;
+}
+
+FCKMenuBlock.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled )
+{
+ var oItem = new FCKMenuItem( this, name, label, iconPathOrStripInfoArrayOrIndex, isDisabled ) ;
+
+ 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 )
+{
+ 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' ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublockpanel.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublockpanel.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenublockpanel.js (revision 1015)
@@ -0,0 +1,55 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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() ;
+
+FCKMenuBlockPanel.prototype.TypeName = 'FCKMenuBlockPanel' ; // @Packager.RemoveLine
+
+// 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.SkinPath + 'fck_editor.css' ) ;
+
+ // 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() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenuitem.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenuitem.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckmenuitem.js (revision 1015)
@@ -0,0 +1,161 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 )
+{
+ 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 ) ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKMenuItem_Cleanup ) ;
+}
+
+FCKMenuItem.prototype.TypeName = 'FCKMenuItem' ; // @Packager.RemoveLine
+
+FCKMenuItem.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled )
+{
+ this.HasSubMenu = true ;
+ return this.SubMenu.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled ) ;
+}
+
+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 ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckpanel.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckpanel.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckpanel.js (revision 1015)
@@ -0,0 +1,340 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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.
+ this._Popup = this._Window.createPopup() ;
+ oDocument = this.Document = this._Popup.document ;
+
+ FCK.IECleanup.AddItem( this, FCKPanel_Cleanup ) ;
+ }
+ else
+ {
+ var oIFrame = this._IFrame = this._Window.document.createElement('iframe') ;
+ oIFrame.src = 'javascript:void(0)' ;
+ oIFrame.allowTransparency = true ;
+ oIFrame.frameBorder = '0' ;
+ oIFrame.scrolling = 'no' ;
+ oIFrame.width = oIFrame.height = 0 ;
+ FCKDomTools.SetElementStyles( oIFrame,
+ {
+ position : 'absolute',
+ zIndex : FCKConfig.FloatingPanelsZIndex
+ } ) ;
+
+ if ( this._Window == window.parent && window.frameElement )
+ {
+ var scrollPos = null ;
+ if ( FCKBrowserInfo.IsGecko && FCK && FCK.EditorDocument )
+ scrollPos = [ FCK.EditorDocument.body.scrollLeft, FCK.EditorDocument.body.scrollTop ] ;
+ window.frameElement.parentNode.insertBefore( oIFrame, window.frameElement ) ;
+ if ( scrollPos )
+ {
+ var restoreFunc = function()
+ {
+ FCK.EditorDocument.body.scrollLeft = scrollPos[0] ;
+ FCK.EditorDocument.body.scrollTop = scrollPos[1] ;
+ }
+ setTimeout( restoreFunc, 500 ) ;
+ }
+ }
+ else
+ 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 = '
' ;
+
+ // Initialize the IFRAME document body.
+ oDocument.open() ;
+ oDocument.write( '' + sBase + '<\/head><\/body><\/html>' ) ;
+ oDocument.close() ;
+
+ 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 ) ;
+
+ oDocument.body.bgColor = '#FF0000' ; // @Packager.RemoveLine - Just to be sure that the context menu popup is not bigger that it should be.
+
+ // 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.TypeName = 'FCKPanel' ; // @Packager.RemoveLine
+
+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 ) ;
+}
+
+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 ( this.IsRTL )
+ {
+ if ( this.IsContextMenu )
+ x = x - iMainWidth + 1 ;
+ else if ( relElement )
+ x = ( x * -1 ) + relElement.offsetWidth - iMainWidth ;
+ }
+
+ // 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() ;
+
+ 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 ;
+
+ var oPos = FCKTools.GetElementPosition(
+ relElement.nodeType == 9 ?
+ ( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :
+ relElement,
+ this._Window ) ;
+
+ 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 ;
+ }
+
+ if ( x < 0 )
+ x = 0 ;
+
+ // Set the context menu DIV in the specified location.
+ FCKDomTools.SetElementStyles( this._IFrame,
+ {
+ left : x + 'px',
+ top : y + 'px'
+ } ) ;
+
+ var iWidth = iMainWidth ;
+ var iHeight = eMainNode.offsetHeight ;
+
+ this._IFrame.width = iWidth ;
+ this._IFrame.height = iHeight ;
+
+ // Move the focus to the IFRAME so we catch the "onblur".
+ this._IFrame.contentWindow.focus() ;
+ }
+
+ this._IsOpened = true ;
+
+ FCKTools.RunFunction( this.OnShow, this ) ;
+}
+
+FCKPanel.prototype.Hide = function( ignoreOnHide )
+{
+ if ( this._Popup )
+ this._Popup.hide() ;
+ else
+ {
+ if ( !this._IsOpened )
+ return ;
+
+ // Enable the editor to fire the "OnBlur".
+ if ( typeof( FCKFocusManager ) != 'undefined' )
+ FCKFocusManager.Unlock() ;
+
+ // It is better to set the sizes to 0, otherwise Firefox would have
+ // rendering problems.
+ this._IFrame.width = this._IFrame.height = 0 ;
+
+ this._IsOpened = false ;
+
+ 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 ;
+
+ FCKTools.RunFunction( this.OnHide, this ) ;
+ }
+}
+
+function FCKPanel_Cleanup()
+{
+ this._Popup = null ;
+ this._Window = null ;
+ this.Document = null ;
+ this.MainNode = null ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckplugin.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckplugin.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckplugin.js (revision 1015)
@@ -0,0 +1,56 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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' ) ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckspecialcombo.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckspecialcombo.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckspecialcombo.js (revision 1015)
@@ -0,0 +1,377 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 = ' ' ;
+ 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.SkinPath + 'fck_editor.css' ) ;
+ 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 = '
' ;
+
+ 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 = '
' ;
+// 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 )
+ {
+ for ( var key in this.Items )
+ this.Items[key] = null ;
+ }
+
+ var itemsholder = this._ItemsHolderEl ;
+ while ( itemsholder.firstChild )
+ itemsholder.removeChild( itemsholder.firstChild ) ;
+}
+
+FCKSpecialCombo.prototype.AddItem = function( id, html, label, bgColor )
+{
+ //
Bold 1
+ 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 ) ? ' ' : 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 ;
+
+ 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 = '
' ;
+
+ this._LabelEl = oField.getElementsByTagName('label')[0] ; // Memory Leak
+ this._LabelEl.innerHTML = this.Label ;
+ }
+ else
+ {
+ oField.className = 'TB_Button_Off' ;
+ //oField.innerHTML = '
' + this.Caption + '' ;
+ //oField.innerHTML = '' ;
+
+ // Gets the correct CSS class to use for the specified style (param).
+ oField.innerHTML = '' +
+ '' +
+ //' ' +
+ ' ' +
+ '' + this.Caption + ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ ' ' +
+ '
' ;
+ }
+
+
+ // 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:
+
+
+*/
Index: /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckstyle.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckstyle.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/classes/fckstyle.js (revision 1015)
@@ -0,0 +1,1280 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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:
+ * '" ;
+
+ return sTags ;
+}
+
+function _FCK_KeystrokeHandler_OnKeystroke( keystroke, keystrokeValue )
+{
+ if ( FCK.Status != FCK_STATUS_COMPLETE )
+ return false ;
+
+ if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
+ {
+ switch ( keystrokeValue )
+ {
+ case 'Paste' :
+ return !FCK.Paste() ;
+
+ case 'Cut' :
+ FCKUndo.SaveUndoStep() ;
+ return false ;
+ }
+ }
+ else
+ {
+ // In source mode, some actions must have their default behavior.
+ if ( keystrokeValue.Equals( 'Paste', 'Undo', 'Redo', 'SelectAll', 'Cut' ) )
+ return false ;
+ }
+
+ // The return value indicates if the default behavior of the keystroke must
+ // be cancelled. Let's do that only if the Execute() call explicitly returns "false".
+ var oCommand = FCK.Commands.GetCommand( keystrokeValue ) ;
+ return ( oCommand.Execute.apply( oCommand, FCKTools.ArgumentsToArray( arguments, 2 ) ) !== false ) ;
+}
+
+// Set the FCK.LinkedField reference to the field that will be used to post the
+// editor data.
+(function()
+{
+ // There is a bug on IE... getElementById returns any META tag that has the
+ // name set to the ID you are looking for. So the best way in to get the array
+ // by names and look for the correct one.
+ // As ASP.Net generates a ID that is different from the Name, we must also
+ // look for the field based on the ID (the first one is the ID).
+
+ var oDocument = window.parent.document ;
+
+ // Try to get the field using the ID.
+ var eLinkedField = oDocument.getElementById( FCK.Name ) ;
+
+ var i = 0;
+ while ( eLinkedField || i == 0 )
+ {
+ if ( eLinkedField && eLinkedField.tagName.toLowerCase().Equals( 'input', 'textarea' ) )
+ {
+ FCK.LinkedField = eLinkedField ;
+ break ;
+ }
+
+ eLinkedField = oDocument.getElementsByName( FCK.Name )[i++] ;
+ }
+})() ;
+
+var FCKTempBin =
+{
+ Elements : new Array(),
+
+ AddElement : function( element )
+ {
+ var iIndex = this.Elements.length ;
+ this.Elements[ iIndex ] = element ;
+ return iIndex ;
+ },
+
+ RemoveElement : function( index )
+ {
+ var e = this.Elements[ index ] ;
+ this.Elements[ index ] = null ;
+ return e ;
+ },
+
+ Reset : function()
+ {
+ var i = 0 ;
+ while ( i < this.Elements.length )
+ this.Elements[ i++ ] = null ;
+ this.Elements.length = 0 ;
+ }
+} ;
+
+
+
+// # Focus Manager: Manages the focus in the editor.
+var FCKFocusManager = FCK.FocusManager =
+{
+ IsLocked : false,
+
+ AddWindow : function( win, sendToEditingArea )
+ {
+ var oTarget ;
+
+ if ( FCKBrowserInfo.IsIE )
+ oTarget = win.nodeType == 1 ? win : win.frameElement ? win.frameElement : win.document ;
+ else if ( FCKBrowserInfo.IsSafari )
+ oTarget = win ;
+ else
+ oTarget = win.document ;
+
+ FCKTools.AddEventListener( oTarget, 'blur', FCKFocusManager_Win_OnBlur ) ;
+ FCKTools.AddEventListener( oTarget, 'focus', sendToEditingArea ? FCKFocusManager_Win_OnFocus_Area : FCKFocusManager_Win_OnFocus ) ;
+ },
+
+ RemoveWindow : function( win )
+ {
+ if ( FCKBrowserInfo.IsIE )
+ oTarget = win.nodeType == 1 ? win : win.frameElement ? win.frameElement : win.document ;
+ else
+ oTarget = win.document ;
+
+ FCKTools.RemoveEventListener( oTarget, 'blur', FCKFocusManager_Win_OnBlur ) ;
+ FCKTools.RemoveEventListener( oTarget, 'focus', FCKFocusManager_Win_OnFocus_Area ) ;
+ FCKTools.RemoveEventListener( oTarget, 'focus', FCKFocusManager_Win_OnFocus ) ;
+ },
+
+ Lock : function()
+ {
+ this.IsLocked = true ;
+ },
+
+ Unlock : function()
+ {
+ if ( this._HasPendingBlur )
+ FCKFocusManager._Timer = window.setTimeout( FCKFocusManager_FireOnBlur, 100 ) ;
+
+ this.IsLocked = false ;
+ },
+
+ _ResetTimer : function()
+ {
+ this._HasPendingBlur = false ;
+
+ if ( this._Timer )
+ {
+ window.clearTimeout( this._Timer ) ;
+ delete this._Timer ;
+ }
+ }
+} ;
+
+function FCKFocusManager_Win_OnBlur()
+{
+ if ( typeof(FCK) != 'undefined' && FCK.HasFocus )
+ {
+ FCKFocusManager._ResetTimer() ;
+ FCKFocusManager._Timer = window.setTimeout( FCKFocusManager_FireOnBlur, 100 ) ;
+ }
+}
+
+function FCKFocusManager_FireOnBlur()
+{
+ if ( FCKFocusManager.IsLocked )
+ FCKFocusManager._HasPendingBlur = true ;
+ else
+ {
+ FCK.HasFocus = false ;
+ FCK.Events.FireEvent( "OnBlur" ) ;
+ }
+}
+
+function FCKFocusManager_Win_OnFocus_Area()
+{
+ FCK.Focus() ;
+ FCKFocusManager_Win_OnFocus() ;
+}
+
+function FCKFocusManager_Win_OnFocus()
+{
+ FCKFocusManager._ResetTimer() ;
+
+ if ( !FCK.HasFocus && !FCKFocusManager.IsLocked )
+ {
+ FCK.HasFocus = true ;
+ FCK.Events.FireEvent( "OnFocus" ) ;
+ }
+}
+
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_contextmenu.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_contextmenu.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_contextmenu.js (revision 1015)
@@ -0,0 +1,329 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 the FCK.ContextMenu object that is responsible for all
+ * Context Menu operations in the editing area.
+ */
+
+FCK.ContextMenu = new Object() ;
+FCK.ContextMenu.Listeners = new Array() ;
+
+FCK.ContextMenu.RegisterListener = function( listener )
+{
+ if ( listener )
+ this.Listeners.push( listener ) ;
+}
+
+function FCK_ContextMenu_Init()
+{
+ var oInnerContextMenu = FCK.ContextMenu._InnerContextMenu = new FCKContextMenu( FCKBrowserInfo.IsIE ? window : window.parent, FCKLang.Dir ) ;
+ oInnerContextMenu.CtrlDisable = FCKConfig.BrowserContextMenuOnCtrl ;
+ oInnerContextMenu.OnBeforeOpen = FCK_ContextMenu_OnBeforeOpen ;
+ oInnerContextMenu.OnItemClick = FCK_ContextMenu_OnItemClick ;
+
+ // Get the registering function.
+ var oMenu = FCK.ContextMenu ;
+
+ // Register all configured context menu listeners.
+ for ( var i = 0 ; i < FCKConfig.ContextMenu.length ; i++ )
+ oMenu.RegisterListener( FCK_ContextMenu_GetListener( FCKConfig.ContextMenu[i] ) ) ;
+}
+
+function FCK_ContextMenu_GetListener( listenerName )
+{
+ switch ( listenerName )
+ {
+ case 'Generic' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ menu.AddItem( 'Cut' , FCKLang.Cut , 7, FCKCommands.GetCommand( 'Cut' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ menu.AddItem( 'Copy' , FCKLang.Copy , 8, FCKCommands.GetCommand( 'Copy' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ menu.AddItem( 'Paste' , FCKLang.Paste , 9, FCKCommands.GetCommand( 'Paste' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ }} ;
+
+ case 'Table' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ var bIsTable = ( tagName == 'TABLE' ) ;
+ var bIsCell = ( !bIsTable && FCKSelection.HasAncestorNode( 'TABLE' ) ) ;
+
+ if ( bIsCell )
+ {
+ menu.AddSeparator() ;
+ var oItem = menu.AddItem( 'Cell' , FCKLang.CellCM ) ;
+ oItem.AddItem( 'TableInsertCellBefore' , FCKLang.InsertCellBefore, 69 ) ;
+ oItem.AddItem( 'TableInsertCellAfter' , FCKLang.InsertCellAfter, 58 ) ;
+ oItem.AddItem( 'TableDeleteCells' , FCKLang.DeleteCells, 59 ) ;
+ if ( FCKBrowserInfo.IsGecko )
+ oItem.AddItem( 'TableMergeCells' , FCKLang.MergeCells, 60,
+ FCKCommands.GetCommand( 'TableMergeCells' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ else
+ {
+ oItem.AddItem( 'TableMergeRight' , FCKLang.MergeRight, 60,
+ FCKCommands.GetCommand( 'TableMergeRight' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ oItem.AddItem( 'TableMergeDown' , FCKLang.MergeDown, 60,
+ FCKCommands.GetCommand( 'TableMergeDown' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ }
+ oItem.AddItem( 'TableHorizontalSplitCell' , FCKLang.HorizontalSplitCell, 61,
+ FCKCommands.GetCommand( 'TableHorizontalSplitCell' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ oItem.AddItem( 'TableVerticalSplitCell' , FCKLang.VerticalSplitCell, 61,
+ FCKCommands.GetCommand( 'TableVerticalSplitCell' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+ oItem.AddSeparator() ;
+ oItem.AddItem( 'TableCellProp' , FCKLang.CellProperties, 57,
+ FCKCommands.GetCommand( 'TableCellProp' ).GetState() == FCK_TRISTATE_DISABLED ) ;
+
+ menu.AddSeparator() ;
+ oItem = menu.AddItem( 'Row' , FCKLang.RowCM ) ;
+ oItem.AddItem( 'TableInsertRowBefore' , FCKLang.InsertRowBefore, 70 ) ;
+ oItem.AddItem( 'TableInsertRowAfter' , FCKLang.InsertRowAfter, 62 ) ;
+ oItem.AddItem( 'TableDeleteRows' , FCKLang.DeleteRows, 63 ) ;
+
+ menu.AddSeparator() ;
+ oItem = menu.AddItem( 'Column' , FCKLang.ColumnCM ) ;
+ oItem.AddItem( 'TableInsertColumnBefore', FCKLang.InsertColumnBefore, 71 ) ;
+ oItem.AddItem( 'TableInsertColumnAfter' , FCKLang.InsertColumnAfter, 64 ) ;
+ oItem.AddItem( 'TableDeleteColumns' , FCKLang.DeleteColumns, 65 ) ;
+ }
+
+ if ( bIsTable || bIsCell )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'TableDelete' , FCKLang.TableDelete ) ;
+ menu.AddItem( 'TableProp' , FCKLang.TableProperties, 39 ) ;
+ }
+ }} ;
+
+ case 'Link' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ var bInsideLink = ( tagName == 'A' || FCKSelection.HasAncestorNode( 'A' ) ) ;
+
+ if ( bInsideLink || FCK.GetNamedCommandState( 'Unlink' ) != FCK_TRISTATE_DISABLED )
+ {
+ // Go up to the anchor to test its properties
+ var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
+ var bIsAnchor = ( oLink && oLink.name.length > 0 && oLink.href.length == 0 ) ;
+ // If it isn't a link then don't add the Link context menu
+ if ( bIsAnchor )
+ return ;
+
+ menu.AddSeparator() ;
+ if ( bInsideLink )
+ menu.AddItem( 'Link', FCKLang.EditLink , 34 ) ;
+ menu.AddItem( 'Unlink' , FCKLang.RemoveLink , 35 ) ;
+ }
+ }} ;
+
+ case 'Image' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'IMG' && !tag.getAttribute( '_fckfakelement' ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Image', FCKLang.ImageProperties, 37 ) ;
+ }
+ }} ;
+
+ case 'Anchor' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ // Go up to the anchor to test its properties
+ var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
+ var bIsAnchor = ( oLink && oLink.name.length > 0 ) ;
+
+ if ( bIsAnchor || ( tagName == 'IMG' && tag.getAttribute( '_fckanchor' ) ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Anchor', FCKLang.AnchorProp, 36 ) ;
+ menu.AddItem( 'AnchorDelete', FCKLang.AnchorDelete ) ;
+ }
+ }} ;
+
+ case 'Flash' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'IMG' && tag.getAttribute( '_fckflash' ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Flash', FCKLang.FlashProperties, 38 ) ;
+ }
+ }} ;
+
+ case 'Form' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( FCKSelection.HasAncestorNode('FORM') )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Form', FCKLang.FormProp, 48 ) ;
+ }
+ }} ;
+
+ case 'Checkbox' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'INPUT' && tag.type == 'checkbox' )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Checkbox', FCKLang.CheckboxProp, 49 ) ;
+ }
+ }} ;
+
+ case 'Radio' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'INPUT' && tag.type == 'radio' )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Radio', FCKLang.RadioButtonProp, 50 ) ;
+ }
+ }} ;
+
+ case 'TextField' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'INPUT' && ( tag.type == 'text' || tag.type == 'password' ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'TextField', FCKLang.TextFieldProp, 51 ) ;
+ }
+ }} ;
+
+ case 'HiddenField' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'IMG' && tag.getAttribute( '_fckinputhidden' ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'HiddenField', FCKLang.HiddenFieldProp, 56 ) ;
+ }
+ }} ;
+
+ case 'ImageButton' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'INPUT' && tag.type == 'image' )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'ImageButton', FCKLang.ImageButtonProp, 55 ) ;
+ }
+ }} ;
+
+ case 'Button' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'INPUT' && ( tag.type == 'button' || tag.type == 'submit' || tag.type == 'reset' ) )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Button', FCKLang.ButtonProp, 54 ) ;
+ }
+ }} ;
+
+ case 'Select' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'SELECT' )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Select', FCKLang.SelectionFieldProp, 53 ) ;
+ }
+ }} ;
+
+ case 'Textarea' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( tagName == 'TEXTAREA' )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'Textarea', FCKLang.TextareaProp, 52 ) ;
+ }
+ }} ;
+
+ case 'BulletedList' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( FCKSelection.HasAncestorNode('UL') )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'BulletedList', FCKLang.BulletedListProp, 27 ) ;
+ }
+ }} ;
+
+ case 'NumberedList' :
+ return {
+ AddItems : function( menu, tag, tagName )
+ {
+ if ( FCKSelection.HasAncestorNode('OL') )
+ {
+ menu.AddSeparator() ;
+ menu.AddItem( 'NumberedList', FCKLang.NumberedListProp, 26 ) ;
+ }
+ }} ;
+ // @Packager.Remove.Start
+ default :
+ alert( 'Unknown context menu listener "' + listenerName + '"' ) ;
+ // @Packager.Remove.End
+ }
+ return null ;
+}
+
+function FCK_ContextMenu_OnBeforeOpen()
+{
+ // Update the UI.
+ FCK.Events.FireEvent( 'OnSelectionChange' ) ;
+
+ // Get the actual selected tag (if any).
+ var oTag, sTagName ;
+
+ // The extra () is to avoid a warning with strict error checking. This is ok.
+ if ( (oTag = FCKSelection.GetSelectedElement()) )
+ sTagName = oTag.tagName ;
+
+ // Cleanup the current menu items.
+ var oMenu = FCK.ContextMenu._InnerContextMenu ;
+ oMenu.RemoveAllItems() ;
+
+ // Loop through the listeners.
+ var aListeners = FCK.ContextMenu.Listeners ;
+ for ( var i = 0 ; i < aListeners.length ; i++ )
+ aListeners[i].AddItems( oMenu, oTag, sTagName ) ;
+}
+
+function FCK_ContextMenu_OnItemClick( item )
+{
+ FCK.Focus() ;
+ FCKCommands.GetCommand( item.Name ).Execute() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_gecko.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_gecko.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_gecko.js (revision 1015)
@@ -0,0 +1,458 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ( FCKBrowserInfo.IsGecko ) // 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() ;
+ }
+ else if ( FCKConfig.ShowDropDialog )
+ FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security' ) ;
+ 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 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 = FCK.EditorWindow.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 tag, or the End key is pressed.
+ var parentTag = node.parentNode.tagName.toLowerCase() ;
+ if ( ! ( parentTag == 'a' ||
+ ( ! ( 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 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()] ) )
+ 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] )
+ 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._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 ) ;
+ }
+
+ this._ExecCheckEmptyBlock = function()
+ {
+ FCK._FillEmptyBlock( FCK.EditorDocument.body.firstChild ) ;
+ var sel = FCK.EditorWindow.getSelection() ;
+ if ( !sel || sel.rangeCount < 1 )
+ return ;
+ var range = sel.getRangeAt( 0 );
+ FCK._FillEmptyBlock( range.startContainer ) ;
+ }
+
+ 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 )
+ {
+ var cancelHandler = function( evt ){ if ( ! FCK.MouseDownFlag ) evt.returnValue = false ; }
+ this.EditorDocument.addEventListener( 'dragenter', cancelHandler, true ) ;
+ this.EditorDocument.addEventListener( 'dragover', cancelHandler, 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 ) ;
+ }
+ if ( FCKBrowserInfo.IsGecko )
+ this.AttachToOnSelectionChange( this._ExecCheckEmptyBlock ) ;
+
+ // 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,
+
+ Cut : true,
+ Copy : 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) { FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security' ) ; }
+ break ;
+ case 'Cut' :
+ try { FCK.ExecuteNamedCommand( 'Cut', null, true ) ; }
+ catch (e) { alert(FCKLang.PasteErrorCut) ; }
+ break ;
+ case 'Copy' :
+ try { FCK.ExecuteNamedCommand( 'Copy', null, true ) ; }
+ catch (e) { alert(FCKLang.PasteErrorCopy) ; }
+ 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 )
+{
+ html = FCKConfig.ProtectedSource.Protect( html ) ;
+ html = FCK.ProtectEvents( html ) ;
+ html = FCK.ProtectUrls( html ) ;
+ html = FCK.ProtectTags( html ) ;
+
+ // Save an undo snapshot first.
+ FCKUndo.SaveUndoStep() ;
+
+ // Insert the HTML code.
+ this.EditorDocument.execCommand( 'inserthtml', false, html ) ;
+ this.Focus() ;
+
+ // 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, ' ' ) ;
+ 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() ;
+
+ 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 ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_ie.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_ie.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fck_ie.js (revision 1015)
@@ -0,0 +1,420 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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.
+ * (IE specific implementations)
+ */
+
+FCK.Description = "FCKeditor for Internet Explorer 5.5+" ;
+
+FCK._GetBehaviorsStyle = function()
+{
+ if ( !FCK._BehaviorsStyle )
+ {
+ var sBasePath = FCKConfig.FullBasePath ;
+ var sTableBehavior = '' ;
+ var sStyle ;
+
+ // The behaviors should be pointed using the FullBasePath to avoid security
+ // errors when using a different BaseHref.
+ sStyle = '' ;
+ FCK._BehaviorsStyle = sStyle ;
+ }
+
+ return FCK._BehaviorsStyle ;
+}
+
+function Doc_OnMouseUp()
+{
+ if ( FCK.EditorWindow.event.srcElement.tagName == 'HTML' )
+ {
+ FCK.Focus() ;
+ FCK.EditorWindow.event.cancelBubble = true ;
+ FCK.EditorWindow.event.returnValue = false ;
+ }
+}
+
+function Doc_OnPaste()
+{
+ var body = FCK.EditorDocument.body ;
+
+ body.detachEvent( 'onpaste', Doc_OnPaste ) ;
+
+ var ret = FCK.Paste( !FCKConfig.ForcePasteAsPlainText && !FCKConfig.AutoDetectPasteFromWord ) ;
+
+ body.attachEvent( 'onpaste', Doc_OnPaste ) ;
+
+ return ret ;
+}
+
+function Doc_OnDblClick()
+{
+ FCK.OnDoubleClick( FCK.EditorWindow.event.srcElement ) ;
+ FCK.EditorWindow.event.cancelBubble = true ;
+}
+
+function Doc_OnSelectionChange()
+{
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+}
+
+function Doc_OnDrop()
+{
+ if ( FCK.MouseDownFlag )
+ {
+ FCK.MouseDownFlag = false ;
+ return ;
+ }
+ var evt = FCK.EditorWindow.event ;
+ if ( FCKConfig.ForcePasteAsPlainText )
+ {
+ if ( FCK._CheckIsPastingEnabled() || FCKConfig.ShowDropDialog )
+ FCK.PasteAsPlainText( evt.dataTransfer.getData( 'Text' ) ) ;
+ }
+ else
+ {
+ if ( FCKConfig.ShowDropDialog )
+ FCKTools.RunFunction( FCKDialog.OpenDialog,
+ FCKDialog, ['FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security'] ) ;
+ }
+ evt.returnValue = false ;
+ evt.cancelBubble = true ;
+}
+
+FCK.InitializeBehaviors = function( dontReturn )
+{
+ // Set the focus to the editable area when clicking in the document area.
+ // TODO: The cursor must be positioned at the end.
+ this.EditorDocument.attachEvent( 'onmouseup', Doc_OnMouseUp ) ;
+
+ // Intercept pasting operations
+ this.EditorDocument.body.attachEvent( 'onpaste', Doc_OnPaste ) ;
+
+ // Intercept drop operations
+ this.EditorDocument.body.attachEvent( 'ondrop', Doc_OnDrop ) ;
+
+ // Reset the context menu.
+ FCK.ContextMenu._InnerContextMenu.AttachToElement( FCK.EditorDocument.body ) ;
+
+ this.EditorDocument.attachEvent("onkeydown", FCK._KeyDownListener ) ;
+
+ this.EditorDocument.attachEvent("ondblclick", Doc_OnDblClick ) ;
+
+ // Catch cursor selection changes.
+ this.EditorDocument.attachEvent("onselectionchange", Doc_OnSelectionChange ) ;
+}
+
+FCK.InsertHtml = function( html )
+{
+ html = FCKConfig.ProtectedSource.Protect( html ) ;
+ html = FCK.ProtectEvents( html ) ;
+ html = FCK.ProtectUrls( html ) ;
+ html = FCK.ProtectTags( html ) ;
+
+// FCK.Focus() ;
+ FCK.EditorWindow.focus() ;
+
+ FCKUndo.SaveUndoStep() ;
+
+ // Gets the actual selection.
+ var oSel = FCK.EditorDocument.selection ;
+
+ // Deletes the actual selection contents.
+ if ( oSel.type.toLowerCase() == 'control' )
+ oSel.clear() ;
+
+ // Using the following trick, any comment in the beginning of the HTML will
+ // be preserved.
+ html = ' ' + html ;
+
+ // Insert the HTML.
+ oSel.createRange().pasteHTML( html ) ;
+
+ // Remove the fake node
+ FCK.EditorDocument.getElementById('__fakeFCKRemove__').removeNode( true ) ;
+
+ FCKDocumentProcessor.Process( FCK.EditorDocument ) ;
+
+ // For some strange reason the SaveUndoStep() call doesn't activate the undo button at the first InsertHtml() call.
+ this.Events.FireEvent( "OnSelectionChange" ) ;
+}
+
+FCK.SetInnerHtml = function( html ) // IE Only
+{
+ var oDoc = FCK.EditorDocument ;
+ // Using the following trick, any comment in the beginning of the HTML will
+ // be preserved.
+ oDoc.body.innerHTML = '
' + html ;
+ oDoc.getElementById('__fakeFCKRemove__').removeNode( true ) ;
+}
+
+function FCK_PreloadImages()
+{
+ var oPreloader = new FCKImagePreloader() ;
+
+ // Add the configured images.
+ oPreloader.AddImages( FCKConfig.PreloadImages ) ;
+
+ // Add the skin icons strip.
+ oPreloader.AddImages( FCKConfig.SkinPath + 'fck_strip.gif' ) ;
+
+ oPreloader.OnComplete = LoadToolbarSetup ;
+ oPreloader.Start() ;
+}
+
+// Disable the context menu in the editor (outside the editing area).
+function Document_OnContextMenu()
+{
+ return ( event.srcElement._FCKShowContextMenu == true ) ;
+}
+document.oncontextmenu = Document_OnContextMenu ;
+
+function FCK_Cleanup()
+{
+ this.LinkedField = null ;
+ this.EditorWindow = null ;
+ this.EditorDocument = null ;
+}
+
+FCK._ExecPaste = function()
+{
+ // As we call ExecuteNamedCommand('Paste'), it would enter in a loop. So, let's use a semaphore.
+ if ( FCK._PasteIsRunning )
+ return true ;
+
+ if ( FCKConfig.ForcePasteAsPlainText )
+ {
+ FCK.PasteAsPlainText() ;
+ return false ;
+ }
+
+ var sHTML = FCK._CheckIsPastingEnabled( true ) ;
+
+ if ( sHTML === false )
+ FCKTools.RunFunction( FCKDialog.OpenDialog, FCKDialog, ['FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security'] ) ;
+ else
+ {
+ if ( FCKConfig.AutoDetectPasteFromWord && sHTML.length > 0 )
+ {
+ var re = /<\w[^>]*(( class="?MsoNormal"?)|(="mso-))/gi ;
+ if ( re.test( sHTML ) )
+ {
+ if ( confirm( FCKLang.PasteWordConfirm ) )
+ {
+ FCK.PasteFromWord() ;
+ return false ;
+ }
+ }
+ }
+
+ // Instead of inserting the retrieved HTML, let's leave the OS work for us,
+ // by calling FCK.ExecuteNamedCommand( 'Paste' ). It could give better results.
+
+ // Enable the semaphore to avoid a loop.
+ FCK._PasteIsRunning = true ;
+
+ FCK.ExecuteNamedCommand( 'Paste' ) ;
+
+ // Removes the semaphore.
+ delete FCK._PasteIsRunning ;
+ }
+
+ // Let's always make a custom implementation (return false), otherwise
+ // the new Keyboard Handler may conflict with this code, and the CTRL+V code
+ // could result in a simple "V" being pasted.
+ return false ;
+}
+
+FCK.PasteAsPlainText = function( forceText )
+{
+ if ( !FCK._CheckIsPastingEnabled() )
+ {
+ FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteAsText, 'dialog/fck_paste.html', 400, 330, 'PlainText' ) ;
+ return ;
+ }
+
+ // Get the data available in the clipboard in text format.
+ var sText = null ;
+ if ( ! forceText )
+ sText = clipboardData.getData("Text") ;
+ else
+ sText = forceText ;
+
+ if ( sText && sText.length > 0 )
+ {
+ // Replace the carriage returns with
+ sText = FCKTools.HTMLEncode( sText ) ;
+ sText = FCKTools.ProcessLineBreaks( window, FCKConfig, sText ) ;
+
+ // Insert the resulting data in the editor.
+ this.InsertHtml( sText ) ;
+ }
+}
+
+FCK._CheckIsPastingEnabled = function( returnContents )
+{
+ // The following seams to be the only reliable way to check is script
+ // pasting operations are enabled in the security settings of IE6 and IE7.
+ // It adds a little bit of overhead to the check, but so far that's the
+ // only way, mainly because of IE7.
+
+ FCK._PasteIsEnabled = false ;
+
+ document.body.attachEvent( 'onpaste', FCK_CheckPasting_Listener ) ;
+
+ // The execCommand in GetClipboardHTML will fire the "onpaste", only if the
+ // security settings are enabled.
+ var oReturn = FCK.GetClipboardHTML() ;
+
+ document.body.detachEvent( 'onpaste', FCK_CheckPasting_Listener ) ;
+
+ if ( FCK._PasteIsEnabled )
+ {
+ if ( !returnContents )
+ oReturn = true ;
+ }
+ else
+ oReturn = false ;
+
+ delete FCK._PasteIsEnabled ;
+
+ return oReturn ;
+}
+
+function FCK_CheckPasting_Listener()
+{
+ FCK._PasteIsEnabled = true ;
+}
+
+FCK.GetClipboardHTML = function()
+{
+ var oDiv = document.getElementById( '___FCKHiddenDiv' ) ;
+
+ if ( !oDiv )
+ {
+ oDiv = document.createElement( 'DIV' ) ;
+ oDiv.id = '___FCKHiddenDiv' ;
+
+ var oDivStyle = oDiv.style ;
+ oDivStyle.position = 'absolute' ;
+ oDivStyle.visibility = oDivStyle.overflow = 'hidden' ;
+ oDivStyle.width = oDivStyle.height = 1 ;
+
+ document.body.appendChild( oDiv ) ;
+ }
+
+ oDiv.innerHTML = '' ;
+
+ var oTextRange = document.body.createTextRange() ;
+ oTextRange.moveToElementText( oDiv ) ;
+ oTextRange.execCommand( 'Paste' ) ;
+
+ var sData = oDiv.innerHTML ;
+ oDiv.innerHTML = '' ;
+
+ return sData ;
+}
+
+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() ;
+
+ // Remove any existing link in the selection.
+ FCK.ExecuteNamedCommand( 'Unlink', null, false, !!noUndo ) ;
+
+ if ( url.length > 0 )
+ {
+ // If there are several images, and you try to link each one, all the images get inside the link:
+ // -> -> due to the call to 'CreateLink' (bug in IE)
+ if (FCKSelection.GetType() == 'Control')
+ {
+ // Create a link
+ var oLink = this.EditorDocument.createElement( 'A' ) ;
+ oLink.href = url ;
+
+ // Get the selected object
+ var oControl = FCKSelection.GetSelectedElement() ;
+ // Put the link just before the object
+ oControl.parentNode.insertBefore(oLink, oControl) ;
+ // Move the object inside the link
+ oControl.parentNode.removeChild( oControl ) ;
+ oLink.appendChild( oControl ) ;
+
+ return [ oLink ] ;
+ }
+
+ // 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 ) ;
+
+ // Look for the just create link.
+ var oLinks = this.EditorDocument.links ;
+
+ for ( i = 0 ; i < oLinks.length ; i++ )
+ {
+ var oLink = oLinks[i] ;
+
+ // Check it this a newly created link.
+ // getAttribute must be used. oLink.url may cause problems with IE7 (#555).
+ if ( oLink.getAttribute( 'href', 2 ) == sTempUrl )
+ {
+ var sInnerHtml = oLink.innerHTML ; // Save the innerHTML (IE changes it if it is like an URL).
+ oLink.href = url ;
+ oLink.innerHTML = sInnerHtml ; // Restore the innerHTML.
+
+ // If the last child is a move it outside the link or it
+ // will be too easy to select this link again #388.
+ var oLastChild = oLink.lastChild ;
+ if ( oLastChild && oLastChild.nodeName == 'BR' )
+ {
+ // Move the BR after the link.
+ FCKDomTools.InsertAfterNode( oLink, oLink.removeChild( oLastChild ) ) ;
+ }
+
+ aCreatedLinks.push( oLink ) ;
+ }
+ }
+ }
+
+ return aCreatedLinks ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckbrowserinfo.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckbrowserinfo.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckbrowserinfo.js (revision 1015)
@@ -0,0 +1,59 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Contains browser detection information.
+ */
+
+var s = navigator.userAgent.toLowerCase() ;
+
+var FCKBrowserInfo =
+{
+ IsIE : /*@cc_on!@*/false,
+ IsIE7 : /*@cc_on!@*/false && s.Contains('msie 7'),
+ IsGecko : s.Contains('gecko/'),
+ IsSafari : s.Contains(' applewebkit/'), // Read "IsWebKit"
+ IsOpera : !!window.opera,
+ IsMac : s.Contains('macintosh')
+} ;
+
+// Completes the browser info with further Gecko information.
+(function( browserInfo )
+{
+ browserInfo.IsGeckoLike = ( browserInfo.IsGecko || browserInfo.IsSafari || browserInfo.IsOpera ) ;
+
+ if ( browserInfo.IsGecko )
+ {
+ var geckoVersion = s.match( /gecko\/(\d+)/ )[1] ;
+
+ // Actually "10" refers to Gecko versions before Firefox 1.5, when
+ // Gecko 1.8 (build 20051111) has been released.
+
+ // Some browser (like Mozilla 1.7.13) may have a Gecko build greater
+ // than 20051111, so we must also check for the revision number not to
+ // be 1.7 (we are assuming that rv < 1.7 will not have build > 20051111).
+
+ // TODO: Future versions may consider the rv number only, but it is
+ // still to check that all Gecko based browser present the rv number.
+ browserInfo.IsGecko10 = ( ( geckoVersion < 20051111 ) || ( /rv:1\.7/.test(s) ) ) ;
+ browserInfo.IsGecko19 = /rv:1\.9/.test(s) ;
+ }
+ else
+ browserInfo.IsGecko10 = false ;
+})(FCKBrowserInfo) ;
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcodeformatter.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcodeformatter.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcodeformatter.js (revision 1015)
@@ -0,0 +1,100 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Format the HTML.
+ */
+
+var FCKCodeFormatter = new Object() ;
+
+FCKCodeFormatter.Init = function()
+{
+ var oRegex = this.Regex = new Object() ;
+
+ // Regex for line breaks.
+ oRegex.BlocksOpener = /\<(P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|TITLE|META|LINK|BASE|SCRIPT|LINK|TD|TH|AREA|OPTION)[^\>]*\>/gi ;
+ oRegex.BlocksCloser = /\<\/(P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|TITLE|META|LINK|BASE|SCRIPT|LINK|TD|TH|AREA|OPTION)[^\>]*\>/gi ;
+
+ oRegex.NewLineTags = /\<(BR|HR)[^\>]*\>/gi ;
+
+ oRegex.MainTags = /\<\/?(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR)[^\>]*\>/gi ;
+
+ oRegex.LineSplitter = /\s*\n+\s*/g ;
+
+ // Regex for indentation.
+ oRegex.IncreaseIndent = /^\<(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR|UL|OL)[ \/\>]/i ;
+ oRegex.DecreaseIndent = /^\<\/(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR|UL|OL)[ \>]/i ;
+ oRegex.FormatIndentatorRemove = new RegExp( '^' + FCKConfig.FormatIndentator ) ;
+
+ oRegex.ProtectedTags = /(]*>)([\s\S]*?)(<\/PRE>)/gi ;
+}
+
+FCKCodeFormatter._ProtectData = function( outer, opener, data, closer )
+{
+ return opener + '___FCKpd___' + FCKCodeFormatter.ProtectedData.AddItem( data ) + closer ;
+}
+
+FCKCodeFormatter.Format = function( html )
+{
+ if ( !this.Regex )
+ this.Init() ;
+
+ // Protected content that remain untouched during the
+ // process go in the following array.
+ FCKCodeFormatter.ProtectedData = new Array() ;
+
+ var sFormatted = html.replace( this.Regex.ProtectedTags, FCKCodeFormatter._ProtectData ) ;
+
+ // Line breaks.
+ sFormatted = sFormatted.replace( this.Regex.BlocksOpener, '\n$&' ) ;
+ sFormatted = sFormatted.replace( this.Regex.BlocksCloser, '$&\n' ) ;
+ sFormatted = sFormatted.replace( this.Regex.NewLineTags, '$&\n' ) ;
+ sFormatted = sFormatted.replace( this.Regex.MainTags, '\n$&\n' ) ;
+
+ // Indentation.
+ var sIndentation = '' ;
+
+ var asLines = sFormatted.split( this.Regex.LineSplitter ) ;
+ sFormatted = '' ;
+
+ for ( var i = 0 ; i < asLines.length ; i++ )
+ {
+ var sLine = asLines[i] ;
+
+ if ( sLine.length == 0 )
+ continue ;
+
+ if ( this.Regex.DecreaseIndent.test( sLine ) )
+ sIndentation = sIndentation.replace( this.Regex.FormatIndentatorRemove, '' ) ;
+
+ sFormatted += sIndentation + sLine + '\n' ;
+
+ if ( this.Regex.IncreaseIndent.test( sLine ) )
+ sIndentation += FCKConfig.FormatIndentator ;
+ }
+
+ // Now we put back the protected data.
+ for ( var j = 0 ; j < FCKCodeFormatter.ProtectedData.length ; j++ )
+ {
+ var oRegex = new RegExp( '___FCKpd___' + j ) ;
+ sFormatted = sFormatted.replace( oRegex, FCKCodeFormatter.ProtectedData[j].replace( /\$/g, '$$$$' ) ) ;
+ }
+
+ return sFormatted.Trim() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcommands.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcommands.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckcommands.js (revision 1015)
@@ -0,0 +1,167 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Define all commands available in the editor.
+ */
+
+var FCKCommands = FCK.Commands = new Object() ;
+FCKCommands.LoadedCommands = new Object() ;
+
+FCKCommands.RegisterCommand = function( commandName, command )
+{
+ this.LoadedCommands[ commandName ] = command ;
+}
+
+FCKCommands.GetCommand = function( commandName )
+{
+ var oCommand = FCKCommands.LoadedCommands[ commandName ] ;
+
+ if ( oCommand )
+ return oCommand ;
+
+ switch ( commandName )
+ {
+ case 'Bold' :
+ case 'Italic' :
+ case 'Underline' :
+ case 'StrikeThrough':
+ case 'Subscript' :
+ case 'Superscript' : oCommand = new FCKCoreStyleCommand( commandName ) ; break ;
+
+ case 'RemoveFormat' : oCommand = new FCKRemoveFormatCommand() ; break ;
+
+ case 'DocProps' : oCommand = new FCKDialogCommand( 'DocProps' , FCKLang.DocProps , 'dialog/fck_docprops.html' , 400, 390, FCKCommands.GetFullPageState ) ; break ;
+ case 'Templates' : oCommand = new FCKDialogCommand( 'Templates' , FCKLang.DlgTemplatesTitle , 'dialog/fck_template.html' , 380, 450 ) ; break ;
+ case 'Link' : oCommand = new FCKDialogCommand( 'Link' , FCKLang.DlgLnkWindowTitle , 'dialog/fck_link.html' , 400, 330 ) ; break ;
+ case 'Unlink' : oCommand = new FCKUnlinkCommand() ; break ;
+ case 'Anchor' : oCommand = new FCKDialogCommand( 'Anchor' , FCKLang.DlgAnchorTitle , 'dialog/fck_anchor.html' , 370, 170 ) ; break ;
+ case 'AnchorDelete' : oCommand = new FCKAnchorDeleteCommand() ; break ;
+ case 'BulletedList' : oCommand = new FCKDialogCommand( 'BulletedList', FCKLang.BulletedListProp , 'dialog/fck_listprop.html?UL' , 370, 170 ) ; break ;
+ case 'NumberedList' : oCommand = new FCKDialogCommand( 'NumberedList', FCKLang.NumberedListProp , 'dialog/fck_listprop.html?OL' , 370, 170 ) ; break ;
+ case 'About' : oCommand = new FCKDialogCommand( 'About' , FCKLang.About , 'dialog/fck_about.html' , 400, 330 ) ; break ;
+
+ case 'Find' : oCommand = new FCKDialogCommand( 'Find' , FCKLang.DlgFindAndReplaceTitle , 'dialog/fck_replace.html' , 340, 250 ) ; break ;
+ case 'Replace' : oCommand = new FCKDialogCommand( 'Replace' , FCKLang.DlgFindAndReplaceTitle , 'dialog/fck_replace.html' , 340, 250 ) ; break ;
+
+ case 'Image' : oCommand = new FCKDialogCommand( 'Image' , FCKLang.DlgImgTitle , 'dialog/fck_image.html' , 450, 400 ) ; break ;
+ case 'Flash' : oCommand = new FCKDialogCommand( 'Flash' , FCKLang.DlgFlashTitle , 'dialog/fck_flash.html' , 450, 400 ) ; break ;
+ case 'SpecialChar' : oCommand = new FCKDialogCommand( 'SpecialChar', FCKLang.DlgSpecialCharTitle , 'dialog/fck_specialchar.html' , 400, 320 ) ; break ;
+ case 'Smiley' : oCommand = new FCKDialogCommand( 'Smiley' , FCKLang.DlgSmileyTitle , 'dialog/fck_smiley.html' , FCKConfig.SmileyWindowWidth, FCKConfig.SmileyWindowHeight ) ; break ;
+ case 'Table' : oCommand = new FCKDialogCommand( 'Table' , FCKLang.DlgTableTitle , 'dialog/fck_table.html' , 450, 250 ) ; break ;
+ case 'TableProp' : oCommand = new FCKDialogCommand( 'Table' , FCKLang.DlgTableTitle , 'dialog/fck_table.html?Parent', 400, 250 ) ; break ;
+ case 'TableCellProp': oCommand = new FCKDialogCommand( 'TableCell' , FCKLang.DlgCellTitle , 'dialog/fck_tablecell.html' , 550, 250 ) ; break ;
+
+ case 'Style' : oCommand = new FCKStyleCommand() ; break ;
+
+ case 'FontName' : oCommand = new FCKFontNameCommand() ; break ;
+ case 'FontSize' : oCommand = new FCKFontSizeCommand() ; break ;
+ case 'FontFormat' : oCommand = new FCKFormatBlockCommand() ; break ;
+
+ case 'Source' : oCommand = new FCKSourceCommand() ; break ;
+ case 'Preview' : oCommand = new FCKPreviewCommand() ; break ;
+ case 'Save' : oCommand = new FCKSaveCommand() ; break ;
+ case 'NewPage' : oCommand = new FCKNewPageCommand() ; break ;
+ case 'PageBreak' : oCommand = new FCKPageBreakCommand() ; break ;
+ case 'Rule' : oCommand = new FCKRuleCommand() ; break ;
+
+ case 'TextColor' : oCommand = new FCKTextColorCommand('ForeColor') ; break ;
+ case 'BGColor' : oCommand = new FCKTextColorCommand('BackColor') ; break ;
+
+ case 'Paste' : oCommand = new FCKPasteCommand() ; break ;
+ case 'PasteText' : oCommand = new FCKPastePlainTextCommand() ; break ;
+ case 'PasteWord' : oCommand = new FCKPasteWordCommand() ; break ;
+
+ case 'JustifyLeft' : oCommand = new FCKJustifyCommand( 'left' ) ; break ;
+ case 'JustifyCenter' : oCommand = new FCKJustifyCommand( 'center' ) ; break ;
+ case 'JustifyRight' : oCommand = new FCKJustifyCommand( 'right' ) ; break ;
+ case 'JustifyFull' : oCommand = new FCKJustifyCommand( 'justify' ) ; break ;
+ case 'Indent' : oCommand = new FCKIndentCommand( 'indent', FCKConfig.IndentLength ) ; break ;
+ case 'Outdent' : oCommand = new FCKIndentCommand( 'outdent', FCKConfig.IndentLength * -1 ) ; break ;
+ case 'Blockquote' : oCommand = new FCKBlockQuoteCommand() ; break ;
+
+ case 'TableInsertRowAfter' : oCommand = new FCKTableCommand('TableInsertRowAfter') ; break ;
+ case 'TableInsertRowBefore' : oCommand = new FCKTableCommand('TableInsertRowBefore') ; break ;
+ case 'TableDeleteRows' : oCommand = new FCKTableCommand('TableDeleteRows') ; break ;
+ case 'TableInsertColumnAfter' : oCommand = new FCKTableCommand('TableInsertColumnAfter') ; break ;
+ case 'TableInsertColumnBefore' : oCommand = new FCKTableCommand('TableInsertColumnBefore') ; break ;
+ case 'TableDeleteColumns' : oCommand = new FCKTableCommand('TableDeleteColumns') ; break ;
+ case 'TableInsertCellAfter' : oCommand = new FCKTableCommand('TableInsertCellAfter') ; break ;
+ case 'TableInsertCellBefore' : oCommand = new FCKTableCommand('TableInsertCellBefore') ; break ;
+ case 'TableDeleteCells' : oCommand = new FCKTableCommand('TableDeleteCells') ; break ;
+ case 'TableMergeCells' : oCommand = new FCKTableCommand('TableMergeCells') ; break ;
+ case 'TableMergeRight' : oCommand = new FCKTableCommand('TableMergeRight') ; break ;
+ case 'TableMergeDown' : oCommand = new FCKTableCommand('TableMergeDown') ; break ;
+ case 'TableHorizontalSplitCell' : oCommand = new FCKTableCommand('TableHorizontalSplitCell') ; break ;
+ case 'TableVerticalSplitCell' : oCommand = new FCKTableCommand('TableVerticalSplitCell') ; break ;
+ case 'TableDelete' : oCommand = new FCKTableCommand('TableDelete') ; break ;
+
+ case 'Form' : oCommand = new FCKDialogCommand( 'Form' , FCKLang.Form , 'dialog/fck_form.html' , 380, 230 ) ; break ;
+ case 'Checkbox' : oCommand = new FCKDialogCommand( 'Checkbox' , FCKLang.Checkbox , 'dialog/fck_checkbox.html' , 380, 230 ) ; break ;
+ case 'Radio' : oCommand = new FCKDialogCommand( 'Radio' , FCKLang.RadioButton , 'dialog/fck_radiobutton.html' , 380, 230 ) ; break ;
+ case 'TextField' : oCommand = new FCKDialogCommand( 'TextField' , FCKLang.TextField , 'dialog/fck_textfield.html' , 380, 230 ) ; break ;
+ case 'Textarea' : oCommand = new FCKDialogCommand( 'Textarea' , FCKLang.Textarea , 'dialog/fck_textarea.html' , 380, 230 ) ; break ;
+ case 'HiddenField' : oCommand = new FCKDialogCommand( 'HiddenField', FCKLang.HiddenField , 'dialog/fck_hiddenfield.html' , 380, 230 ) ; break ;
+ case 'Button' : oCommand = new FCKDialogCommand( 'Button' , FCKLang.Button , 'dialog/fck_button.html' , 380, 230 ) ; break ;
+ case 'Select' : oCommand = new FCKDialogCommand( 'Select' , FCKLang.SelectionField, 'dialog/fck_select.html' , 400, 380 ) ; break ;
+ case 'ImageButton' : oCommand = new FCKDialogCommand( 'ImageButton', FCKLang.ImageButton , 'dialog/fck_image.html?ImageButton', 450, 400 ) ; break ;
+
+ case 'SpellCheck' : oCommand = new FCKSpellCheckCommand() ; break ;
+ case 'FitWindow' : oCommand = new FCKFitWindow() ; break ;
+
+ case 'Undo' : oCommand = new FCKUndoCommand() ; break ;
+ case 'Redo' : oCommand = new FCKRedoCommand() ; break ;
+ case 'Copy' : oCommand = new FCKCopyCommand() ; break ;
+
+ case 'SelectAll' : oCommand = new FCKSelectAllCommand() ; break ;
+ case 'InsertOrderedList' : oCommand = new FCKListCommand( 'insertorderedlist', 'ol' ) ; break ;
+ case 'InsertUnorderedList' : oCommand = new FCKListCommand( 'insertunorderedlist', 'ul' ) ; break ;
+ case 'ShowBlocks' : oCommand = new FCKShowBlockCommand( 'ShowBlocks', FCKConfig.StartupShowBlocks ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ) ; break ;
+
+ // Generic Undefined command (usually used when a command is under development).
+ case 'Undefined' : oCommand = new FCKUndefinedCommand() ; break ;
+
+ // By default we assume that it is a named command.
+ default:
+ if ( FCKRegexLib.NamedCommands.test( commandName ) )
+ oCommand = new FCKNamedCommand( commandName ) ;
+ else
+ {
+ alert( FCKLang.UnknownCommand.replace( /%1/g, commandName ) ) ;
+ return null ;
+ }
+ }
+
+ FCKCommands.LoadedCommands[ commandName ] = oCommand ;
+
+ return oCommand ;
+}
+
+// Gets the state of the "Document Properties" button. It must be enabled only
+// when "Full Page" editing is available.
+FCKCommands.GetFullPageState = function()
+{
+ return FCKConfig.FullPage ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
+}
+
+
+FCKCommands.GetBooleanState = function( isDisabled )
+{
+ return isDisabled ? FCK_TRISTATE_DISABLED : FCK_TRISTATE_OFF ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckconfig.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckconfig.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckconfig.js (revision 1015)
@@ -0,0 +1,239 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Creates and initializes the FCKConfig object.
+ */
+
+var FCKConfig = FCK.Config = new Object() ;
+
+/*
+ For the next major version (probably 3.0) we should move all this stuff to
+ another dedicated object and leave FCKConfig as a holder object for settings only).
+*/
+
+// Editor Base Path
+if ( document.location.protocol == 'file:' )
+{
+ FCKConfig.BasePath = decodeURIComponent( document.location.pathname.substr(1) ) ;
+ FCKConfig.BasePath = FCKConfig.BasePath.replace( /\\/gi, '/' ) ;
+
+ // The way to address local files is different according to the OS.
+ // In Windows it is file:// but in MacOs it is file:/// so let's get it automatically
+ var sFullProtocol = document.location.href.match( /^(file\:\/{2,3})/ )[1] ;
+ // #945 Opera does strange things with files loaded from the disk, and it fails in Mac to load xml files
+ if ( FCKBrowserInfo.IsOpera )
+ sFullProtocol += 'localhost/' ;
+
+ FCKConfig.BasePath = sFullProtocol + FCKConfig.BasePath.substring( 0, FCKConfig.BasePath.lastIndexOf( '/' ) + 1) ;
+ FCKConfig.FullBasePath = FCKConfig.BasePath ;
+}
+else
+{
+ FCKConfig.BasePath = document.location.pathname.substring( 0, document.location.pathname.lastIndexOf( '/' ) + 1) ;
+ FCKConfig.FullBasePath = document.location.protocol + '//' + document.location.host + FCKConfig.BasePath ;
+}
+
+FCKConfig.EditorPath = FCKConfig.BasePath.replace( /editor\/$/, '' ) ;
+
+// There is a bug in Gecko. If the editor is hidden on startup, an error is
+// thrown when trying to get the screen dimensions.
+try
+{
+ FCKConfig.ScreenWidth = screen.width ;
+ FCKConfig.ScreenHeight = screen.height ;
+}
+catch (e)
+{
+ FCKConfig.ScreenWidth = 800 ;
+ FCKConfig.ScreenHeight = 600 ;
+}
+
+// Override the actual configuration values with the values passed throw the
+// hidden field "___Config".
+FCKConfig.ProcessHiddenField = function()
+{
+ this.PageConfig = new Object() ;
+
+ // Get the hidden field.
+ var oConfigField = window.parent.document.getElementById( FCK.Name + '___Config' ) ;
+
+ // Do nothing if the config field was not defined.
+ if ( ! oConfigField ) return ;
+
+ var aCouples = oConfigField.value.split('&') ;
+
+ for ( var i = 0 ; i < aCouples.length ; i++ )
+ {
+ if ( aCouples[i].length == 0 )
+ continue ;
+
+ var aConfig = aCouples[i].split( '=' ) ;
+ var sKey = decodeURIComponent( aConfig[0] ) ;
+ var sVal = decodeURIComponent( aConfig[1] ) ;
+
+ if ( sKey == 'CustomConfigurationsPath' ) // The Custom Config File path must be loaded immediately.
+ FCKConfig[ sKey ] = sVal ;
+
+ else if ( sVal.toLowerCase() == "true" ) // If it is a boolean TRUE.
+ this.PageConfig[ sKey ] = true ;
+
+ else if ( sVal.toLowerCase() == "false" ) // If it is a boolean FALSE.
+ this.PageConfig[ sKey ] = false ;
+
+ else if ( sVal.length > 0 && !isNaN( sVal ) ) // If it is a number.
+ this.PageConfig[ sKey ] = parseInt( sVal, 10 ) ;
+
+ else // In any other case it is a string.
+ this.PageConfig[ sKey ] = sVal ;
+ }
+}
+
+function FCKConfig_LoadPageConfig()
+{
+ var oPageConfig = FCKConfig.PageConfig ;
+ for ( var sKey in oPageConfig )
+ FCKConfig[ sKey ] = oPageConfig[ sKey ] ;
+}
+
+function FCKConfig_PreProcess()
+{
+ var oConfig = FCKConfig ;
+
+ // Force debug mode if fckdebug=true in the QueryString (main page).
+ if ( oConfig.AllowQueryStringDebug )
+ {
+ try
+ {
+ if ( (/fckdebug=true/i).test( window.top.location.search ) )
+ oConfig.Debug = true ;
+ }
+ catch (e) { /* Ignore it. Much probably we are inside a FRAME where the "top" is in another domain (security error). */ }
+ }
+
+ // Certifies that the "PluginsPath" configuration ends with a slash.
+ if ( !oConfig.PluginsPath.EndsWith('/') )
+ oConfig.PluginsPath += '/' ;
+
+ // EditorAreaCSS accepts a single path string, a list of paths separated by
+ // a comma or and array of paths.
+ // In the string cases, transform it in an array.
+ if ( typeof( oConfig.EditorAreaCSS ) == 'string' )
+ oConfig.EditorAreaCSS = oConfig.EditorAreaCSS.split(',') ;
+
+ var sComboPreviewCSS = oConfig.ToolbarComboPreviewCSS ;
+ if ( !sComboPreviewCSS || sComboPreviewCSS.length == 0 )
+ oConfig.ToolbarComboPreviewCSS = oConfig.EditorAreaCSS ;
+ else if ( typeof( sComboPreviewCSS ) == 'string' )
+ oConfig.ToolbarComboPreviewCSS = [ sComboPreviewCSS ] ;
+}
+
+// Define toolbar sets collection.
+FCKConfig.ToolbarSets = new Object() ;
+
+// Defines the plugins collection.
+FCKConfig.Plugins = new Object() ;
+FCKConfig.Plugins.Items = new Array() ;
+
+FCKConfig.Plugins.Add = function( name, langs, path )
+{
+ FCKConfig.Plugins.Items.AddItem( [name, langs, path] ) ;
+}
+
+// FCKConfig.ProtectedSource: object that holds a collection of Regular
+// Expressions that defined parts of the raw HTML that must remain untouched
+// like custom tags, scripts, server side code, etc...
+FCKConfig.ProtectedSource = new Object() ;
+
+// Generates a string used to identify and locate the Protected Tags comments.
+FCKConfig.ProtectedSource._CodeTag = (new Date()).valueOf() ;
+
+// Initialize the regex array with the default ones.
+FCKConfig.ProtectedSource.RegexEntries = [
+ // First of any other protection, we must protect all comments to avoid
+ // loosing them (of course, IE related).
+ //g ,
+
+ // Script tags will also be forced to be protected, otherwise IE will execute them.
+ /' + document.getElementById( 'xToolbarSpace' ).innerHTML + '' ) ;
+ eTargetDocument.close() ;
+
+ FCKTools.AddEventListener( eTargetDocument, 'contextmenu', FCKTools.CancelEvent ) ;
+
+ // Load external resources (must be done here, otherwise Firefox will not
+ // have the document DOM ready to be used right away.
+ FCKTools.AppendStyleSheet( eTargetDocument, FCKConfig.SkinPath + 'fck_editor.css' ) ;
+
+ oToolbarSet = eToolbarTarget.__FCKToolbarSet = new FCKToolbarSet( eTargetDocument ) ;
+ oToolbarSet._IFrame = eToolbarIFrame ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( eToolbarTarget, FCKToolbarSet_Target_Cleanup ) ;
+ }
+
+ oToolbarSet.CurrentInstance = FCK ;
+
+ FCK.AttachToOnSelectionChange( oToolbarSet.RefreshItemsState ) ;
+
+ return oToolbarSet ;
+}
+
+function FCK_OnBlur( editorInstance )
+{
+ var eToolbarSet = editorInstance.ToolbarSet ;
+
+ if ( eToolbarSet.CurrentInstance == editorInstance )
+ eToolbarSet.Disable() ;
+}
+
+function FCK_OnFocus( editorInstance )
+{
+ var oToolbarset = editorInstance.ToolbarSet ;
+ var oInstance = editorInstance || FCK ;
+
+ // Unregister the toolbar window from the current instance.
+ oToolbarset.CurrentInstance.FocusManager.RemoveWindow( oToolbarset._IFrame.contentWindow ) ;
+
+ // Set the new current instance.
+ oToolbarset.CurrentInstance = oInstance ;
+
+ // Register the toolbar window in the current instance.
+ oInstance.FocusManager.AddWindow( oToolbarset._IFrame.contentWindow, true ) ;
+
+ oToolbarset.Enable() ;
+}
+
+function FCKToolbarSet_Cleanup()
+{
+ this._TargetElement = null ;
+ this._IFrame = null ;
+}
+
+function FCKToolbarSet_Target_Cleanup()
+{
+ this.__FCKToolbarSet = null ;
+}
+
+var FCKToolbarSet = function( targetDocument )
+{
+ this._Document = targetDocument ;
+
+ // Get the element that will hold the elements structure.
+ this._TargetElement = targetDocument.getElementById( 'xToolbar' ) ;
+
+ // Setup the expand and collapse handlers.
+ var eExpandHandle = targetDocument.getElementById( 'xExpandHandle' ) ;
+ var eCollapseHandle = targetDocument.getElementById( 'xCollapseHandle' ) ;
+
+ eExpandHandle.title = FCKLang.ToolbarExpand ;
+ FCKTools.AddEventListener( eExpandHandle, 'click', FCKToolbarSet_Expand_OnClick ) ;
+
+ eCollapseHandle.title = FCKLang.ToolbarCollapse ;
+ FCKTools.AddEventListener( eCollapseHandle, 'click', FCKToolbarSet_Collapse_OnClick ) ;
+
+ // Set the toolbar state at startup.
+ if ( !FCKConfig.ToolbarCanCollapse || FCKConfig.ToolbarStartExpanded )
+ this.Expand() ;
+ else
+ this.Collapse() ;
+
+ // Enable/disable the collapse handler
+ eCollapseHandle.style.display = FCKConfig.ToolbarCanCollapse ? '' : 'none' ;
+
+ if ( FCKConfig.ToolbarCanCollapse )
+ eCollapseHandle.style.display = '' ;
+ else
+ targetDocument.getElementById( 'xTBLeftBorder' ).style.display = '' ;
+
+ // Set the default properties.
+ this.Toolbars = new Array() ;
+ this.IsLoaded = false ;
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( this, FCKToolbarSet_Cleanup ) ;
+}
+
+function FCKToolbarSet_Expand_OnClick()
+{
+ FCK.ToolbarSet.Expand() ;
+}
+
+function FCKToolbarSet_Collapse_OnClick()
+{
+ FCK.ToolbarSet.Collapse() ;
+}
+
+FCKToolbarSet.prototype.Expand = function()
+{
+ this._ChangeVisibility( false ) ;
+}
+
+FCKToolbarSet.prototype.Collapse = function()
+{
+ this._ChangeVisibility( true ) ;
+}
+
+FCKToolbarSet.prototype._ChangeVisibility = function( collapse )
+{
+ this._Document.getElementById( 'xCollapsed' ).style.display = collapse ? '' : 'none' ;
+ this._Document.getElementById( 'xExpanded' ).style.display = collapse ? 'none' : '' ;
+
+ if ( FCKBrowserInfo.IsGecko )
+ {
+ // I had to use "setTimeout" because Gecko was not responding in a right
+ // way when calling window.onresize() directly.
+ FCKTools.RunFunction( window.onresize ) ;
+ }
+}
+
+FCKToolbarSet.prototype.Load = function( toolbarSetName )
+{
+ this.Name = toolbarSetName ;
+
+ this.Items = new Array() ;
+
+ // Reset the array of toolbar items that are active only on WYSIWYG mode.
+ this.ItemsWysiwygOnly = new Array() ;
+
+ // Reset the array of toolbar items that are sensitive to the cursor position.
+ this.ItemsContextSensitive = new Array() ;
+
+ // Cleanup the target element.
+ this._TargetElement.innerHTML = '' ;
+
+ var ToolbarSet = FCKConfig.ToolbarSets[toolbarSetName] ;
+
+ if ( !ToolbarSet )
+ {
+ alert( FCKLang.UnknownToolbarSet.replace( /%1/g, toolbarSetName ) ) ;
+ return ;
+ }
+
+ this.Toolbars = new Array() ;
+
+ for ( var x = 0 ; x < ToolbarSet.length ; x++ )
+ {
+ var oToolbarItems = ToolbarSet[x] ;
+
+ // If the configuration for the toolbar is missing some element or has any extra comma
+ // this item won't be valid, so skip it and keep on processing.
+ if ( !oToolbarItems )
+ continue ;
+
+ var oToolbar ;
+
+ if ( typeof( oToolbarItems ) == 'string' )
+ {
+ if ( oToolbarItems == '/' )
+ oToolbar = new FCKToolbarBreak() ;
+ }
+ else
+ {
+ oToolbar = new FCKToolbar() ;
+
+ for ( var j = 0 ; j < oToolbarItems.length ; j++ )
+ {
+ var sItem = oToolbarItems[j] ;
+
+ if ( sItem == '-')
+ oToolbar.AddSeparator() ;
+ else
+ {
+ var oItem = FCKToolbarItems.GetItem( sItem ) ;
+ if ( oItem )
+ {
+ oToolbar.AddItem( oItem ) ;
+
+ this.Items.push( oItem ) ;
+
+ if ( !oItem.SourceView )
+ this.ItemsWysiwygOnly.push( oItem ) ;
+
+ if ( oItem.ContextSensitive )
+ this.ItemsContextSensitive.push( oItem ) ;
+ }
+ }
+ }
+
+ // oToolbar.AddTerminator() ;
+ }
+
+ oToolbar.Create( this._TargetElement ) ;
+
+ this.Toolbars[ this.Toolbars.length ] = oToolbar ;
+ }
+
+ FCKTools.DisableSelection( this._Document.getElementById( 'xCollapseHandle' ).parentNode ) ;
+
+ if ( FCK.Status != FCK_STATUS_COMPLETE )
+ FCK.Events.AttachEvent( 'OnStatusChange', this.RefreshModeState ) ;
+ else
+ this.RefreshModeState() ;
+
+ this.IsLoaded = true ;
+ this.IsEnabled = true ;
+
+ FCKTools.RunFunction( this.OnLoad ) ;
+}
+
+FCKToolbarSet.prototype.Enable = function()
+{
+ if ( this.IsEnabled )
+ return ;
+
+ this.IsEnabled = true ;
+
+ var aItems = this.Items ;
+ for ( var i = 0 ; i < aItems.length ; i++ )
+ aItems[i].RefreshState() ;
+}
+
+FCKToolbarSet.prototype.Disable = function()
+{
+ if ( !this.IsEnabled )
+ return ;
+
+ this.IsEnabled = false ;
+
+ var aItems = this.Items ;
+ for ( var i = 0 ; i < aItems.length ; i++ )
+ aItems[i].Disable() ;
+}
+
+FCKToolbarSet.prototype.RefreshModeState = function( editorInstance )
+{
+ if ( FCK.Status != FCK_STATUS_COMPLETE )
+ return ;
+
+ var oToolbarSet = editorInstance ? editorInstance.ToolbarSet : this ;
+ var aItems = oToolbarSet.ItemsWysiwygOnly ;
+
+ if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
+ {
+ // Enable all buttons that are available on WYSIWYG mode only.
+ for ( var i = 0 ; i < aItems.length ; i++ )
+ aItems[i].Enable() ;
+
+ // Refresh the buttons state.
+ oToolbarSet.RefreshItemsState( editorInstance ) ;
+ }
+ else
+ {
+ // Refresh the buttons state.
+ oToolbarSet.RefreshItemsState( editorInstance ) ;
+
+ // Disable all buttons that are available on WYSIWYG mode only.
+ for ( var j = 0 ; j < aItems.length ; j++ )
+ aItems[j].Disable() ;
+ }
+}
+
+FCKToolbarSet.prototype.RefreshItemsState = function( editorInstance )
+{
+// FCKDebug.Output( 'Refreshing Commands...' ) ; // @Packager.RemoveLine
+
+ var aItems = ( editorInstance ? editorInstance.ToolbarSet : this ).ItemsContextSensitive ;
+
+ for ( var i = 0 ; i < aItems.length ; i++ )
+ aItems[i].RefreshState() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools.js (revision 1015)
@@ -0,0 +1,580 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Utility functions.
+ */
+
+var FCKTools = new Object() ;
+
+FCKTools.CreateBogusBR = function( targetDocument )
+{
+ var eBR = targetDocument.createElement( 'br' ) ;
+// eBR.setAttribute( '_moz_editor_bogus_node', 'TRUE' ) ;
+ eBR.setAttribute( 'type', '_moz' ) ;
+ return eBR ;
+}
+
+// Returns a reference to the appended style sheet or an array with all the appended references
+FCKTools.AppendStyleSheet = function( documentElement, cssFileUrlOrArray )
+{
+ if ( typeof( cssFileUrlOrArray ) == 'string' )
+ return this._AppendStyleSheet( documentElement, cssFileUrlOrArray ) ;
+ else
+ {
+ var aStyleSheeArray = new Array() ;
+
+ for ( var i = 0 ; i < cssFileUrlOrArray.length ; i++ )
+ aStyleSheeArray.push(this._AppendStyleSheet( documentElement, cssFileUrlOrArray[i] ) ) ;
+
+ return aStyleSheeArray ;
+ }
+}
+
+FCKTools.AppendStyleString = function ( documentElement, cssStyles )
+{
+ this._AppendStyleString( documentElement, cssStyles ) ;
+}
+
+FCKTools.GetElementDocument = function ( element )
+{
+ return element.ownerDocument || element.document ;
+}
+
+// Get the window object where the element is placed in.
+FCKTools.GetElementWindow = function( element )
+{
+ return this.GetDocumentWindow( this.GetElementDocument( element ) ) ;
+}
+
+FCKTools.GetDocumentWindow = function( document )
+{
+ // With Safari, there is not way to retrieve the window from the document, so we must fix it.
+ if ( FCKBrowserInfo.IsSafari && !document.parentWindow )
+ this.FixDocumentParentWindow( window.top ) ;
+
+ return document.parentWindow || document.defaultView ;
+}
+
+/*
+ This is a Safari specific function that fix the reference to the parent
+ window from the document object.
+*/
+FCKTools.FixDocumentParentWindow = function( targetWindow )
+{
+ targetWindow.document.parentWindow = targetWindow ;
+
+ for ( var i = 0 ; i < targetWindow.frames.length ; i++ )
+ FCKTools.FixDocumentParentWindow( targetWindow.frames[i] ) ;
+}
+
+FCKTools.HTMLEncode = function( text )
+{
+ if ( !text )
+ return '' ;
+
+ text = text.replace( /&/g, '&' ) ;
+ text = text.replace( //g, '>' ) ;
+
+ return text ;
+}
+
+FCKTools.HTMLDecode = function( text )
+{
+ if ( !text )
+ return '' ;
+
+ text = text.replace( />/g, '>' ) ;
+ text = text.replace( /</g, '<' ) ;
+ text = text.replace( /&/g, '&' ) ;
+
+ return text ;
+}
+
+FCKTools._ProcessLineBreaksForPMode = function( oEditor, text, liState, node, strArray )
+{
+ var closeState = 0 ;
+ var blockStartTag = "" ;
+ var blockEndTag = "
" ;
+ var lineBreakTag = " " ;
+ if ( liState )
+ {
+ blockStartTag = "" ;
+ blockEndTag = " " ;
+ closeState = 1 ;
+ }
+
+ // Are we currently inside a tag now?
+ // If yes, close it at the next double line break.
+ while ( node && node != oEditor.FCK.EditorDocument.body )
+ {
+ if ( node.tagName.toLowerCase() == 'p' )
+ {
+ closeState = 1 ;
+ break;
+ }
+ node = node.parentNode ;
+ }
+
+ for ( var i = 0 ; i < text.length ; i++ )
+ {
+ var c = text.charAt( i ) ;
+ if ( c == '\r' )
+ continue ;
+
+ if ( c != '\n' )
+ {
+ strArray.push( c ) ;
+ continue ;
+ }
+
+ // Now we have encountered a line break.
+ // Check if the next character is also a line break.
+ var n = text.charAt( i + 1 ) ;
+ if ( n == '\r' )
+ {
+ i++ ;
+ n = text.charAt( i + 1 ) ;
+ }
+ if ( n == '\n' )
+ {
+ i++ ; // ignore next character - we have already processed it.
+ if ( closeState )
+ strArray.push( blockEndTag ) ;
+ strArray.push( blockStartTag ) ;
+ closeState = 1 ;
+ }
+ else
+ strArray.push( lineBreakTag ) ;
+ }
+}
+
+FCKTools._ProcessLineBreaksForDivMode = function( oEditor, text, liState, node, strArray )
+{
+ var closeState = 0 ;
+ var blockStartTag = "
" ;
+ var blockEndTag = "
" ;
+ if ( liState )
+ {
+ blockStartTag = "" ;
+ blockEndTag = " " ;
+ closeState = 1 ;
+ }
+
+ // Are we currently inside a tag now?
+ // If yes, close it at the next double line break.
+ while ( node && node != oEditor.FCK.EditorDocument.body )
+ {
+ if ( node.tagName.toLowerCase() == 'div' )
+ {
+ closeState = 1 ;
+ break ;
+ }
+ node = node.parentNode ;
+ }
+
+ for ( var i = 0 ; i < text.length ; i++ )
+ {
+ var c = text.charAt( i ) ;
+ if ( c == '\r' )
+ continue ;
+
+ if ( c != '\n' )
+ {
+ strArray.push( c ) ;
+ continue ;
+ }
+
+ if ( closeState )
+ {
+ if ( strArray[ strArray.length - 1 ] == blockStartTag )
+ {
+ // A div tag must have some contents inside for it to be visible.
+ strArray.push( " " ) ;
+ }
+ strArray.push( blockEndTag ) ;
+ }
+ strArray.push( blockStartTag ) ;
+ closeState = 1 ;
+ }
+ if ( closeState )
+ strArray.push( blockEndTag ) ;
+}
+
+FCKTools._ProcessLineBreaksForBrMode = function( oEditor, text, liState, node, strArray )
+{
+ var closeState = 0 ;
+ var blockStartTag = "
" ;
+ var blockEndTag = "" ;
+ if ( liState )
+ {
+ blockStartTag = "
" ;
+ blockEndTag = " " ;
+ closeState = 1 ;
+ }
+
+ for ( var i = 0 ; i < text.length ; i++ )
+ {
+ var c = text.charAt( i ) ;
+ if ( c == '\r' )
+ continue ;
+
+ if ( c != '\n' )
+ {
+ strArray.push( c ) ;
+ continue ;
+ }
+
+ if ( closeState && blockEndTag.length )
+ strArray.push ( blockEndTag ) ;
+ strArray.push( blockStartTag ) ;
+ closeState = 1 ;
+ }
+}
+
+FCKTools.ProcessLineBreaks = function( oEditor, oConfig, text )
+{
+ var enterMode = oConfig.EnterMode.toLowerCase() ;
+ var strArray = [] ;
+
+ // Is the caret or selection inside an
tag now?
+ var liState = 0 ;
+ var range = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ;
+ range.MoveToSelection() ;
+ var node = range._Range.startContainer ;
+ while ( node && node.nodeType != 1 )
+ node = node.parentNode ;
+ if ( node && node.tagName.toLowerCase() == 'li' )
+ liState = 1 ;
+
+ if ( enterMode == 'p' )
+ this._ProcessLineBreaksForPMode( oEditor, text, liState, node, strArray ) ;
+ else if ( enterMode == 'div' )
+ this._ProcessLineBreaksForDivMode( oEditor, text, liState, node, strArray ) ;
+ else if ( enterMode == 'br' )
+ this._ProcessLineBreaksForBrMode( oEditor, text, liState, node, strArray ) ;
+ return strArray.join( "" ) ;
+}
+
+/**
+ * Adds an option to a SELECT element.
+ */
+FCKTools.AddSelectOption = function( selectElement, optionText, optionValue )
+{
+ var oOption = FCKTools.GetElementDocument( selectElement ).createElement( "OPTION" ) ;
+
+ oOption.text = optionText ;
+ oOption.value = optionValue ;
+
+ selectElement.options.add(oOption) ;
+
+ return oOption ;
+}
+
+FCKTools.RunFunction = function( func, thisObject, paramsArray, timerWindow )
+{
+ if ( func )
+ this.SetTimeout( func, 0, thisObject, paramsArray, timerWindow ) ;
+}
+
+FCKTools.SetTimeout = function( func, milliseconds, thisObject, paramsArray, timerWindow )
+{
+ return ( timerWindow || window ).setTimeout(
+ function()
+ {
+ if ( paramsArray )
+ func.apply( thisObject, [].concat( paramsArray ) ) ;
+ else
+ func.apply( thisObject ) ;
+ },
+ milliseconds ) ;
+}
+
+FCKTools.SetInterval = function( func, milliseconds, thisObject, paramsArray, timerWindow )
+{
+ return ( timerWindow || window ).setInterval(
+ function()
+ {
+ func.apply( thisObject, paramsArray || [] ) ;
+ },
+ milliseconds ) ;
+}
+
+FCKTools.ConvertStyleSizeToHtml = function( size )
+{
+ return size.EndsWith( '%' ) ? size : parseInt( size, 10 ) ;
+}
+
+FCKTools.ConvertHtmlSizeToStyle = function( size )
+{
+ return size.EndsWith( '%' ) ? size : ( size + 'px' ) ;
+}
+
+// START iCM MODIFICATIONS
+// Amended to accept a list of one or more ascensor tag names
+// Amended to check the element itself before working back up through the parent hierarchy
+FCKTools.GetElementAscensor = function( element, ascensorTagNames )
+{
+// var e = element.parentNode ;
+ var e = element ;
+ var lstTags = "," + ascensorTagNames.toUpperCase() + "," ;
+
+ while ( e )
+ {
+ if ( lstTags.indexOf( "," + e.nodeName.toUpperCase() + "," ) != -1 )
+ return e ;
+
+ e = e.parentNode ;
+ }
+ return null ;
+}
+// END iCM MODIFICATIONS
+
+FCKTools.CreateEventListener = function( func, params )
+{
+ var f = function()
+ {
+ var aAllParams = [] ;
+
+ for ( var i = 0 ; i < arguments.length ; i++ )
+ aAllParams.push( arguments[i] ) ;
+
+ func.apply( this, aAllParams.concat( params ) ) ;
+ }
+
+ return f ;
+}
+
+FCKTools.IsStrictMode = function( document )
+{
+ // There is no compatMode in Safari, but it seams that it always behave as
+ // CSS1Compat, so let's assume it as the default.
+ return ( 'CSS1Compat' == ( document.compatMode || 'CSS1Compat' ) ) ;
+}
+
+// Transforms a "arguments" object to an array.
+FCKTools.ArgumentsToArray = function( args, startIndex, maxLength )
+{
+ startIndex = startIndex || 0 ;
+ maxLength = maxLength || args.length ;
+
+ var argsArray = new Array() ;
+
+ for ( var i = startIndex ; i < startIndex + maxLength && i < args.length ; i++ )
+ argsArray.push( args[i] ) ;
+
+ return argsArray ;
+}
+
+FCKTools.CloneObject = function( sourceObject )
+{
+ var fCloneCreator = function() {} ;
+ fCloneCreator.prototype = sourceObject ;
+ return new fCloneCreator ;
+}
+
+// Appends a bogus at the end of the element, if not yet available.
+FCKTools.AppendBogusBr = function( element )
+{
+ if ( !element )
+ return ;
+
+ var eLastChild = this.GetLastItem( element.getElementsByTagName('br') ) ;
+
+ if ( !eLastChild || ( eLastChild.getAttribute( 'type', 2 ) != '_moz' && eLastChild.getAttribute( '_moz_dirty' ) == null ) )
+ {
+ var doc = this.GetElementDocument( element ) ;
+
+ if ( FCKBrowserInfo.IsOpera )
+ element.appendChild( doc.createTextNode('') ) ;
+ else
+ element.appendChild( this.CreateBogusBR( doc ) ) ;
+ }
+}
+
+FCKTools.GetLastItem = function( list )
+{
+ if ( list.length > 0 )
+ return list[ list.length - 1 ] ;
+
+ return null ;
+}
+
+FCKTools.GetDocumentPosition = function( w, node )
+{
+ var x = 0 ;
+ var y = 0 ;
+ var curNode = node ;
+ while ( curNode && curNode != w.document.body )
+ {
+ x += curNode.offsetLeft - curNode.scrollLeft ;
+ y += curNode.offsetTop - curNode.scrollTop ;
+ curNode = curNode.offsetParent ;
+ }
+ return { "x" : x, "y" : y } ;
+}
+
+FCKTools.GetWindowPosition = function( w, node )
+{
+ var pos = this.GetDocumentPosition( w, node ) ;
+ var scroll = FCKTools.GetScrollPosition( w ) ;
+ pos.x -= scroll.X ;
+ pos.y -= scroll.Y ;
+ return pos ;
+}
+
+FCKTools.ProtectFormStyles = function( formNode )
+{
+ if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' )
+ return [] ;
+ var hijackRecord = [] ;
+ var hijackNames = [ 'style', 'className' ] ;
+ for ( var i = 0 ; i < hijackNames.length ; i++ )
+ {
+ var name = hijackNames[i] ;
+ if ( formNode.elements.namedItem( name ) )
+ {
+ var hijackNode = formNode.elements.namedItem( name ) ;
+ hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] ) ;
+ formNode.removeChild( hijackNode ) ;
+ }
+ }
+ return hijackRecord ;
+}
+
+FCKTools.RestoreFormStyles = function( formNode, hijackRecord )
+{
+ if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' )
+ return ;
+ if ( hijackRecord.length > 0 )
+ {
+ for ( var i = hijackRecord.length - 1 ; i >= 0 ; i-- )
+ {
+ var node = hijackRecord[i][0] ;
+ var sibling = hijackRecord[i][1] ;
+ if ( sibling )
+ formNode.insertBefore( node, sibling ) ;
+ else
+ formNode.appendChild( node ) ;
+ }
+ }
+}
+
+// Perform a one-step DFS walk.
+FCKTools.GetNextNode = function( node, limitNode )
+{
+ if ( node.firstChild )
+ return node.firstChild ;
+ else if ( node.nextSibling )
+ return node.nextSibling ;
+ else
+ {
+ var ancestor = node.parentNode ;
+ while ( ancestor )
+ {
+ if ( ancestor == limitNode )
+ return null ;
+ if ( ancestor.nextSibling )
+ return ancestor.nextSibling ;
+ else
+ ancestor = ancestor.parentNode ;
+ }
+ }
+ return null ;
+}
+
+FCKTools.GetNextTextNode = function( textnode, limitNode, checkStop )
+{
+ node = this.GetNextNode( textnode, limitNode ) ;
+ if ( checkStop && node && checkStop( node ) )
+ return null ;
+ while ( node && node.nodeType != 3 )
+ {
+ node = this.GetNextNode( node, limitNode ) ;
+ if ( checkStop && node && checkStop( node ) )
+ return null ;
+ }
+ return node ;
+}
+
+/**
+ * Merge all objects passed by argument into a single object.
+ */
+FCKTools.Merge = function()
+{
+ var args = arguments ;
+ var o = args[0] ;
+
+ for ( var i = 1 ; i < args.length ; i++ )
+ {
+ var arg = args[i] ;
+ for ( var p in arg )
+ o[p] = arg[p] ;
+ }
+
+ return o ;
+}
+
+/**
+ * Check if the passed argument is a real Array. It may not working when
+ * calling it cross windows.
+ */
+FCKTools.IsArray = function( it )
+{
+ return ( it instanceof Array ) ;
+}
+
+/**
+ * Appends a "length" property to an object, containing the number of
+ * properties available on it, excluded the append property itself.
+ */
+FCKTools.AppendLengthProperty = function( targetObject, propertyName )
+{
+ var counter = 0 ;
+
+ for ( var n in targetObject )
+ counter++ ;
+
+ return targetObject[ propertyName || 'length' ] = counter ;
+}
+
+/**
+ * Gets the browser parsed version of a css text (style attribute value). On
+ * some cases, the browser makes changes to the css text, returning a different
+ * value. For example, hexadecimal colors get transformed to rgb().
+ */
+FCKTools.NormalizeCssText = function( unparsedCssText )
+{
+ // Injects the style in a temporary span object, so the browser parses it,
+ // retrieving its final format.
+ var tempSpan = document.createElement( 'span' ) ;
+ tempSpan.style.cssText = unparsedCssText ;
+ return tempSpan.style.cssText ;
+}
+
+/**
+ * Utility function to wrap a call to an object's method,
+ * so it can be passed for example to an event handler,
+ * and then it will be executed with 'this' being the object.
+ */
+FCKTools.Hitch = function( obj, methodName )
+{
+ return function() { obj[methodName].apply(obj, arguments); } ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_gecko.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_gecko.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_gecko.js (revision 1015)
@@ -0,0 +1,270 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Utility functions. (Gecko version).
+ */
+
+FCKTools.CancelEvent = function( e )
+{
+ if ( e )
+ e.preventDefault() ;
+}
+
+FCKTools.DisableSelection = function( element )
+{
+ if ( FCKBrowserInfo.IsGecko )
+ element.style.MozUserSelect = 'none' ; // Gecko only.
+ else
+ element.style.userSelect = 'none' ; // CSS3 (not supported yet).
+}
+
+// Appends a CSS file to a document.
+FCKTools._AppendStyleSheet = function( documentElement, cssFileUrl )
+{
+ var e = documentElement.createElement( 'LINK' ) ;
+ e.rel = 'stylesheet' ;
+ e.type = 'text/css' ;
+ e.href = cssFileUrl ;
+ documentElement.getElementsByTagName("HEAD")[0].appendChild( e ) ;
+ return e ;
+}
+
+// Appends a CSS style string to a document.
+FCKTools._AppendStyleString = function( documentElement, cssStyles )
+{
+ var e = documentElement.createElement( "STYLE" ) ;
+ e.appendChild( documentElement.createTextNode( cssStyles ) ) ;
+ documentElement.getElementsByTagName( "HEAD" )[0].appendChild( e ) ;
+ return e ;
+}
+
+// Removes all attributes and values from the element.
+FCKTools.ClearElementAttributes = function( element )
+{
+ // Loop throw all attributes in the element
+ for ( var i = 0 ; i < element.attributes.length ; i++ )
+ {
+ // Remove the element by name.
+ element.removeAttribute( element.attributes[i].name, 0 ) ; // 0 : Case Insensitive
+ }
+}
+
+// Returns an Array of strings with all defined in the elements inside another element.
+FCKTools.GetAllChildrenIds = function( parentElement )
+{
+ // Create the array that will hold all Ids.
+ var aIds = new Array() ;
+
+ // Define a recursive function that search for the Ids.
+ var fGetIds = function( parent )
+ {
+ for ( var i = 0 ; i < parent.childNodes.length ; i++ )
+ {
+ var sId = parent.childNodes[i].id ;
+
+ // Check if the Id is defined for the element.
+ if ( sId && sId.length > 0 ) aIds[ aIds.length ] = sId ;
+
+ // Recursive call.
+ fGetIds( parent.childNodes[i] ) ;
+ }
+ }
+
+ // Start the recursive calls.
+ fGetIds( parentElement ) ;
+
+ return aIds ;
+}
+
+// Replaces a tag with its contents. For example "My tag "
+// will be replaced with "My tag ".
+FCKTools.RemoveOuterTags = function( e )
+{
+ var oFragment = e.ownerDocument.createDocumentFragment() ;
+
+ for ( var i = 0 ; i < e.childNodes.length ; i++ )
+ oFragment.appendChild( e.childNodes[i].cloneNode(true) ) ;
+
+ e.parentNode.replaceChild( oFragment, e ) ;
+}
+
+FCKTools.CreateXmlObject = function( object )
+{
+ switch ( object )
+ {
+ case 'XmlHttp' :
+ return new XMLHttpRequest() ;
+ case 'DOMDocument' :
+ return document.implementation.createDocument( '', '', null ) ;
+ }
+ return null ;
+}
+
+FCKTools.GetScrollPosition = function( relativeWindow )
+{
+ return { X : relativeWindow.pageXOffset, Y : relativeWindow.pageYOffset } ;
+}
+
+FCKTools.AddEventListener = function( sourceObject, eventName, listener )
+{
+ sourceObject.addEventListener( eventName, listener, false ) ;
+}
+
+FCKTools.RemoveEventListener = function( sourceObject, eventName, listener )
+{
+ sourceObject.removeEventListener( eventName, listener, false ) ;
+}
+
+// Listeners attached with this function cannot be detached.
+FCKTools.AddEventListenerEx = function( sourceObject, eventName, listener, paramsArray )
+{
+ sourceObject.addEventListener(
+ eventName,
+ function( e )
+ {
+ listener.apply( sourceObject, [ e ].concat( paramsArray || [] ) ) ;
+ },
+ false
+ ) ;
+}
+
+// Returns and object with the "Width" and "Height" properties.
+FCKTools.GetViewPaneSize = function( win )
+{
+ return { Width : win.innerWidth, Height : win.innerHeight } ;
+}
+
+FCKTools.SaveStyles = function( element )
+{
+ var data = FCKTools.ProtectFormStyles( element ) ;
+
+ var oSavedStyles = new Object() ;
+
+ if ( element.className.length > 0 )
+ {
+ oSavedStyles.Class = element.className ;
+ element.className = '' ;
+ }
+
+ var sInlineStyle = element.getAttribute( 'style' ) ;
+
+ if ( sInlineStyle && sInlineStyle.length > 0 )
+ {
+ oSavedStyles.Inline = sInlineStyle ;
+ element.setAttribute( 'style', '', 0 ) ; // 0 : Case Insensitive
+ }
+
+ FCKTools.RestoreFormStyles( element, data ) ;
+ return oSavedStyles ;
+}
+
+FCKTools.RestoreStyles = function( element, savedStyles )
+{
+ var data = FCKTools.ProtectFormStyles( element ) ;
+ element.className = savedStyles.Class || '' ;
+
+ if ( savedStyles.Inline )
+ element.setAttribute( 'style', savedStyles.Inline, 0 ) ; // 0 : Case Insensitive
+ else
+ element.removeAttribute( 'style', 0 ) ;
+ FCKTools.RestoreFormStyles( element, data ) ;
+}
+
+FCKTools.RegisterDollarFunction = function( targetWindow )
+{
+ targetWindow.$ = function( id )
+ {
+ return this.document.getElementById( id ) ;
+ } ;
+}
+
+FCKTools.AppendElement = function( target, elementName )
+{
+ return target.appendChild( target.ownerDocument.createElement( elementName ) ) ;
+}
+
+// Get the coordinates of an element.
+// @el : The element to get the position.
+// @relativeWindow: The window to which we want the coordinates relative to.
+FCKTools.GetElementPosition = function( el, relativeWindow )
+{
+ // Initializes the Coordinates object that will be returned by the function.
+ var c = { X:0, Y:0 } ;
+
+ var oWindow = relativeWindow || window ;
+
+ var oOwnerWindow = FCKTools.GetElementWindow( el ) ;
+
+ var previousElement = null ;
+ // Loop throw the offset chain.
+ while ( el )
+ {
+ var sPosition = oOwnerWindow.getComputedStyle(el, '').position ;
+
+ // Check for non "static" elements.
+ // 'FCKConfig.FloatingPanelsZIndex' -- Submenus are under a positioned IFRAME.
+ if ( sPosition && sPosition != 'static' && el.style.zIndex != FCKConfig.FloatingPanelsZIndex )
+ break ;
+
+ /*
+ FCKDebug.Output( el.tagName + ":" + "offset=" + el.offsetLeft + "," + el.offsetTop + " "
+ + "scroll=" + el.scrollLeft + "," + el.scrollTop ) ;
+ */
+
+ c.X += el.offsetLeft - el.scrollLeft ;
+ c.Y += el.offsetTop - el.scrollTop ;
+
+ // Backtrack due to offsetParent's calculation by the browser ignores scrollLeft and scrollTop.
+ // Backtracking is not needed for Opera
+ if ( ! FCKBrowserInfo.IsOpera )
+ {
+ var scrollElement = previousElement ;
+ while ( scrollElement && scrollElement != el )
+ {
+ c.X -= scrollElement.scrollLeft ;
+ c.Y -= scrollElement.scrollTop ;
+ scrollElement = scrollElement.parentNode ;
+ }
+ }
+
+ previousElement = el ;
+ if ( el.offsetParent )
+ el = el.offsetParent ;
+ else
+ {
+ if ( oOwnerWindow != oWindow )
+ {
+ el = oOwnerWindow.frameElement ;
+ previousElement = null ;
+ if ( el )
+ oOwnerWindow = FCKTools.GetElementWindow( el ) ;
+ }
+ else
+ {
+ c.X += el.scrollLeft ;
+ c.Y += el.scrollTop ;
+ break ;
+ }
+ }
+ }
+
+ // Return the Coordinates object
+ return c ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_ie.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_ie.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fcktools_ie.js (revision 1015)
@@ -0,0 +1,229 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ *
+ * Utility functions. (IE version).
+ */
+
+FCKTools.CancelEvent = function( e )
+{
+ return false ;
+}
+
+// Appends one or more CSS files to a document.
+FCKTools._AppendStyleSheet = function( documentElement, cssFileUrl )
+{
+ return documentElement.createStyleSheet( cssFileUrl ).owningElement ;
+}
+
+// Appends a CSS style string to a document.
+FCKTools._AppendStyleString = function( documentElement, cssStyles )
+{
+ var s = documentElement.createStyleSheet( "" ) ;
+ s.cssText = cssStyles ;
+ return s ;
+}
+
+// Removes all attributes and values from the element.
+FCKTools.ClearElementAttributes = function( element )
+{
+ element.clearAttributes() ;
+}
+
+FCKTools.GetAllChildrenIds = function( parentElement )
+{
+ var aIds = new Array() ;
+ for ( var i = 0 ; i < parentElement.all.length ; i++ )
+ {
+ var sId = parentElement.all[i].id ;
+ if ( sId && sId.length > 0 )
+ aIds[ aIds.length ] = sId ;
+ }
+ return aIds ;
+}
+
+FCKTools.RemoveOuterTags = function( e )
+{
+ e.insertAdjacentHTML( 'beforeBegin', e.innerHTML ) ;
+ e.parentNode.removeChild( e ) ;
+}
+
+FCKTools.CreateXmlObject = function( object )
+{
+ var aObjs ;
+
+ switch ( object )
+ {
+ case 'XmlHttp' :
+ aObjs = [ 'MSXML2.XmlHttp', 'Microsoft.XmlHttp' ] ;
+ break ;
+
+ case 'DOMDocument' :
+ aObjs = [ 'MSXML2.DOMDocument', 'Microsoft.XmlDom' ] ;
+ break ;
+ }
+
+ for ( var i = 0 ; i < 2 ; i++ )
+ {
+ try { return new ActiveXObject( aObjs[i] ) ; }
+ catch (e)
+ {}
+ }
+
+ if ( FCKLang.NoActiveX )
+ {
+ alert( FCKLang.NoActiveX ) ;
+ FCKLang.NoActiveX = null ;
+ }
+ return null ;
+}
+
+FCKTools.DisableSelection = function( element )
+{
+ element.unselectable = 'on' ;
+
+ var e, i = 0 ;
+ // The extra () is to avoid a warning with strict error checking. This is ok.
+ while ( (e = element.all[ i++ ]) )
+ {
+ switch ( e.tagName )
+ {
+ case 'IFRAME' :
+ case 'TEXTAREA' :
+ case 'INPUT' :
+ case 'SELECT' :
+ /* Ignore the above tags */
+ break ;
+ default :
+ e.unselectable = 'on' ;
+ }
+ }
+}
+
+FCKTools.GetScrollPosition = function( relativeWindow )
+{
+ var oDoc = relativeWindow.document ;
+
+ // Try with the doc element.
+ var oPos = { X : oDoc.documentElement.scrollLeft, Y : oDoc.documentElement.scrollTop } ;
+
+ if ( oPos.X > 0 || oPos.Y > 0 )
+ return oPos ;
+
+ // If no scroll, try with the body.
+ return { X : oDoc.body.scrollLeft, Y : oDoc.body.scrollTop } ;
+}
+
+FCKTools.AddEventListener = function( sourceObject, eventName, listener )
+{
+ sourceObject.attachEvent( 'on' + eventName, listener ) ;
+}
+
+FCKTools.RemoveEventListener = function( sourceObject, eventName, listener )
+{
+ sourceObject.detachEvent( 'on' + eventName, listener ) ;
+}
+
+// Listeners attached with this function cannot be detached.
+FCKTools.AddEventListenerEx = function( sourceObject, eventName, listener, paramsArray )
+{
+ // Ok... this is a closures party, but is the only way to make it clean of memory leaks.
+ var o = new Object() ;
+ o.Source = sourceObject ;
+ o.Params = paramsArray || [] ; // Memory leak if we have DOM objects here.
+ o.Listener = function( ev )
+ {
+ if ( !ev ) // Assertion // @Packager.RemoveLine
+ throw( 'ev is undefined' ) ; // Assertion // @Packager.RemoveLine
+ return listener.apply( o.Source, [ ev ].concat( o.Params ) ) ;
+ }
+
+ if ( FCK.IECleanup )
+ FCK.IECleanup.AddItem( null, function() { o.Source = null ; o.Params = null ; } ) ;
+
+ sourceObject.attachEvent( 'on' + eventName, o.Listener ) ;
+
+ sourceObject = null ; // Memory leak cleaner (because of the above closure).
+ paramsArray = null ; // Memory leak cleaner (because of the above closure).
+}
+
+// Returns and object with the "Width" and "Height" properties.
+FCKTools.GetViewPaneSize = function( win )
+{
+ var oSizeSource ;
+
+ var oDoc = win.document.documentElement ;
+ if ( oDoc && oDoc.clientWidth ) // IE6 Strict Mode
+ oSizeSource = oDoc ;
+ else
+ oSizeSource = win.document.body ; // Other IEs
+
+ if ( oSizeSource )
+ return { Width : oSizeSource.clientWidth, Height : oSizeSource.clientHeight } ;
+ else
+ return { Width : 0, Height : 0 } ;
+}
+
+FCKTools.SaveStyles = function( element )
+{
+ var data = FCKTools.ProtectFormStyles( element ) ;
+
+ var oSavedStyles = new Object() ;
+
+ if ( element.className.length > 0 )
+ {
+ oSavedStyles.Class = element.className ;
+ element.className = '' ;
+ }
+
+ var sInlineStyle = element.style.cssText ;
+
+ if ( sInlineStyle.length > 0 )
+ {
+ oSavedStyles.Inline = sInlineStyle ;
+ element.style.cssText = '' ;
+ }
+
+ FCKTools.RestoreFormStyles( element, data ) ;
+ return oSavedStyles ;
+}
+
+FCKTools.RestoreStyles = function( element, savedStyles )
+{
+ var data = FCKTools.ProtectFormStyles( element ) ;
+ element.className = savedStyles.Class || '' ;
+ element.style.cssText = savedStyles.Inline || '' ;
+ FCKTools.RestoreFormStyles( element, data ) ;
+}
+
+FCKTools.RegisterDollarFunction = function( targetWindow )
+{
+ targetWindow.$ = targetWindow.document.getElementById ;
+}
+
+FCKTools.AppendElement = function( target, elementName )
+{
+ return target.appendChild( this.GetElementDocument( target ).createElement( elementName ) ) ;
+}
+
+// This function may be used by Regex replacements.
+FCKTools.ToLowerCase = function( strValue )
+{
+ return strValue.toLowerCase() ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckundo.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckundo.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckundo.js (revision 1015)
@@ -0,0 +1,220 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 ==
+ */
+
+var FCKUndo = new Object() ;
+
+FCKUndo.SavedData = new Array() ;
+FCKUndo.CurrentIndex = -1 ;
+FCKUndo.TypesCount = 0 ;
+FCKUndo.Changed = false ; // Is the document changed in respect to its initial image?
+FCKUndo.MaxTypes = 25 ;
+FCKUndo.Typing = false ;
+
+FCKUndo._GetBookmark = function()
+{
+ var range = new FCKDomRange( FCK.EditorWindow ) ;
+ try
+ {
+ // There are some tricky cases where this might fail (e.g. having a lone empty table in IE)
+ range.MoveToSelection() ;
+ }
+ catch ( e )
+ {
+ return null ;
+ }
+ if ( FCKBrowserInfo.IsIE )
+ {
+ var bookmark = range.CreateBookmark() ;
+ var dirtyHtml = FCK.EditorDocument.body.innerHTML ;
+ range.MoveToBookmark( bookmark ) ;
+ return [ bookmark, dirtyHtml ] ;
+ }
+ return range.CreateBookmark2() ;
+}
+
+FCKUndo._SelectBookmark = function( bookmark )
+{
+ if ( ! bookmark )
+ return ;
+
+ var range = new FCKDomRange( FCK.EditorWindow ) ;
+ if ( bookmark instanceof Object )
+ {
+ if ( FCKBrowserInfo.IsIE )
+ range.MoveToBookmark( bookmark[0] ) ;
+ else
+ range.MoveToBookmark2( bookmark ) ;
+ try
+ {
+ // this does not always succeed, there are still some tricky cases where it fails
+ // e.g. add a special character at end of document, undo, redo -> error
+ range.Select() ;
+ }
+ catch ( e )
+ {
+ // if select restore fails, put the caret at the end of the document
+ range.MoveToPosition( FCK.EditorDocument.body, 4 ) ;
+ range.Select() ;
+ }
+ }
+}
+
+FCKUndo._CompareCursors = function( cursor1, cursor2 )
+{
+ for ( var i = 0 ; i < Math.min( cursor1.length, cursor2.length ) ; i++ )
+ {
+ if ( cursor1[i] < cursor2[i] )
+ return -1;
+ else if (cursor1[i] > cursor2[i] )
+ return 1;
+ }
+ if ( cursor1.length < cursor2.length )
+ return -1;
+ else if (cursor1.length > cursor2.length )
+ return 1;
+ return 0;
+}
+
+FCKUndo._CheckIsBookmarksEqual = function( bookmark1, bookmark2 )
+{
+ if ( ! ( bookmark1 && bookmark2 ) )
+ return false ;
+ if ( FCKBrowserInfo.IsIE )
+ {
+ var startOffset1 = bookmark1[1].search( bookmark1[0].StartId ) ;
+ var startOffset2 = bookmark2[1].search( bookmark2[0].StartId ) ;
+ var endOffset1 = bookmark1[1].search( bookmark1[0].EndId ) ;
+ var endOffset2 = bookmark2[1].search( bookmark2[0].EndId ) ;
+ return startOffset1 == startOffset2 && endOffset1 == endOffset2 ;
+ }
+ else
+ {
+ return this._CompareCursors( bookmark1.Start, bookmark2.Start ) == 0
+ && this._CompareCursors( bookmark1.End, bookmark2.End ) == 0 ;
+ }
+}
+
+FCKUndo.SaveUndoStep = function()
+{
+ if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
+ return ;
+
+ // Assume the editor content is changed when SaveUndoStep() is called after the first time.
+ // This also enables the undo button in toolbar.
+ if ( this.SavedData.length )
+ this.Changed = true ;
+
+ // Get the HTML content.
+ var sHtml = FCK.EditorDocument.body.innerHTML ;
+ var bookmark = this._GetBookmark() ;
+
+ // Shrink the array to the current level.
+ this.SavedData = this.SavedData.slice( 0, this.CurrentIndex + 1 ) ;
+
+ // Cancel operation if the new step is identical to the previous one.
+ if ( this.CurrentIndex > 0
+ && sHtml == this.SavedData[ this.CurrentIndex ][0]
+ && this._CheckIsBookmarksEqual( bookmark, this.SavedData[ this.CurrentIndex ][1] ) )
+ return ;
+ // Save the selection and caret position in the first undo level for the first change.
+ else if ( this.CurrentIndex == 0 && this.SavedData.length && sHtml == this.SavedData[0][0] )
+ {
+ this.SavedData[0][1] = bookmark ;
+ return ;
+ }
+
+ // If we reach the Maximum number of undo levels, we must remove the first
+ // entry of the list shifting all elements.
+ if ( this.CurrentIndex + 1 >= FCKConfig.MaxUndoLevels )
+ this.SavedData.shift() ;
+ else
+ this.CurrentIndex++ ;
+
+ // Save the new level in front of the actual position.
+ this.SavedData[ this.CurrentIndex ] = [ sHtml, bookmark ] ;
+
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+}
+
+FCKUndo.CheckUndoState = function()
+{
+ return ( this.Changed || this.CurrentIndex > 0 ) ;
+}
+
+FCKUndo.CheckRedoState = function()
+{
+ return ( this.CurrentIndex < ( this.SavedData.length - 1 ) ) ;
+}
+
+FCKUndo.Undo = function()
+{
+ if ( this.CheckUndoState() )
+ {
+ // If it is the first step.
+ if ( this.CurrentIndex == ( this.SavedData.length - 1 ) )
+ {
+ // Save the actual state for a possible "Redo" call.
+ this.SaveUndoStep() ;
+ }
+
+ // Go a step back.
+ this._ApplyUndoLevel( --this.CurrentIndex ) ;
+
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+ }
+}
+
+FCKUndo.Redo = function()
+{
+ if ( this.CheckRedoState() )
+ {
+ // Go a step forward.
+ this._ApplyUndoLevel( ++this.CurrentIndex ) ;
+
+ FCK.Events.FireEvent( "OnSelectionChange" ) ;
+ }
+}
+
+FCKUndo._ApplyUndoLevel = function( level )
+{
+ var oData = this.SavedData[ level ] ;
+
+ if ( !oData )
+ return ;
+
+ // Update the editor contents with that step data.
+ if ( FCKBrowserInfo.IsIE )
+ {
+ if ( oData[1] && oData[1][1] )
+ FCK.SetInnerHtml( oData[1][1] ) ;
+ else
+ FCK.SetInnerHtml( oData[0] ) ;
+ }
+ else
+ FCK.EditorDocument.body.innerHTML = oData[0] ;
+
+ // Restore the selection
+ this._SelectBookmark( oData[1] ) ;
+
+ this.TypesCount = 0 ;
+ this.Changed = false ;
+ this.Typing = false ;
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckurlparams.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckurlparams.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckurlparams.js (revision 1015)
@@ -0,0 +1,39 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 the FCKURLParams object that is used to get all parameters
+ * passed by the URL QueryString (after the "?").
+ */
+
+// #### URLParams: holds all URL passed parameters (like ?Param1=Value1&Param2=Value2)
+var FCKURLParams = new Object() ;
+
+(function()
+{
+ var aParams = document.location.search.substr(1).split('&') ;
+ for ( var i = 0 ; i < aParams.length ; i++ )
+ {
+ var aParam = aParams[i].split('=') ;
+ var sParamName = decodeURIComponent( aParam[0] ) ;
+ var sParamValue = decodeURIComponent( aParam[1] ) ;
+
+ FCKURLParams[ sParamName ] = sParamValue ;
+ }
+})();
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml.js (revision 1015)
@@ -0,0 +1,460 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 the FCKXHtml object, responsible for the XHTML operations.
+ */
+
+var FCKXHtml = new Object() ;
+
+FCKXHtml.CurrentJobNum = 0 ;
+
+FCKXHtml.GetXHTML = function( node, includeNode, format )
+{
+ FCKDomTools.CheckAndRemovePaddingNode( node.ownerDocument, FCKConfig.EnterMode ) ;
+ FCKXHtmlEntities.Initialize() ;
+
+ // Set the correct entity to use for empty blocks.
+ this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
+
+ // Save the current IsDirty state. The XHTML processor may change the
+ // original HTML, dirtying it.
+ var bIsDirty = FCK.IsDirty() ;
+
+ // Special blocks are blocks of content that remain untouched during the
+ // process. It is used for SCRIPTs and STYLEs.
+ FCKXHtml.SpecialBlocks = new Array() ;
+
+ // Create the XML DOMDocument object.
+ this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
+
+ // Add a root element that holds all child nodes.
+ this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
+
+ FCKXHtml.CurrentJobNum++ ;
+
+// var dTimer = new Date() ;
+
+ if ( includeNode )
+ this._AppendNode( this.MainNode, node ) ;
+ else
+ this._AppendChildNodes( this.MainNode, node, false ) ;
+
+ // Get the resulting XHTML as a string.
+ var sXHTML = this._GetMainXmlString() ;
+
+// alert( 'Time: ' + ( ( ( new Date() ) - dTimer ) ) + ' ms' ) ;
+
+ this.XML = null ;
+
+ // Safari adds xmlns="http://www.w3.org/1999/xhtml" to the root node (#963)
+ if ( FCKBrowserInfo.IsSafari )
+ sXHTML = sXHTML.replace( /^/, '' ) ;
+
+ // Strip the "XHTML" root node.
+ sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
+
+ // Add a space in the tags with no closing tags, like ->
+ sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
+
+ if ( FCKConfig.ForceSimpleAmpersand )
+ sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
+
+ if ( format )
+ sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
+
+ // Now we put back the SpecialBlocks contents.
+ for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
+ {
+ var oRegex = new RegExp( '___FCKsi___' + i ) ;
+ sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
+ }
+
+ // Replace entities marker with the ampersand.
+ sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
+
+ // Restore the IsDirty state if it was not dirty.
+ if ( !bIsDirty )
+ FCK.ResetIsDirty() ;
+
+ FCKDomTools.EnforcePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
+ return sXHTML ;
+}
+
+FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
+{
+ try
+ {
+ if ( attributeValue == undefined || attributeValue == null )
+ attributeValue = '' ;
+ else if ( attributeValue.replace )
+ {
+ if ( FCKConfig.ForceSimpleAmpersand )
+ attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
+
+ // Entities must be replaced in the attribute values.
+ attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ;
+ }
+
+ // Create the attribute.
+ var oXmlAtt = this.XML.createAttribute( attributeName ) ;
+ oXmlAtt.value = attributeValue ;
+
+ // Set the attribute in the node.
+ xmlNode.attributes.setNamedItem( oXmlAtt ) ;
+ }
+ catch (e)
+ {}
+}
+
+FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
+{
+ var oNode = htmlNode.firstChild ;
+
+ while ( oNode )
+ {
+ this._AppendNode( xmlNode, oNode ) ;
+ oNode = oNode.nextSibling ;
+ }
+
+ // Trim block elements. This is also needed to avoid Firefox leaving extra
+ // BRs at the end of them.
+ if ( isBlockElement && htmlNode.tagName && htmlNode.tagName.toLowerCase() != 'pre' )
+ {
+ FCKDomTools.TrimNode( xmlNode ) ;
+
+ if ( FCKConfig.FillEmptyBlocks )
+ {
+ var lastChild = xmlNode.lastChild ;
+ if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName == 'br' )
+ this._AppendEntity( xmlNode, this._NbspEntity ) ;
+ }
+ }
+
+ // If the resulting node is empty.
+ if ( xmlNode.childNodes.length == 0 )
+ {
+ if ( isBlockElement && FCKConfig.FillEmptyBlocks )
+ {
+ this._AppendEntity( xmlNode, this._NbspEntity ) ;
+ return xmlNode ;
+ }
+
+ var sNodeName = xmlNode.nodeName ;
+
+ // Some inline elements are required to have something inside (span, strong, etc...).
+ if ( FCKListsLib.InlineChildReqElements[ sNodeName ] )
+ return null ;
+
+ // We can't use short representation of empty elements that are not marked
+ // as empty in th XHTML DTD.
+ if ( !FCKListsLib.EmptyElements[ sNodeName ] )
+ xmlNode.appendChild( this.XML.createTextNode('') ) ;
+ }
+
+ return xmlNode ;
+}
+
+FCKXHtml._AppendNode = function( xmlNode, htmlNode )
+{
+ if ( !htmlNode )
+ return false ;
+
+ switch ( htmlNode.nodeType )
+ {
+ // Element Node.
+ case 1 :
+ // If we detect a inside a in Gecko, turn it into a line break instead.
+ // This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
+ if ( FCKBrowserInfo.IsGecko
+ && htmlNode.tagName.toLowerCase() == 'br'
+ && htmlNode.parentNode.tagName.toLowerCase() == 'pre' )
+ {
+ var val = '\r' ;
+ if ( htmlNode == htmlNode.parentNode.firstChild )
+ val += '\r' ;
+ return FCKXHtml._AppendNode( xmlNode, this.XML.createTextNode( val ) ) ;
+ }
+
+ // Here we found an element that is not the real element, but a
+ // fake one (like the Flash placeholder image), so we must get the real one.
+ if ( htmlNode.getAttribute('_fckfakelement') )
+ return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
+
+ // Ignore bogus BR nodes in the DOM.
+ if ( FCKBrowserInfo.IsGecko &&
+ ( htmlNode.hasAttribute('_moz_editor_bogus_node') || htmlNode.getAttribute( 'type' ) == '_moz' ) )
+ return false ;
+
+ // This is for elements that are instrumental to FCKeditor and
+ // must be removed from the final HTML.
+ if ( htmlNode.getAttribute('_fcktemp') )
+ return false ;
+
+ // Get the element name.
+ var sNodeName = htmlNode.tagName.toLowerCase() ;
+
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // IE doens't include the scope name in the nodeName. So, add the namespace.
+ if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
+ sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ;
+ }
+ else
+ {
+ if ( sNodeName.StartsWith( 'fck:' ) )
+ sNodeName = sNodeName.Remove( 0,4 ) ;
+ }
+
+ // Check if the node name is valid, otherwise ignore this tag.
+ // If the nodeName starts with a slash, it is a orphan closing tag.
+ // On some strange cases, the nodeName is empty, even if the node exists.
+ if ( !FCKRegexLib.ElementName.test( sNodeName ) )
+ return false ;
+
+ // The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
+ // So here, the "mark" is checked... if the element is Ok, then mark it.
+ if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
+ return false ;
+
+ var oNode = this.XML.createElement( sNodeName ) ;
+
+ // Add all attributes.
+ FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
+
+ htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
+
+ // Tag specific processing.
+ var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
+
+ if ( oTagProcessor )
+ oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
+ else
+ oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ;
+
+ if ( !oNode )
+ return false ;
+
+ xmlNode.appendChild( oNode ) ;
+
+ break ;
+
+ // Text Node.
+ case 3 :
+ if ( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) )
+ return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
+ return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
+
+ // Comment
+ case 8 :
+ // IE catches the as a comment, but it has no
+ // innerHTML, so we can catch it, and ignore it.
+ if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
+ break ;
+
+ try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
+ catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
+ break ;
+
+ // Unknown Node type.
+ default :
+ xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
+ break ;
+ }
+ return true ;
+}
+
+// Append an item to the SpecialBlocks array and returns the tag to be used.
+FCKXHtml._AppendSpecialItem = function( item )
+{
+ return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ;
+}
+
+FCKXHtml._AppendEntity = function( xmlNode, entity )
+{
+ xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
+}
+
+FCKXHtml._AppendTextNode = function( targetNode, textValue )
+{
+ var bHadText = textValue.length > 0 ;
+ if ( bHadText )
+ targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
+ return bHadText ;
+}
+
+// Retrieves a entity (internal format) for a given character.
+function FCKXHtml_GetEntity( character )
+{
+ // We cannot simply place the entities in the text, because the XML parser
+ // will translate & to &. So we use a temporary marker which is replaced
+ // in the end of the processing.
+ var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
+ return '#?-:' + sEntity + ';' ;
+}
+
+// An object that hold tag specific operations.
+FCKXHtml.TagProcessors =
+{
+ img : function( node, htmlNode )
+ {
+ // The "ALT" attribute is required in XHTML.
+ if ( ! node.attributes.getNamedItem( 'alt' ) )
+ FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
+
+ var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
+ if ( sSavedUrl != null )
+ FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
+
+ return node ;
+ },
+
+ a : function( node, htmlNode )
+ {
+ // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
+ if ( htmlNode.innerHTML.Trim().length == 0 && !htmlNode.name )
+ return false ;
+
+ var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
+ if ( sSavedUrl != null )
+ FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
+
+
+ // Anchors with content has been marked with an additional class, now we must remove it.
+ if ( FCKBrowserInfo.IsIE )
+ {
+ // Buggy IE, doesn't copy the name of changed anchors.
+ if ( htmlNode.name )
+ FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
+ }
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
+
+ return node ;
+ },
+
+ script : function( node, htmlNode )
+ {
+ // The "TYPE" attribute is required in XHTML.
+ if ( ! node.attributes.getNamedItem( 'type' ) )
+ FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
+
+ node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
+
+ return node ;
+ },
+
+ style : function( node, htmlNode )
+ {
+ // The "TYPE" attribute is required in XHTML.
+ if ( ! node.attributes.getNamedItem( 'type' ) )
+ FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
+
+ var cssText = htmlNode.innerHTML ;
+ if ( FCKBrowserInfo.IsIE ) // Bug #403 : IE always appends a \r\n to the beginning of StyleNode.innerHTML
+ cssText = cssText.replace( /^(\r\n|\n|\r)/, '' ) ;
+
+ node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( cssText ) ) ) ;
+
+ return node ;
+ },
+
+ pre : function ( node, htmlNode )
+ {
+ for ( var i = 0 ; i < htmlNode.childNodes.length ; i++ )
+ {
+ var item = htmlNode.childNodes[i] ;
+ var val = item.nodeValue ;
+ if ( item.nodeType == 3 && i == 0 )
+ node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( '\r\n' + val ) ) ) ;
+ else
+ FCKXHtml._AppendNode( node, item ) ;
+ }
+ return node ;
+ },
+
+ title : function( node, htmlNode )
+ {
+ node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
+
+ return node ;
+ },
+
+ // Fix nested and .
+ ol : function( node, htmlNode, targetNode )
+ {
+ if ( htmlNode.innerHTML.Trim().length == 0 )
+ return false ;
+
+ var ePSibling = targetNode.lastChild ;
+
+ if ( ePSibling && ePSibling.nodeType == 3 )
+ ePSibling = ePSibling.previousSibling ;
+
+ if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
+ {
+ htmlNode._fckxhtmljob = null ;
+ FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
+ return false ;
+ }
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
+
+ return node ;
+ },
+
+ span : function( node, htmlNode )
+ {
+ // Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
+ if ( htmlNode.innerHTML.length == 0 )
+ return false ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
+
+ return node ;
+ },
+
+ // IE loses contents of iframes, and Gecko does give it back HtmlEncoded
+ // Note: Opera does lose the content and doesn't provide it in the innerHTML string
+ iframe : function( node, htmlNode )
+ {
+ var sHtml = htmlNode.innerHTML ;
+
+ // Gecko does give back the encoded html
+ if ( FCKBrowserInfo.IsGecko )
+ sHtml = FCKTools.HTMLDecode( sHtml );
+
+ // Remove the saved urls here as the data won't be processed as nodes
+ sHtml = sHtml.replace( /\s_fcksavedurl="[^"]*"/g, '' ) ;
+
+ node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( sHtml ) ) ) ;
+
+ return node ;
+ },
+
+ body : function( node, htmlNode )
+ {
+ node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
+ // Remove spellchecker attributes added for Firefox when converting to HTML code (Bug #1351).
+ node.removeAttribute( 'spellcheck' ) ;
+ return node ;
+ }
+} ;
+
+FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_gecko.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_gecko.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_gecko.js (revision 1015)
@@ -0,0 +1,105 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 the FCKXHtml object, responsible for the XHTML operations.
+ * Gecko specific.
+ */
+
+FCKXHtml._GetMainXmlString = function()
+{
+ // Create the XMLSerializer.
+ var oSerializer = new XMLSerializer() ;
+
+ // Return the serialized XML as a string.
+ return oSerializer.serializeToString( this.MainNode ) ;
+}
+
+FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node )
+{
+ var aAttributes = htmlNode.attributes ;
+
+ for ( var n = 0 ; n < aAttributes.length ; n++ )
+ {
+ var oAttribute = aAttributes[n] ;
+
+ if ( oAttribute.specified )
+ {
+ var sAttName = oAttribute.nodeName.toLowerCase() ;
+ var sAttValue ;
+
+ // Ignore any attribute starting with "_fck".
+ if ( sAttName.StartsWith( '_fck' ) )
+ continue ;
+ // There is a bug in Mozilla that returns '_moz_xxx' attributes as specified.
+ else if ( sAttName.indexOf( '_moz' ) == 0 )
+ continue ;
+ // There are one cases (on Gecko) when the oAttribute.nodeValue must be used:
+ // - for the "class" attribute
+ else if ( sAttName == 'class' )
+ {
+ sAttValue = oAttribute.nodeValue.replace( FCKRegexLib.FCK_Class, '' ) ;
+ if ( sAttValue.length == 0 )
+ continue ;
+ }
+ // XHTML doens't support attribute minimization like "CHECKED". It must be transformed to checked="checked".
+ else if ( oAttribute.nodeValue === true )
+ sAttValue = sAttName ;
+ else
+ sAttValue = htmlNode.getAttribute( sAttName, 2 ) ; // We must use getAttribute to get it exactly as it is defined.
+
+ this._AppendAttribute( node, sAttName, sAttValue ) ;
+ }
+ }
+}
+
+if ( FCKBrowserInfo.IsOpera )
+{
+ // Opera moves the element outside head (#1166).
+
+ // Save a reference to the XML node, so we can use it for
+ // orphan s.
+ FCKXHtml.TagProcessors['head'] = function( node, htmlNode )
+ {
+ FCKXHtml.XML._HeadElement = node ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
+
+ return node ;
+ }
+
+ // Check whether a element is outside , and move it to the
+ // proper place.
+ FCKXHtml.TagProcessors['meta'] = function( node, htmlNode, xmlNode )
+ {
+ if ( htmlNode.parentNode.nodeName.toLowerCase() != 'head' )
+ {
+ var headElement = FCKXHtml.XML._HeadElement ;
+
+ if ( headElement && xmlNode != headElement )
+ {
+ delete htmlNode._fckxhtmljob ;
+ FCKXHtml._AppendNode( headElement, htmlNode ) ;
+ return null ;
+ }
+ }
+
+ return node ;
+ }
+}
Index: /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_ie.js
===================================================================
--- /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_ie.js (revision 1015)
+++ /FCKeditor/tags/2.5 Beta/editor/_source/internals/fckxhtml_ie.js (revision 1015)
@@ -0,0 +1,208 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 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 the FCKXHtml object, responsible for the XHTML operations.
+ * IE specific.
+ */
+
+FCKXHtml._GetMainXmlString = function()
+{
+ return this.MainNode.xml ;
+}
+
+FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node, nodeName )
+{
+ var aAttributes = htmlNode.attributes ;
+
+ for ( var n = 0 ; n < aAttributes.length ; n++ )
+ {
+ var oAttribute = aAttributes[n] ;
+
+ if ( oAttribute.specified )
+ {
+ var sAttName = oAttribute.nodeName.toLowerCase() ;
+ var sAttValue ;
+
+ // Ignore any attribute starting with "_fck".
+ if ( sAttName.StartsWith( '_fck' ) )
+ continue ;
+ // The following must be done because of a bug on IE regarding the style
+ // attribute. It returns "null" for the nodeValue.
+ else if ( sAttName == 'style' )
+ {
+ var data = FCKTools.ProtectFormStyles( htmlNode ) ;
+ sAttValue = htmlNode.style.cssText.replace( FCKRegexLib.StyleProperties, FCKTools.ToLowerCase ) ;
+ FCKTools.RestoreFormStyles( htmlNode, data ) ;
+ }
+ // There are two cases when the oAttribute.nodeValue must be used:
+ // - for the "class" attribute
+ // - for events attributes (on IE only).
+ else if ( sAttName == 'class' )
+ {
+ sAttValue = oAttribute.nodeValue.replace( FCKRegexLib.FCK_Class, '' ) ;
+ if ( sAttValue.length == 0 )
+ continue ;
+ }
+ else if ( sAttName.indexOf('on') == 0 )
+ sAttValue = oAttribute.nodeValue ;
+ else if ( nodeName == 'body' && sAttName == 'contenteditable' )
+ continue ;
+ // XHTML doens't support attribute minimization like "CHECKED". It must be transformed to checked="checked".
+ else if ( oAttribute.nodeValue === true )
+ sAttValue = sAttName ;
+ else
+ {
+ // We must use getAttribute to get it exactly as it is defined.
+ // There are some rare cases that IE throws an error here, so we must try/catch.
+ try
+ {
+ sAttValue = htmlNode.getAttribute( sAttName, 2 ) ;
+ }
+ catch (e) {}
+ }
+ this._AppendAttribute( node, sAttName, sAttValue || oAttribute.nodeValue ) ;
+ }
+ }
+}
+
+FCKXHtml.TagProcessors['meta'] = function( node, htmlNode )
+{
+ var oHttpEquiv = node.attributes.getNamedItem( 'http-equiv' ) ;
+
+ if ( oHttpEquiv == null || oHttpEquiv.value.length == 0 )
+ {
+ // Get the http-equiv value from the outerHTML.
+ var sHttpEquiv = htmlNode.outerHTML.match( FCKRegexLib.MetaHttpEquiv ) ;
+
+ if ( sHttpEquiv )
+ {
+ sHttpEquiv = sHttpEquiv[1] ;
+ FCKXHtml._AppendAttribute( node, 'http-equiv', sHttpEquiv ) ;
+ }
+ }
+
+ return node ;
+}
+
+// IE automatically changes tags to .
+FCKXHtml.TagProcessors['font'] = function( node, htmlNode )
+{
+ if ( node.attributes.length == 0 )
+ node = FCKXHtml.XML.createDocumentFragment() ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
+
+ return node ;
+}
+
+// IE doens't see the value attribute as an attribute for the tag.
+FCKXHtml.TagProcessors['input'] = function( node, htmlNode )
+{
+ if ( htmlNode.name )
+ FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
+
+ if ( htmlNode.value && !node.attributes.getNamedItem( 'value' ) )
+ FCKXHtml._AppendAttribute( node, 'value', htmlNode.value ) ;
+
+ if ( !node.attributes.getNamedItem( 'type' ) )
+ FCKXHtml._AppendAttribute( node, 'type', 'text' ) ;
+
+ return node ;
+}
+
+// IE ignores the "SELECTED" attribute so we must add it manually.
+FCKXHtml.TagProcessors['option'] = function( node, htmlNode )
+{
+ if ( htmlNode.selected && !node.attributes.getNamedItem( 'selected' ) )
+ FCKXHtml._AppendAttribute( node, 'selected', 'selected' ) ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
+
+ return node ;
+}
+
+// IE ignores the "COORDS" and "SHAPE" attribute so we must add it manually.
+FCKXHtml.TagProcessors['area'] = function( node, htmlNode )
+{
+ if ( ! node.attributes.getNamedItem( 'coords' ) )
+ {
+ var sCoords = htmlNode.getAttribute( 'coords', 2 ) ;
+ if ( sCoords && sCoords != '0,0,0' )
+ FCKXHtml._AppendAttribute( node, 'coords', sCoords ) ;
+ }
+
+ if ( ! node.attributes.getNamedItem( 'shape' ) )
+ {
+ var sShape = htmlNode.getAttribute( 'shape', 2 ) ;
+ if ( sShape && sShape.length > 0 )
+ FCKXHtml._AppendAttribute( node, 'shape', sShape.toLowerCase() ) ;
+ }
+
+ return node ;
+}
+
+FCKXHtml.TagProcessors['label'] = function( node, htmlNode )
+{
+ if ( htmlNode.htmlFor.length > 0 )
+ FCKXHtml._AppendAttribute( node, 'for', htmlNode.htmlFor ) ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
+
+ return node ;
+}
+
+FCKXHtml.TagProcessors['form'] = function( node, htmlNode )
+{
+ if ( htmlNode.acceptCharset && htmlNode.acceptCharset.length > 0 && htmlNode.acceptCharset != 'UNKNOWN' )
+ FCKXHtml._AppendAttribute( node, 'accept-charset', htmlNode.acceptCharset ) ;
+
+ // IE has a bug and htmlNode.attributes['name'].specified=false if there is
+ // no element with id="name" inside the form (#360 and SF-BUG-1155726).
+ var nameAtt = htmlNode.attributes['name'] ;
+
+ if ( nameAtt && nameAtt.value.length > 0 )
+ FCKXHtml._AppendAttribute( node, 'name', nameAtt.value ) ;
+
+ node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
+
+ return node ;
+}
+
+// IE doens't hold the name attribute as an attribute for the