initial commit

This commit is contained in:
Siwat Sirichai 2025-06-08 16:22:20 +07:00
commit 252dac3143
1516 changed files with 694271 additions and 0 deletions

View file

@ -0,0 +1,209 @@
/*
* 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 ==
*
* FCKContextMenu Class: renders an control a context menu.
*/
var FCKContextMenu = function( parentWindow, langDir )
{
this.CtrlDisable = false ;
var oPanel = this._Panel = new FCKPanel( parentWindow ) ;
oPanel.AppendStyleSheet( FCKConfig.SkinPath + 'fck_editor.css' ) ;
oPanel.IsContextMenu = true ;
// The FCKTools.DisableSelection doesn't seems to work to avoid dragging of the icons in Mozilla
// so we stop the start of the dragging
if ( FCKBrowserInfo.IsGecko )
oPanel.Document.addEventListener( 'draggesture', function(e) {e.preventDefault(); return false;}, true ) ;
var oMenuBlock = this._MenuBlock = new FCKMenuBlock() ;
oMenuBlock.Panel = oPanel ;
oMenuBlock.OnClick = FCKTools.CreateEventListener( FCKContextMenu_MenuBlock_OnClick, this ) ;
this._Redraw = true ;
}
FCKContextMenu.prototype.SetMouseClickWindow = function( mouseClickWindow )
{
if ( !FCKBrowserInfo.IsIE )
{
this._Document = mouseClickWindow.document ;
if ( FCKBrowserInfo.IsOpera && !( 'oncontextmenu' in document.createElement('foo') ) )
{
this._Document.addEventListener( 'mousedown', FCKContextMenu_Document_OnMouseDown, false ) ;
this._Document.addEventListener( 'mouseup', FCKContextMenu_Document_OnMouseUp, false ) ;
}
this._Document.addEventListener( 'contextmenu', FCKContextMenu_Document_OnContextMenu, false ) ;
}
}
FCKContextMenu.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled )
{
var oItem = this._MenuBlock.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled) ;
this._Redraw = true ;
return oItem ;
}
FCKContextMenu.prototype.AddSeparator = function()
{
this._MenuBlock.AddSeparator() ;
this._Redraw = true ;
}
FCKContextMenu.prototype.RemoveAllItems = function()
{
this._MenuBlock.RemoveAllItems() ;
this._Redraw = true ;
}
FCKContextMenu.prototype.AttachToElement = function( element )
{
if ( FCKBrowserInfo.IsIE )
FCKTools.AddEventListenerEx( element, 'contextmenu', FCKContextMenu_AttachedElement_OnContextMenu, this ) ;
else
element._FCKContextMenu = this ;
}
function FCKContextMenu_Document_OnContextMenu( e )
{
var el = e.target ;
while ( el )
{
if ( el._FCKContextMenu )
{
if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
return true ;
FCKTools.CancelEvent( e ) ;
FCKContextMenu_AttachedElement_OnContextMenu( e, el._FCKContextMenu, el ) ;
return false ;
}
el = el.parentNode ;
}
return true ;
}
var FCKContextMenu_OverrideButton ;
function FCKContextMenu_Document_OnMouseDown( e )
{
if( !e || e.button != 2 )
return false ;
var el = e.target ;
while ( el )
{
if ( el._FCKContextMenu )
{
if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
return true ;
var overrideButton = FCKContextMenu_OverrideButton ;
if( !overrideButton )
{
var doc = e.target.ownerDocument ;
overrideButton = FCKContextMenu_OverrideButton = doc.createElement('input') ;
overrideButton.type = 'button' ;
var buttonHolder = doc.createElement('p') ;
doc.body.appendChild( buttonHolder ) ;
buttonHolder.appendChild( overrideButton ) ;
}
overrideButton.style.cssText = 'position:absolute;top:' + ( e.clientY - 2 ) +
'px;left:' + ( e.clientX - 2 ) +
'px;width:5px;height:5px;opacity:0.01' ;
}
el = el.parentNode ;
}
return false ;
}
function FCKContextMenu_Document_OnMouseUp( e )
{
var overrideButton = FCKContextMenu_OverrideButton ;
if ( overrideButton )
{
var parent = overrideButton.parentNode ;
parent.parentNode.removeChild( parent ) ;
FCKContextMenu_OverrideButton = undefined ;
if( e && e.button == 2 )
{
FCKContextMenu_Document_OnContextMenu( e ) ;
return false ;
}
}
}
function FCKContextMenu_AttachedElement_OnContextMenu( ev, fckContextMenu, el )
{
if ( fckContextMenu.CtrlDisable && ( ev.ctrlKey || ev.metaKey ) )
return true ;
var eTarget = el || this ;
if ( fckContextMenu.OnBeforeOpen )
fckContextMenu.OnBeforeOpen.call( fckContextMenu, eTarget ) ;
if ( fckContextMenu._MenuBlock.Count() == 0 )
return false ;
if ( fckContextMenu._Redraw )
{
fckContextMenu._MenuBlock.Create( fckContextMenu._Panel.MainNode ) ;
fckContextMenu._Redraw = false ;
}
// This will avoid that the content of the context menu can be dragged in IE
// as the content of the panel is recreated we need to do it every time
FCKTools.DisableSelection( fckContextMenu._Panel.Document.body ) ;
var x = 0 ;
var y = 0 ;
if ( FCKBrowserInfo.IsIE )
{
x = ev.screenX ;
y = ev.screenY ;
}
else if ( FCKBrowserInfo.IsSafari )
{
x = ev.clientX ;
y = ev.clientY ;
}
else
{
x = ev.pageX ;
y = ev.pageY ;
}
fckContextMenu._Panel.Show( x, y, ev.currentTarget || null ) ;
return false ;
}
function FCKContextMenu_MenuBlock_OnClick( menuItem, contextMenu )
{
contextMenu._Panel.Hide() ;
FCKTools.RunFunction( contextMenu.OnItemClick, contextMenu, menuItem ) ;
}

View file

@ -0,0 +1,119 @@
/*
* 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 ==
*
* The Data Processor is responsible for transforming the input and output data
* in the editor. For more info:
* http://dev.fckeditor.net/wiki/Components/DataProcessor
*
* The default implementation offers the base XHTML compatibility features of
* FCKeditor. Further Data Processors may be implemented for other purposes.
*
*/
var FCKDataProcessor = function()
{}
FCKDataProcessor.prototype =
{
/*
* Returns a string representing the HTML format of "data". The returned
* value will be loaded in the editor.
* The HTML must be from <html> to </html>, including <head>, <body> and
* eventually the DOCTYPE.
* Note: HTML comments may already be part of the data because of the
* pre-processing made with ProtectedSource.
* @param {String} data The data to be converted in the
* DataProcessor specific format.
*/
ConvertToHtml : function( data )
{
// The default data processor must handle two different cases depending
// on the FullPage setting. Custom Data Processors will not be
// compatible with FullPage, much probably.
if ( FCKConfig.FullPage )
{
// Save the DOCTYPE.
FCK.DocTypeDeclaration = data.match( FCKRegexLib.DocTypeTag ) ;
// Check if the <body> tag is available.
if ( !FCKRegexLib.HasBodyTag.test( data ) )
data = '<body>' + data + '</body>' ;
// Check if the <html> tag is available.
if ( !FCKRegexLib.HtmlOpener.test( data ) )
data = '<html dir="' + FCKConfig.ContentLangDirection + '">' + data + '</html>' ;
// Check if the <head> tag is available.
if ( !FCKRegexLib.HeadOpener.test( data ) )
data = data.replace( FCKRegexLib.HtmlOpener, '$&<head><title></title></head>' ) ;
return data ;
}
else
{
var html =
FCKConfig.DocType +
'<html dir="' + FCKConfig.ContentLangDirection + '"' ;
// On IE, if you are using a DOCTYPE different of HTML 4 (like
// XHTML), you must force the vertical scroll to show, otherwise
// the horizontal one may appear when the page needs vertical scrolling.
// TODO : Check it with IE7 and make it IE6- if it is the case.
if ( FCKBrowserInfo.IsIE && FCKConfig.DocType.length > 0 && !FCKRegexLib.Html4DocType.test( FCKConfig.DocType ) )
html += ' style="overflow-y: scroll"' ;
html += '><head><title></title></head>' +
'<body' + FCKConfig.GetBodyAttributes() + '>' +
data +
'</body></html>' ;
return html ;
}
},
/*
* Converts a DOM (sub-)tree to a string in the data format.
* @param {Object} rootNode The node that contains the DOM tree to be
* converted to the data format.
* @param {Boolean} excludeRoot Indicates that the root node must not
* be included in the conversion, only its children.
* @param {Boolean} format Indicates that the data must be formatted
* for human reading. Not all Data Processors may provide it.
*/
ConvertToDataFormat : function( rootNode, excludeRoot, ignoreIfEmptyParagraph, format )
{
var data = FCKXHtml.GetXHTML( rootNode, !excludeRoot, format ) ;
if ( ignoreIfEmptyParagraph && FCKRegexLib.EmptyOutParagraph.test( data ) )
return '' ;
return data ;
},
/*
* Makes any necessary changes to a piece of HTML for insertion in the
* editor selection position.
* @param {String} html The HTML to be fixed.
*/
FixHtml : function( html )
{
return html ;
}
} ;

View file

@ -0,0 +1,46 @@
/*
* 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 is a generic Document Fragment object. It is not intended to provide
* the W3C implementation, but is a way to fix the missing of a real Document
* Fragment in IE (where document.createDocumentFragment() returns a normal
* document instead), giving a standard interface for it.
* (IE Implementation)
*/
var FCKDocumentFragment = function( parentDocument, baseDocFrag )
{
this.RootNode = baseDocFrag || parentDocument.createDocumentFragment() ;
}
FCKDocumentFragment.prototype =
{
// Append the contents of this Document Fragment to another element.
AppendTo : function( targetNode )
{
targetNode.appendChild( this.RootNode ) ;
},
InsertAfterNode : function( existingNode )
{
FCKDomTools.InsertAfterNode( existingNode, this.RootNode ) ;
}
}

View file

@ -0,0 +1,58 @@
/*
* 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 is a generic Document Fragment object. It is not intended to provide
* the W3C implementation, but is a way to fix the missing of a real Document
* Fragment in IE (where document.createDocumentFragment() returns a normal
* document instead), giving a standard interface for it.
* (IE Implementation)
*/
var FCKDocumentFragment = function( parentDocument )
{
this._Document = parentDocument ;
this.RootNode = parentDocument.createElement( 'div' ) ;
}
// Append the contents of this Document Fragment to another node.
FCKDocumentFragment.prototype =
{
AppendTo : function( targetNode )
{
FCKDomTools.MoveChildren( this.RootNode, targetNode ) ;
},
AppendHtml : function( html )
{
var eTmpDiv = this._Document.createElement( 'div' ) ;
eTmpDiv.innerHTML = html ;
FCKDomTools.MoveChildren( eTmpDiv, this.RootNode ) ;
},
InsertAfterNode : function( existingNode )
{
var eRoot = this.RootNode ;
var eLast ;
while( ( eLast = eRoot.lastChild ) )
FCKDomTools.InsertAfterNode( existingNode, eRoot.removeChild( eLast ) ) ;
}
} ;

View file

@ -0,0 +1,905 @@
/*
* 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 ==
*
* Class for working with a selection range, much like the W3C DOM Range, but
* it is not intended to be an implementation of the W3C interface.
*/
var FCKDomRange = function( sourceWindow )
{
this.Window = sourceWindow ;
this._Cache = {} ;
}
FCKDomRange.prototype =
{
_UpdateElementInfo : function()
{
var innerRange = this._Range ;
if ( !innerRange )
this.Release( true ) ;
else
{
// For text nodes, the node itself is the StartNode.
var eStart = innerRange.startContainer ;
var eEnd = innerRange.endContainer ;
var oElementPath = new FCKElementPath( eStart ) ;
this.StartNode = eStart.nodeType == 3 ? eStart : eStart.childNodes[ innerRange.startOffset ] ;
this.StartContainer = eStart ;
this.StartBlock = oElementPath.Block ;
this.StartBlockLimit = oElementPath.BlockLimit ;
if ( eStart != eEnd )
oElementPath = new FCKElementPath( eEnd ) ;
// The innerRange.endContainer[ innerRange.endOffset ] is not
// usually part of the range, but the marker for the range end. So,
// let's get the previous available node as the real end.
var eEndNode = eEnd ;
if ( innerRange.endOffset == 0 )
{
while ( eEndNode && !eEndNode.previousSibling )
eEndNode = eEndNode.parentNode ;
if ( eEndNode )
eEndNode = eEndNode.previousSibling ;
}
else if ( eEndNode.nodeType == 1 )
eEndNode = eEndNode.childNodes[ innerRange.endOffset - 1 ] ;
this.EndNode = eEndNode ;
this.EndContainer = eEnd ;
this.EndBlock = oElementPath.Block ;
this.EndBlockLimit = oElementPath.BlockLimit ;
}
this._Cache = {} ;
},
CreateRange : function()
{
return new FCKW3CRange( this.Window.document ) ;
},
DeleteContents : function()
{
if ( this._Range )
{
this._Range.deleteContents() ;
this._UpdateElementInfo() ;
}
},
ExtractContents : function()
{
if ( this._Range )
{
var docFrag = this._Range.extractContents() ;
this._UpdateElementInfo() ;
return docFrag ;
}
},
CheckIsCollapsed : function()
{
if ( this._Range )
return this._Range.collapsed ;
},
Collapse : function( toStart )
{
if ( this._Range )
this._Range.collapse( toStart ) ;
this._UpdateElementInfo() ;
},
Clone : function()
{
var oClone = FCKTools.CloneObject( this ) ;
if ( this._Range )
oClone._Range = this._Range.cloneRange() ;
return oClone ;
},
MoveToNodeContents : function( targetNode )
{
if ( !this._Range )
this._Range = this.CreateRange() ;
this._Range.selectNodeContents( targetNode ) ;
this._UpdateElementInfo() ;
},
MoveToElementStart : function( targetElement )
{
this.SetStart(targetElement,1) ;
this.SetEnd(targetElement,1) ;
},
// Moves to the first editing point inside a element. For example, in a
// element tree like "<p><b><i></i></b> Text</p>", the start editing point
// is "<p><b><i>^</i></b> Text</p>" (inside <i>).
MoveToElementEditStart : function( targetElement )
{
var child ;
while ( ( child = targetElement.firstChild ) && child.nodeType == 1 && FCKListsLib.EmptyElements[ child.nodeName.toLowerCase() ] == null )
targetElement = child ;
this.MoveToElementStart( targetElement ) ;
},
InsertNode : function( node )
{
if ( this._Range )
this._Range.insertNode( node ) ;
},
CheckIsEmpty : function()
{
if ( this.CheckIsCollapsed() )
return true ;
// Inserts the contents of the range in a div tag.
var eToolDiv = this.Window.document.createElement( 'div' ) ;
this._Range.cloneContents().AppendTo( eToolDiv ) ;
FCKDomTools.TrimNode( eToolDiv ) ;
return ( eToolDiv.innerHTML.length == 0 ) ;
},
/**
* Checks if the start boundary of the current range is "visually" (like a
* selection caret) at the beginning of the block. It means that some
* things could be brefore the range, like spaces or empty inline elements,
* but it would still be considered at the beginning of the block.
*/
CheckStartOfBlock : function()
{
var cache = this._Cache ;
var bIsStartOfBlock = cache.IsStartOfBlock ;
if ( bIsStartOfBlock != undefined )
return bIsStartOfBlock ;
// Take the block reference.
var block = this.StartBlock || this.StartBlockLimit ;
var container = this._Range.startContainer ;
var offset = this._Range.startOffset ;
var currentNode ;
if ( offset > 0 )
{
// First, check the start container. If it is a text node, get the
// substring of the node value before the range offset.
if ( container.nodeType == 3 )
{
var textValue = container.nodeValue.substr( 0, offset ).Trim() ;
// If we have some text left in the container, we are not at
// the end for the block.
if ( textValue.length != 0 )
return cache.IsStartOfBlock = false ;
}
else
currentNode = container.childNodes[ offset - 1 ] ;
}
// We'll not have a currentNode if the container was a text node, or
// the offset is zero.
if ( !currentNode )
currentNode = FCKDomTools.GetPreviousSourceNode( container, true, null, block ) ;
while ( currentNode )
{
switch ( currentNode.nodeType )
{
case 1 :
// It's not an inline element.
if ( !FCKListsLib.InlineChildReqElements[ currentNode.nodeName.toLowerCase() ] )
return cache.IsStartOfBlock = false ;
break ;
case 3 :
// It's a text node with real text.
if ( currentNode.nodeValue.Trim().length > 0 )
return cache.IsStartOfBlock = false ;
}
currentNode = FCKDomTools.GetPreviousSourceNode( currentNode, false, null, block ) ;
}
return cache.IsStartOfBlock = true ;
},
/**
* Checks if the end boundary of the current range is "visually" (like a
* selection caret) at the end of the block. It means that some things
* could be after the range, like spaces, empty inline elements, or a
* single <br>, but it would still be considered at the end of the block.
*/
CheckEndOfBlock : function( refreshSelection )
{
var isEndOfBlock = this._Cache.IsEndOfBlock ;
if ( isEndOfBlock != undefined )
return isEndOfBlock ;
// Take the block reference.
var block = this.EndBlock || this.EndBlockLimit ;
var container = this._Range.endContainer ;
var offset = this._Range.endOffset ;
var currentNode ;
// First, check the end container. If it is a text node, get the
// substring of the node value after the range offset.
if ( container.nodeType == 3 )
{
var textValue = container.nodeValue ;
if ( offset < textValue.length )
{
textValue = textValue.substr( offset ) ;
// If we have some text left in the container, we are not at
// the end for the block.
if ( textValue.Trim().length != 0 )
return this._Cache.IsEndOfBlock = false ;
}
}
else
currentNode = container.childNodes[ offset ] ;
// We'll not have a currentNode if the container was a text node, of
// the offset is out the container children limits (after it probably).
if ( !currentNode )
currentNode = FCKDomTools.GetNextSourceNode( container, true, null, block ) ;
var hadBr = false ;
while ( currentNode )
{
switch ( currentNode.nodeType )
{
case 1 :
var nodeName = currentNode.nodeName.toLowerCase() ;
// It's an inline element.
if ( FCKListsLib.InlineChildReqElements[ nodeName ] )
break ;
// It is the first <br> found.
if ( nodeName == 'br' && !hadBr )
{
hadBr = true ;
break ;
}
return this._Cache.IsEndOfBlock = false ;
case 3 :
// It's a text node with real text.
if ( currentNode.nodeValue.Trim().length > 0 )
return this._Cache.IsEndOfBlock = false ;
}
currentNode = FCKDomTools.GetNextSourceNode( currentNode, false, null, block ) ;
}
if ( refreshSelection )
this.Select() ;
return this._Cache.IsEndOfBlock = true ;
},
// This is an "intrusive" way to create a bookmark. It includes <span> tags
// in the range boundaries. The advantage of it is that it is possible to
// handle DOM mutations when moving back to the bookmark.
// Attention: the inclusion of nodes in the DOM is a design choice and
// should not be changed as there are other points in the code that may be
// using those nodes to perform operations. See GetBookmarkNode.
// For performance, includeNodes=true if intended to SelectBookmark.
CreateBookmark : function( includeNodes )
{
// Create the bookmark info (random IDs).
var oBookmark =
{
StartId : (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'S',
EndId : (new Date()).valueOf() + Math.floor(Math.random()*1000) + 'E'
} ;
var oDoc = this.Window.document ;
var eStartSpan ;
var eEndSpan ;
var oClone ;
// For collapsed ranges, add just the start marker.
if ( !this.CheckIsCollapsed() )
{
eEndSpan = oDoc.createElement( 'span' ) ;
eEndSpan.style.display = 'none' ;
eEndSpan.id = oBookmark.EndId ;
eEndSpan.setAttribute( '_fck_bookmark', true ) ;
// For IE, it must have something inside, otherwise it may be
// removed during DOM operations.
// if ( FCKBrowserInfo.IsIE )
eEndSpan.innerHTML = '&nbsp;' ;
oClone = this.Clone() ;
oClone.Collapse( false ) ;
oClone.InsertNode( eEndSpan ) ;
}
eStartSpan = oDoc.createElement( 'span' ) ;
eStartSpan.style.display = 'none' ;
eStartSpan.id = oBookmark.StartId ;
eStartSpan.setAttribute( '_fck_bookmark', true ) ;
// For IE, it must have something inside, otherwise it may be removed
// during DOM operations.
// if ( FCKBrowserInfo.IsIE )
eStartSpan.innerHTML = '&nbsp;' ;
oClone = this.Clone() ;
oClone.Collapse( true ) ;
oClone.InsertNode( eStartSpan ) ;
if ( includeNodes )
{
oBookmark.StartNode = eStartSpan ;
oBookmark.EndNode = eEndSpan ;
}
// Update the range position.
if ( eEndSpan )
{
this.SetStart( eStartSpan, 4 ) ;
this.SetEnd( eEndSpan, 3 ) ;
}
else
this.MoveToPosition( eStartSpan, 4 ) ;
return oBookmark ;
},
// This one should be a part of a hypothetic "bookmark" object.
GetBookmarkNode : function( bookmark, start )
{
var doc = this.Window.document ;
if ( start )
return bookmark.StartNode || doc.getElementById( bookmark.StartId ) ;
else
return bookmark.EndNode || doc.getElementById( bookmark.EndId ) ;
},
MoveToBookmark : function( bookmark, preserveBookmark )
{
var eStartSpan = this.GetBookmarkNode( bookmark, true ) ;
var eEndSpan = this.GetBookmarkNode( bookmark, false ) ;
this.SetStart( eStartSpan, 3 ) ;
if ( !preserveBookmark )
FCKDomTools.RemoveNode( eStartSpan ) ;
// If collapsed, the end span will not be available.
if ( eEndSpan )
{
this.SetEnd( eEndSpan, 3 ) ;
if ( !preserveBookmark )
FCKDomTools.RemoveNode( eEndSpan ) ;
}
else
this.Collapse( true ) ;
this._UpdateElementInfo() ;
},
// Non-intrusive bookmark algorithm
CreateBookmark2 : function()
{
// If there is no range then get out of here.
// It happens on initial load in Safari #962 and if the editor it's hidden also in Firefox
if ( ! this._Range )
return { "Start" : 0, "End" : 0 } ;
// First, we record down the offset values
var bookmark =
{
"Start" : [ this._Range.startOffset ],
"End" : [ this._Range.endOffset ]
} ;
// Since we're treating the document tree as normalized, we need to backtrack the text lengths
// of previous text nodes into the offset value.
var curStart = this._Range.startContainer.previousSibling ;
var curEnd = this._Range.endContainer.previousSibling ;
// Also note that the node that we use for "address base" would change during backtracking.
var addrStart = this._Range.startContainer ;
var addrEnd = this._Range.endContainer ;
while ( curStart && curStart.nodeType == 3 )
{
bookmark.Start[0] += curStart.length ;
addrStart = curStart ;
curStart = curStart.previousSibling ;
}
while ( curEnd && curEnd.nodeType == 3 )
{
bookmark.End[0] += curEnd.length ;
addrEnd = curEnd ;
curEnd = curEnd.previousSibling ;
}
// If the object pointed to by the startOffset and endOffset are text nodes, we need
// to backtrack and add in the text offset to the bookmark addresses.
if ( addrStart.nodeType == 1 && addrStart.childNodes[bookmark.Start[0]] && addrStart.childNodes[bookmark.Start[0]].nodeType == 3 )
{
var curNode = addrStart.childNodes[bookmark.Start[0]] ;
var offset = 0 ;
while ( curNode.previousSibling && curNode.previousSibling.nodeType == 3 )
{
curNode = curNode.previousSibling ;
offset += curNode.length ;
}
addrStart = curNode ;
bookmark.Start[0] = offset ;
}
if ( addrEnd.nodeType == 1 && addrEnd.childNodes[bookmark.End[0]] && addrEnd.childNodes[bookmark.End[0]].nodeType == 3 )
{
var curNode = addrEnd.childNodes[bookmark.End[0]] ;
var offset = 0 ;
while ( curNode.previousSibling && curNode.previousSibling.nodeType == 3 )
{
curNode = curNode.previousSibling ;
offset += curNode.length ;
}
addrEnd = curNode ;
bookmark.End[0] = offset ;
}
// Then, we record down the precise position of the container nodes
// by walking up the DOM tree and counting their childNode index
bookmark.Start = FCKDomTools.GetNodeAddress( addrStart, true ).concat( bookmark.Start ) ;
bookmark.End = FCKDomTools.GetNodeAddress( addrEnd, true ).concat( bookmark.End ) ;
return bookmark;
},
MoveToBookmark2 : function( bookmark )
{
// Reverse the childNode counting algorithm in CreateBookmark2()
var curStart = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.Start.slice( 0, -1 ), true ) ;
var curEnd = FCKDomTools.GetNodeFromAddress( this.Window.document, bookmark.End.slice( 0, -1 ), true ) ;
// Generate the W3C Range object and update relevant data
this.Release( true ) ;
this._Range = new FCKW3CRange( this.Window.document ) ;
var startOffset = bookmark.Start[ bookmark.Start.length - 1 ] ;
var endOffset = bookmark.End[ bookmark.End.length - 1 ] ;
while ( curStart.nodeType == 3 && startOffset > curStart.length )
{
if ( ! curStart.nextSibling || curStart.nextSibling.nodeType != 3 )
break ;
startOffset -= curStart.length ;
curStart = curStart.nextSibling ;
}
while ( curEnd.nodeType == 3 && endOffset > curEnd.length )
{
if ( ! curEnd.nextSibling || curEnd.nextSibling.nodeType != 3 )
break ;
endOffset -= curEnd.length ;
curEnd = curEnd.nextSibling ;
}
this._Range.setStart( curStart, startOffset ) ;
this._Range.setEnd( curEnd, endOffset ) ;
this._UpdateElementInfo() ;
},
MoveToPosition : function( targetElement, position )
{
this.SetStart( targetElement, position ) ;
this.Collapse( true ) ;
},
/*
* Moves the position of the start boundary of the range to a specific position
* relatively to a element.
* @position:
* 1 = After Start <target>^contents</target>
* 2 = Before End <target>contents^</target>
* 3 = Before Start ^<target>contents</target>
* 4 = After End <target>contents</target>^
*/
SetStart : function( targetElement, position, noInfoUpdate )
{
var oRange = this._Range ;
if ( !oRange )
oRange = this._Range = this.CreateRange() ;
switch( position )
{
case 1 : // After Start <target>^contents</target>
oRange.setStart( targetElement, 0 ) ;
break ;
case 2 : // Before End <target>contents^</target>
oRange.setStart( targetElement, targetElement.childNodes.length ) ;
break ;
case 3 : // Before Start ^<target>contents</target>
oRange.setStartBefore( targetElement ) ;
break ;
case 4 : // After End <target>contents</target>^
oRange.setStartAfter( targetElement ) ;
}
if ( !noInfoUpdate )
this._UpdateElementInfo() ;
},
/*
* Moves the position of the start boundary of the range to a specific position
* relatively to a element.
* @position:
* 1 = After Start <target>^contents</target>
* 2 = Before End <target>contents^</target>
* 3 = Before Start ^<target>contents</target>
* 4 = After End <target>contents</target>^
*/
SetEnd : function( targetElement, position, noInfoUpdate )
{
var oRange = this._Range ;
if ( !oRange )
oRange = this._Range = this.CreateRange() ;
switch( position )
{
case 1 : // After Start <target>^contents</target>
oRange.setEnd( targetElement, 0 ) ;
break ;
case 2 : // Before End <target>contents^</target>
oRange.setEnd( targetElement, targetElement.childNodes.length ) ;
break ;
case 3 : // Before Start ^<target>contents</target>
oRange.setEndBefore( targetElement ) ;
break ;
case 4 : // After End <target>contents</target>^
oRange.setEndAfter( targetElement ) ;
}
if ( !noInfoUpdate )
this._UpdateElementInfo() ;
},
Expand : function( unit )
{
var oNode, oSibling ;
switch ( unit )
{
// Expand the range to include all inline parent elements if we are
// are in their boundary limits.
// For example (where [ ] are the range limits):
// Before => Some <b>[<i>Some sample text]</i></b>.
// After => Some [<b><i>Some sample text</i></b>].
case 'inline_elements' :
// Expand the start boundary.
if ( this._Range.startOffset == 0 )
{
oNode = this._Range.startContainer ;
if ( oNode.nodeType != 1 )
oNode = oNode.previousSibling ? null : oNode.parentNode ;
if ( oNode )
{
while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
{
this._Range.setStartBefore( oNode ) ;
if ( oNode != oNode.parentNode.firstChild )
break ;
oNode = oNode.parentNode ;
}
}
}
// Expand the end boundary.
oNode = this._Range.endContainer ;
var offset = this._Range.endOffset ;
if ( ( oNode.nodeType == 3 && offset >= oNode.nodeValue.length ) || ( oNode.nodeType == 1 && offset >= oNode.childNodes.length ) || ( oNode.nodeType != 1 && oNode.nodeType != 3 ) )
{
if ( oNode.nodeType != 1 )
oNode = oNode.nextSibling ? null : oNode.parentNode ;
if ( oNode )
{
while ( FCKListsLib.InlineNonEmptyElements[ oNode.nodeName.toLowerCase() ] )
{
this._Range.setEndAfter( oNode ) ;
if ( oNode != oNode.parentNode.lastChild )
break ;
oNode = oNode.parentNode ;
}
}
}
break ;
case 'block_contents' :
case 'list_contents' :
var boundarySet = FCKListsLib.BlockBoundaries ;
if ( unit == 'list_contents' || FCKConfig.EnterMode == 'br' )
boundarySet = FCKListsLib.ListBoundaries ;
if ( this.StartBlock && FCKConfig.EnterMode != 'br' && unit == 'block_contents' )
this.SetStart( this.StartBlock, 1 ) ;
else
{
// Get the start node for the current range.
oNode = this._Range.startContainer ;
// If it is an element, get the node right before of it (in source order).
if ( oNode.nodeType == 1 )
{
var lastNode = oNode.childNodes[ this._Range.startOffset ] ;
if ( lastNode )
oNode = FCKDomTools.GetPreviousSourceNode( lastNode, true ) ;
else
oNode = oNode.lastChild || oNode ;
}
// We must look for the left boundary, relative to the range
// start, which is limited by a block element.
while ( oNode
&& ( oNode.nodeType != 1
|| ( oNode != this.StartBlockLimit
&& !boundarySet[ oNode.nodeName.toLowerCase() ] ) ) )
{
this._Range.setStartBefore( oNode ) ;
oNode = oNode.previousSibling || oNode.parentNode ;
}
}
if ( this.EndBlock && FCKConfig.EnterMode != 'br' && unit == 'block_contents' && this.EndBlock.nodeName.toLowerCase() != 'li' )
this.SetEnd( this.EndBlock, 2 ) ;
else
{
oNode = this._Range.endContainer ;
if ( oNode.nodeType == 1 )
oNode = oNode.childNodes[ this._Range.endOffset ] || oNode.lastChild ;
// We must look for the right boundary, relative to the range
// end, which is limited by a block element.
while ( oNode
&& ( oNode.nodeType != 1
|| ( oNode != this.StartBlockLimit
&& !boundarySet[ oNode.nodeName.toLowerCase() ] ) ) )
{
this._Range.setEndAfter( oNode ) ;
oNode = oNode.nextSibling || oNode.parentNode ;
}
// In EnterMode='br', the end <br> boundary element must
// be included in the expanded range.
if ( oNode && oNode.nodeName.toLowerCase() == 'br' )
this._Range.setEndAfter( oNode ) ;
}
this._UpdateElementInfo() ;
}
},
/**
* Split the block element for the current range. It deletes the contents
* of the range and splits the block in the collapsed position, resulting
* in two sucessive blocks. The range is then positioned in the middle of
* them.
*
* It returns and object with the following properties:
* - PreviousBlock : a reference to the block element that preceeds
* the range after the split.
* - NextBlock : a reference to the block element that preceeds the
* range after the split.
* - WasStartOfBlock : a boolean indicating that the range was
* originaly at the start of the block.
* - WasEndOfBlock : a boolean indicating that the range was originaly
* at the end of the block.
*
* If the range was originaly at the start of the block, no split will happen
* and the PreviousBlock value will be null. The same is valid for the
* NextBlock value if the range was at the end of the block.
*/
SplitBlock : function()
{
if ( !this._Range )
this.MoveToSelection() ;
// The range boundaries must be in the same "block limit" element.
if ( this.StartBlockLimit == this.EndBlockLimit )
{
// Get the current blocks.
var eStartBlock = this.StartBlock ;
var eEndBlock = this.EndBlock ;
var oElementPath = null ;
if ( FCKConfig.EnterMode != 'br' )
{
if ( !eStartBlock )
{
eStartBlock = this.FixBlock( true ) ;
eEndBlock = this.EndBlock ; // FixBlock may have fixed the EndBlock too.
}
if ( !eEndBlock )
eEndBlock = this.FixBlock( false ) ;
}
// Get the range position.
var bIsStartOfBlock = ( eStartBlock != null && this.CheckStartOfBlock() ) ;
var bIsEndOfBlock = ( eEndBlock != null && this.CheckEndOfBlock() ) ;
// Delete the current contents.
if ( !this.CheckIsEmpty() )
this.DeleteContents() ;
if ( eStartBlock && eEndBlock && eStartBlock == eEndBlock )
{
if ( bIsEndOfBlock )
{
oElementPath = new FCKElementPath( this.StartContainer ) ;
this.MoveToPosition( eEndBlock, 4 ) ;
eEndBlock = null ;
}
else if ( bIsStartOfBlock )
{
oElementPath = new FCKElementPath( this.StartContainer ) ;
this.MoveToPosition( eStartBlock, 3 ) ;
eStartBlock = null ;
}
else
{
// Extract the contents of the block from the selection point to the end of its contents.
this.SetEnd( eStartBlock, 2 ) ;
var eDocFrag = this.ExtractContents() ;
// Duplicate the block element after it.
eEndBlock = eStartBlock.cloneNode( false ) ;
eEndBlock.removeAttribute( 'id', false ) ;
// Place the extracted contents in the duplicated block.
eDocFrag.AppendTo( eEndBlock ) ;
FCKDomTools.InsertAfterNode( eStartBlock, eEndBlock ) ;
this.MoveToPosition( eStartBlock, 4 ) ;
// In Gecko, the last child node must be a bogus <br>.
// Note: bogus <br> added under <ul> or <ol> would cause lists to be incorrectly rendered.
if ( FCKBrowserInfo.IsGecko &&
! eStartBlock.nodeName.IEquals( ['ul', 'ol'] ) )
FCKTools.AppendBogusBr( eStartBlock ) ;
}
}
return {
PreviousBlock : eStartBlock,
NextBlock : eEndBlock,
WasStartOfBlock : bIsStartOfBlock,
WasEndOfBlock : bIsEndOfBlock,
ElementPath : oElementPath
} ;
}
return null ;
},
// Transform a block without a block tag in a valid block (orphan text in the body or td, usually).
FixBlock : function( isStart )
{
// Bookmark the range so we can restore it later.
var oBookmark = this.CreateBookmark() ;
// Collapse the range to the requested ending boundary.
this.Collapse( isStart ) ;
// Expands it to the block contents.
this.Expand( 'block_contents' ) ;
// Create the fixed block.
var oFixedBlock = this.Window.document.createElement( FCKConfig.EnterMode ) ;
// Move the contents of the temporary range to the fixed block.
this.ExtractContents().AppendTo( oFixedBlock ) ;
FCKDomTools.TrimNode( oFixedBlock ) ;
// Insert the fixed block into the DOM.
this.InsertNode( oFixedBlock ) ;
// Move the range back to the bookmarked place.
this.MoveToBookmark( oBookmark ) ;
return oFixedBlock ;
},
Release : function( preserveWindow )
{
if ( !preserveWindow )
this.Window = null ;
this.StartNode = null ;
this.StartContainer = null ;
this.StartBlock = null ;
this.StartBlockLimit = null ;
this.EndNode = null ;
this.EndContainer = null ;
this.EndBlock = null ;
this.EndBlockLimit = null ;
this._Range = null ;
this._Cache = null ;
},
CheckHasRange : function()
{
return !!this._Range ;
},
GetTouchedStartNode : function()
{
var range = this._Range ;
var container = range.startContainer ;
if ( range.collapsed || container.nodeType != 1 )
return container ;
return container.childNodes[ range.startOffset ] || container ;
},
GetTouchedEndNode : function()
{
var range = this._Range ;
var container = range.endContainer ;
if ( range.collapsed || container.nodeType != 1 )
return container ;
return container.childNodes[ range.endOffset - 1 ] || container ;
}
} ;

View file

@ -0,0 +1,104 @@
/*
* 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 ==
*
* Class for working with a selection range, much like the W3C DOM Range, but
* it is not intended to be an implementation of the W3C interface.
* (Gecko Implementation)
*/
FCKDomRange.prototype.MoveToSelection = function()
{
this.Release( true ) ;
var oSel = this.Window.getSelection() ;
if ( oSel && oSel.rangeCount > 0 )
{
this._Range = FCKW3CRange.CreateFromRange( this.Window.document, oSel.getRangeAt(0) ) ;
this._UpdateElementInfo() ;
}
else
if ( this.Window.document )
this.MoveToElementStart( this.Window.document.body ) ;
}
FCKDomRange.prototype.Select = function()
{
var oRange = this._Range ;
if ( oRange )
{
var startContainer = oRange.startContainer ;
// If we have a collapsed range, inside an empty element, we must add
// something to it, otherwise the caret will not be visible.
if ( oRange.collapsed && startContainer.nodeType == 1 && startContainer.childNodes.length == 0 )
startContainer.appendChild( oRange._Document.createTextNode('') ) ;
var oDocRange = this.Window.document.createRange() ;
oDocRange.setStart( startContainer, oRange.startOffset ) ;
try
{
oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
}
catch ( e )
{
// There is a bug in Firefox implementation (it would be too easy
// otherwise). The new start can't be after the end (W3C says it can).
// So, let's create a new range and collapse it to the desired point.
if ( e.toString().Contains( 'NS_ERROR_ILLEGAL_VALUE' ) )
{
oRange.collapse( true ) ;
oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
}
else
throw( e ) ;
}
var oSel = this.Window.getSelection() ;
oSel.removeAllRanges() ;
// We must add a clone otherwise Firefox will have rendering issues.
oSel.addRange( oDocRange ) ;
}
}
// Not compatible with bookmark created with CreateBookmark2.
// The bookmark nodes will be deleted from the document.
FCKDomRange.prototype.SelectBookmark = function( bookmark )
{
var domRange = this.Window.document.createRange() ;
var startNode = this.GetBookmarkNode( bookmark, true ) ;
var endNode = this.GetBookmarkNode( bookmark, false ) ;
domRange.setStart( startNode.parentNode, FCKDomTools.GetIndexOf( startNode ) ) ;
FCKDomTools.RemoveNode( startNode ) ;
if ( endNode )
{
domRange.setEnd( endNode.parentNode, FCKDomTools.GetIndexOf( endNode ) ) ;
FCKDomTools.RemoveNode( endNode ) ;
}
var selection = this.Window.getSelection() ;
selection.removeAllRanges() ;
selection.addRange( domRange ) ;
}

View file

@ -0,0 +1,199 @@
/*
* 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 ==
*
* Class for working with a selection range, much like the W3C DOM Range, but
* it is not intended to be an implementation of the W3C interface.
* (IE Implementation)
*/
FCKDomRange.prototype.MoveToSelection = function()
{
this.Release( true ) ;
this._Range = new FCKW3CRange( this.Window.document ) ;
var oSel = this.Window.document.selection ;
if ( oSel.type != 'Control' )
{
var eMarkerStart = this._GetSelectionMarkerTag( true ) ;
var eMarkerEnd = this._GetSelectionMarkerTag( false ) ;
if ( !eMarkerStart && !eMarkerEnd )
{
this._Range.setStart( this.Window.document.body, 0 ) ;
this._UpdateElementInfo() ;
return ;
}
// Set the start boundary.
this._Range.setStart( eMarkerStart.parentNode, FCKDomTools.GetIndexOf( eMarkerStart ) ) ;
eMarkerStart.parentNode.removeChild( eMarkerStart ) ;
// Set the end boundary.
this._Range.setEnd( eMarkerEnd.parentNode, FCKDomTools.GetIndexOf( eMarkerEnd ) ) ;
eMarkerEnd.parentNode.removeChild( eMarkerEnd ) ;
this._UpdateElementInfo() ;
}
else
{
var oControl = oSel.createRange().item(0) ;
if ( oControl )
{
this._Range.setStartBefore( oControl ) ;
this._Range.setEndAfter( oControl ) ;
this._UpdateElementInfo() ;
}
}
}
FCKDomRange.prototype.Select = function( forceExpand )
{
if ( this._Range )
this.SelectBookmark( this.CreateBookmark( true ), forceExpand ) ;
}
// Not compatible with bookmark created with CreateBookmark2.
// The bookmark nodes will be deleted from the document.
FCKDomRange.prototype.SelectBookmark = function( bookmark, forceExpand )
{
var bIsCollapsed = this.CheckIsCollapsed() ;
var bIsStartMakerAlone ;
var dummySpan ;
// Create marker tags for the start and end boundaries.
var eStartMarker = this.GetBookmarkNode( bookmark, true ) ;
if ( !eStartMarker )
return ;
var eEndMarker ;
if ( !bIsCollapsed )
eEndMarker = this.GetBookmarkNode( bookmark, false ) ;
// Create the main range which will be used for the selection.
var oIERange = this.Window.document.body.createTextRange() ;
// Position the range at the start boundary.
oIERange.moveToElementText( eStartMarker ) ;
oIERange.moveStart( 'character', 1 ) ;
if ( eEndMarker )
{
// Create a tool range for the end.
var oIERangeEnd = this.Window.document.body.createTextRange() ;
// Position the tool range at the end.
oIERangeEnd.moveToElementText( eEndMarker ) ;
// Move the end boundary of the main range to match the tool range.
oIERange.setEndPoint( 'EndToEnd', oIERangeEnd ) ;
oIERange.moveEnd( 'character', -1 ) ;
}
else
{
bIsStartMakerAlone = ( forceExpand || !eStartMarker.previousSibling || eStartMarker.previousSibling.nodeName.toLowerCase() == 'br' ) && !eStartMarker.nextSibing ;
// Append a temporary <span>&nbsp;</span> before the selection.
// This is needed to avoid IE destroying selections inside empty
// inline elements, like <b></b> (#253).
// It is also needed when placing the selection right after an inline
// element to avoid the selection moving inside of it.
dummySpan = this.Window.document.createElement( 'span' ) ;
dummySpan.innerHTML = '&#65279;' ; // Zero Width No-Break Space (U+FEFF). See #1359.
eStartMarker.parentNode.insertBefore( dummySpan, eStartMarker ) ;
if ( bIsStartMakerAlone )
{
// To expand empty blocks or line spaces after <br>, we need
// instead to have any char, which will be later deleted using the
// selection.
// \ufeff = Zero Width No-Break Space (U+FEFF). See #1359.
eStartMarker.parentNode.insertBefore( this.Window.document.createTextNode( '\ufeff' ), eStartMarker ) ;
}
}
if ( !this._Range )
this._Range = this.CreateRange() ;
// Remove the markers (reset the position, because of the changes in the DOM tree).
this._Range.setStartBefore( eStartMarker ) ;
eStartMarker.parentNode.removeChild( eStartMarker ) ;
if ( bIsCollapsed )
{
if ( bIsStartMakerAlone )
{
// Move the selection start to include the temporary &nbsp;.
oIERange.moveStart( 'character', -1 ) ;
oIERange.select() ;
// Remove our temporary stuff.
this.Window.document.selection.clear() ;
}
else
oIERange.select() ;
FCKDomTools.RemoveNode( dummySpan ) ;
}
else
{
this._Range.setEndBefore( eEndMarker ) ;
eEndMarker.parentNode.removeChild( eEndMarker ) ;
oIERange.select() ;
}
}
FCKDomRange.prototype._GetSelectionMarkerTag = function( toStart )
{
var doc = this.Window.document ;
var selection = doc.selection ;
// Get a range for the start boundary.
var oRange ;
// IE may throw an "unspecified error" on some cases (it happened when
// loading _samples/default.html), so try/catch.
try
{
oRange = selection.createRange() ;
}
catch (e)
{
return null ;
}
// IE might take the range object to the main window instead of inside the editor iframe window.
// This is known to happen when the editor window has not been selected before (See #933).
// We need to avoid that.
if ( oRange.parentElement().document != doc )
return null ;
oRange.collapse( toStart === true ) ;
// Paste a marker element at the collapsed range and get it from the DOM.
var sMarkerId = 'fck_dom_range_temp_' + (new Date()).valueOf() + '_' + Math.floor(Math.random()*1000) ;
oRange.pasteHTML( '<span id="' + sMarkerId + '"></span>' ) ;
return doc.getElementById( sMarkerId ) ;
}

View file

@ -0,0 +1,318 @@
/*
* 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 can be used to interate through nodes inside a range.
*
* During interation, the provided range can become invalid, due to document
* mutations, so CreateBookmark() used to restore it after processing, if
* needed.
*/
var FCKDomRangeIterator = function( range )
{
/**
* The FCKDomRange object that marks the interation boundaries.
*/
this.Range = range ;
/**
* Indicates that <br> elements must be used as paragraph boundaries.
*/
this.ForceBrBreak = false ;
/**
* Guarantees that the iterator will always return "real" block elements.
* If "false", elements like <li>, <th> and <td> are returned. If "true", a
* dedicated block element block element will be created inside those
* elements to hold the selected content.
*/
this.EnforceRealBlocks = false ;
}
FCKDomRangeIterator.CreateFromSelection = function( targetWindow )
{
var range = new FCKDomRange( targetWindow ) ;
range.MoveToSelection() ;
return new FCKDomRangeIterator( range ) ;
}
FCKDomRangeIterator.prototype =
{
/**
* Get the next paragraph element. It automatically breaks the document
* when necessary to generate block elements for the paragraphs.
*/
GetNextParagraph : function()
{
// The block element to be returned.
var block ;
// The range object used to identify the paragraph contents.
var range ;
// Indicated that the current element in the loop is the last one.
var isLast ;
// Instructs to cleanup remaining BRs.
var removePreviousBr ;
var removeLastBr ;
var boundarySet = this.ForceBrBreak ? FCKListsLib.ListBoundaries : FCKListsLib.BlockBoundaries ;
// This is the first iteration. Let's initialize it.
if ( !this._LastNode )
{
var range = this.Range.Clone() ;
range.Expand( this.ForceBrBreak ? 'list_contents' : 'block_contents' ) ;
this._NextNode = range.GetTouchedStartNode() ;
this._LastNode = range.GetTouchedEndNode() ;
// Let's reuse this variable.
range = null ;
}
var currentNode = this._NextNode ;
var lastNode = this._LastNode ;
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 ] )
{
// <br> boundaries must be part of the range. It will
// happen only if ForceBrBreak.
if ( nodeName == 'br' )
includeNode = true ;
else if ( !range && currentNode.childNodes.length == 0 && nodeName != 'hr' )
{
// If we have found an empty block, and haven't started
// the range yet, it means we must return this block.
block = currentNode ;
isLast = currentNode == lastNode ;
break ;
}
// The range must finish right before the boundary,
// including possibly skipped empty spaces. (#1603)
if ( range )
range.SetEnd( currentNode, 3, true ) ;
closeRange = true ;
}
else
{
// If we have child nodes, let's check them.
if ( currentNode.firstChild )
{
// If we don't have a range yet, let's start it.
if ( !range )
{
range = new FCKDomRange( this.Range.Window ) ;
range.SetStart( currentNode, 3, true ) ;
}
currentNode = currentNode.firstChild ;
continue ;
}
includeNode = true ;
}
}
else if ( currentNode.nodeType == 3 )
{
// Ignore normal whitespaces (i.e. not including &nbsp; or
// other unicode whitespaces) before/after a block node.
if ( /^[\r\n\t ]+$/.test( currentNode.nodeValue ) )
includeNode = false ;
}
// The current node is good to be part of the range and we are
// starting a new range, initialize it first.
if ( includeNode && !range )
{
range = new FCKDomRange( this.Range.Window ) ;
range.SetStart( currentNode, 3, true ) ;
}
// The last node has been found.
isLast = ( ( !closeRange || includeNode ) && currentNode == lastNode ) ;
// isLast = ( currentNode == lastNode && ( currentNode.nodeType != 1 || currentNode.childNodes.length == 0 ) ) ;
// If we are in an element boundary, let's check if it is time
// to close the range, otherwise we include the parent within it.
if ( range && !closeRange )
{
while ( !currentNode.nextSibling && !isLast )
{
var parentNode = currentNode.parentNode ;
if ( boundarySet[ parentNode.nodeName.toLowerCase() ] )
{
closeRange = true ;
isLast = isLast || ( parentNode == lastNode ) ;
break ;
}
currentNode = parentNode ;
includeNode = true ;
isLast = ( currentNode == lastNode ) ;
continueFromSibling = true ;
}
}
// Now finally include the node.
if ( includeNode )
range.SetEnd( currentNode, 4, true ) ;
// We have found a block boundary. Let's close the range and move out of the
// loop.
if ( ( closeRange || isLast ) && range )
{
range._UpdateElementInfo() ;
if ( range.StartNode == range.EndNode
&& range.StartNode.parentNode == range.StartBlockLimit
&& range.StartNode.getAttribute && range.StartNode.getAttribute( '_fck_bookmark' ) )
range = null ;
else
break ;
}
if ( isLast )
break ;
currentNode = FCKDomTools.GetNextSourceNode( currentNode, continueFromSibling, null, lastNode ) ;
}
// Now, based on the processed range, look for (or create) the block to be returned.
if ( !block )
{
// If no range has been found, this is the end.
if ( !range )
{
this._NextNode = null ;
return null ;
}
block = range.StartBlock ;
if ( !block
&& !this.EnforceRealBlocks
&& range.StartBlockLimit.nodeName.IEquals( 'DIV', 'TH', 'TD' )
&& range.CheckStartOfBlock()
&& range.CheckEndOfBlock() )
{
block = range.StartBlockLimit ;
}
else if ( !block || ( this.EnforceRealBlocks && block.nodeName.toLowerCase() == 'li' ) )
{
// Create the fixed block.
block = this.Range.Window.document.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
// Move the contents of the temporary range to the fixed block.
range.ExtractContents().AppendTo( block ) ;
FCKDomTools.TrimNode( block ) ;
// Insert the fixed block into the DOM.
range.InsertNode( block ) ;
removePreviousBr = true ;
removeLastBr = true ;
}
else if ( block.nodeName.toLowerCase() != 'li' )
{
// If the range doesn't includes the entire contents of the
// block, we must split it, isolating the range in a dedicated
// block.
if ( !range.CheckStartOfBlock() || !range.CheckEndOfBlock() )
{
// The resulting block will be a clone of the current one.
block = block.cloneNode( false ) ;
// Extract the range contents, moving it to the new block.
range.ExtractContents().AppendTo( block ) ;
FCKDomTools.TrimNode( block ) ;
// Split the block. At this point, the range will be in the
// right position for our intents.
var splitInfo = range.SplitBlock() ;
removePreviousBr = !splitInfo.WasStartOfBlock ;
removeLastBr = !splitInfo.WasEndOfBlock ;
FCKDebug.Output( 'removePreviousBr=' + removePreviousBr + ',removeLastBr=' + removeLastBr ) ;
// Insert the new block into the DOM.
range.InsertNode( block ) ;
}
}
else if ( !isLast )
{
// LIs are returned as is, with all their children (due to the
// nested lists). But, the next node is the node right after
// the current range, which could be an <li> child (nested
// lists) or the next sibling <li>.
this._NextNode = block == lastNode ? null : FCKDomTools.GetNextSourceNode( range.EndNode, true, null, lastNode ) ;
return block ;
}
}
if ( removePreviousBr )
{
var previousSibling = block.previousSibling ;
if ( previousSibling && previousSibling.nodeType == 1 )
{
if ( previousSibling.nodeName.toLowerCase() == 'br' )
previousSibling.parentNode.removeChild( previousSibling ) ;
else if ( previousSibling.lastChild && previousSibling.lastChild.nodeName.IEquals( 'br' ) )
previousSibling.removeChild( previousSibling.lastChild ) ;
}
}
if ( removeLastBr )
{
var lastChild = block.lastChild ;
if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName.toLowerCase() == 'br' )
block.removeChild( lastChild ) ;
}
// Get a reference for the next element. This is important because the
// above block can be removed or changed, so we can rely on it for the
// next interation.
this._NextNode = ( isLast || block == lastNode ) ? null : FCKDomTools.GetNextSourceNode( block, true, null, lastNode ) ;
return block ;
}
} ;

View file

@ -0,0 +1,324 @@
/*
* 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 ) ;
}
/**
* @param {String} html The complete HTML for the page, including DOCTYPE and the <html> tag.
*/
FCKEditingArea.prototype.Start = function( html, secondCall )
{
var eTargetElement = this.TargetElement ;
var oTargetDocument = FCKTools.GetElementDocument( eTargetElement ) ;
// Remove all child nodes from the target.
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 <base> tag... it must have a </base> closer,
// otherwise the all successive tags will be set as children nodes of the <base>.
if ( FCKBrowserInfo.IsIE )
html = html.replace( /(<base[^>]*?)\s*\/?>(?!\s*<\/base>)/gi, '$1></base>' ) ;
else if ( !secondCall )
{
// Gecko moves some tags out of the body to the head, so we must use
// innerHTML to set the body contents (SF BUG 1526154).
// Extract the BODY contents from the html.
var oMatchBefore = html.match( FCKRegexLib.BeforeBody ) ;
var oMatchAfter = html.match( FCKRegexLib.AfterBody ) ;
if ( oMatchBefore && oMatchAfter )
{
var sBody = html.substr( oMatchBefore[1].length,
html.length - oMatchBefore[1].length - oMatchAfter[1].length ) ; // This is the BODY tag contents.
html =
oMatchBefore[1] + // This is the HTML until the <body...> tag, inclusive.
'&nbsp;' +
oMatchAfter[1] ; // This is the HTML from the </body> tag, inclusive.
// If nothing in the body, place a BOGUS tag so the cursor will appear.
if ( FCKBrowserInfo.IsGecko && ( sBody.length == 0 || FCKRegexLib.EmptyParagraph.test( sBody ) ) )
sBody = '<br type="_moz">' ;
this._BodyHTML = sBody ;
}
else
this._BodyHTML = html ; // Invalid HTML input.
}
// 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!<img src='some_url'>!bla2" in the source and then switching
// back to design.
if ( FCKBrowserInfo.IsGecko10 )
this.Window.setTimeout( FCKEditingArea_CompleteStart, 500 ) ;
else
FCKEditingArea_CompleteStart.call( this.Window ) ;
}
else
{
var eTextarea = this.Textarea = oTargetDocument.createElement( 'textarea' ) ;
eTextarea.className = 'SourceField' ;
eTextarea.dir = 'ltr' ;
FCKDomTools.SetElementStyles( eTextarea,
{
width : '100%',
height : '100%',
border : 'none',
resize : 'none',
outline : 'none'
} ) ;
eTargetElement.appendChild( eTextarea ) ;
eTextarea.value = html ;
// Fire the "OnLoad" event.
FCKTools.RunFunction( this.OnLoad ) ;
}
}
// "this" here is FCKEditingArea.Window
function FCKEditingArea_CompleteStart()
{
// On Firefox, the DOM takes a little to become available. So we must wait for it in a loop.
if ( !this.document.body )
{
this.setTimeout( FCKEditingArea_CompleteStart, 50 ) ;
return ;
}
var oEditorArea = this._FCKEditingArea ;
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 (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() ;
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() ;
var parentNode = range.parentElement() ;
var parentTag = parentNode.nodeName.toLowerCase() ;
// Only apply the fix when in a block, and the block is empty.
if ( parentNode.childNodes.length > 0 ||
!( FCKListsLib.BlockElements[parentTag] ||
FCKListsLib.NonEmptyBlockElements[parentTag] ) )
{
return ;
}
range.moveEnd( "character", 1 ) ;
range.select() ;
if ( range.boundingWidth > 0 )
{
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 ;
}
}

View file

@ -0,0 +1,88 @@
/*
* 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)
// and if it doesn't contain other blocks.
if ( !eBlock && sElementName == 'div' && !FCKElementPath._CheckHasBlock( e ) )
eBlock = e ;
else
eBlockLimit = e ;
}
}
aElements.push( e ) ;
if ( sElementName == 'body' )
break ;
}
e = e.parentNode ;
}
this.Block = eBlock ;
this.BlockLimit = eBlockLimit ;
this.Elements = aElements ;
}
/**
* Check if an element contains any block element.
*/
FCKElementPath._CheckHasBlock = function( element )
{
var childNodes = element.childNodes ;
for ( var i = 0, count = childNodes.length ; i < count ; i++ )
{
var child = childNodes[i] ;
if ( child.nodeType == 1 && FCKListsLib.BlockElements[ child.nodeName.toLowerCase() ] )
return true ;
}
return false ;
}

View file

@ -0,0 +1,653 @@
/*
* 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 <Enter> keystroke.
* May be "p", "div", "br". Default is "p".
* @shiftEnterMode : the behavior for the <Shift>+<Enter> keystroke.
* May be "p", "div", "br". Defaults to "br".
*/
var FCKEnterKey = function( targetWindow, enterMode, shiftEnterMode, tabSpaces )
{
this.Window = targetWindow ;
this.EnterMode = enterMode || 'p' ;
this.ShiftEnterMode = shiftEnterMode || 'br' ;
// Setup the Keystroke Handler.
var oKeystrokeHandler = new FCKKeystrokeHandler( false ) ;
oKeystrokeHandler._EnterKey = this ;
oKeystrokeHandler.OnKeystroke = FCKEnterKey_OnKeystroke ;
oKeystrokeHandler.SetKeystrokes( [
[ 13 , 'Enter' ],
[ SHIFT + 13, 'ShiftEnter' ],
[ 9 , 'Tab' ],
[ 8 , 'Backspace' ],
[ CTRL + 8 , 'CtrlBackspace' ],
[ 46 , 'Delete' ]
] ) ;
if ( tabSpaces > 0 )
{
this.TabText = '' ;
while ( tabSpaces-- > 0 )
this.TabText += '\xa0' ;
}
oKeystrokeHandler.AttachToElement( targetWindow.document ) ;
}
function FCKEnterKey_OnKeystroke( keyCombination, keystrokeValue )
{
var oEnterKey = this._EnterKey ;
try
{
switch ( keystrokeValue )
{
case 'Enter' :
return oEnterKey.DoEnter() ;
break ;
case 'ShiftEnter' :
return oEnterKey.DoShiftEnter() ;
break ;
case 'Backspace' :
return oEnterKey.DoBackspace() ;
break ;
case 'Delete' :
return oEnterKey.DoDelete() ;
break ;
case 'Tab' :
return oEnterKey.DoTab() ;
break ;
case 'CtrlBackspace' :
return oEnterKey.DoCtrlBackspace() ;
break ;
}
}
catch (e)
{
// If for any reason we are not able to handle it, go
// ahead with the browser default behavior.
}
return false ;
}
/*
* Executes the <Enter> key behavior.
*/
FCKEnterKey.prototype.DoEnter = function( mode, hasShift )
{
// Save an undo snapshot before doing anything
FCKUndo.SaveUndoStep() ;
this._HasShift = ( hasShift === true ) ;
var parentElement = FCKSelection.GetParentElement() ;
var parentPath = new FCKElementPath( parentElement ) ;
var sMode = mode || this.EnterMode ;
if ( sMode == 'br' || parentPath.Block && parentPath.Block.tagName.toLowerCase() == 'pre' )
return this._ExecuteEnterBr() ;
else
return this._ExecuteEnterBlock( sMode ) ;
}
/*
* Executes the <Shift>+<Enter> key behavior.
*/
FCKEnterKey.prototype.DoShiftEnter = function()
{
return this.DoEnter( this.ShiftEnterMode, true ) ;
}
/*
* Executes the <Backspace> key behavior.
*/
FCKEnterKey.prototype.DoBackspace = function()
{
var bCustom = false ;
// Get the current selection.
var oRange = new FCKDomRange( this.Window ) ;
oRange.MoveToSelection() ;
// Kludge for #247
if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
{
this._FixIESelectAllBug( oRange ) ;
return true ;
}
var isCollapsed = oRange.CheckIsCollapsed() ;
if ( !isCollapsed )
{
// Bug #327, Backspace with an img selection would activate the default action in IE.
// Let's override that with our logic here.
if ( FCKBrowserInfo.IsIE && this.Window.document.selection.type.toLowerCase() == "control" )
{
var controls = this.Window.document.selection.createRange() ;
for ( var i = controls.length - 1 ; i >= 0 ; i-- )
{
var el = controls.item( i ) ;
el.parentNode.removeChild( el ) ;
}
return true ;
}
return false ;
}
var oStartBlock = oRange.StartBlock ;
var oEndBlock = oRange.EndBlock ;
// The selection boundaries must be in the same "block limit" element
if ( oRange.StartBlockLimit == oRange.EndBlockLimit && oStartBlock && oEndBlock )
{
if ( !isCollapsed )
{
var bEndOfBlock = oRange.CheckEndOfBlock() ;
oRange.DeleteContents() ;
if ( oStartBlock != oEndBlock )
{
oRange.SetStart(oEndBlock,1) ;
oRange.SetEnd(oEndBlock,1) ;
// if ( bEndOfBlock )
// oEndBlock.parentNode.removeChild( oEndBlock ) ;
}
oRange.Select() ;
bCustom = ( oStartBlock == oEndBlock ) ;
}
if ( oRange.CheckStartOfBlock() )
{
var oCurrentBlock = oRange.StartBlock ;
var ePrevious = FCKDomTools.GetPreviousSourceElement( oCurrentBlock, true, [ 'BODY', oRange.StartBlockLimit.nodeName ], ['UL','OL'] ) ;
bCustom = this._ExecuteBackspace( oRange, ePrevious, oCurrentBlock ) ;
}
else if ( FCKBrowserInfo.IsGeckoLike )
{
// Firefox and Opera (#1095) loose the selection when executing
// CheckStartOfBlock, so we must reselect.
oRange.Select() ;
}
}
oRange.Release() ;
return bCustom ;
}
FCKEnterKey.prototype.DoCtrlBackspace = function()
{
FCKUndo.SaveUndoStep() ;
var oRange = new FCKDomRange( this.Window ) ;
oRange.MoveToSelection() ;
if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
{
this._FixIESelectAllBug( oRange ) ;
return true ;
}
return false ;
}
FCKEnterKey.prototype._ExecuteBackspace = function( range, previous, currentBlock )
{
var bCustom = false ;
// We could be in a nested LI.
if ( !previous && currentBlock && currentBlock.nodeName.IEquals( 'LI' ) && currentBlock.parentNode.parentNode.nodeName.IEquals( 'LI' ) )
{
this._OutdentWithSelection( currentBlock, range ) ;
return true ;
}
if ( previous && previous.nodeName.IEquals( 'LI' ) )
{
var oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
while ( oNestedList )
{
previous = FCKDomTools.GetLastChild( oNestedList, 'LI' ) ;
oNestedList = FCKDomTools.GetLastChild( previous, ['UL','OL'] ) ;
}
}
if ( previous && currentBlock )
{
// If we are in a LI, and the previous block is not an LI, we must outdent it.
if ( currentBlock.nodeName.IEquals( 'LI' ) && !previous.nodeName.IEquals( 'LI' ) )
{
this._OutdentWithSelection( currentBlock, range ) ;
return true ;
}
// Take a reference to the parent for post processing cleanup.
var oCurrentParent = currentBlock.parentNode ;
var sPreviousName = previous.nodeName.toLowerCase() ;
if ( FCKListsLib.EmptyElements[ sPreviousName ] != null || sPreviousName == 'table' )
{
FCKDomTools.RemoveNode( previous ) ;
bCustom = true ;
}
else
{
// Remove the current block.
FCKDomTools.RemoveNode( currentBlock ) ;
// Remove any empty tag left by the block removal.
while ( oCurrentParent.innerHTML.Trim().length == 0 )
{
var oParent = oCurrentParent.parentNode ;
oParent.removeChild( oCurrentParent ) ;
oCurrentParent = oParent ;
}
// Cleanup the previous and the current elements.
FCKDomTools.LTrimNode( currentBlock ) ;
FCKDomTools.RTrimNode( previous ) ;
// Append a space to the previous.
// Maybe it is not always desirable...
// previous.appendChild( this.Window.document.createTextNode( ' ' ) ) ;
// Set the range to the end of the previous element and bookmark it.
range.SetStart( previous, 2, true ) ;
range.Collapse( true ) ;
var oBookmark = range.CreateBookmark( true ) ;
// Move the contents of the block to the previous element and delete it.
// But for some block types (e.g. table), moving the children to the previous block makes no sense.
// So a check is needed. (See #1081)
if ( ! currentBlock.tagName.IEquals( [ 'TABLE' ] ) )
FCKDomTools.MoveChildren( currentBlock, previous ) ;
// Place the selection at the bookmark.
range.SelectBookmark( oBookmark ) ;
bCustom = true ;
}
}
return bCustom ;
}
/*
* Executes the <Delete> key behavior.
*/
FCKEnterKey.prototype.DoDelete = function()
{
// Save an undo snapshot before doing anything
// This is to conform with the behavior seen in MS Word
FCKUndo.SaveUndoStep() ;
// The <Delete> has the same effect as the <Backspace>, so we have the same
// results if we just move to the next block and apply the same <Backspace> logic.
var bCustom = false ;
// Get the current selection.
var oRange = new FCKDomRange( this.Window ) ;
oRange.MoveToSelection() ;
// Kludge for #247
if ( FCKBrowserInfo.IsIE && this._CheckIsAllContentsIncluded( oRange, this.Window.document.body ) )
{
this._FixIESelectAllBug( oRange ) ;
return true ;
}
// There is just one special case for collapsed selections at the end of a block.
if ( oRange.CheckIsCollapsed() && oRange.CheckEndOfBlock( FCKBrowserInfo.IsGeckoLike ) )
{
var oCurrentBlock = oRange.StartBlock ;
var eCurrentCell = FCKTools.GetElementAscensor( oCurrentBlock, 'td' );
var eNext = FCKDomTools.GetNextSourceElement( oCurrentBlock, true, [ oRange.StartBlockLimit.nodeName ],
['UL','OL','TR'], true ) ;
// Bug #1323 : if we're in a table cell, and the next node belongs to a different cell, then don't
// delete anything.
if ( eCurrentCell )
{
var eNextCell = FCKTools.GetElementAscensor( eNext, 'td' );
if ( eNextCell != eCurrentCell )
return true ;
}
bCustom = this._ExecuteBackspace( oRange, oCurrentBlock, eNext ) ;
}
oRange.Release() ;
return bCustom ;
}
/*
* Executes the <Tab> key behavior.
*/
FCKEnterKey.prototype.DoTab = function()
{
var oRange = new FCKDomRange( this.Window );
oRange.MoveToSelection() ;
// If the user pressed <tab> inside a table, we should give him the default behavior ( moving between cells )
// instead of giving him more non-breaking spaces. (Bug #973)
var node = oRange._Range.startContainer ;
while ( node )
{
if ( node.nodeType == 1 )
{
var tagName = node.tagName.toLowerCase() ;
if ( tagName == "tr" || tagName == "td" || tagName == "th" || tagName == "tbody" || tagName == "table" )
return false ;
else
break ;
}
node = node.parentNode ;
}
if ( this.TabText )
{
oRange.DeleteContents() ;
oRange.InsertNode( this.Window.document.createTextNode( this.TabText ) ) ;
oRange.Collapse( false ) ;
oRange.Select() ;
}
return true ;
}
FCKEnterKey.prototype._ExecuteEnterBlock = function( blockTag, range )
{
// Get the current selection.
var oRange = range || new FCKDomRange( this.Window ) ;
var oSplitInfo = oRange.SplitBlock() ;
// FCKDebug.OutputObject( oSplitInfo ) ;
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 )
{
// If the next block is an <li> with another list tree as the first child
// We'll need to append a placeholder or the list item wouldn't be editable. (Bug #1420)
if ( eNextBlock.nodeName.IEquals( 'li' ) && eNextBlock.firstChild
&& eNextBlock.firstChild.nodeName.IEquals( ['ul', 'ol'] ) )
eNextBlock.insertBefore( eNextBlock.ownerDocument.createTextNode( '\xa0' ), eNextBlock.firstChild ) ;
// Move the selection to the end block.
if ( eNextBlock )
oRange.MoveToElementEditStart( eNextBlock ) ;
}
else
{
if ( bIsStartOfBlock && bIsEndOfBlock && ePreviousBlock.tagName.toUpperCase() == 'LI' )
{
oRange.MoveToElementStart( ePreviousBlock ) ;
this._OutdentWithSelection( ePreviousBlock, oRange ) ;
oRange.Release() ;
return true ;
}
var eNewBlock ;
if ( ePreviousBlock )
{
var sPreviousBlockTag = ePreviousBlock.tagName.toUpperCase() ;
// If is a header tag, or we are in a Shift+Enter (#77),
// create a new block element (later in the code).
if ( !this._HasShift && !(/^H[1-6]$/).test( sPreviousBlockTag ) )
{
// Otherwise, duplicate the previous block.
eNewBlock = FCKDomTools.CloneElement( ePreviousBlock ) ;
}
}
else if ( eNextBlock )
eNewBlock = FCKDomTools.CloneElement( eNextBlock ) ;
if ( !eNewBlock )
eNewBlock = this.Window.document.createElement( blockTag ) ;
// Recreate the inline elements tree, which was available
// before the hitting enter, so the same styles will be
// available in the new block.
var elementPath = oSplitInfo.ElementPath ;
if ( elementPath )
{
for ( var i = 0, len = elementPath.Elements.length ; i < len ; i++ )
{
var element = elementPath.Elements[i] ;
if ( element == elementPath.Block || element == elementPath.BlockLimit )
break ;
if ( FCKListsLib.InlineChildReqElements[ element.nodeName.toLowerCase() ] )
{
element = FCKDomTools.CloneElement( element ) ;
FCKDomTools.MoveChildren( eNewBlock, element ) ;
eNewBlock.appendChild( element ) ;
}
}
}
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( eNewBlock ) ;
oRange.InsertNode( eNewBlock ) ;
// This is tricky, but to make the new block visible correctly
// we must select it.
if ( FCKBrowserInfo.IsIE )
{
// Move the selection to the new block.
oRange.MoveToNodeContents( eNewBlock ) ;
oRange.Select() ;
}
// Move the selection to the new block.
oRange.MoveToElementEditStart( bIsStartOfBlock && !bIsEndOfBlock ? eNextBlock : eNewBlock ) ;
}
if ( FCKBrowserInfo.IsSafari )
FCKDomTools.ScrollIntoView( eNextBlock || eNewBlock, false ) ;
else if ( FCKBrowserInfo.IsGeckoLike )
( eNextBlock || 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 ;
var bIsPre = false ;
if ( !bHasShift && sStartBlockTag == 'LI' )
return this._ExecuteEnterBlock( null, oRange ) ;
// If we are at the end of a header block.
if ( !bHasShift && bIsEndOfBlock && (/^H[1-6]$/).test( sStartBlockTag ) )
{
// Insert a BR after the current paragraph.
FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createElement( 'br' ) ) ;
// The space is required by Gecko only to make the cursor blink.
if ( FCKBrowserInfo.IsGecko )
FCKDomTools.InsertAfterNode( oRange.StartBlock, this.Window.document.createTextNode( '' ) ) ;
// IE and Gecko have different behaviors regarding the position.
oRange.SetStart( oRange.StartBlock.nextSibling, FCKBrowserInfo.IsIE ? 3 : 1 ) ;
}
else
{
var eLineBreak ;
bIsPre = sStartBlockTag.IEquals( 'pre' ) ;
if ( bIsPre )
eLineBreak = this.Window.document.createTextNode( FCKBrowserInfo.IsIE ? '\r' : '\n' ) ;
else
eLineBreak = this.Window.document.createElement( 'br' ) ;
oRange.InsertNode( eLineBreak ) ;
// The space is required by Gecko only to make the cursor blink.
if ( FCKBrowserInfo.IsGecko )
FCKDomTools.InsertAfterNode( eLineBreak, this.Window.document.createTextNode( '' ) ) ;
// If we are at the end of a block, we must be sure the bogus node is available in that block.
if ( bIsEndOfBlock && FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( eLineBreak.parentNode ) ;
if ( FCKBrowserInfo.IsIE )
oRange.SetStart( eLineBreak, 4 ) ;
else
oRange.SetStart( eLineBreak.nextSibling, 1 ) ;
if ( ! FCKBrowserInfo.IsIE )
{
var dummy = null ;
if ( FCKBrowserInfo.IsOpera )
dummy = this.Window.document.createElement( 'span' ) ;
else
dummy = this.Window.document.createElement( 'br' ) ;
eLineBreak.parentNode.insertBefore( dummy, eLineBreak.nextSibling ) ;
if ( FCKBrowserInfo.IsSafari )
FCKDomTools.ScrollIntoView( dummy, false ) ;
else
dummy.scrollIntoView( false ) ;
dummy.parentNode.removeChild( dummy ) ;
}
}
// This collapse guarantees the cursor will be blinking.
oRange.Collapse( true ) ;
oRange.Select( bIsPre ) ;
}
// Release the resources used by the range.
oRange.Release() ;
return true ;
}
// Outdents a LI, maintaining the selection defined on a range.
FCKEnterKey.prototype._OutdentWithSelection = function( li, range )
{
var oBookmark = range.CreateBookmark() ;
FCKListHandler.OutdentListItem( li ) ;
range.MoveToBookmark( oBookmark ) ;
range.Select() ;
}
// Is all the contents under a node included by a range?
FCKEnterKey.prototype._CheckIsAllContentsIncluded = function( range, node )
{
var startOk = false ;
var endOk = false ;
/*
FCKDebug.Output( 'sc='+range.StartContainer.nodeName+
',so='+range._Range.startOffset+
',ec='+range.EndContainer.nodeName+
',eo='+range._Range.endOffset ) ;
*/
if ( range.StartContainer == node || range.StartContainer == node.firstChild )
startOk = ( range._Range.startOffset == 0 ) ;
if ( range.EndContainer == node || range.EndContainer == node.lastChild )
{
var nodeLength = range.EndContainer.nodeType == 3 ? range.EndContainer.length : range.EndContainer.childNodes.length ;
endOk = ( range._Range.endOffset == nodeLength ) ;
}
return startOk && endOk ;
}
// Kludge for #247
FCKEnterKey.prototype._FixIESelectAllBug = function( range )
{
var doc = this.Window.document ;
doc.body.innerHTML = '' ;
var editBlock ;
if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) )
{
editBlock = doc.createElement( FCKConfig.EnterMode ) ;
doc.body.appendChild( editBlock ) ;
}
else
editBlock = doc.body ;
range.MoveToNodeContents( editBlock ) ;
range.Collapse( true ) ;
range.Select() ;
range.Release() ;
}

View file

@ -0,0 +1,71 @@
/*
* 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
{
// Check that the event handler isn't already registered with the same listener
// It doesn't detect function pointers belonging to an object (at least in Gecko)
if ( aTargets.IndexOf( functionPointer ) == -1 )
aTargets.push( functionPointer ) ;
}
}
FCKEvents.prototype.FireEvent = function( eventName, params )
{
var bReturnValue = true ;
var oCalls = this._RegisteredEvents[ eventName ] ;
if ( oCalls )
{
for ( var i = 0 ; i < oCalls.length ; i++ )
{
try
{
bReturnValue = ( oCalls[ i ]( this.Owner, params ) && bReturnValue ) ;
}
catch(e)
{
// Ignore the following error. It may happen if pointing to a
// script not anymore available (#934):
// -2146823277 = Can't execute code from a freed script
if ( e.number != -2146823277 )
throw e ;
}
}
}
return bReturnValue ;
}

View file

@ -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 )
{
// <div class="TB_Button_Image"><img src="strip.gif" style="top:-16px"></div>
eIcon = document.createElement( 'DIV' ) ;
eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
eIconImage.src = this.Path ;
eIconImage.style.top = sPos ;
}
else
{
// <img class="TB_Button_Image" src="spacer.gif" style="background-position: 0px -16px;background-image: url(strip.gif);">
eIcon = document.createElement( 'IMG' ) ;
eIcon.src = FCK_SPACER_PATH ;
eIcon.style.backgroundPosition = '0px ' + sPos ;
eIcon.style.backgroundImage = 'url("' + this.Path + '")' ;
}
}
else // It is using a single icon image.
{
if ( FCKBrowserInfo.IsIE )
{
// IE makes the button 1px higher if using the <img> directly, so we
// are changing to the <div> system to clip the image correctly.
eIcon = document.createElement( 'DIV' ) ;
eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
eIconImage.src = this.Path ? this.Path : FCK_SPACER_PATH ;
}
else
{
// This is not working well with IE. See notes above.
// <img class="TB_Button_Image" src="smiley.gif">
eIcon = document.createElement( 'IMG' ) ;
eIcon.src = this.Path ? this.Path : FCK_SPACER_PATH ;
}
}
eIcon.className = 'TB_Button_Image' ;
return eIcon ;
}

View file

@ -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() ;
}

View file

@ -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() ;
}

View file

@ -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 ;
}

View file

@ -0,0 +1,153 @@
/*
* 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.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 )
{
if ( menuBlock.Hide )
menuBlock.Hide() ;
FCKTools.RunFunction( menuBlock.OnClick, menuBlock, [ clickedItem ] ) ;
}
function FCKMenuBlock_Item_OnActivate( menuBlock )
{
var oActiveItem = menuBlock._ActiveItem ;
if ( oActiveItem && oActiveItem != this )
{
// Set the focus to this menu block window (to fire OnBlur on opened panels).
if ( !FCKBrowserInfo.IsIE && oActiveItem.HasSubMenu && !this.HasSubMenu )
{
menuBlock._Window.focus() ;
// Due to the event model provided by Opera, we need to set
// HasFocus here as the above focus() call will not fire the focus
// event in the panel immediately (#1200).
menuBlock.Panel.HasFocus = true ;
}
oActiveItem.Deactivate() ;
}
menuBlock._ActiveItem = this ;
}
function FCKMenuBlock_Cleanup()
{
this._Window = null ;
this._ItemsTable = null ;
}
// ################# //
var FCKMenuSeparator = function()
{}
FCKMenuSeparator.prototype.Create = function( parentTable )
{
var oDoc = FCKTools.GetElementDocument( parentTable ) ;
var r = parentTable.insertRow(-1) ;
var eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator MN_Icon' ;
eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator' ;
eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator' ;
eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
}

View file

@ -0,0 +1,54 @@
/*
* 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() ;
// 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() ;
}

View file

@ -0,0 +1,160 @@
/*
* 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.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 ;
}

View file

@ -0,0 +1,359 @@
/*
* 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 = '<base href="' + window.document.location + '">' ;
// Initialize the IFRAME document body.
oDocument.open() ;
oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ;
oDocument.close() ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'blur', FCKPanel_Window_OnBlur, this ) ;
}
oDocument.dir = FCKLang.Dir ;
FCKTools.AddEventListener( oDocument, 'contextmenu', FCKTools.CancelEvent ) ;
// Create the main DIV that is used as the panel base.
this.MainNode = oDocument.body.appendChild( oDocument.createElement('DIV') ) ;
// The "float" property must be set so Firefox calculates the size correctly.
this.MainNode.style.cssFloat = this.IsRTL ? 'right' : 'left' ;
}
FCKPanel.prototype.AppendStyleSheet = function( styleSheet )
{
FCKTools.AppendStyleSheet( this.Document, styleSheet ) ;
}
FCKPanel.prototype.Preload = function( x, y, relElement )
{
// The offsetWidth and offsetHeight properties are not available if the
// element is not visible. So we must "show" the popup with no size to
// be able to use that values in the second call (IE only).
if ( this._Popup )
this._Popup.show( x, y, 0, 0, relElement ) ;
}
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() ;
// Due to a bug on FF3, we must ensure that the parent panel will
// blur (#1584).
FCKPanel_Window_OnBlur( null, this.ParentPanel ) ;
}
// Be sure we'll not have more than one Panel opened at the same time.
if ( FCKPanel._OpenedPanel )
FCKPanel._OpenedPanel.Hide() ;
FCKDomTools.SetElementStyles( eMainNode,
{
width : width ? width + 'px' : '',
height : height ? height + 'px' : ''
} ) ;
iMainWidth = eMainNode.offsetWidth ;
if ( !width ) this._IFrame.width = 1 ;
if ( !height ) this._IFrame.height = 1 ;
// This is weird... but with Firefox, we must get the offsetWidth before
// setting the _IFrame size (which returns "0"), and then after that,
// to return the correct width. Remove the first step and it will not
// work when the editor is in RTL.
//
// The "|| eMainNode.firstChild.offsetWidth" part has been added
// for Opera compatibility (see #570).
iMainWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
// Base the popup coordinates upon the coordinates of relElement.
var oPos = FCKTools.GetDocumentPosition( this._Window,
relElement.nodeType == 9 ?
( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :
relElement ) ;
// Minus the offsets provided by any positioned parent element of the panel iframe.
var positionedAncestor = FCKDomTools.GetPositionedAncestor( FCKTools.GetElementWindow( this._IFrame ), this._IFrame.parentNode ) ;
if ( positionedAncestor )
{
var nPos = FCKTools.GetDocumentPosition( FCKTools.GetElementWindow( positionedAncestor ), positionedAncestor ) ;
oPos.x -= nPos.x ;
oPos.y -= nPos.y ;
}
if ( this.IsRTL && !this.IsContextMenu )
x = ( x * -1 ) ;
x += oPos.x ;
y += oPos.y ;
if ( this.IsRTL )
{
if ( this.IsContextMenu )
x = x - iMainWidth + 1 ;
else if ( relElement )
x = x + relElement.offsetWidth - iMainWidth ;
}
else
{
var oViewPaneSize = FCKTools.GetViewPaneSize( this._Window ) ;
var oScrollPosition = FCKTools.GetScrollPosition( this._Window ) ;
var iViewPaneHeight = oViewPaneSize.Height + oScrollPosition.Y ;
var iViewPaneWidth = oViewPaneSize.Width + oScrollPosition.X ;
if ( ( x + iMainWidth ) > iViewPaneWidth )
x -= x + iMainWidth - iViewPaneWidth ;
if ( ( y + eMainNode.offsetHeight ) > iViewPaneHeight )
y -= y + eMainNode.offsetHeight - iViewPaneHeight ;
}
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() ;
FCKPanel._OpenedPanel = this ;
}
this._IsOpened = true ;
FCKTools.RunFunction( this.OnShow, this ) ;
}
FCKPanel.prototype.Hide = function( ignoreOnHide )
{
if ( this._Popup )
this._Popup.hide() ;
else
{
if ( !this._IsOpened || this._LockCounter > 0 )
return ;
// Enable the editor to fire the "OnBlur".
if ( typeof( FCKFocusManager ) != 'undefined' )
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 ;
}

View file

@ -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' ) ;
}

View file

@ -0,0 +1,376 @@
/*
* 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 = '&nbsp;' ;
this.Caption = caption ;
this.Tooltip = caption ;
this.Style = FCK_TOOLBARITEM_ICONTEXT ;
this.Enabled = true ;
this.Items = new Object() ;
this._Panel = new FCKPanel( parentWindow || window ) ;
this._Panel.AppendStyleSheet( FCKConfig.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 = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
this._ItemsHolderEl = this._PanelBox.getElementsByTagName('TD')[0] ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKSpecialCombo_Cleanup ) ;
// this._Panel.StyleSheet = FCKConfig.SkinPath + 'fck_contextmenu.css' ;
// this._Panel.Create() ;
// this._Panel.PanelDiv.className += ' SC_Panel' ;
// this._Panel.PanelDiv.innerHTML = '<table cellpadding="0" cellspacing="0" width="100%" style="TABLE-LAYOUT: fixed"><tr><td nowrap></td></tr></table>' ;
// this._ItemsHolderEl = this._Panel.PanelDiv.getElementsByTagName('TD')[0] ;
}
function FCKSpecialCombo_ItemOnMouseOver()
{
this.className += ' SC_ItemOver' ;
}
function FCKSpecialCombo_ItemOnMouseOut()
{
this.className = this.originalClass ;
}
function FCKSpecialCombo_ItemOnClick( ev, specialCombo, itemId )
{
this.className = this.originalClass ;
specialCombo._Panel.Hide() ;
specialCombo.SetLabel( this.FCKItemLabel ) ;
if ( typeof( specialCombo.OnSelect ) == 'function' )
specialCombo.OnSelect( itemId, this ) ;
}
FCKSpecialCombo.prototype.ClearItems = function ()
{
if ( this.Items )
this.Items = {} ;
var itemsholder = this._ItemsHolderEl ;
while ( itemsholder.firstChild )
itemsholder.removeChild( itemsholder.firstChild ) ;
}
FCKSpecialCombo.prototype.AddItem = function( id, html, label, bgColor )
{
// <div class="SC_Item" onmouseover="this.className='SC_Item SC_ItemOver';" onmouseout="this.className='SC_Item';"><b>Bold 1</b></div>
var oDiv = this._ItemsHolderEl.appendChild( this._Panel.Document.createElement( 'DIV' ) ) ;
oDiv.className = oDiv.originalClass = 'SC_Item' ;
oDiv.innerHTML = html ;
oDiv.FCKItemLabel = label || id ;
oDiv.Selected = false ;
// In IE, the width must be set so the borders are shown correctly when the content overflows.
if ( FCKBrowserInfo.IsIE )
oDiv.style.width = '100%' ;
if ( bgColor )
oDiv.style.backgroundColor = bgColor ;
FCKTools.AddEventListenerEx( oDiv, 'mouseover', FCKSpecialCombo_ItemOnMouseOver ) ;
FCKTools.AddEventListenerEx( oDiv, 'mouseout', FCKSpecialCombo_ItemOnMouseOut ) ;
FCKTools.AddEventListenerEx( oDiv, 'click', FCKSpecialCombo_ItemOnClick, [ this, id ] ) ;
this.Items[ id.toString().toLowerCase() ] = oDiv ;
return oDiv ;
}
FCKSpecialCombo.prototype.SelectItem = function( item )
{
if ( typeof item == 'string' )
item = this.Items[ item.toString().toLowerCase() ] ;
if ( item )
{
item.className = item.originalClass = 'SC_ItemSelected' ;
item.Selected = true ;
}
}
FCKSpecialCombo.prototype.SelectItemByLabel = function( itemLabel, setLabel )
{
for ( var id in this.Items )
{
var oDiv = this.Items[id] ;
if ( oDiv.FCKItemLabel == itemLabel )
{
oDiv.className = oDiv.originalClass = 'SC_ItemSelected' ;
oDiv.Selected = true ;
if ( setLabel )
this.SetLabel( itemLabel ) ;
}
}
}
FCKSpecialCombo.prototype.DeselectAll = function( clearLabel )
{
for ( var i in this.Items )
{
if ( !this.Items[i] ) continue;
this.Items[i].className = this.Items[i].originalClass = 'SC_Item' ;
this.Items[i].Selected = false ;
}
if ( clearLabel )
this.SetLabel( '' ) ;
}
FCKSpecialCombo.prototype.SetLabelById = function( id )
{
id = id ? id.toString().toLowerCase() : '' ;
var oDiv = this.Items[ id ] ;
this.SetLabel( oDiv ? oDiv.FCKItemLabel : '' ) ;
}
FCKSpecialCombo.prototype.SetLabel = function( text )
{
text = ( !text || text.length == 0 ) ? '&nbsp;' : text ;
if ( text == this.Label )
return ;
this.Label = text ;
var labelEl = this._LabelEl ;
if ( labelEl )
{
labelEl.innerHTML = text ;
// It may happen that the label is some HTML, including tags. This
// would be a problem because when the user click on those tags, the
// combo will get the selection from the editing area. So we must
// disable any kind of selection here.
FCKTools.DisableSelection( labelEl ) ;
}
}
FCKSpecialCombo.prototype.SetEnabled = function( isEnabled )
{
this.Enabled = isEnabled ;
// In IE it can happen when the page is reloaded that _OuterTable is null, so check its existence
if ( this._OuterTable )
this._OuterTable.className = isEnabled ? '' : 'SC_FieldDisabled' ;
}
FCKSpecialCombo.prototype.Create = function( targetElement )
{
var oDoc = FCKTools.GetElementDocument( targetElement ) ;
var eOuterTable = this._OuterTable = targetElement.appendChild( oDoc.createElement( 'TABLE' ) ) ;
eOuterTable.cellPadding = 0 ;
eOuterTable.cellSpacing = 0 ;
eOuterTable.insertRow(-1) ;
var sClass ;
var bShowLabel ;
switch ( this.Style )
{
case FCK_TOOLBARITEM_ONLYICON :
sClass = 'TB_ButtonType_Icon' ;
bShowLabel = false;
break ;
case FCK_TOOLBARITEM_ONLYTEXT :
sClass = 'TB_ButtonType_Text' ;
bShowLabel = false;
break ;
case FCK_TOOLBARITEM_ICONTEXT :
bShowLabel = true;
break ;
}
if ( this.Caption && this.Caption.length > 0 && bShowLabel )
{
var oCaptionCell = eOuterTable.rows[0].insertCell(-1) ;
oCaptionCell.innerHTML = this.Caption ;
oCaptionCell.className = 'SC_FieldCaption' ;
}
// Create the main DIV element.
var oField = FCKTools.AppendElement( eOuterTable.rows[0].insertCell(-1), 'div' ) ;
if ( bShowLabel )
{
oField.className = 'SC_Field' ;
oField.style.width = this.FieldWidth + 'px' ;
oField.innerHTML = '<table width="100%" cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldLabel"><label>&nbsp;</label></td><td class="SC_FieldButton">&nbsp;</td></tr></tbody></table>' ;
this._LabelEl = oField.getElementsByTagName('label')[0] ; // Memory Leak
this._LabelEl.innerHTML = this.Label ;
}
else
{
oField.className = 'TB_Button_Off' ;
//oField.innerHTML = '<span className="SC_FieldCaption">' + this.Caption + '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
//oField.innerHTML = '<table cellpadding="0" cellspacing="0" style="TABLE-LAYOUT: fixed;"><tbody><tr><td class="SC_FieldButton" style="border-left: none;">&nbsp;</td></tr></tbody></table>' ;
// Gets the correct CSS class to use for the specified style (param).
oField.innerHTML = '<table title="' + this.Tooltip + '" class="' + sClass + '" cellspacing="0" cellpadding="0" border="0">' +
'<tr>' +
//'<td class="TB_Icon"><img src="' + FCKConfig.SkinPath + 'toolbar/' + this.Command.Name.toLowerCase() + '.gif" width="21" height="21"></td>' +
'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
'<td class="TB_Text">' + this.Caption + '</td>' +
'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
'<td class="TB_ButtonArrow"><img src="' + FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif" width="5" height="3"></td>' +
'<td><img class="TB_Button_Padding" src="' + FCK_SPACER_PATH + '" /></td>' +
'</tr>' +
'</table>' ;
}
// Events Handlers
FCKTools.AddEventListenerEx( oField, 'mouseover', FCKSpecialCombo_OnMouseOver, this ) ;
FCKTools.AddEventListenerEx( oField, 'mouseout', FCKSpecialCombo_OnMouseOut, this ) ;
FCKTools.AddEventListenerEx( oField, 'click', FCKSpecialCombo_OnClick, this ) ;
FCKTools.DisableSelection( this._Panel.Document.body ) ;
}
function FCKSpecialCombo_Cleanup()
{
this._LabelEl = null ;
this._OuterTable = null ;
this._ItemsHolderEl = null ;
this._PanelBox = null ;
if ( this.Items )
{
for ( var key in this.Items )
this.Items[key] = null ;
}
}
function FCKSpecialCombo_OnMouseOver( ev, specialCombo )
{
if ( specialCombo.Enabled )
{
switch ( specialCombo.Style )
{
case FCK_TOOLBARITEM_ONLYICON :
this.className = 'TB_Button_On_Over';
break ;
case FCK_TOOLBARITEM_ONLYTEXT :
this.className = 'TB_Button_On_Over';
break ;
case FCK_TOOLBARITEM_ICONTEXT :
this.className = 'SC_Field SC_FieldOver' ;
break ;
}
}
}
function FCKSpecialCombo_OnMouseOut( ev, specialCombo )
{
switch ( specialCombo.Style )
{
case FCK_TOOLBARITEM_ONLYICON :
this.className = 'TB_Button_Off';
break ;
case FCK_TOOLBARITEM_ONLYTEXT :
this.className = 'TB_Button_Off';
break ;
case FCK_TOOLBARITEM_ICONTEXT :
this.className='SC_Field' ;
break ;
}
}
function FCKSpecialCombo_OnClick( e, specialCombo )
{
// For Mozilla we must stop the event propagation to avoid it hiding
// the panel because of a click outside of it.
// if ( e )
// {
// e.stopPropagation() ;
// FCKPanelEventHandlers.OnDocumentClick( e ) ;
// }
if ( specialCombo.Enabled )
{
var oPanel = specialCombo._Panel ;
var oPanelBox = specialCombo._PanelBox ;
var oItemsHolder = specialCombo._ItemsHolderEl ;
var iMaxHeight = specialCombo.PanelMaxHeight ;
if ( specialCombo.OnBeforeClick )
specialCombo.OnBeforeClick( specialCombo ) ;
// This is a tricky thing. We must call the "Load" function, otherwise
// it will not be possible to retrieve "oItemsHolder.offsetHeight" (IE only).
if ( FCKBrowserInfo.IsIE )
oPanel.Preload( 0, this.offsetHeight, this ) ;
if ( oItemsHolder.offsetHeight > iMaxHeight )
// {
oPanelBox.style.height = iMaxHeight + 'px' ;
// if ( FCKBrowserInfo.IsGecko )
// oPanelBox.style.overflow = '-moz-scrollbars-vertical' ;
// }
else
oPanelBox.style.height = '' ;
// oPanel.PanelDiv.style.width = specialCombo.PanelWidth + 'px' ;
oPanel.Show( 0, this.offsetHeight, this ) ;
}
// return false ;
}
/*
Sample Combo Field HTML output:
<div class="SC_Field" style="width: 80px;">
<table width="100%" cellpadding="0" cellspacing="0" style="table-layout: fixed;">
<tbody>
<tr>
<td class="SC_FieldLabel"><label>&nbsp;</label></td>
<td class="SC_FieldButton">&nbsp;</td>
</tr>
</tbody>
</table>
</div>
*/

File diff suppressed because it is too large Load diff

View file

@ -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 ==
*
* FCKToolbar Class: represents a toolbar in the toolbarset. It is a group of
* toolbar items.
*/
var FCKToolbar = function()
{
this.Items = new Array() ;
}
FCKToolbar.prototype.AddItem = function( item )
{
return this.Items[ this.Items.length ] = item ;
}
FCKToolbar.prototype.AddButton = function( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state )
{
if ( typeof( iconPathOrStripInfoArrayOrIndex ) == 'number' )
iconPathOrStripInfoArrayOrIndex = [ this.DefaultIconsStrip, this.DefaultIconSize, iconPathOrStripInfoArrayOrIndex ] ;
var oButton = new FCKToolbarButtonUI( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state ) ;
oButton._FCKToolbar = this ;
oButton.OnClick = FCKToolbar_OnItemClick ;
return this.AddItem( oButton ) ;
}
function FCKToolbar_OnItemClick( item )
{
var oToolbar = item._FCKToolbar ;
if ( oToolbar.OnItemClick )
oToolbar.OnItemClick( oToolbar, item ) ;
}
FCKToolbar.prototype.AddSeparator = function()
{
this.AddItem( new FCKToolbarSeparator() ) ;
}
FCKToolbar.prototype.Create = function( parentElement )
{
var oDoc = FCKTools.GetElementDocument( parentElement ) ;
var e = oDoc.createElement( 'table' ) ;
e.className = 'TB_Toolbar' ;
e.style.styleFloat = e.style.cssFloat = ( FCKLang.Dir == 'ltr' ? 'left' : 'right' ) ;
e.dir = FCKLang.Dir ;
e.cellPadding = 0 ;
e.cellSpacing = 0 ;
var targetRow = e.insertRow(-1) ;
// Insert the start cell.
var eCell ;
if ( !this.HideStart )
{
eCell = targetRow.insertCell(-1) ;
eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_Start' ;
}
for ( var i = 0 ; i < this.Items.length ; i++ )
{
this.Items[i].Create( targetRow.insertCell(-1) ) ;
}
// Insert the ending cell.
if ( !this.HideEnd )
{
eCell = targetRow.insertCell(-1) ;
eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_End' ;
}
parentElement.appendChild( e ) ;
}
var FCKToolbarSeparator = function()
{}
FCKToolbarSeparator.prototype.Create = function( parentElement )
{
FCKTools.AppendElement( parentElement, 'div' ).className = 'TB_Separator' ;
}

View file

@ -0,0 +1,36 @@
/*
* 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 ==
*
* FCKToolbarBreak Class: breaks the toolbars.
* It makes it possible to force the toolbar to break to a new line.
* This is the Gecko specific implementation.
*/
var FCKToolbarBreak = function()
{}
FCKToolbarBreak.prototype.Create = function( targetElement )
{
var oBreakDiv = targetElement.ownerDocument.createElement( 'div' ) ;
oBreakDiv.style.clear = oBreakDiv.style.cssFloat = FCKLang.Dir == 'rtl' ? 'right' : 'left' ;
targetElement.appendChild( oBreakDiv ) ;
}

View file

@ -0,0 +1,38 @@
/*
* 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 ==
*
* FCKToolbarBreak Class: breaks the toolbars.
* It makes it possible to force the toolbar to break to a new line.
* This is the IE specific implementation.
*/
var FCKToolbarBreak = function()
{}
FCKToolbarBreak.prototype.Create = function( targetElement )
{
var oBreakDiv = FCKTools.GetElementDocument( targetElement ).createElement( 'div' ) ;
oBreakDiv.className = 'TB_Break' ;
oBreakDiv.style.clear = FCKLang.Dir == 'rtl' ? 'left' : 'right' ;
targetElement.appendChild( oBreakDiv ) ;
}

View file

@ -0,0 +1,76 @@
/*
* 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 ==
*
* FCKToolbarButton Class: represents a button in the toolbar.
*/
var FCKToolbarButton = function( commandName, label, tooltip, style, sourceView, contextSensitive, icon )
{
this.CommandName = commandName ;
this.Label = label ;
this.Tooltip = tooltip ;
this.Style = style ;
this.SourceView = sourceView ? true : false ;
this.ContextSensitive = contextSensitive ? true : false ;
if ( icon == null )
this.IconPath = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
else if ( typeof( icon ) == 'number' )
this.IconPath = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
else
this.IconPath = icon ;
}
FCKToolbarButton.prototype.Create = function( targetElement )
{
this._UIButton = new FCKToolbarButtonUI( this.CommandName, this.Label, this.Tooltip, this.IconPath, this.Style ) ;
this._UIButton.OnClick = this.Click ;
this._UIButton._ToolbarButton = this ;
this._UIButton.Create( targetElement ) ;
}
FCKToolbarButton.prototype.RefreshState = function()
{
// Gets the actual state.
var eState = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
// If there are no state changes than do nothing and return.
if ( eState == this._UIButton.State ) return ;
// Sets the actual state.
this._UIButton.ChangeState( eState ) ;
}
FCKToolbarButton.prototype.Click = function()
{
var oToolbarButton = this._ToolbarButton || this ;
FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oToolbarButton.CommandName ).Execute() ;
}
FCKToolbarButton.prototype.Enable = function()
{
this.RefreshState() ;
}
FCKToolbarButton.prototype.Disable = function()
{
// Sets the actual state.
this._UIButton.ChangeState( FCK_TRISTATE_DISABLED ) ;
}

View file

@ -0,0 +1,198 @@
/*
* 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 ==
*
* FCKToolbarButtonUI Class: interface representation of a toolbar button.
*/
var FCKToolbarButtonUI = function( name, label, tooltip, iconPathOrStripInfoArray, style, state )
{
this.Name = name ;
this.Label = label || name ;
this.Tooltip = tooltip || this.Label ;
this.Style = style || FCK_TOOLBARITEM_ONLYICON ;
this.State = state || FCK_TRISTATE_OFF ;
this.Icon = new FCKIcon( iconPathOrStripInfoArray ) ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKToolbarButtonUI_Cleanup ) ;
}
FCKToolbarButtonUI.prototype._CreatePaddingElement = function( document )
{
var oImg = document.createElement( 'IMG' ) ;
oImg.className = 'TB_Button_Padding' ;
oImg.src = FCK_SPACER_PATH ;
return oImg ;
}
FCKToolbarButtonUI.prototype.Create = function( parentElement )
{
var oDoc = FCKTools.GetElementDocument( parentElement ) ;
// Create the Main Element.
var oMainElement = this.MainElement = oDoc.createElement( 'DIV' ) ;
oMainElement.title = this.Tooltip ;
// The following will prevent the button from catching the focus.
if ( FCKBrowserInfo.IsGecko )
oMainElement.onmousedown = FCKTools.CancelEvent ;
FCKTools.AddEventListenerEx( oMainElement, 'mouseover', FCKToolbarButtonUI_OnMouseOver, this ) ;
FCKTools.AddEventListenerEx( oMainElement, 'mouseout', FCKToolbarButtonUI_OnMouseOut, this ) ;
FCKTools.AddEventListenerEx( oMainElement, 'click', FCKToolbarButtonUI_OnClick, this ) ;
this.ChangeState( this.State, true ) ;
if ( this.Style == FCK_TOOLBARITEM_ONLYICON && !this.ShowArrow )
{
// <td><div class="TB_Button_On" title="Smiley">{Image}</div></td>
oMainElement.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
}
else
{
// <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td>{Image}</td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
// <td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td><img class="TB_Button_Padding"></td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
var oTable = oMainElement.appendChild( oDoc.createElement( 'TABLE' ) ) ;
oTable.cellPadding = 0 ;
oTable.cellSpacing = 0 ;
var oRow = oTable.insertRow(-1) ;
// The Image cell (icon or padding).
var oCell = oRow.insertCell(-1) ;
if ( this.Style == FCK_TOOLBARITEM_ONLYICON || this.Style == FCK_TOOLBARITEM_ICONTEXT )
oCell.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
else
oCell.appendChild( this._CreatePaddingElement( oDoc ) ) ;
if ( this.Style == FCK_TOOLBARITEM_ONLYTEXT || this.Style == FCK_TOOLBARITEM_ICONTEXT )
{
// The Text cell.
oCell = oRow.insertCell(-1) ;
oCell.className = 'TB_Button_Text' ;
oCell.noWrap = true ;
oCell.appendChild( oDoc.createTextNode( this.Label ) ) ;
}
if ( this.ShowArrow )
{
if ( this.Style != FCK_TOOLBARITEM_ONLYICON )
{
// A padding cell.
oRow.insertCell(-1).appendChild( this._CreatePaddingElement( oDoc ) ) ;
}
oCell = oRow.insertCell(-1) ;
var eImg = oCell.appendChild( oDoc.createElement( 'IMG' ) ) ;
eImg.src = FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif' ;
eImg.width = 5 ;
eImg.height = 3 ;
}
// The last padding cell.
oCell = oRow.insertCell(-1) ;
oCell.appendChild( this._CreatePaddingElement( oDoc ) ) ;
}
parentElement.appendChild( oMainElement ) ;
}
FCKToolbarButtonUI.prototype.ChangeState = function( newState, force )
{
if ( !force && this.State == newState )
return ;
var e = this.MainElement ;
// In IE it can happen when the page is reloaded that MainElement is null, so exit here
if ( !e )
return ;
switch ( parseInt( newState, 10 ) )
{
case FCK_TRISTATE_OFF :
e.className = 'TB_Button_Off' ;
break ;
case FCK_TRISTATE_ON :
e.className = 'TB_Button_On' ;
break ;
case FCK_TRISTATE_DISABLED :
e.className = 'TB_Button_Disabled' ;
break ;
}
this.State = newState ;
}
function FCKToolbarButtonUI_OnMouseOver( ev, button )
{
if ( button.State == FCK_TRISTATE_OFF )
this.className = 'TB_Button_Off_Over' ;
else if ( button.State == FCK_TRISTATE_ON )
this.className = 'TB_Button_On_Over' ;
}
function FCKToolbarButtonUI_OnMouseOut( ev, button )
{
if ( button.State == FCK_TRISTATE_OFF )
this.className = 'TB_Button_Off' ;
else if ( button.State == FCK_TRISTATE_ON )
this.className = 'TB_Button_On' ;
}
function FCKToolbarButtonUI_OnClick( ev, button )
{
if ( button.OnClick && button.State != FCK_TRISTATE_DISABLED )
button.OnClick( button ) ;
}
function FCKToolbarButtonUI_Cleanup()
{
// This one should not cause memory leak, but just for safety, let's clean
// it up.
this.MainElement = null ;
}
/*
Sample outputs:
This is the base structure. The variation is the image that is marked as {Image}:
<td><div class="TB_Button_On" title="Smiley">{Image}</div></td>
<td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td>{Image}</td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
<td><div class="TB_Button_On" title="Smiley"><table cellpadding="0" cellspacing="0"><tr><td><img class="TB_Button_Padding"></td><td nowrap>Toolbar Button</td><td><img class="TB_Button_Padding"></td></tr></table></div></td>
These are samples of possible {Image} values:
Strip - IE version:
<div class="TB_Button_Image"><img src="strip.gif" style="top:-16px"></div>
Strip : Firefox, Safari and Opera version
<img class="TB_Button_Image" style="background-position: 0px -16px;background-image: url(strip.gif);">
No-Strip : Browser independent:
<img class="TB_Button_Image" src="smiley.gif">
*/

View file

@ -0,0 +1,139 @@
/*
* 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 ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontFormatCombo = function( tooltip, style )
{
if ( tooltip === false )
return ;
this.CommandName = 'FontFormat' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.NormalLabel = 'Normal' ;
this.PanelWidth = 190 ;
this.DefaultLabel = FCKConfig.DefaultFontFormatLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontFormatCombo.prototype = new FCKToolbarStyleCombo( false ) ;
FCKToolbarFontFormatCombo.prototype.GetLabel = function()
{
return FCKLang.FontFormat ;
}
FCKToolbarFontFormatCombo.prototype.GetStyles = function()
{
var styles = {} ;
// Get the format names from the language file.
var aNames = FCKLang['FontFormats'].split(';') ;
var oNames = {
p : aNames[0],
pre : aNames[1],
address : aNames[2],
h1 : aNames[3],
h2 : aNames[4],
h3 : aNames[5],
h4 : aNames[6],
h5 : aNames[7],
h6 : aNames[8],
div : aNames[9] || ( aNames[0] + ' (DIV)')
} ;
// Get the available formats from the configuration file.
var elements = FCKConfig.FontFormats.split(';') ;
for ( var i = 0 ; i < elements.length ; i++ )
{
var elementName = elements[ i ] ;
var style = FCKStyles.GetStyle( '_FCK_' + elementName ) ;
if ( style )
{
style.Label = oNames[ elementName ] ;
styles[ '_FCK_' + elementName ] = style ;
}
else
alert( "The FCKConfig.CoreStyles['" + elementName + "'] setting was not found. Please check the fckconfig.js file" ) ;
}
return styles ;
}
FCKToolbarFontFormatCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
{
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var blockElement = path.Block ;
if ( blockElement )
{
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( blockElement ) )
{
targetSpecialCombo.SetLabel( style.Label ) ;
return ;
}
}
}
}
targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
}
FCKToolbarFontFormatCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var blockElement = path.Block ;
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( blockElement ) )
{
targetSpecialCombo.SelectItem( item ) ;
return ;
}
}
}
}

View file

@ -0,0 +1,98 @@
/*
* 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 ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontsCombo = function( tooltip, style )
{
this.CommandName = 'FontName' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultFontLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontsCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
FCKToolbarFontsCombo.prototype.GetLabel = function()
{
return FCKLang.Font ;
}
FCKToolbarFontsCombo.prototype.GetStyles = function()
{
var baseStyle = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
if ( !baseStyle )
{
alert( "The FCKConfig.CoreStyles['Size'] setting was not found. Please check the fckconfig.js file" ) ;
return {} ;
}
var styles = {} ;
var fonts = FCKConfig.FontNames.split(';') ;
for ( var i = 0 ; i < fonts.length ; i++ )
{
var fontParts = fonts[i].split('/') ;
var font = fontParts[0] ;
var caption = fontParts[1] || font ;
var style = FCKTools.CloneObject( baseStyle ) ;
style.SetVariable( 'Font', font ) ;
style.Label = caption ;
styles[ caption ] = style ;
}
return styles ;
}
FCKToolbarFontsCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckActive( path ) )
{
targetSpecialCombo.SelectItem( item ) ;
return ;
}
}
}
}

View file

@ -0,0 +1,76 @@
/*
* 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 ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontSizeCombo = function( tooltip, style )
{
this.CommandName = 'FontSize' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultFontSizeLabel || '' ;
this.FieldWidth = 70 ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontSizeCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
FCKToolbarFontSizeCombo.prototype.GetLabel = function()
{
return FCKLang.FontSize ;
}
FCKToolbarFontSizeCombo.prototype.GetStyles = function()
{
var baseStyle = FCKStyles.GetStyle( '_FCK_Size' ) ;
if ( !baseStyle )
{
alert( "The FCKConfig.CoreStyles['FontFace'] setting was not found. Please check the fckconfig.js file" ) ;
return {} ;
}
var styles = {} ;
var fonts = FCKConfig.FontSizes.split(';') ;
for ( var i = 0 ; i < fonts.length ; i++ )
{
var fontParts = fonts[i].split('/') ;
var font = fontParts[0] ;
var caption = fontParts[1] || font ;
var style = FCKTools.CloneObject( baseStyle ) ;
style.SetVariable( 'Size', font ) ;
style.Label = caption ;
styles[ caption ] = style ;
}
return styles ;
}
FCKToolbarFontSizeCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
FCKToolbarFontSizeCombo.prototype.StyleCombo_OnBeforeClick = FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick ;

View file

@ -0,0 +1,92 @@
/*
* 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 ==
*
* FCKToolbarPanelButton Class: represents a special button in the toolbar
* that shows a panel when pressed.
*/
var FCKToolbarPanelButton = function( commandName, label, tooltip, style, icon )
{
this.CommandName = commandName ;
var oIcon ;
if ( icon == null )
oIcon = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
else if ( typeof( icon ) == 'number' )
oIcon = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
var oUIButton = this._UIButton = new FCKToolbarButtonUI( commandName, label, tooltip, oIcon, style ) ;
oUIButton._FCKToolbarPanelButton = this ;
oUIButton.ShowArrow = true ;
oUIButton.OnClick = FCKToolbarPanelButton_OnButtonClick ;
}
FCKToolbarPanelButton.prototype.TypeName = 'FCKToolbarPanelButton' ;
FCKToolbarPanelButton.prototype.Create = function( parentElement )
{
parentElement.className += 'Menu' ;
this._UIButton.Create( parentElement ) ;
var oPanel = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName )._Panel ;
oPanel._FCKToolbarPanelButton = this ;
var eLineDiv = oPanel.Document.body.appendChild( oPanel.Document.createElement( 'div' ) ) ;
eLineDiv.style.position = 'absolute' ;
eLineDiv.style.top = '0px' ;
var eLine = this.LineImg = eLineDiv.appendChild( oPanel.Document.createElement( 'IMG' ) ) ;
eLine.className = 'TB_ConnectionLine' ;
eLine.style.position = 'absolute' ;
// eLine.style.backgroundColor = 'Red' ;
eLine.src = FCK_SPACER_PATH ;
oPanel.OnHide = FCKToolbarPanelButton_OnPanelHide ;
}
/*
Events
*/
function FCKToolbarPanelButton_OnButtonClick( toolbarButton )
{
var oButton = this._FCKToolbarPanelButton ;
var e = oButton._UIButton.MainElement ;
oButton._UIButton.ChangeState( FCK_TRISTATE_ON ) ;
oButton.LineImg.style.width = ( e.offsetWidth - 2 ) + 'px' ;
FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oButton.CommandName ).Execute( 0, e.offsetHeight - 1, e ) ; // -1 to be over the border
}
function FCKToolbarPanelButton_OnPanelHide()
{
var oMenuButton = this._FCKToolbarPanelButton ;
oMenuButton._UIButton.ChangeState( FCK_TRISTATE_OFF ) ;
}
// The Panel Button works like a normal button so the refresh state functions
// defined for the normal button can be reused here.
FCKToolbarPanelButton.prototype.RefreshState = FCKToolbarButton.prototype.RefreshState ;
FCKToolbarPanelButton.prototype.Enable = FCKToolbarButton.prototype.Enable ;
FCKToolbarPanelButton.prototype.Disable = FCKToolbarButton.prototype.Disable ;

View file

@ -0,0 +1,143 @@
/*
* 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 ==
*
* FCKToolbarSpecialCombo Class: This is a "abstract" base class to be used
* by the special combo toolbar elements like font name, font size, paragraph format, etc...
*
* The following properties and methods must be implemented when inheriting from
* this class:
* - Property: CommandName [ The command name to be executed ]
* - Method: GetLabel() [ Returns the label ]
* - CreateItems( targetSpecialCombo ) [ Add all items in the special combo ]
*/
var FCKToolbarSpecialCombo = function()
{
this.SourceView = false ;
this.ContextSensitive = true ;
//this._LastValue = null ;
}
FCKToolbarSpecialCombo.prototype.DefaultLabel = '' ;
function FCKToolbarSpecialCombo_OnSelect( itemId, item )
{
FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).Execute( itemId, item ) ;
}
FCKToolbarSpecialCombo.prototype.Create = function( targetElement )
{
this._Combo = new FCKSpecialCombo( this.GetLabel(), this.FieldWidth, this.PanelWidth, this.PanelMaxHeight, FCKBrowserInfo.IsIE ? window : FCKTools.GetElementWindow( targetElement ).parent ) ;
/*
this._Combo.FieldWidth = this.FieldWidth != null ? this.FieldWidth : 100 ;
this._Combo.PanelWidth = this.PanelWidth != null ? this.PanelWidth : 150 ;
this._Combo.PanelMaxHeight = this.PanelMaxHeight != null ? this.PanelMaxHeight : 150 ;
*/
//this._Combo.Command.Name = this.Command.Name;
// this._Combo.Label = this.Label ;
this._Combo.Tooltip = this.Tooltip ;
this._Combo.Style = this.Style ;
this.CreateItems( this._Combo ) ;
this._Combo.Create( targetElement ) ;
this._Combo.CommandName = this.CommandName ;
this._Combo.OnSelect = FCKToolbarSpecialCombo_OnSelect ;
}
function FCKToolbarSpecialCombo_RefreshActiveItems( combo, value )
{
combo.DeselectAll() ;
combo.SelectItem( value ) ;
combo.SetLabelById( value ) ;
}
FCKToolbarSpecialCombo.prototype.RefreshState = function()
{
// Gets the actual state.
var eState ;
// if ( FCK.EditMode == FCK_EDITMODE_SOURCE && ! this.SourceView )
// eState = FCK_TRISTATE_DISABLED ;
// else
// {
var sValue = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
// FCKDebug.Output( 'RefreshState of Special Combo "' + this.TypeOf + '" - State: ' + sValue ) ;
if ( sValue != FCK_TRISTATE_DISABLED )
{
eState = FCK_TRISTATE_ON ;
if ( this.RefreshActiveItems )
this.RefreshActiveItems( this._Combo, sValue ) ;
else
{
if ( this._LastValue !== sValue)
{
this._LastValue = sValue ;
if ( !sValue || sValue.length == 0 )
{
this._Combo.DeselectAll() ;
this._Combo.SetLabel( this.DefaultLabel ) ;
}
else
FCKToolbarSpecialCombo_RefreshActiveItems( this._Combo, sValue ) ;
}
}
}
else
eState = FCK_TRISTATE_DISABLED ;
// }
// If there are no state changes then do nothing and return.
if ( eState == this.State ) return ;
if ( eState == FCK_TRISTATE_DISABLED )
{
this._Combo.DeselectAll() ;
this._Combo.SetLabel( '' ) ;
}
// Sets the actual state.
this.State = eState ;
// Updates the graphical state.
this._Combo.SetEnabled( eState != FCK_TRISTATE_DISABLED ) ;
}
FCKToolbarSpecialCombo.prototype.Enable = function()
{
this.RefreshState() ;
}
FCKToolbarSpecialCombo.prototype.Disable = function()
{
this.State = FCK_TRISTATE_DISABLED ;
this._Combo.DeselectAll() ;
this._Combo.SetLabel( '' ) ;
this._Combo.SetEnabled( false ) ;
}

View file

@ -0,0 +1,200 @@
/*
* 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 ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarStyleCombo = function( tooltip, style )
{
if ( tooltip === false )
return ;
this.CommandName = 'Style' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultStyleLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarStyleCombo.prototype = new FCKToolbarSpecialCombo ;
FCKToolbarStyleCombo.prototype.GetLabel = function()
{
return FCKLang.Style ;
}
FCKToolbarStyleCombo.prototype.GetStyles = function()
{
var styles = {} ;
var allStyles = FCK.ToolbarSet.CurrentInstance.Styles.GetStyles() ;
for ( var styleName in allStyles )
{
var style = allStyles[ styleName ] ;
if ( !style.IsCore )
styles[ styleName ] = style ;
}
return styles ;
}
FCKToolbarStyleCombo.prototype.CreateItems = function( targetSpecialCombo )
{
var targetDoc = targetSpecialCombo._Panel.Document ;
// Add the Editor Area CSS to the panel so the style classes are previewed correctly.
FCKTools.AppendStyleSheet( targetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
FCKTools.AppendStyleString( targetDoc, FCKConfig.EditorAreaStyles ) ;
targetDoc.body.className += ' ForceBaseFont' ;
// Add ID and Class to the body.
FCKConfig.ApplyBodyAttributes( targetDoc.body ) ;
// Get the styles list.
var styles = this.GetStyles() ;
for ( var styleName in styles )
{
var style = styles[ styleName ] ;
// Object type styles have no preview.
var caption = style.GetType() == FCK_STYLE_OBJECT ?
styleName :
FCKToolbarStyleCombo_BuildPreview( style, style.Label || styleName ) ;
var item = targetSpecialCombo.AddItem( styleName, caption ) ;
item.Style = style ;
}
// We must prepare the list before showing it.
targetSpecialCombo.OnBeforeClick = this.StyleCombo_OnBeforeClick ;
}
FCKToolbarStyleCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
{
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var elements = path.Elements ;
for ( var e = 0 ; e < elements.length ; e++ )
{
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( elements[ e ], true ) )
{
targetSpecialCombo.SetLabel( style.Label || style.Name ) ;
return ;
}
}
}
}
targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
}
FCKToolbarStyleCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Two things are done here:
// - In a control selection, get the element name, so we'll display styles
// for that element only.
// - Select the styles that are active for the current selection.
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement ;
var path ;
var tagName ;
var selection = FCK.ToolbarSet.CurrentInstance.Selection ;
if ( selection.GetType() == 'Control' )
{
startElement = selection.GetSelectedElement() ;
tagName = startElement.nodeName.toLowerCase() ;
}
else
{
startElement = selection.GetBoundaryParentElement( true ) ;
path = new FCKElementPath( startElement ) ;
}
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( ( tagName && style.Element == tagName ) || ( !tagName && style.GetType() != FCK_STYLE_OBJECT ) )
{
item.style.display = '' ;
if ( ( path && style.CheckActive( path ) ) || ( !path && style.CheckElementRemovable( startElement, true ) ) )
targetSpecialCombo.SelectItem( style.Name ) ;
}
else
item.style.display = 'none' ;
}
}
function FCKToolbarStyleCombo_BuildPreview( style, caption )
{
var styleType = style.GetType() ;
var html = [] ;
if ( styleType == FCK_STYLE_BLOCK )
html.push( '<div class="BaseFont">' ) ;
var elementName = style.Element ;
// Avoid <bdo> in the preview.
if ( elementName == 'bdo' )
elementName = 'span' ;
html = [ '<', elementName ] ;
// Assign all defined attributes.
var attribs = style._StyleDesc.Attributes ;
if ( attribs )
{
for ( var att in attribs )
{
html.push( ' ', att, '="', style.GetFinalAttributeValue( att ), '"' ) ;
}
}
// Assign the style attribute.
if ( style._GetStyleText().length > 0 )
html.push( ' style="', style.GetFinalStyleValue(), '"' ) ;
html.push( '>', caption, '</', elementName, '>' ) ;
if ( styleType == FCK_STYLE_BLOCK )
html.push( '</div>' ) ;
return html.join( '' ) ;
}

View file

@ -0,0 +1,447 @@
/*
* 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 partially implements the W3C DOM Range for browser that don't
* support the standards (like IE):
* http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html
*/
var FCKW3CRange = function( parentDocument )
{
this._Document = parentDocument ;
this.startContainer = null ;
this.startOffset = null ;
this.endContainer = null ;
this.endOffset = null ;
this.collapsed = true ;
}
FCKW3CRange.CreateRange = function( parentDocument )
{
// We could opt to use the Range implementation of the browsers. The problem
// is that every browser have different bugs on their implementations,
// mostly related to different interpretations of the W3C specifications.
// So, for now, let's use our implementation and pray for browsers fixings
// soon. Otherwise will go crazy on trying to find out workarounds.
/*
// Get the browser implementation of the range, if available.
if ( parentDocument.createRange )
{
var range = parentDocument.createRange() ;
if ( typeof( range.startContainer ) != 'undefined' )
return range ;
}
*/
return new FCKW3CRange( parentDocument ) ;
}
FCKW3CRange.CreateFromRange = function( parentDocument, sourceRange )
{
var range = FCKW3CRange.CreateRange( parentDocument ) ;
range.setStart( sourceRange.startContainer, sourceRange.startOffset ) ;
range.setEnd( sourceRange.endContainer, sourceRange.endOffset ) ;
return range ;
}
FCKW3CRange.prototype =
{
_UpdateCollapsed : function()
{
this.collapsed = ( this.startContainer == this.endContainer && this.startOffset == this.endOffset ) ;
},
// W3C requires a check for the new position. If it is after the end
// boundary, the range should be collapsed to the new start. It seams we
// will not need this check for our use of this class so we can ignore it for now.
setStart : function( refNode, offset )
{
this.startContainer = refNode ;
this.startOffset = offset ;
if ( !this.endContainer )
{
this.endContainer = refNode ;
this.endOffset = offset ;
}
this._UpdateCollapsed() ;
},
// W3C requires a check for the new position. If it is before the start
// boundary, the range should be collapsed to the new end. It seams we
// will not need this check for our use of this class so we can ignore it for now.
setEnd : function( refNode, offset )
{
this.endContainer = refNode ;
this.endOffset = offset ;
if ( !this.startContainer )
{
this.startContainer = refNode ;
this.startOffset = offset ;
}
this._UpdateCollapsed() ;
},
setStartAfter : function( refNode )
{
this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
},
setStartBefore : function( refNode )
{
this.setStart( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
},
setEndAfter : function( refNode )
{
this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) + 1 ) ;
},
setEndBefore : function( refNode )
{
this.setEnd( refNode.parentNode, FCKDomTools.GetIndexOf( refNode ) ) ;
},
collapse : function( toStart )
{
if ( toStart )
{
this.endContainer = this.startContainer ;
this.endOffset = this.startOffset ;
}
else
{
this.startContainer = this.endContainer ;
this.startOffset = this.endOffset ;
}
this.collapsed = true ;
},
selectNodeContents : function( refNode )
{
this.setStart( refNode, 0 ) ;
this.setEnd( refNode, refNode.nodeType == 3 ? refNode.data.length : refNode.childNodes.length ) ;
},
insertNode : function( newNode )
{
var startContainer = this.startContainer ;
var startOffset = this.startOffset ;
// If we are in a text node.
if ( startContainer.nodeType == 3 )
{
startContainer.splitText( startOffset ) ;
// Check if it is necessary to update the end boundary.
if ( startContainer == this.endContainer )
this.setEnd( startContainer.nextSibling, this.endOffset - this.startOffset ) ;
// Insert the new node it after the text node.
FCKDomTools.InsertAfterNode( startContainer, newNode ) ;
return ;
}
else
{
// Simply insert the new node before the current start node.
startContainer.insertBefore( newNode, startContainer.childNodes[ startOffset ] || null ) ;
// Check if it is necessary to update the end boundary.
if ( startContainer == this.endContainer )
{
this.endOffset++ ;
this.collapsed = false ;
}
}
},
deleteContents : function()
{
if ( this.collapsed )
return ;
this._ExecContentsAction( 0 ) ;
},
extractContents : function()
{
var docFrag = new FCKDocumentFragment( this._Document ) ;
if ( !this.collapsed )
this._ExecContentsAction( 1, docFrag ) ;
return docFrag ;
},
// The selection may be lost when cloning (due to the splitText() call).
cloneContents : function()
{
var docFrag = new FCKDocumentFragment( this._Document ) ;
if ( !this.collapsed )
this._ExecContentsAction( 2, docFrag ) ;
return docFrag ;
},
_ExecContentsAction : function( action, docFrag )
{
var startNode = this.startContainer ;
var endNode = this.endContainer ;
var startOffset = this.startOffset ;
var endOffset = this.endOffset ;
var removeStartNode = false ;
var removeEndNode = false ;
// Check the start and end nodes and make the necessary removals or changes.
// Start from the end, otherwise DOM mutations (splitText) made in the
// start boundary may interfere on the results here.
// For text containers, we must simply split the node and point to the
// second part. The removal will be handled by the rest of the code .
if ( endNode.nodeType == 3 )
endNode = endNode.splitText( endOffset ) ;
else
{
// If the end container has children and the offset is pointing
// to a child, then we should start from it.
if ( endNode.childNodes.length > 0 )
{
// If the offset points after the last node.
if ( endOffset > endNode.childNodes.length - 1 )
{
// Let's create a temporary node and mark it for removal.
endNode = FCKDomTools.InsertAfterNode( endNode.lastChild, this._Document.createTextNode('') ) ;
removeEndNode = true ;
}
else
endNode = endNode.childNodes[ endOffset ] ;
}
}
// For text containers, we must simply split the node. The removal will
// be handled by the rest of the code .
if ( startNode.nodeType == 3 )
{
startNode.splitText( startOffset ) ;
// In cases the end node is the same as the start node, the above
// splitting will also split the end, so me must move the end to
// the second part of the split.
if ( startNode == endNode )
endNode = startNode.nextSibling ;
}
else
{
// If the start container has children and the offset is pointing
// to a child, then we should start from its previous sibling.
if ( startNode.childNodes.length > 0 && startOffset <= startNode.childNodes.length - 1 )
{
// If the offset points to the first node, we don't have a
// sibling, so let's use the first one, but mark it for removal.
if ( startOffset == 0 )
{
// Let's create a temporary node and mark it for removal.
startNode = startNode.insertBefore( this._Document.createTextNode(''), startNode.firstChild ) ;
removeStartNode = true ;
}
else
startNode = startNode.childNodes[ startOffset ].previousSibling ;
}
}
// Get the parent nodes tree for the start and end boundaries.
var startParents = FCKDomTools.GetParents( startNode ) ;
var endParents = FCKDomTools.GetParents( endNode ) ;
// Compare them, to find the top most siblings.
var i, topStart, topEnd ;
for ( i = 0 ; i < startParents.length ; i++ )
{
topStart = startParents[i] ;
topEnd = endParents[i] ;
// The compared nodes will match until we find the top most
// siblings (different nodes that have the same parent).
// "i" will hold the index in the parents array for the top
// most element.
if ( topStart != topEnd )
break ;
}
var clone, levelStartNode, levelClone, currentNode, currentSibling ;
if ( docFrag )
clone = docFrag.RootNode ;
// Remove all successive sibling nodes for every node in the
// startParents tree.
for ( var j = i ; j < startParents.length ; j++ )
{
levelStartNode = startParents[j] ;
// For Extract and Clone, we must clone this level.
if ( clone && levelStartNode != startNode ) // action = 0 = Delete
levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == startNode ) ) ;
currentNode = levelStartNode.nextSibling ;
while( currentNode )
{
// Stop processing when the current node matches a node in the
// endParents tree or if it is the endNode.
if ( currentNode == endParents[j] || currentNode == endNode )
break ;
// Cache the next sibling.
currentSibling = currentNode.nextSibling ;
// If cloning, just clone it.
if ( action == 2 ) // 2 = Clone
clone.appendChild( currentNode.cloneNode( true ) ) ;
else
{
// Both Delete and Extract will remove the node.
currentNode.parentNode.removeChild( currentNode ) ;
// When Extracting, move the removed node to the docFrag.
if ( action == 1 ) // 1 = Extract
clone.appendChild( currentNode ) ;
}
currentNode = currentSibling ;
}
if ( clone )
clone = levelClone ;
}
if ( docFrag )
clone = docFrag.RootNode ;
// Remove all previous sibling nodes for every node in the
// endParents tree.
for ( var k = i ; k < endParents.length ; k++ )
{
levelStartNode = endParents[k] ;
// For Extract and Clone, we must clone this level.
if ( action > 0 && levelStartNode != endNode ) // action = 0 = Delete
levelClone = clone.appendChild( levelStartNode.cloneNode( levelStartNode == endNode ) ) ;
// The processing of siblings may have already been done by the parent.
if ( !startParents[k] || levelStartNode.parentNode != startParents[k].parentNode )
{
currentNode = levelStartNode.previousSibling ;
while( currentNode )
{
// Stop processing when the current node matches a node in the
// startParents tree or if it is the startNode.
if ( currentNode == startParents[k] || currentNode == startNode )
break ;
// Cache the next sibling.
currentSibling = currentNode.previousSibling ;
// If cloning, just clone it.
if ( action == 2 ) // 2 = Clone
clone.insertBefore( currentNode.cloneNode( true ), clone.firstChild ) ;
else
{
// Both Delete and Extract will remove the node.
currentNode.parentNode.removeChild( currentNode ) ;
// When Extracting, mode the removed node to the docFrag.
if ( action == 1 ) // 1 = Extract
clone.insertBefore( currentNode, clone.firstChild ) ;
}
currentNode = currentSibling ;
}
}
if ( clone )
clone = levelClone ;
}
if ( action == 2 ) // 2 = Clone.
{
// No changes in the DOM should be done, so fix the split text (if any).
var startTextNode = this.startContainer ;
if ( startTextNode.nodeType == 3 )
{
startTextNode.data += startTextNode.nextSibling.data ;
startTextNode.parentNode.removeChild( startTextNode.nextSibling ) ;
}
var endTextNode = this.endContainer ;
if ( endTextNode.nodeType == 3 && endTextNode.nextSibling )
{
endTextNode.data += endTextNode.nextSibling.data ;
endTextNode.parentNode.removeChild( endTextNode.nextSibling ) ;
}
}
else
{
// Collapse the range.
// If a node has been partially selected, collapse the range between
// topStart and topEnd. Otherwise, simply collapse it to the start. (W3C specs).
if ( topStart && topEnd && ( startNode.parentNode != topStart.parentNode || endNode.parentNode != topEnd.parentNode ) )
{
var endIndex = FCKDomTools.GetIndexOf( topEnd ) ;
// If the start node is to be removed, we must correct the
// index to reflect the removal.
if ( removeStartNode && topEnd.parentNode == startNode.parentNode )
endIndex-- ;
this.setStart( topEnd.parentNode, endIndex ) ;
}
// Collapse it to the start.
this.collapse( true ) ;
}
// Cleanup any marked node.
if( removeStartNode )
startNode.parentNode.removeChild( startNode ) ;
if( removeEndNode && endNode.parentNode )
endNode.parentNode.removeChild( endNode ) ;
},
cloneRange : function()
{
return FCKW3CRange.CreateFromRange( this._Document, this ) ;
}
} ;

View file

@ -0,0 +1,108 @@
/*
* 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 ==
*
* FCKXml Class: class to load and manipulate XML files.
* (IE specific implementation)
*/
var FCKXml = function()
{
this.Error = false ;
}
FCKXml.GetAttribute = function( node, attName, defaultValue )
{
var attNode = node.attributes.getNamedItem( attName ) ;
return attNode ? attNode.value : defaultValue ;
}
/**
* Transforms a XML element node in a JavaScript object. Attributes defined for
* the element will be available as properties, as long as child element
* nodes, but the later will generate arrays with property names prefixed with "$".
*
* For example, the following XML element:
*
* <SomeNode name="Test" key="2">
* <MyChild id="10">
* <OtherLevel name="Level 3" />
* </MyChild>
* <MyChild id="25" />
* <AnotherChild price="499" />
* </SomeNode>
*
* ... results in the following object:
*
* {
* name : "Test",
* key : "2",
* $MyChild :
* [
* {
* id : "10",
* $OtherLevel :
* {
* name : "Level 3"
* }
* },
* {
* id : "25"
* }
* ],
* $AnotherChild :
* [
* {
* price : "499"
* }
* ]
* }
*/
FCKXml.TransformToObject = function( element )
{
if ( !element )
return null ;
var obj = {} ;
var attributes = element.attributes ;
for ( var i = 0 ; i < attributes.length ; i++ )
{
var att = attributes[i] ;
obj[ att.name ] = att.value ;
}
var childNodes = element.childNodes ;
for ( i = 0 ; i < childNodes.length ; i++ )
{
var child = childNodes[i] ;
if ( child.nodeType == 1 )
{
var childName = '$' + child.nodeName ;
var childList = obj[ childName ] ;
if ( !childList )
childList = obj[ childName ] = [] ;
childList.push( this.TransformToObject( child ) ) ;
}
}
return obj ;
}

View file

@ -0,0 +1,87 @@
/*
* 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 ==
*
* FCKXml Class: class to load and manipulate XML files.
*/
FCKXml.prototype =
{
LoadUrl : function( urlToCall )
{
this.Error = false ;
var oFCKXml = this ;
var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
oXmlHttp.open( "GET", urlToCall, false ) ;
oXmlHttp.send( null ) ;
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 )
this.DOMDocument = oXmlHttp.responseXML ;
else if ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 )
this.DOMDocument = oXmlHttp.responseXML ;
else
this.DOMDocument = null ;
if ( this.DOMDocument == null || this.DOMDocument.firstChild == null )
{
this.Error = true ;
if (window.confirm( 'Error loading "' + urlToCall + '"\r\nDo you want to see more info?' ) )
alert( 'URL requested: "' + urlToCall + '"\r\n' +
'Server response:\r\nStatus: ' + oXmlHttp.status + '\r\n' +
'Response text:\r\n' + oXmlHttp.responseText ) ;
}
},
SelectNodes : function( xpath, contextNode )
{
if ( this.Error )
return new Array() ;
var aNodeArray = new Array();
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ;
if ( xPathResult )
{
var oNode = xPathResult.iterateNext() ;
while( oNode )
{
aNodeArray[aNodeArray.length] = oNode ;
oNode = xPathResult.iterateNext();
}
}
return aNodeArray ;
},
SelectSingleNode : function( xpath, contextNode )
{
if ( this.Error )
return null ;
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), 9, null);
if ( xPathResult && xPathResult.singleNodeValue )
return xPathResult.singleNodeValue ;
else
return null ;
}
} ;

View file

@ -0,0 +1,88 @@
/*
* 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 ==
*
* FCKXml Class: class to load and manipulate XML files.
* (IE specific implementation)
*/
FCKXml.prototype =
{
LoadUrl : function( urlToCall )
{
this.Error = false ;
var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
if ( !oXmlHttp )
{
this.Error = true ;
return ;
}
oXmlHttp.open( "GET", urlToCall, false ) ;
oXmlHttp.send( null ) ;
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 )
this.DOMDocument = oXmlHttp.responseXML ;
else if ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 )
{
this.DOMDocument = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
this.DOMDocument.async = false ;
this.DOMDocument.resolveExternals = false ;
this.DOMDocument.loadXML( oXmlHttp.responseText ) ;
}
else
{
this.DOMDocument = null ;
}
if ( this.DOMDocument == null || this.DOMDocument.firstChild == null )
{
this.Error = true ;
if (window.confirm( 'Error loading "' + urlToCall + '"\r\nDo you want to see more info?' ) )
alert( 'URL requested: "' + urlToCall + '"\r\n' +
'Server response:\r\nStatus: ' + oXmlHttp.status + '\r\n' +
'Response text:\r\n' + oXmlHttp.responseText ) ;
}
},
SelectNodes : function( xpath, contextNode )
{
if ( this.Error )
return new Array() ;
if ( contextNode )
return contextNode.selectNodes( xpath ) ;
else
return this.DOMDocument.selectNodes( xpath ) ;
},
SelectSingleNode : function( xpath, contextNode )
{
if ( this.Error )
return null ;
if ( contextNode )
return contextNode.selectSingleNode( xpath ) ;
else
return this.DOMDocument.selectSingleNode( xpath ) ;
}
} ;

View file

@ -0,0 +1,470 @@
/*
* 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 ==
*
* Definition of other commands that are not available internaly in the
* browser (see FCKNamedCommand).
*/
// ### General Dialog Box Commands.
var FCKDialogCommand = function( name, title, url, width, height, getStateFunction, getStateParam )
{
this.Name = name ;
this.Title = title ;
this.Url = url ;
this.Width = width ;
this.Height = height ;
this.GetStateFunction = getStateFunction ;
this.GetStateParam = getStateParam ;
this.Resizable = false ;
}
FCKDialogCommand.prototype.Execute = function()
{
FCKDialog.OpenDialog( 'FCKDialog_' + this.Name , this.Title, this.Url, this.Width, this.Height, null, null, this.Resizable ) ;
}
FCKDialogCommand.prototype.GetState = function()
{
if ( this.GetStateFunction )
return this.GetStateFunction( this.GetStateParam ) ;
else
return FCK_TRISTATE_OFF ;
}
// Generic Undefined command (usually used when a command is under development).
var FCKUndefinedCommand = function()
{
this.Name = 'Undefined' ;
}
FCKUndefinedCommand.prototype.Execute = function()
{
alert( FCKLang.NotImplemented ) ;
}
FCKUndefinedCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
// ### FormatBlock
var FCKFormatBlockCommand = function()
{}
FCKFormatBlockCommand.prototype =
{
Name : 'FormatBlock',
Execute : FCKStyleCommand.prototype.Execute,
GetState : function()
{
return FCK.EditorDocument ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}
};
// ### FontName
var FCKFontNameCommand = function()
{}
FCKFontNameCommand.prototype =
{
Name : 'FontName',
Execute : FCKStyleCommand.prototype.Execute,
GetState : FCKFormatBlockCommand.prototype.GetState
};
// ### FontSize
var FCKFontSizeCommand = function()
{}
FCKFontSizeCommand.prototype =
{
Name : 'FontSize',
Execute : FCKStyleCommand.prototype.Execute,
GetState : FCKFormatBlockCommand.prototype.GetState
};
// ### Preview
var FCKPreviewCommand = function()
{
this.Name = 'Preview' ;
}
FCKPreviewCommand.prototype.Execute = function()
{
FCK.Preview() ;
}
FCKPreviewCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
// ### Save
var FCKSaveCommand = function()
{
this.Name = 'Save' ;
}
FCKSaveCommand.prototype.Execute = function()
{
// Get the linked field form.
var oForm = FCK.GetParentForm() ;
if ( typeof( oForm.onsubmit ) == 'function' )
{
var bRet = oForm.onsubmit() ;
if ( bRet != null && bRet === false )
return ;
}
// Submit the form.
// If there's a button named "submit" then the form.submit() function is masked and
// can't be called in Mozilla, so we call the click() method of that button.
if ( typeof( oForm.submit ) == 'function' )
oForm.submit() ;
else
oForm.submit.click() ;
}
FCKSaveCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
// ### NewPage
var FCKNewPageCommand = function()
{
this.Name = 'NewPage' ;
}
FCKNewPageCommand.prototype.Execute = function()
{
FCKUndo.SaveUndoStep() ;
FCK.SetData( '' ) ;
FCKUndo.Typing = true ;
FCK.Focus() ;
}
FCKNewPageCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
// ### Source button
var FCKSourceCommand = function()
{
this.Name = 'Source' ;
}
FCKSourceCommand.prototype.Execute = function()
{
if ( FCKConfig.SourcePopup ) // Until v2.2, it was mandatory for FCKBrowserInfo.IsGecko.
{
var iWidth = FCKConfig.ScreenWidth * 0.65 ;
var iHeight = FCKConfig.ScreenHeight * 0.65 ;
FCKDialog.OpenDialog( 'FCKDialog_Source', FCKLang.Source, 'dialog/fck_source.html', iWidth, iHeight, null, null, true ) ;
}
else
FCK.SwitchEditMode() ;
}
FCKSourceCommand.prototype.GetState = function()
{
return ( FCK.EditMode == FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_OFF : FCK_TRISTATE_ON ) ;
}
// ### Undo
var FCKUndoCommand = function()
{
this.Name = 'Undo' ;
}
FCKUndoCommand.prototype.Execute = function()
{
FCKUndo.Undo() ;
}
FCKUndoCommand.prototype.GetState = function()
{
return ( FCKUndo.CheckUndoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
}
// ### Redo
var FCKRedoCommand = function()
{
this.Name = 'Redo' ;
}
FCKRedoCommand.prototype.Execute = function()
{
FCKUndo.Redo() ;
}
FCKRedoCommand.prototype.GetState = function()
{
return ( FCKUndo.CheckRedoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
}
// ### Page Break
var FCKPageBreakCommand = function()
{
this.Name = 'PageBreak' ;
}
FCKPageBreakCommand.prototype.Execute = function()
{
// Take an undo snapshot before changing the document
FCKUndo.SaveUndoStep() ;
// var e = FCK.EditorDocument.createElement( 'CENTER' ) ;
// e.style.pageBreakAfter = 'always' ;
// Tidy was removing the empty CENTER tags, so the following solution has
// been found. It also validates correctly as XHTML 1.0 Strict.
var e = FCK.EditorDocument.createElement( 'DIV' ) ;
e.style.pageBreakAfter = 'always' ;
e.innerHTML = '<span style="DISPLAY:none">&nbsp;</span>' ;
var oFakeImage = FCKDocumentProcessor_CreateFakeImage( 'FCK__PageBreak', e ) ;
var oRange = new FCKDomRange( FCK.EditorWindow ) ;
oRange.MoveToSelection() ;
var oSplitInfo = oRange.SplitBlock() ;
if ( oSplitInfo.NextBlock )
oSplitInfo.NextBlock.parentNode.insertBefore( oFakeImage, oSplitInfo.NextBlock ) ;
else
oSplitInfo.PreviousBlock.parentNode.insertBefore( oFakeImage, oSplitInfo.PreviousBlock.nextSibling ) ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
FCKPageBreakCommand.prototype.GetState = function()
{
return 0 ; // FCK_TRISTATE_OFF
}
// FCKUnlinkCommand - by Johnny Egeland (johnny@coretrek.com)
var FCKUnlinkCommand = function()
{
this.Name = 'Unlink' ;
}
FCKUnlinkCommand.prototype.Execute = function()
{
// Take an undo snapshot before changing the document
FCKUndo.SaveUndoStep() ;
if ( FCKBrowserInfo.IsGeckoLike )
{
var oLink = FCK.Selection.MoveToAncestorNode( 'A' ) ;
// The unlink command can generate a span in Firefox, so let's do it our way. See #430
if ( oLink )
FCKTools.RemoveOuterTags( oLink ) ;
return ;
}
FCK.ExecuteNamedCommand( this.Name ) ;
}
FCKUnlinkCommand.prototype.GetState = function()
{
var state = FCK.GetNamedCommandState( this.Name ) ;
// Check that it isn't an anchor
if ( state == FCK_TRISTATE_OFF && FCK.EditMode == FCK_EDITMODE_WYSIWYG )
{
var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
var bIsAnchor = ( oLink && oLink.name.length > 0 && oLink.href.length == 0 ) ;
if ( bIsAnchor )
state = FCK_TRISTATE_DISABLED ;
}
return state ;
}
// FCKSelectAllCommand
var FCKSelectAllCommand = function()
{
this.Name = 'SelectAll' ;
}
FCKSelectAllCommand.prototype.Execute = function()
{
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
{
FCK.ExecuteNamedCommand( 'SelectAll' ) ;
}
else
{
// Select the contents of the textarea
var textarea = FCK.EditingArea.Textarea ;
if ( FCKBrowserInfo.IsIE )
{
textarea.createTextRange().execCommand( 'SelectAll' ) ;
}
else
{
textarea.selectionStart = 0 ;
textarea.selectionEnd = textarea.value.length ;
}
textarea.focus() ;
}
}
FCKSelectAllCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
// FCKPasteCommand
var FCKPasteCommand = function()
{
this.Name = 'Paste' ;
}
FCKPasteCommand.prototype =
{
Execute : function()
{
if ( FCKBrowserInfo.IsIE )
FCK.Paste() ;
else
FCK.ExecuteNamedCommand( 'Paste' ) ;
},
GetState : function()
{
return FCK.GetNamedCommandState( 'Paste' ) ;
}
} ;
// FCKRuleCommand
var FCKRuleCommand = function()
{
this.Name = 'Rule' ;
}
FCKRuleCommand.prototype =
{
Execute : function()
{
FCKUndo.SaveUndoStep() ;
FCK.InsertElement( 'hr' ) ;
},
GetState : function()
{
return FCK.GetNamedCommandState( 'InsertHorizontalRule' ) ;
}
} ;
// FCKCopyCommand
var FCKCopyCommand = function()
{
this.Name = 'Copy' ;
}
FCKCopyCommand.prototype =
{
Execute : function()
{
FCK.ExecuteNamedCommand( this.Name ) ;
},
GetState : function()
{
// Strangely, the cut command happens to have the correct states for both Copy and Cut in all browsers.
return FCK.GetNamedCommandState( 'Cut' ) ;
}
};
var FCKAnchorDeleteCommand = function()
{
this.Name = 'AnchorDelete' ;
}
FCKAnchorDeleteCommand.prototype =
{
Execute : function()
{
if (FCK.Selection.GetType() == 'Control')
{
FCK.Selection.Delete();
}
else
{
var oFakeImage = FCK.Selection.GetSelectedElement() ;
if ( oFakeImage )
{
if ( oFakeImage.tagName == 'IMG' && oFakeImage.getAttribute('_fckanchor') )
oAnchor = FCK.GetRealElement( oFakeImage ) ;
else
oFakeImage = null ;
}
//Search for a real anchor
if ( !oFakeImage )
{
oAnchor = FCK.Selection.MoveToAncestorNode( 'A' ) ;
if ( oAnchor )
FCK.Selection.SelectNode( oAnchor ) ;
}
// If it's also a link, then just remove the name and exit
if ( oAnchor.href.length != 0 )
{
oAnchor.removeAttribute( 'name' ) ;
// Remove temporary class for IE
if ( FCKBrowserInfo.IsIE )
oAnchor.className = oAnchor.className.replace( FCKRegexLib.FCK_Class, '' ) ;
return ;
}
// We need to remove the anchor
// If we got a fake image, then just remove it and we're done
if ( oFakeImage )
{
oFakeImage.parentNode.removeChild( oFakeImage ) ;
return ;
}
// Empty anchor, so just remove it
if ( oAnchor.innerHTML.length == 0 )
{
oAnchor.parentNode.removeChild( oAnchor ) ;
return ;
}
// Anchor with content, leave the content
FCKTools.RemoveOuterTags( oAnchor ) ;
}
if ( FCKBrowserInfo.IsGecko )
FCK.Selection.Collapse( true ) ;
},
GetState : function()
{
return FCK.GetNamedCommandState( 'Unlink') ;
}
};

View file

@ -0,0 +1,250 @@
/*
* 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 ==
*
* FCKBlockQuoteCommand Class: adds or removes blockquote tags.
*/
var FCKBlockQuoteCommand = function()
{
}
FCKBlockQuoteCommand.prototype =
{
Execute : function()
{
FCKUndo.SaveUndoStep() ;
var state = this.GetState() ;
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
var bookmark = range.CreateBookmark() ;
// Kludge for #1592: if the bookmark nodes are in the beginning of
// blockquote, then move them to the nearest block element in the
// blockquote.
if ( FCKBrowserInfo.IsIE )
{
var bStart = range.GetBookmarkNode( bookmark, true ) ;
var bEnd = range.GetBookmarkNode( bookmark, false ) ;
var cursor ;
if ( bStart
&& bStart.parentNode.nodeName.IEquals( 'blockquote' )
&& !bStart.previousSibling )
{
cursor = bStart ;
while ( ( cursor = cursor.nextSibling ) )
{
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
FCKDomTools.MoveNode( bStart, cursor, true ) ;
}
}
if ( bEnd
&& bEnd.parentNode.nodeName.IEquals( 'blockquote' )
&& !bEnd.previousSibling )
{
cursor = bEnd ;
while ( ( cursor = cursor.nextSibling ) )
{
if ( FCKListsLib.BlockElements[ cursor.nodeName.toLowerCase() ] )
{
if ( cursor.firstChild == bStart )
FCKDomTools.InsertAfterNode( bStart, bEnd ) ;
else
FCKDomTools.MoveNode( bEnd, cursor, true ) ;
}
}
}
}
var iterator = new FCKDomRangeIterator( range ) ;
var block ;
if ( state == FCK_TRISTATE_OFF )
{
iterator.EnforceRealBlocks = true ;
var paragraphs = [] ;
while ( ( block = iterator.GetNextParagraph() ) )
paragraphs.push( block ) ;
// If no paragraphs, create one from the current selection position.
if ( paragraphs.length < 1 )
{
para = range.Window.document.createElement( FCKConfig.EnterMode.IEquals( 'p' ) ? 'p' : 'div' ) ;
range.InsertNode( para ) ;
para.appendChild( range.Window.document.createTextNode( '\ufeff' ) ) ;
range.MoveToBookmark( bookmark ) ;
range.MoveToNodeContents( para ) ;
range.Collapse( true ) ;
bookmark = range.CreateBookmark() ;
paragraphs.push( para ) ;
}
// Make sure all paragraphs have the same parent.
var commonParent = paragraphs[0].parentNode ;
var tmp = [] ;
for ( var i = 0 ; i < paragraphs.length ; i++ )
{
block = paragraphs[i] ;
commonParent = FCKDomTools.GetCommonParents( block.parentNode, commonParent ).pop() ;
}
var lastBlock = null ;
while ( paragraphs.length > 0 )
{
block = paragraphs.shift() ;
while ( block.parentNode != commonParent )
block = block.parentNode ;
if ( block != lastBlock )
tmp.push( block ) ;
lastBlock = block ;
}
// If any of the selected blocks is a blockquote, remove it to prevent nested blockquotes.
while ( tmp.length > 0 )
{
block = tmp.shift() ;
if ( block.nodeName.IEquals( 'blockquote' ) )
{
var docFrag = block.ownerDocument.createDocumentFragment() ;
while ( block.firstChild )
{
docFrag.appendChild( block.removeChild( block.firstChild ) ) ;
paragraphs.push( docFrag.lastChild ) ;
}
block.parentNode.replaceChild( docFrag, block ) ;
}
else
paragraphs.push( block ) ;
}
// Now we have all the blocks to be included in a new blockquote node.
var bqBlock = range.Window.document.createElement( 'blockquote' ) ;
commonParent.insertBefore( bqBlock, paragraphs[0] ) ;
while ( paragraphs.length > 0 )
{
block = paragraphs.shift() ;
bqBlock.appendChild( block ) ;
}
}
else if ( state == FCK_TRISTATE_ON )
{
var moveOutNodes = [] ;
while ( ( block = iterator.GetNextParagraph() ) )
{
var bqParent = null ;
var bqChild = null ;
while ( block.parentNode )
{
if ( block.parentNode.nodeName.IEquals( 'blockquote' ) )
{
bqParent = block.parentNode ;
bqChild = block ;
break ;
}
block = block.parentNode ;
}
if ( bqParent && bqChild )
moveOutNodes.push( bqChild ) ;
}
var movedNodes = [] ;
while ( moveOutNodes.length > 0 )
{
var node = moveOutNodes.shift() ;
var bqBlock = node.parentNode ;
// If the node is located at the beginning or the end, just take it out without splitting.
// Otherwise, split the blockquote node and move the paragraph in between the two blockquote nodes.
if ( node == node.parentNode.firstChild )
{
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock ) ;
if ( ! bqBlock.firstChild )
bqBlock.parentNode.removeChild( bqBlock ) ;
}
else if ( node == node.parentNode.lastChild )
{
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
if ( ! bqBlock.firstChild )
bqBlock.parentNode.removeChild( bqBlock ) ;
}
else
FCKDomTools.BreakParent( node, node.parentNode, range ) ;
movedNodes.push( node ) ;
}
if ( FCKConfig.EnterMode.IEquals( 'br' ) )
{
while ( movedNodes.length )
{
var node = movedNodes.shift() ;
var firstTime = true ;
if ( node.nodeName.IEquals( 'div' ) )
{
var docFrag = node.ownerDocument.createDocumentFragment() ;
var needBeginBr = firstTime && node.previousSibling &&
!FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
if ( firstTime && needBeginBr )
docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ;
var needEndBr = node.nextSibling &&
!FCKListsLib.BlockBoundaries[node.nextSibling.nodeName.toLowerCase()] ;
while ( node.firstChild )
docFrag.appendChild( node.removeChild( node.firstChild ) ) ;
if ( needEndBr )
docFrag.appendChild( node.ownerDocument.createElement( 'br' ) ) ;
node.parentNode.replaceChild( docFrag, node ) ;
firstTime = false ;
}
}
}
}
range.MoveToBookmark( bookmark ) ;
range.Select() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
// Disabled if not WYSIWYG.
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
return FCK_TRISTATE_DISABLED ;
var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
var firstBlock = path.Block || path.BlockLimit ;
if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
return FCK_TRISTATE_OFF ;
// See if the first block has a blockquote parent.
for ( var i = 0 ; i < path.Elements.length ; i++ )
{
if ( path.Elements[i].nodeName.IEquals( 'blockquote' ) )
return FCK_TRISTATE_ON ;
}
return FCK_TRISTATE_OFF ;
}
} ;

View file

@ -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 ==
*
* FCKCoreStyleCommand Class: controls the execution of a core style. Core
* styles are usually represented as buttons in the toolbar., like Bold and
* Italic.
*/
var FCKCoreStyleCommand = function( coreStyleName )
{
this.Name = 'CoreStyle' ;
this.StyleName = '_FCK_' + coreStyleName ;
this.IsActive = false ;
FCKStyles.AttachStyleStateChange( this.StyleName, this._OnStyleStateChange, this ) ;
}
FCKCoreStyleCommand.prototype =
{
Execute : function()
{
FCKUndo.SaveUndoStep() ;
if ( this.IsActive )
FCKStyles.RemoveStyle( this.StyleName ) ;
else
FCKStyles.ApplyStyle( this.StyleName ) ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
return this.IsActive ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ;
},
_OnStyleStateChange : function( styleName, isActive )
{
this.IsActive = isActive ;
}
};

View file

@ -0,0 +1,180 @@
/*
* 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 ==
*
* Stretch the editor to full window size and back.
*/
var FCKFitWindow = function()
{
this.Name = 'FitWindow' ;
}
FCKFitWindow.prototype.Execute = function()
{
var eEditorFrame = window.frameElement ;
var eEditorFrameStyle = eEditorFrame.style ;
var eMainWindow = parent ;
var eDocEl = eMainWindow.document.documentElement ;
var eBody = eMainWindow.document.body ;
var eBodyStyle = eBody.style ;
var eParent ;
// No original style properties known? Go fullscreen.
if ( !this.IsMaximized )
{
// Registering an event handler when the window gets resized.
if( FCKBrowserInfo.IsIE )
eMainWindow.attachEvent( 'onresize', FCKFitWindow_Resize ) ;
else
eMainWindow.addEventListener( 'resize', FCKFitWindow_Resize, true ) ;
// Save the scrollbars position.
this._ScrollPos = FCKTools.GetScrollPosition( eMainWindow ) ;
// Save and reset the styles for the entire node tree. They could interfere in the result.
eParent = eEditorFrame ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while( (eParent = eParent.parentNode) )
{
if ( eParent.nodeType == 1 )
{
eParent._fckSavedStyles = FCKTools.SaveStyles( eParent ) ;
eParent.style.zIndex = FCKConfig.FloatingPanelsZIndex - 1 ;
}
}
// Hide IE scrollbars (in strict mode).
if ( FCKBrowserInfo.IsIE )
{
this.documentElementOverflow = eDocEl.style.overflow ;
eDocEl.style.overflow = 'hidden' ;
eBodyStyle.overflow = 'hidden' ;
}
else
{
// Hide the scroolbars in Firefox.
eBodyStyle.overflow = 'hidden' ;
eBodyStyle.width = '0px' ;
eBodyStyle.height = '0px' ;
}
// Save the IFRAME styles.
this._EditorFrameStyles = FCKTools.SaveStyles( eEditorFrame ) ;
// Resize.
var oViewPaneSize = FCKTools.GetViewPaneSize( eMainWindow ) ;
eEditorFrameStyle.position = "absolute";
eEditorFrameStyle.zIndex = FCKConfig.FloatingPanelsZIndex - 1;
eEditorFrameStyle.left = "0px";
eEditorFrameStyle.top = "0px";
eEditorFrameStyle.width = oViewPaneSize.Width + "px";
eEditorFrameStyle.height = oViewPaneSize.Height + "px";
// Giving the frame some (huge) borders on his right and bottom
// side to hide the background that would otherwise show when the
// editor is in fullsize mode and the window is increased in size
// not for IE, because IE immediately adapts the editor on resize,
// without showing any of the background oddly in firefox, the
// editor seems not to fill the whole frame, so just setting the
// background of it to white to cover the page laying behind it anyway.
if ( !FCKBrowserInfo.IsIE )
{
eEditorFrameStyle.borderRight = eEditorFrameStyle.borderBottom = "9999px solid white" ;
eEditorFrameStyle.backgroundColor = "white";
}
// Scroll to top left.
eMainWindow.scrollTo(0, 0);
// Is the editor still not on the top left? Let's find out and fix that as well. (Bug #174)
var editorPos = FCKTools.GetWindowPosition( eMainWindow, eEditorFrame ) ;
if ( editorPos.x != 0 )
eEditorFrameStyle.left = ( -1 * editorPos.x ) + "px" ;
if ( editorPos.y != 0 )
eEditorFrameStyle.top = ( -1 * editorPos.y ) + "px" ;
this.IsMaximized = true ;
}
else // Resize to original size.
{
// Remove the event handler of window resizing.
if( FCKBrowserInfo.IsIE )
eMainWindow.detachEvent( "onresize", FCKFitWindow_Resize ) ;
else
eMainWindow.removeEventListener( "resize", FCKFitWindow_Resize, true ) ;
// Restore the CSS position for the entire node tree.
eParent = eEditorFrame ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while( (eParent = eParent.parentNode) )
{
if ( eParent._fckSavedStyles )
{
FCKTools.RestoreStyles( eParent, eParent._fckSavedStyles ) ;
eParent._fckSavedStyles = null ;
}
}
// Restore IE scrollbars
if ( FCKBrowserInfo.IsIE )
eDocEl.style.overflow = this.documentElementOverflow ;
// Restore original size
FCKTools.RestoreStyles( eEditorFrame, this._EditorFrameStyles ) ;
// Restore the window scroll position.
eMainWindow.scrollTo( this._ScrollPos.X, this._ScrollPos.Y ) ;
this.IsMaximized = false ;
}
FCKToolbarItems.GetItem('FitWindow').RefreshState() ;
// It seams that Firefox restarts the editing area when making this changes.
// On FF 1.0.x, the area is not anymore editable. On FF 1.5+, the special
//configuration, like DisableFFTableHandles and DisableObjectResizing get
//lost, so we must reset it. Also, the cursor position and selection are
//also lost, even if you comment the following line (MakeEditable).
// if ( FCKBrowserInfo.IsGecko10 ) // Initially I thought it was a FF 1.0 only problem.
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
FCK.EditingArea.MakeEditable() ;
FCK.Focus() ;
}
FCKFitWindow.prototype.GetState = function()
{
if ( FCKConfig.ToolbarLocation != 'In' )
return FCK_TRISTATE_DISABLED ;
else
return ( this.IsMaximized ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF );
}
function FCKFitWindow_Resize()
{
var oViewPaneSize = FCKTools.GetViewPaneSize( parent ) ;
var eEditorFrameStyle = window.frameElement.style ;
eEditorFrameStyle.width = oViewPaneSize.Width + 'px' ;
eEditorFrameStyle.height = oViewPaneSize.Height + 'px' ;
}

View file

@ -0,0 +1,280 @@
/*
* 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 ==
*
* FCKIndentCommand Class: controls block indentation.
*/
var FCKIndentCommand = function( name, offset )
{
this.Name = name ;
this.Offset = offset ;
this.IndentCSSProperty = FCKConfig.ContentLangDirection.IEquals( 'ltr' ) ? 'marginLeft' : 'marginRight' ;
}
FCKIndentCommand._InitIndentModeParameters = function()
{
if ( FCKConfig.IndentClasses && FCKConfig.IndentClasses.length > 0 )
{
this._UseIndentClasses = true ;
this._IndentClassMap = {} ;
for ( var i = 0 ; i < FCKConfig.IndentClasses.length ;i++ )
this._IndentClassMap[FCKConfig.IndentClasses[i]] = i + 1 ;
this._ClassNameRegex = new RegExp( '(?:^|\\s+)(' + FCKConfig.IndentClasses.join( '|' ) + ')(?=$|\\s)' ) ;
}
else
this._UseIndentClasses = false ;
}
FCKIndentCommand.prototype =
{
Execute : function()
{
// Save an undo snapshot before doing anything.
FCKUndo.SaveUndoStep() ;
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
var bookmark = range.CreateBookmark() ;
// Two cases to handle here: either we're in a list, or not.
// If we're in a list, then the indent/outdent operations would be done on the list nodes.
// Otherwise, apply the operation on the nearest block nodes.
var nearestListBlock = FCKDomTools.GetCommonParentNode( range.StartNode || range.StartContainer ,
range.EndNode || range.EndContainer,
['ul', 'ol'] ) ;
if ( nearestListBlock )
this._IndentList( range, nearestListBlock ) ;
else
this._IndentBlock( range ) ;
range.MoveToBookmark( bookmark ) ;
range.Select() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
// Disabled if not WYSIWYG.
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
return FCK_TRISTATE_DISABLED ;
// Initialize parameters if not already initialzed.
if ( FCKIndentCommand._UseIndentClasses == undefined )
FCKIndentCommand._InitIndentModeParameters() ;
// If we're not in a list, and the starting block's indentation is zero, and the current
// command is the outdent command, then we should return FCK_TRISTATE_DISABLED.
var startContainer = FCKSelection.GetBoundaryParentElement( true ) ;
var endContainer = FCKSelection.GetBoundaryParentElement( false ) ;
var listNode = FCKDomTools.GetCommonParentNode( startContainer, endContainer, ['ul','ol'] ) ;
if ( listNode )
{
if ( this.Name.IEquals( 'outdent' ) )
return FCK_TRISTATE_OFF ;
var firstItem = FCKTools.GetElementAscensor( startContainer, 'li' ) ;
if ( !firstItem || !firstItem.previousSibling )
return FCK_TRISTATE_DISABLED ;
return FCK_TRISTATE_OFF ;
}
if ( ! FCKIndentCommand._UseIndentClasses && this.Name.IEquals( 'indent' ) )
return FCK_TRISTATE_OFF;
var path = new FCKElementPath( startContainer ) ;
var firstBlock = path.Block || path.BlockLimit ;
if ( !firstBlock )
return FCK_TRISTATE_DISABLED ;
if ( FCKIndentCommand._UseIndentClasses )
{
var indentClass = firstBlock.className.match( FCKIndentCommand._ClassNameRegex ) ;
var indentStep = 0 ;
if ( indentClass != null )
{
indentClass = indentClass[1] ;
indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;
}
if ( ( this.Name == 'outdent' && indentStep == 0 ) ||
( this.Name == 'indent' && indentStep == FCKConfig.IndentClasses.length ) )
return FCK_TRISTATE_DISABLED ;
return FCK_TRISTATE_OFF ;
}
else
{
var indent = parseInt( firstBlock.style[this.IndentCSSProperty], 10 ) ;
if ( isNaN( indent ) )
indent = 0 ;
if ( indent <= 0 )
return FCK_TRISTATE_DISABLED ;
return FCK_TRISTATE_OFF ;
}
},
_IndentBlock : function( range )
{
var iterator = new FCKDomRangeIterator( range ) ;
range.Expand( 'block_contents' ) ;
var commonParents = FCKDomTools.GetCommonParents( range.StartContainer, range.EndContainer ) ;
var nearestParent = commonParents[commonParents.length - 1] ;
var block ;
while ( ( block = iterator.GetNextParagraph() ) )
{
// We don't want to indent subtrees recursively, so only perform the indent operation
// if the block itself is the nearestParent, or the block's parent is the nearestParent.
if ( ! ( block == nearestParent || block.parentNode == nearestParent ) )
continue ;
if ( FCKIndentCommand._UseIndentClasses )
{
// Transform current class name to indent step index.
var indentClass = block.className.match( FCKIndentCommand._ClassNameRegex ) ;
var indentStep = 0 ;
if ( indentClass != null )
{
indentClass = indentClass[1] ;
indentStep = FCKIndentCommand._IndentClassMap[indentClass] ;
}
// Operate on indent step index, transform indent step index back to class name.
if ( this.Name.IEquals( 'outdent' ) )
indentStep-- ;
else if ( this.Name.IEquals( 'indent' ) )
indentStep++ ;
indentStep = Math.min( indentStep, FCKConfig.IndentClasses.length ) ;
indentStep = Math.max( indentStep, 0 ) ;
var className = block.className.replace( FCKIndentCommand._ClassNameRegex, '' ) ;
if ( indentStep < 1 )
block.className = className ;
else
block.className = ( className.length > 0 ? className + ' ' : '' ) +
FCKConfig.IndentClasses[indentStep - 1] ;
}
else
{
// Offset distance is assumed to be in pixels for now.
var currentOffset = parseInt( block.style[this.IndentCSSProperty], 10 ) ;
if ( isNaN( currentOffset ) )
currentOffset = 0 ;
currentOffset += this.Offset ;
currentOffset = Math.max( currentOffset, 0 ) ;
currentOffset = Math.ceil( currentOffset / this.Offset ) * this.Offset ;
block.style[this.IndentCSSProperty] = currentOffset ? currentOffset + FCKConfig.IndentUnit : '' ;
if ( block.getAttribute( 'style' ) == '' )
block.removeAttribute( 'style' ) ;
}
}
},
_IndentList : function( range, listNode )
{
// Our starting and ending points of the range might be inside some blocks under a list item...
// So before playing with the iterator, we need to expand the block to include the list items.
var startContainer = range.StartContainer ;
var endContainer = range.EndContainer ;
while ( startContainer && startContainer.parentNode != listNode )
startContainer = startContainer.parentNode ;
while ( endContainer && endContainer.parentNode != listNode )
endContainer = endContainer.parentNode ;
if ( ! startContainer || ! endContainer )
return ;
// Now we can iterate over the individual items on the same tree depth.
var block = startContainer ;
var itemsToMove = [] ;
var stopFlag = false ;
while ( stopFlag == false )
{
if ( block == endContainer )
stopFlag = true ;
itemsToMove.push( block ) ;
block = block.nextSibling ;
}
if ( itemsToMove.length < 1 )
return ;
// Do indent or outdent operations on the array model of the list, not the list's DOM tree itself.
// The array model demands that it knows as much as possible about the surrounding lists, we need
// to feed it the further ancestor node that is still a list.
var listParents = FCKDomTools.GetParents( listNode ) ;
for ( var i = 0 ; i < listParents.length ; i++ )
{
if ( listParents[i].nodeName.IEquals( ['ul', 'ol'] ) )
{
listNode = listParents[i] ;
break ;
}
}
var indentOffset = this.Name.IEquals( 'indent' ) ? 1 : -1 ;
var startItem = itemsToMove[0] ;
var lastItem = itemsToMove[ itemsToMove.length - 1 ] ;
var markerObj = {} ;
// Convert the list DOM tree into a one dimensional array.
var listArray = FCKDomTools.ListToArray( listNode, markerObj ) ;
// Apply indenting or outdenting on the array.
var baseIndent = listArray[lastItem._FCK_ListArray_Index].indent ;
for ( var i = startItem._FCK_ListArray_Index ; i <= lastItem._FCK_ListArray_Index ; i++ )
listArray[i].indent += indentOffset ;
for ( var i = lastItem._FCK_ListArray_Index + 1 ; i < listArray.length && listArray[i].indent > baseIndent ; i++ )
listArray[i].indent += indentOffset ;
/* For debug use only
var PrintArray = function( listArray, doc )
{
var s = [] ;
for ( var i = 0 ; i < listArray.length ; i++ )
{
for ( var j in listArray[i] )
{
if ( j != 'contents' )
s.push( j + ":" + listArray[i][j] + "; " ) ;
else
{
var docFrag = doc.createDocumentFragment() ;
var tmpNode = doc.createElement( 'span' ) ;
for ( var k = 0 ; k < listArray[i][j].length ; k++ )
docFrag.appendChild( listArray[i][j][k].cloneNode( true ) ) ;
tmpNode.appendChild( docFrag ) ;
s.push( j + ":" + tmpNode.innerHTML + "; ") ;
}
}
s.push( '\n' ) ;
}
alert( s.join('') ) ;
}
PrintArray( listArray, FCK.EditorDocument ) ;
*/
// Convert the array back to a DOM forest (yes we might have a few subtrees now).
// And replace the old list with the new forest.
var newList = FCKDomTools.ArrayToList( listArray ) ;
if ( newList )
listNode.parentNode.replaceChild( newList.listNode, listNode ) ;
// Clean up the markers.
FCKDomTools.ClearAllMarkers( markerObj ) ;
}
} ;

View file

@ -0,0 +1,173 @@
/*
* 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 ==
*
* FCKJustifyCommand Class: controls block justification.
*/
var FCKJustifyCommand = function( alignValue )
{
this.AlignValue = alignValue ;
// Detect whether this is the instance for the default alignment.
var contentDir = FCKConfig.ContentLangDirection.toLowerCase() ;
this.IsDefaultAlign = ( alignValue == 'left' && contentDir == 'ltr' ) ||
( alignValue == 'right' && contentDir == 'rtl' ) ;
// Get the class name to be used by this instance.
var cssClassName = this._CssClassName = ( function()
{
var classes = FCKConfig.JustifyClasses ;
if ( classes )
{
switch ( alignValue )
{
case 'left' :
return classes[0] ;
case 'center' :
return classes[1] ;
case 'right' :
return classes[2] ;
case 'justify' :
return classes[3] ;
}
}
return null ;
} )() ;
if ( cssClassName && cssClassName.length > 0 )
this._CssClassRegex = new RegExp( '(?:^|\\s+)' + cssClassName + '(?=$|\\s)' ) ;
}
FCKJustifyCommand._GetClassNameRegex = function()
{
var regex = FCKJustifyCommand._ClassRegex ;
if ( regex != undefined )
return regex ;
var names = [] ;
var classes = FCKConfig.JustifyClasses ;
if ( classes )
{
for ( var i = 0 ; i < 4 ; i++ )
{
var className = classes[i] ;
if ( className && className.length > 0 )
names.push( className ) ;
}
}
if ( names.length > 0 )
regex = new RegExp( '(?:^|\\s+)(?:' + names.join( '|' ) + ')(?=$|\\s)' ) ;
else
regex = null ;
return FCKJustifyCommand._ClassRegex = regex ;
}
FCKJustifyCommand.prototype =
{
Execute : function()
{
// Save an undo snapshot before doing anything.
FCKUndo.SaveUndoStep() ;
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
var currentState = this.GetState() ;
if ( currentState == FCK_TRISTATE_DISABLED )
return ;
// Store a bookmark of the selection since the paragraph iterator might
// change the DOM tree and break selections.
var bookmark = range.CreateBookmark() ;
var cssClassName = this._CssClassName ;
// Apply alignment setting for each paragraph.
var iterator = new FCKDomRangeIterator( range ) ;
var block ;
while ( ( block = iterator.GetNextParagraph() ) )
{
block.removeAttribute( 'align' ) ;
if ( cssClassName )
{
// Remove the any of the alignment classes from the className.
var className = block.className.replace( FCKJustifyCommand._GetClassNameRegex(), '' ) ;
// Append the desired class name.
if ( currentState == FCK_TRISTATE_OFF )
{
if ( className.length > 0 )
className += ' ' ;
block.className = className + cssClassName ;
}
else if ( className.length == 0 )
FCKDomTools.RemoveAttribute( block, 'class' ) ;
}
else
{
var style = block.style ;
if ( currentState == FCK_TRISTATE_OFF )
style.textAlign = this.AlignValue ;
else
{
style.textAlign = '' ;
if ( style.cssText.length == 0 )
block.removeAttribute( 'style' ) ;
}
}
}
// Restore previous selection.
range.MoveToBookmark( bookmark ) ;
range.Select() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
// Disabled if not WYSIWYG.
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
return FCK_TRISTATE_DISABLED ;
// Retrieve the first selected block.
var path = new FCKElementPath( FCKSelection.GetBoundaryParentElement( true ) ) ;
var firstBlock = path.Block || path.BlockLimit ;
if ( !firstBlock || firstBlock.nodeName.toLowerCase() == 'body' )
return FCK_TRISTATE_OFF ;
// Check if the desired style is already applied to the block.
var currentAlign ;
if ( FCKBrowserInfo.IsIE )
currentAlign = firstBlock.currentStyle.textAlign ;
else
currentAlign = FCK.EditorWindow.getComputedStyle( firstBlock, '' ).getPropertyValue( 'text-align' );
currentAlign = currentAlign.replace( /(-moz-|-webkit-|start|auto)/i, '' );
if ( ( !currentAlign && this.IsDefaultAlign ) || currentAlign == this.AlignValue )
return FCK_TRISTATE_ON ;
return FCK_TRISTATE_OFF ;
}
} ;

View file

@ -0,0 +1,382 @@
/*
* 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 ==
*
* Implementation for the "Insert/Remove Ordered/Unordered List" commands.
*/
var FCKListCommand = function( name, tagName )
{
this.Name = name ;
this.TagName = tagName ;
}
FCKListCommand.prototype =
{
GetState : function()
{
// Disabled if not WYSIWYG.
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || ! FCK.EditorWindow )
return FCK_TRISTATE_DISABLED ;
// We'll use the style system's convention to determine list state here...
// If the starting block is a descendant of an <ol> or <ul> node, then we're in a list.
var startContainer = FCKSelection.GetBoundaryParentElement( true ) ;
var listNode = startContainer ;
while ( listNode )
{
if ( listNode.nodeName.IEquals( [ 'ul', 'ol' ] ) )
break ;
listNode = listNode.parentNode ;
}
if ( listNode && listNode.nodeName.IEquals( this.TagName ) )
return FCK_TRISTATE_ON ;
else
return FCK_TRISTATE_OFF ;
},
Execute : function()
{
FCKUndo.SaveUndoStep() ;
var doc = FCK.EditorDocument ;
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
var state = this.GetState() ;
// Midas lists rule #1 says we can create a list even in an empty document.
// But FCKDomRangeIterator wouldn't run if the document is really empty.
// So create a paragraph if the document is empty and we're going to create a list.
if ( state == FCK_TRISTATE_OFF )
{
FCKDomTools.TrimNode( doc.body ) ;
if ( ! doc.body.firstChild )
{
var paragraph = doc.createElement( 'p' ) ;
doc.body.appendChild( paragraph ) ;
range.MoveToNodeContents( paragraph ) ;
}
}
var bookmark = range.CreateBookmark() ;
// Group the blocks up because there are many cases where multiple lists have to be created,
// or multiple lists have to be cancelled.
var listGroups = [] ;
var markerObj = {} ;
var iterator = new FCKDomRangeIterator( range ) ;
var block ;
iterator.ForceBrBreak = ( state == FCK_TRISTATE_OFF ) ;
var nextRangeExists = true ;
var rangeQueue = null ;
while ( nextRangeExists )
{
while ( ( block = iterator.GetNextParagraph() ) )
{
var path = new FCKElementPath( block ) ;
var listNode = null ;
var processedFlag = false ;
var blockLimit = path.BlockLimit ;
// First, try to group by a list ancestor.
for ( var i = path.Elements.length - 1 ; i >= 0 ; i-- )
{
var el = path.Elements[i] ;
if ( el.nodeName.IEquals( ['ol', 'ul'] ) )
{
// If we've encountered a list inside a block limit
// The last group object of the block limit element should
// no longer be valid. Since paragraphs after the list
// should belong to a different group of paragraphs before
// the list. (Bug #1309)
if ( blockLimit._FCK_ListGroupObject )
blockLimit._FCK_ListGroupObject = null ;
var groupObj = el._FCK_ListGroupObject ;
if ( groupObj )
groupObj.contents.push( block ) ;
else
{
groupObj = { 'root' : el, 'contents' : [ block ] } ;
listGroups.push( groupObj ) ;
FCKDomTools.SetElementMarker( markerObj, el, '_FCK_ListGroupObject', groupObj ) ;
}
processedFlag = true ;
break ;
}
}
if ( processedFlag )
continue ;
// No list ancestor? Group by block limit.
var root = blockLimit ;
if ( root._FCK_ListGroupObject )
root._FCK_ListGroupObject.contents.push( block ) ;
else
{
var groupObj = { 'root' : root, 'contents' : [ block ] } ;
FCKDomTools.SetElementMarker( markerObj, root, '_FCK_ListGroupObject', groupObj ) ;
listGroups.push( groupObj ) ;
}
}
if ( FCKBrowserInfo.IsIE )
nextRangeExists = false ;
else
{
if ( rangeQueue == null )
{
rangeQueue = [] ;
var selectionObject = FCK.EditorWindow.getSelection() ;
if ( selectionObject && listGroups.length == 0 )
rangeQueue.push( selectionObject.getRangeAt( 0 ) ) ;
for ( var i = 1 ; selectionObject && i < selectionObject.rangeCount ; i++ )
rangeQueue.push( selectionObject.getRangeAt( i ) ) ;
}
if ( rangeQueue.length < 1 )
nextRangeExists = false ;
else
{
var internalRange = FCKW3CRange.CreateFromRange( doc, rangeQueue.shift() ) ;
range._Range = internalRange ;
range._UpdateElementInfo() ;
if ( range.StartNode.nodeName.IEquals( 'td' ) )
range.SetStart( range.StartNode, 1 ) ;
if ( range.EndNode.nodeName.IEquals( 'td' ) )
range.SetEnd( range.EndNode, 2 ) ;
iterator = new FCKDomRangeIterator( range ) ;
iterator.ForceBrBreak = ( state == FCK_TRISTATE_OFF ) ;
}
}
}
// Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element.
// We either have to build lists or remove lists, for removing a list does not makes sense when we are looking
// at the group that's not rooted at lists. So we have three cases to handle.
var listsCreated = [] ;
while ( listGroups.length > 0 )
{
var groupObj = listGroups.shift() ;
if ( state == FCK_TRISTATE_OFF )
{
if ( groupObj.root.nodeName.IEquals( ['ul', 'ol'] ) )
this._ChangeListType( groupObj, markerObj, listsCreated ) ;
else
this._CreateList( groupObj, listsCreated ) ;
}
else if ( state == FCK_TRISTATE_ON && groupObj.root.nodeName.IEquals( ['ul', 'ol'] ) )
this._RemoveList( groupObj, markerObj ) ;
}
// For all new lists created, merge adjacent, same type lists.
for ( var i = 0 ; i < listsCreated.length ; i++ )
{
var listNode = listsCreated[i] ;
var stopFlag = false ;
var currentNode = listNode ;
while ( ! stopFlag )
{
currentNode = currentNode.nextSibling ;
if ( currentNode && currentNode.nodeType == 3 && currentNode.nodeValue.search( /^[\n\r\t ]*$/ ) == 0 )
continue ;
stopFlag = true ;
}
if ( currentNode && currentNode.nodeName.IEquals( this.TagName ) )
{
currentNode.parentNode.removeChild( currentNode ) ;
while ( currentNode.firstChild )
listNode.appendChild( currentNode.removeChild( currentNode.firstChild ) ) ;
}
stopFlag = false ;
currentNode = listNode ;
while ( ! stopFlag )
{
currentNode = currentNode.previousSibling ;
if ( currentNode && currentNode.nodeType == 3 && currentNode.nodeValue.search( /^[\n\r\t ]*$/ ) == 0 )
continue ;
stopFlag = true ;
}
if ( currentNode && currentNode.nodeName.IEquals( this.TagName ) )
{
currentNode.parentNode.removeChild( currentNode ) ;
while ( currentNode.lastChild )
listNode.insertBefore( currentNode.removeChild( currentNode.lastChild ),
listNode.firstChild ) ;
}
}
// Clean up, restore selection and update toolbar button states.
FCKDomTools.ClearAllMarkers( markerObj ) ;
range.MoveToBookmark( bookmark ) ;
range.Select() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
_ChangeListType : function( groupObj, markerObj, listsCreated )
{
// This case is easy...
// 1. Convert the whole list into a one-dimensional array.
// 2. Change the list type by modifying the array.
// 3. Recreate the whole list by converting the array to a list.
// 4. Replace the original list with the recreated list.
var listArray = FCKDomTools.ListToArray( groupObj.root, markerObj ) ;
var selectedListItems = [] ;
for ( var i = 0 ; i < groupObj.contents.length ; i++ )
{
var itemNode = groupObj.contents[i] ;
itemNode = FCKTools.GetElementAscensor( itemNode, 'li' ) ;
if ( ! itemNode || itemNode._FCK_ListItem_Processed )
continue ;
selectedListItems.push( itemNode ) ;
FCKDomTools.SetElementMarker( markerObj, itemNode, '_FCK_ListItem_Processed', true ) ;
}
var fakeParent = groupObj.root.ownerDocument.createElement( this.TagName ) ;
for ( var i = 0 ; i < selectedListItems.length ; i++ )
{
var listIndex = selectedListItems[i]._FCK_ListArray_Index ;
listArray[listIndex].parent = fakeParent ;
}
var newList = FCKDomTools.ArrayToList( listArray, markerObj ) ;
for ( var i = 0 ; i < newList.listNode.childNodes.length ; i++ )
{
if ( newList.listNode.childNodes[i].nodeName.IEquals( this.TagName ) )
listsCreated.push( newList.listNode.childNodes[i] ) ;
}
groupObj.root.parentNode.replaceChild( newList.listNode, groupObj.root ) ;
},
_CreateList : function( groupObj, listsCreated )
{
var contents = groupObj.contents ;
var doc = groupObj.root.ownerDocument ;
var listContents = [] ;
// It is possible to have the contents returned by DomRangeIterator to be the same as the root.
// e.g. when we're running into table cells.
// In such a case, enclose the childNodes of contents[0] into a <div>.
if ( contents.length == 1 && contents[0] == groupObj.root )
{
var divBlock = doc.createElement( 'div' );
while ( contents[0].firstChild )
divBlock.appendChild( contents[0].removeChild( contents[0].firstChild ) ) ;
contents[0].appendChild( divBlock ) ;
contents[0] = divBlock ;
}
// Calculate the common parent node of all content blocks.
var commonParent = groupObj.contents[0].parentNode ;
for ( var i = 0 ; i < contents.length ; i++ )
commonParent = FCKDomTools.GetCommonParents( commonParent, contents[i].parentNode ).pop() ;
// We want to insert things that are in the same tree level only, so calculate the contents again
// by expanding the selected blocks to the same tree level.
for ( var i = 0 ; i < contents.length ; i++ )
{
var contentNode = contents[i] ;
while ( contentNode.parentNode )
{
if ( contentNode.parentNode == commonParent )
{
listContents.push( contentNode ) ;
break ;
}
contentNode = contentNode.parentNode ;
}
}
if ( listContents.length < 1 )
return ;
// Insert the list to the DOM tree.
var insertAnchor = listContents[listContents.length - 1].nextSibling ;
var listNode = doc.createElement( this.TagName ) ;
listsCreated.push( listNode ) ;
while ( listContents.length )
{
var contentBlock = listContents.shift() ;
var docFrag = doc.createDocumentFragment() ;
while ( contentBlock.firstChild )
docFrag.appendChild( contentBlock.removeChild( contentBlock.firstChild ) ) ;
contentBlock.parentNode.removeChild( contentBlock ) ;
var listItem = doc.createElement( 'li' ) ;
listItem.appendChild( docFrag ) ;
listNode.appendChild( listItem ) ;
}
commonParent.insertBefore( listNode, insertAnchor ) ;
},
_RemoveList : function( groupObj, markerObj )
{
// This is very much like the change list type operation.
// Except that we're changing the selected items' indent to -1 in the list array.
var listArray = FCKDomTools.ListToArray( groupObj.root, markerObj ) ;
var selectedListItems = [] ;
for ( var i = 0 ; i < groupObj.contents.length ; i++ )
{
var itemNode = groupObj.contents[i] ;
itemNode = FCKTools.GetElementAscensor( itemNode, 'li' ) ;
if ( ! itemNode || itemNode._FCK_ListItem_Processed )
continue ;
selectedListItems.push( itemNode ) ;
FCKDomTools.SetElementMarker( markerObj, itemNode, '_FCK_ListItem_Processed', true ) ;
}
var lastListIndex = null ;
for ( var i = 0 ; i < selectedListItems.length ; i++ )
{
var listIndex = selectedListItems[i]._FCK_ListArray_Index ;
listArray[listIndex].indent = -1 ;
lastListIndex = listIndex ;
}
// After cutting parts of the list out with indent=-1, we still have to maintain the array list
// model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the
// list cannot be converted back to a real DOM list.
for ( var i = lastListIndex + 1; i < listArray.length ; i++ )
{
if ( listArray[i].indent > listArray[i-1].indent + 1 )
{
var indentOffset = listArray[i-1].indent + 1 - listArray[i].indent ;
var oldIndent = listArray[i].indent ;
while ( listArray[i] && listArray[i].indent >= oldIndent)
{
listArray[i].indent += indentOffset ;
i++ ;
}
i-- ;
}
}
var newList = FCKDomTools.ArrayToList( listArray, markerObj ) ;
// If groupObj.root is the last element in its parent, or its nextSibling is a <br>, then we should
// not add a <br> after the final item. So, check for the cases and trim the <br>.
if ( groupObj.root.nextSibling == null || groupObj.root.nextSibling.nodeName.IEquals( 'br' ) )
{
if ( newList.listNode.lastChild.nodeName.IEquals( 'br' ) )
newList.listNode.removeChild( newList.listNode.lastChild ) ;
}
groupObj.root.parentNode.replaceChild( newList.listNode, groupObj.root ) ;
}
};

View file

@ -0,0 +1,37 @@
/*
* 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 ==
*
* FCKNamedCommand Class: represents an internal browser command.
*/
var FCKNamedCommand = function( commandName )
{
this.Name = commandName ;
}
FCKNamedCommand.prototype.Execute = function()
{
FCK.ExecuteNamedCommand( this.Name ) ;
}
FCKNamedCommand.prototype.GetState = function()
{
return FCK.GetNamedCommandState( this.Name ) ;
}

View file

@ -0,0 +1,38 @@
/*
* 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 ==
*
* FCKPastePlainTextCommand Class: represents the
* "Paste as Plain Text" command.
*/
var FCKPastePlainTextCommand = function()
{
this.Name = 'PasteText' ;
}
FCKPastePlainTextCommand.prototype.Execute = function()
{
FCK.PasteAsPlainText() ;
}
FCKPastePlainTextCommand.prototype.GetState = function()
{
return FCK.GetNamedCommandState( 'Paste' ) ;
}

View file

@ -0,0 +1,40 @@
/*
* 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 ==
*
* FCKPasteWordCommand Class: represents the "Paste from Word" command.
*/
var FCKPasteWordCommand = function()
{
this.Name = 'PasteWord' ;
}
FCKPasteWordCommand.prototype.Execute = function()
{
FCK.PasteFromWord() ;
}
FCKPasteWordCommand.prototype.GetState = function()
{
if ( FCKConfig.ForcePasteAsPlainText )
return FCK_TRISTATE_DISABLED ;
else
return FCK.GetNamedCommandState( 'Paste' ) ;
}

View file

@ -0,0 +1,45 @@
/*
* 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 ==
*
* FCKRemoveFormatCommand Class: controls the execution of a core style. Core
* styles are usually represented as buttons in the toolbar., like Bold and
* Italic.
*/
var FCKRemoveFormatCommand = function()
{
this.Name = 'RemoveFormat' ;
}
FCKRemoveFormatCommand.prototype =
{
Execute : function()
{
FCKStyles.RemoveAll() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
return FCK.EditorWindow ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}
};

View file

@ -0,0 +1,74 @@
/*
* 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 ==
*
* FCKShowBlockCommand Class: the "Show Blocks" command.
*/
var FCKShowBlockCommand = function( name, defaultState )
{
this.Name = name ;
if ( defaultState != undefined )
this._SavedState = defaultState ;
else
this._SavedState = null ;
}
FCKShowBlockCommand.prototype.Execute = function()
{
var state = this.GetState() ;
if ( state == FCK_TRISTATE_DISABLED )
return ;
var body = FCK.EditorDocument.body ;
if ( state == FCK_TRISTATE_ON )
body.className = body.className.replace( /(^| )FCK__ShowBlocks/g, '' ) ;
else
body.className += ' FCK__ShowBlocks' ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
FCKShowBlockCommand.prototype.GetState = function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
// On some cases FCK.EditorDocument.body is not yet available
if ( !FCK.EditorDocument )
return FCK_TRISTATE_OFF ;
if ( /FCK__ShowBlocks(?:\s|$)/.test( FCK.EditorDocument.body.className ) )
return FCK_TRISTATE_ON ;
return FCK_TRISTATE_OFF ;
}
FCKShowBlockCommand.prototype.SaveState = function()
{
this._SavedState = this.GetState() ;
}
FCKShowBlockCommand.prototype.RestoreState = function()
{
if ( this._SavedState != null && this.GetState() != this._SavedState )
this.Execute() ;
}

View file

@ -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 ==
*
* FCKStyleCommand Class: represents the "Spell Check" command.
* (Gecko specific implementation)
*/
var FCKSpellCheckCommand = function()
{
this.Name = 'SpellCheck' ;
this.IsEnabled = ( FCKConfig.SpellChecker == 'SpellerPages' ) ;
}
FCKSpellCheckCommand.prototype.Execute = function()
{
FCKDialog.OpenDialog( 'FCKDialog_SpellCheck', 'Spell Check', 'dialog/fck_spellerpages.html', 440, 480 ) ;
}
FCKSpellCheckCommand.prototype.GetState = function()
{
return this.IsEnabled ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}

View file

@ -0,0 +1,67 @@
/*
* 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 ==
*
* FCKStyleCommand Class: represents the "Spell Check" command.
* (IE specific implementation)
*/
var FCKSpellCheckCommand = function()
{
this.Name = 'SpellCheck' ;
this.IsEnabled = ( FCKConfig.SpellChecker == 'ieSpell' || FCKConfig.SpellChecker == 'SpellerPages' ) ;
}
FCKSpellCheckCommand.prototype.Execute = function()
{
switch ( FCKConfig.SpellChecker )
{
case 'ieSpell' :
this._RunIeSpell() ;
break ;
case 'SpellerPages' :
FCKDialog.OpenDialog( 'FCKDialog_SpellCheck', 'Spell Check', 'dialog/fck_spellerpages.html', 440, 480 ) ;
break ;
}
}
FCKSpellCheckCommand.prototype._RunIeSpell = function()
{
try
{
var oIeSpell = new ActiveXObject( "ieSpell.ieSpellExtension" ) ;
oIeSpell.CheckAllLinkedDocuments( FCK.EditorDocument ) ;
}
catch( e )
{
if( e.number == -2146827859 )
{
if ( confirm( FCKLang.IeSpellDownload ) )
window.open( FCKConfig.IeSpellDownloadUrl , 'IeSpellDownload' ) ;
}
else
alert( 'Error Loading ieSpell: ' + e.message + ' (' + e.number + ')' ) ;
}
}
FCKSpellCheckCommand.prototype.GetState = function()
{
return this.IsEnabled ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}

View file

@ -0,0 +1,60 @@
/*
* 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 ==
*
* FCKStyleCommand Class: represents the "Style" command.
*/
var FCKStyleCommand = function()
{}
FCKStyleCommand.prototype =
{
Name : 'Style',
Execute : function( styleName, styleComboItem )
{
FCKUndo.SaveUndoStep() ;
if ( styleComboItem.Selected )
FCK.Styles.RemoveStyle( styleComboItem.Style ) ;
else
FCK.Styles.ApplyStyle( styleComboItem.Style ) ;
FCKUndo.SaveUndoStep() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetState : function()
{
if ( !FCK.EditorDocument )
return FCK_TRISTATE_DISABLED ;
if ( FCKSelection.GetType() == 'Control' )
{
var el = FCKSelection.GetSelectedElement() ;
if ( !el || !FCKStyles.CheckHasObjectStyle( el.nodeName.toLowerCase() ) )
return FCK_TRISTATE_DISABLED ;
}
return FCK_TRISTATE_OFF ;
}
};

View file

@ -0,0 +1,106 @@
/*
* 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 ==
*
* FCKPastePlainTextCommand Class: represents the
* "Paste as Plain Text" command.
*/
var FCKTableCommand = function( command )
{
this.Name = command ;
}
FCKTableCommand.prototype.Execute = function()
{
FCKUndo.SaveUndoStep() ;
if ( ! FCKBrowserInfo.IsGecko )
{
switch ( this.Name )
{
case 'TableMergeRight' :
return FCKTableHandler.MergeRight() ;
case 'TableMergeDown' :
return FCKTableHandler.MergeDown() ;
}
}
switch ( this.Name )
{
case 'TableInsertRowAfter' :
return FCKTableHandler.InsertRow( false ) ;
case 'TableInsertRowBefore' :
return FCKTableHandler.InsertRow( true ) ;
case 'TableDeleteRows' :
return FCKTableHandler.DeleteRows() ;
case 'TableInsertColumnAfter' :
return FCKTableHandler.InsertColumn( false ) ;
case 'TableInsertColumnBefore' :
return FCKTableHandler.InsertColumn( true ) ;
case 'TableDeleteColumns' :
return FCKTableHandler.DeleteColumns() ;
case 'TableInsertCellAfter' :
return FCKTableHandler.InsertCell( null, false ) ;
case 'TableInsertCellBefore' :
return FCKTableHandler.InsertCell( null, true ) ;
case 'TableDeleteCells' :
return FCKTableHandler.DeleteCells() ;
case 'TableMergeCells' :
return FCKTableHandler.MergeCells() ;
case 'TableHorizontalSplitCell' :
return FCKTableHandler.HorizontalSplitCell() ;
case 'TableVerticalSplitCell' :
return FCKTableHandler.VerticalSplitCell() ;
case 'TableDelete' :
return FCKTableHandler.DeleteTable() ;
default :
return alert( FCKLang.UnknownCommand.replace( /%1/g, this.Name ) ) ;
}
}
FCKTableCommand.prototype.GetState = function()
{
if ( FCK.EditorDocument != null && FCKSelection.HasAncestorNode( 'TABLE' ) )
{
switch ( this.Name )
{
case 'TableHorizontalSplitCell' :
case 'TableVerticalSplitCell' :
if ( FCKTableHandler.GetSelectedCells().length == 1 )
return FCK_TRISTATE_OFF ;
else
return FCK_TRISTATE_DISABLED ;
case 'TableMergeCells' :
if ( FCKTableHandler.CheckIsSelectionRectangular()
&& FCKTableHandler.GetSelectedCells().length > 1 )
return FCK_TRISTATE_OFF ;
else
return FCK_TRISTATE_DISABLED ;
case 'TableMergeRight' :
return FCKTableHandler.GetMergeRightTarget() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
case 'TableMergeDown' :
return FCKTableHandler.GetMergeDownTarget() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
default :
return FCK_TRISTATE_OFF ;
}
}
else
return FCK_TRISTATE_DISABLED;
}

View file

@ -0,0 +1,197 @@
/*
* 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 ==
*
* FCKTextColorCommand Class: represents the text color comand. It shows the
* color selection panel.
*/
// FCKTextColorCommand Constructor
// type: can be 'ForeColor' or 'BackColor'.
var FCKTextColorCommand = function( type )
{
this.Name = type == 'ForeColor' ? 'TextColor' : 'BGColor' ;
this.Type = type ;
var oWindow ;
if ( FCKBrowserInfo.IsIE )
oWindow = window ;
else if ( FCK.ToolbarSet._IFrame )
oWindow = FCKTools.GetElementWindow( FCK.ToolbarSet._IFrame ) ;
else
oWindow = window.parent ;
this._Panel = new FCKPanel( oWindow ) ;
this._Panel.AppendStyleSheet( FCKConfig.SkinPath + 'fck_editor.css' ) ;
this._Panel.MainNode.className = 'FCK_Panel' ;
this._CreatePanelBody( this._Panel.Document, this._Panel.MainNode ) ;
FCKTools.DisableSelection( this._Panel.Document.body ) ;
}
FCKTextColorCommand.prototype.Execute = function( panelX, panelY, relElement )
{
// Show the Color Panel at the desired position.
this._Panel.Show( panelX, panelY, relElement ) ;
}
FCKTextColorCommand.prototype.SetColor = function( color )
{
FCKUndo.SaveUndoStep() ;
var style = FCKStyles.GetStyle( '_FCK_' +
( this.Type == 'ForeColor' ? 'Color' : 'BackColor' ) ) ;
if ( !color || color.length == 0 )
FCK.Styles.RemoveStyle( style ) ;
else
{
style.SetVariable( 'Color', color ) ;
FCKStyles.ApplyStyle( style ) ;
}
FCKUndo.SaveUndoStep() ;
FCK.Focus() ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
FCKTextColorCommand.prototype.GetState = function()
{
return FCK_TRISTATE_OFF ;
}
function FCKTextColorCommand_OnMouseOver()
{
this.className = 'ColorSelected' ;
}
function FCKTextColorCommand_OnMouseOut()
{
this.className = 'ColorDeselected' ;
}
function FCKTextColorCommand_OnClick( ev, command, color )
{
this.className = 'ColorDeselected' ;
command.SetColor( color ) ;
command._Panel.Hide() ;
}
function FCKTextColorCommand_AutoOnClick( ev, command )
{
this.className = 'ColorDeselected' ;
command.SetColor( '' ) ;
command._Panel.Hide() ;
}
function FCKTextColorCommand_MoreOnClick( ev, command )
{
this.className = 'ColorDeselected' ;
command._Panel.Hide() ;
FCKDialog.OpenDialog( 'FCKDialog_Color', FCKLang.DlgColorTitle, 'dialog/fck_colorselector.html', 400, 330, FCKTools.Hitch(command, 'SetColor') ) ;
}
FCKTextColorCommand.prototype._CreatePanelBody = function( targetDocument, targetDiv )
{
function CreateSelectionDiv()
{
var oDiv = targetDocument.createElement( "DIV" ) ;
oDiv.className = 'ColorDeselected' ;
FCKTools.AddEventListenerEx( oDiv, 'mouseover', FCKTextColorCommand_OnMouseOver ) ;
FCKTools.AddEventListenerEx( oDiv, 'mouseout', FCKTextColorCommand_OnMouseOut ) ;
return oDiv ;
}
// Create the Table that will hold all colors.
var oTable = targetDiv.appendChild( targetDocument.createElement( "TABLE" ) ) ;
oTable.className = 'ForceBaseFont' ; // Firefox 1.5 Bug.
oTable.style.tableLayout = 'fixed' ;
oTable.cellPadding = 0 ;
oTable.cellSpacing = 0 ;
oTable.border = 0 ;
oTable.width = 150 ;
var oCell = oTable.insertRow(-1).insertCell(-1) ;
oCell.colSpan = 8 ;
// Create the Button for the "Automatic" color selection.
var oDiv = oCell.appendChild( CreateSelectionDiv() ) ;
oDiv.innerHTML =
'<table cellspacing="0" cellpadding="0" width="100%" border="0">\
<tr>\
<td><div class="ColorBoxBorder"><div class="ColorBox" style="background-color: #000000"></div></div></td>\
<td nowrap width="100%" align="center">' + FCKLang.ColorAutomatic + '</td>\
</tr>\
</table>' ;
FCKTools.AddEventListenerEx( oDiv, 'click', FCKTextColorCommand_AutoOnClick, this ) ;
// Dirty hack for Opera, Safari and Firefox 3.
if ( !FCKBrowserInfo.IsIE )
oDiv.style.width = '96%' ;
// Create an array of colors based on the configuration file.
var aColors = FCKConfig.FontColors.toString().split(',') ;
// Create the colors table based on the array.
var iCounter = 0 ;
while ( iCounter < aColors.length )
{
var oRow = oTable.insertRow(-1) ;
for ( var i = 0 ; i < 8 ; i++, iCounter++ )
{
// The div will be created even if no more colors are available.
// Extra divs will be hidden later in the code. (#1597)
if ( iCounter < aColors.length )
{
var colorParts = aColors[iCounter].split('/') ;
var colorValue = '#' + colorParts[0] ;
var colorName = colorParts[1] || colorValue ;
}
oDiv = oRow.insertCell(-1).appendChild( CreateSelectionDiv() ) ;
oDiv.innerHTML = '<div class="ColorBoxBorder"><div class="ColorBox" style="background-color: ' + colorValue + '"></div></div>' ;
if ( iCounter >= aColors.length )
oDiv.style.visibility = 'hidden' ;
else
FCKTools.AddEventListenerEx( oDiv, 'click', FCKTextColorCommand_OnClick, [ this, colorName ] ) ;
}
}
// Create the Row and the Cell for the "More Colors..." button.
if ( FCKConfig.EnableMoreFontColors )
{
oCell = oTable.insertRow(-1).insertCell(-1) ;
oCell.colSpan = 8 ;
oDiv = oCell.appendChild( CreateSelectionDiv() ) ;
oDiv.innerHTML = '<table width="100%" cellpadding="0" cellspacing="0" border="0"><tr><td nowrap align="center">' + FCKLang.ColorMoreColors + '</td></tr></table>' ;
FCKTools.AddEventListenerEx( oDiv, 'click', FCKTextColorCommand_MoreOnClick, this ) ;
}
// Dirty hack for Opera, Safari and Firefox 3.
if ( !FCKBrowserInfo.IsIE )
oDiv.style.width = '96%' ;
}

View file

@ -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 ==
*
* Defines some constants used by the editor. These constants are also
* globally available in the page where the editor is placed.
*/
// Editor Instance Status.
var FCK_STATUS_NOTLOADED = window.parent.FCK_STATUS_NOTLOADED = 0 ;
var FCK_STATUS_ACTIVE = window.parent.FCK_STATUS_ACTIVE = 1 ;
var FCK_STATUS_COMPLETE = window.parent.FCK_STATUS_COMPLETE = 2 ;
// Tristate Operations.
var FCK_TRISTATE_OFF = window.parent.FCK_TRISTATE_OFF = 0 ;
var FCK_TRISTATE_ON = window.parent.FCK_TRISTATE_ON = 1 ;
var FCK_TRISTATE_DISABLED = window.parent.FCK_TRISTATE_DISABLED = -1 ;
// For unknown values.
var FCK_UNKNOWN = window.parent.FCK_UNKNOWN = -9 ;
// Toolbar Items Style.
var FCK_TOOLBARITEM_ONLYICON = window.parent.FCK_TOOLBARITEM_ONLYICON = 0 ;
var FCK_TOOLBARITEM_ONLYTEXT = window.parent.FCK_TOOLBARITEM_ONLYTEXT = 1 ;
var FCK_TOOLBARITEM_ICONTEXT = window.parent.FCK_TOOLBARITEM_ICONTEXT = 2 ;
// Edit Mode
var FCK_EDITMODE_WYSIWYG = window.parent.FCK_EDITMODE_WYSIWYG = 0 ;
var FCK_EDITMODE_SOURCE = window.parent.FCK_EDITMODE_SOURCE = 1 ;
var FCK_IMAGES_PATH = 'images/' ; // Check usage.
var FCK_SPACER_PATH = 'images/spacer.gif' ;
var CTRL = 1000 ;
var SHIFT = 2000 ;
var ALT = 4000 ;
var FCK_STYLE_BLOCK = 0 ;
var FCK_STYLE_INLINE = 1 ;
var FCK_STYLE_OBJECT = 2 ;

View file

@ -0,0 +1,168 @@
/*
* 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 ==
*
* Create the FCKeditorAPI object that is available as a global object in
* the page where the editor is placed in.
*/
var FCKeditorAPI ;
function InitializeAPI()
{
var oParentWindow = window.parent ;
if ( !( FCKeditorAPI = oParentWindow.FCKeditorAPI ) )
{
// Make the FCKeditorAPI object available in the parent window. Use
// eval so this core runs in the parent's scope and so it will still be
// available if the editor instance is removed ("Can't execute code
// from a freed script" error).
// Note: we check the existence of oEditor.GetParentForm because some external
// code (like JSON) can extend the Object prototype and we get then extra oEditor
// objects that aren't really FCKeditor instances.
var sScript =
'var FCKeditorAPI = {' +
'Version : "2.5.1",' +
'VersionBuild : "17566",' +
'__Instances : new Object(),' +
'GetInstance : function( name )' +
'{' +
'return this.__Instances[ name ];' +
'},' +
'_FormSubmit : function()' +
'{' +
'for ( var name in FCKeditorAPI.__Instances )' +
'{' +
'var oEditor = FCKeditorAPI.__Instances[ name ] ;' +
'if ( oEditor.GetParentForm && oEditor.GetParentForm() == this )' +
'oEditor.UpdateLinkedField() ;' +
'}' +
'this._FCKOriginalSubmit() ;' +
'},' +
'_FunctionQueue : {' +
'Functions : new Array(),' +
'IsRunning : false,' +
'Add : function( f )' +
'{' +
'this.Functions.push( f );' +
'if ( !this.IsRunning )' +
'this.StartNext();' +
'},' +
'StartNext : function()' +
'{' +
'var aQueue = this.Functions ;' +
'if ( aQueue.length > 0 )' +
'{' +
'this.IsRunning = true;' +
'aQueue[0].call();' +
'}' +
'else ' +
'this.IsRunning = false;' +
'},' +
'Remove : function( f )' +
'{' +
'var aQueue = this.Functions;' +
'var i = 0, fFunc;' +
'while( (fFunc = aQueue[ i ]) )' +
'{' +
'if ( fFunc == f )' +
'aQueue.splice( i,1 );' +
'i++ ;' +
'}' +
'this.StartNext();' +
'}' +
'}' +
'}' ;
// In IE, the "eval" function is not always available (it works with
// the JavaScript samples, but not with the ASP ones, for example).
// So, let's use the execScript instead.
if ( oParentWindow.execScript )
oParentWindow.execScript( sScript, 'JavaScript' ) ;
else
{
if ( FCKBrowserInfo.IsGecko10 )
{
// FF 1.0.4 gives an error with the request bellow. The
// following seams to work well.
eval.call( oParentWindow, sScript ) ;
}
else if ( FCKBrowserInfo.IsSafari || FCKBrowserInfo.IsGecko19 )
{
// oParentWindow.eval in Safari and Gran Paradiso executes in the calling window
// environment, instead of the parent one. The following should make it work.
var oParentDocument = oParentWindow.document ;
var eScript = oParentDocument.createElement('script') ;
eScript.appendChild( oParentDocument.createTextNode( sScript ) ) ;
oParentDocument.documentElement.appendChild( eScript ) ;
}
else
oParentWindow.eval( sScript ) ;
}
FCKeditorAPI = oParentWindow.FCKeditorAPI ;
}
// Add the current instance to the FCKeditorAPI's instances collection.
FCKeditorAPI.__Instances[ FCK.Name ] = FCK ;
}
// Attach to the form onsubmit event and to the form.submit().
function _AttachFormSubmitToAPI()
{
// Get the linked field form.
var oForm = FCK.GetParentForm() ;
if ( oForm )
{
// Attach to the onsubmit event.
FCKTools.AddEventListener( oForm, 'submit', FCK.UpdateLinkedField ) ;
// IE sees oForm.submit function as an 'object'.
if ( !oForm._FCKOriginalSubmit && ( typeof( oForm.submit ) == 'function' || ( !oForm.submit.tagName && !oForm.submit.length ) ) )
{
// Save the original submit.
oForm._FCKOriginalSubmit = oForm.submit ;
// Create our replacement for the submit.
oForm.submit = FCKeditorAPI._FormSubmit ;
}
}
}
function FCKeditorAPI_Cleanup()
{
if ( ! window.FCKUnloadFlag )
return ;
delete FCKeditorAPI.__Instances[ FCK.Name ] ;
}
function FCKeditorAPI_ConfirmCleanup()
{
window.FCKUnloadFlag = true ;
}
FCKTools.AddEventListener( window, 'unload', FCKeditorAPI_Cleanup ) ;
FCKTools.AddEventListener( window, 'beforeunload', FCKeditorAPI_ConfirmCleanup) ;

View file

@ -0,0 +1,166 @@
/*
* 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 ==
*
* Extensions to the JavaScript Core.
*
* All custom extensions functions are PascalCased to differ from the standard
* camelCased ones.
*/
String.prototype.Contains = function( textToCheck )
{
return ( this.indexOf( textToCheck ) > -1 ) ;
}
String.prototype.Equals = function()
{
var aArgs = arguments ;
// The arguments could also be a single array.
if ( aArgs.length == 1 && aArgs[0].pop )
aArgs = aArgs[0] ;
for ( var i = 0 ; i < aArgs.length ; i++ )
{
if ( this == aArgs[i] )
return true ;
}
return false ;
}
String.prototype.IEquals = function()
{
var thisUpper = this.toUpperCase() ;
var aArgs = arguments ;
// The arguments could also be a single array.
if ( aArgs.length == 1 && aArgs[0].pop )
aArgs = aArgs[0] ;
for ( var i = 0 ; i < aArgs.length ; i++ )
{
if ( thisUpper == aArgs[i].toUpperCase() )
return true ;
}
return false ;
}
String.prototype.ReplaceAll = function( searchArray, replaceArray )
{
var replaced = this ;
for ( var i = 0 ; i < searchArray.length ; i++ )
{
replaced = replaced.replace( searchArray[i], replaceArray[i] ) ;
}
return replaced ;
}
String.prototype.StartsWith = function( value )
{
return ( this.substr( 0, value.length ) == value ) ;
}
// Extends the String object, creating a "EndsWith" method on it.
String.prototype.EndsWith = function( value, ignoreCase )
{
var L1 = this.length ;
var L2 = value.length ;
if ( L2 > L1 )
return false ;
if ( ignoreCase )
{
var oRegex = new RegExp( value + '$' , 'i' ) ;
return oRegex.test( this ) ;
}
else
return ( L2 == 0 || this.substr( L1 - L2, L2 ) == value ) ;
}
String.prototype.Remove = function( start, length )
{
var s = '' ;
if ( start > 0 )
s = this.substring( 0, start ) ;
if ( start + length < this.length )
s += this.substring( start + length , this.length ) ;
return s ;
}
String.prototype.Trim = function()
{
// We are not using \s because we don't want "non-breaking spaces to be caught".
return this.replace( /(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '' ) ;
}
String.prototype.LTrim = function()
{
// We are not using \s because we don't want "non-breaking spaces to be caught".
return this.replace( /^[ \t\n\r]*/g, '' ) ;
}
String.prototype.RTrim = function()
{
// We are not using \s because we don't want "non-breaking spaces to be caught".
return this.replace( /[ \t\n\r]*$/g, '' ) ;
}
String.prototype.ReplaceNewLineChars = function( replacement )
{
return this.replace( /\n/g, replacement ) ;
}
String.prototype.Replace = function( regExp, replacement, thisObj )
{
if ( typeof replacement == 'function' )
{
return this.replace( regExp,
function()
{
return replacement.apply( thisObj || this, arguments ) ;
} ) ;
}
else
return this.replace( regExp, replacement ) ;
}
Array.prototype.AddItem = function( item )
{
var i = this.length ;
this[ i ] = item ;
return i ;
}
Array.prototype.IndexOf = function( value )
{
for ( var i = 0 ; i < this.length ; i++ )
{
if ( this[i] == value )
return i ;
}
return -1 ;
}

View file

@ -0,0 +1,122 @@
/*
* 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 is a utility object which can be used to load specific components of
* FCKeditor, including all dependencies.
*/
var FCK_GENERIC = 1 ;
var FCK_GENERIC_SPECIFIC = 2 ;
var FCK_SPECIFIC = 3 ;
var FCKScriptLoader = new Object() ;
FCKScriptLoader.FCKeditorPath = '/fckeditor/' ;
FCKScriptLoader._Scripts = new Object() ;
FCKScriptLoader._LoadedScripts = new Object() ;
FCKScriptLoader._IsIE = (/msie/).test( navigator.userAgent.toLowerCase() ) ;
FCKScriptLoader.Load = function( scriptName )
{
// Check if the script has already been loaded.
if ( scriptName in FCKScriptLoader._LoadedScripts )
return ;
var oScriptInfo = this._Scripts[ scriptName ] ;
if ( !oScriptInfo )
{
alert( 'FCKScriptLoader: The script "' + scriptName + '" could not be loaded' ) ;
return ;
}
for ( var i = 0 ; i < oScriptInfo.Dependency.length ; i++ )
{
this.Load( oScriptInfo.Dependency[i] ) ;
}
var sBaseScriptName = oScriptInfo.BasePath + scriptName.toLowerCase() ;
if ( oScriptInfo.Compatibility == FCK_GENERIC || oScriptInfo.Compatibility == FCK_GENERIC_SPECIFIC )
this._LoadScript( sBaseScriptName + '.js' ) ;
if ( oScriptInfo.Compatibility == FCK_SPECIFIC || oScriptInfo.Compatibility == FCK_GENERIC_SPECIFIC )
{
if ( this._IsIE )
this._LoadScript( sBaseScriptName + '_ie.js' ) ;
else
this._LoadScript( sBaseScriptName + '_gecko.js' ) ;
}
FCKScriptLoader._LoadedScripts[ scriptName ] = true ;
}
FCKScriptLoader._LoadScript = function( scriptPathFromSource )
{
document.write( '<script type="text/javascript" src="' + this.FCKeditorPath + 'editor/_source/' + scriptPathFromSource + '"><\/script>' ) ;
}
FCKScriptLoader.AddScript = function( scriptName, scriptBasePath, dependency, compatibility )
{
this._Scripts[ scriptName ] =
{
BasePath : scriptBasePath || '',
Dependency : dependency || [],
Compatibility : compatibility || FCK_GENERIC
} ;
}
/*
* ####################################
* ### Scripts Definition List
*/
FCKScriptLoader.AddScript( 'FCKConstants' ) ;
FCKScriptLoader.AddScript( 'FCKJSCoreExtensions' ) ;
FCKScriptLoader.AddScript( 'FCK_Xhtml10Transitional', '../dtd/' ) ;
FCKScriptLoader.AddScript( 'FCKDataProcessor' , 'classes/' , ['FCKConfig','FCKBrowserInfo','FCKRegexLib','FCKXHtml'] ) ;
FCKScriptLoader.AddScript( 'FCKDocumentFragment', 'classes/' , ['FCKDomTools'], FCK_SPECIFIC ) ;
FCKScriptLoader.AddScript( 'FCKDomRange' , 'classes/' , ['FCKBrowserInfo','FCKJSCoreExtensions','FCKW3CRange','FCKElementPath','FCKDomTools','FCKTools','FCKDocumentFragment'], FCK_GENERIC_SPECIFIC ) ;
FCKScriptLoader.AddScript( 'FCKDomRangeIterator', 'classes/' , ['FCKDomRange','FCKListsLib'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKElementPath' , 'classes/' , ['FCKListsLib'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKEnterKey' , 'classes/' , ['FCKDomRange','FCKDomTools','FCKTools','FCKKeystrokeHandler','FCKListHandler'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKPanel' , 'classes/' , ['FCKBrowserInfo','FCKConfig','FCKTools'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKImagePreloader' , 'classes/' ) ;
FCKScriptLoader.AddScript( 'FCKKeystrokeHandler', 'classes/' , ['FCKConstants','FCKBrowserInfo','FCKTools'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKStyle' , 'classes/' , ['FCKConstants','FCKDomRange','FCKDomRangeIterator','FCKDomTools','FCKListsLib','FCK_Xhtml10Transitional'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKW3CRange' , 'classes/' , ['FCKDomTools','FCKTools','FCKDocumentFragment'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKBrowserInfo' , 'internals/' , ['FCKJSCoreExtensions'] ) ;
FCKScriptLoader.AddScript( 'FCKCodeFormatter' , 'internals/' ) ;
FCKScriptLoader.AddScript( 'FCKConfig' , 'internals/' , ['FCKBrowserInfo','FCKConstants'] ) ;
FCKScriptLoader.AddScript( 'FCKDebug' , 'internals/' , ['FCKConfig'] ) ;
FCKScriptLoader.AddScript( 'FCKDomTools' , 'internals/' , ['FCKJSCoreExtensions','FCKBrowserInfo','FCKTools'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKListsLib' , 'internals/' ) ;
FCKScriptLoader.AddScript( 'FCKListHandler' , 'internals/' , ['FCKConfig', 'FCKDocumentFragment', 'FCKJSCoreExtensions','FCKDomTools'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKRegexLib' , 'internals/' ) ;
FCKScriptLoader.AddScript( 'FCKStyles' , 'internals/' , ['FCKConfig', 'FCKDocumentFragment', 'FCKDomRange','FCKDomTools','FCKElementPath','FCKTools'], FCK_GENERIC ) ;
FCKScriptLoader.AddScript( 'FCKTools' , 'internals/' , ['FCKJSCoreExtensions','FCKBrowserInfo'], FCK_GENERIC_SPECIFIC ) ;
FCKScriptLoader.AddScript( 'FCKXHtml' , 'internals/' , ['FCKBrowserInfo','FCKCodeFormatter','FCKConfig','FCKDomTools','FCKListsLib','FCKRegexLib','FCKTools','FCKXHtmlEntities'], FCK_GENERIC_SPECIFIC ) ;
FCKScriptLoader.AddScript( 'FCKXHtmlEntities' , 'internals/' , ['FCKConfig'] ) ;
// ####################################

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,325 @@
/*
* 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 ) ;
}
}} ;
}
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() ;
}

View file

@ -0,0 +1,465 @@
/*
* 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 <a> links can be expanded in Gecko's editor
// when the caret moved left or up from another block element below.
if ( keyCode < 33 || keyCode > 40 )
return ;
}
var blockEmptyStop = function( node )
{
if ( node.nodeType != 1 )
return false ;
var tag = node.tagName.toLowerCase() ;
return ( FCKListsLib.BlockElements[tag] || FCKListsLib.EmptyElements[tag] ) ;
}
var moveCursor = function()
{
var selection = 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 <a> 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 <a> nodes occupies a caret
// position. So if the user presses the left key and we reset the caret position here, the user
// wouldn't be able to go back.
if ( FCKBrowserInfo.IsOpera && keyCode == 37 )
return ;
// now we want to get out of our current parent node, adopt the next parent, and move the caret to
// the appropriate text node under our new parent.
// our new parent might be our current parent's siblings if we are lucky.
range.setStart( nextTextNode, 0 ) ;
range.setEnd( nextTextNode, 0 ) ;
}
else
{
// no suitable next siblings under our grandparent! what to do next?
while ( node.parentNode
&& node.parentNode != FCK.EditorDocument.body
&& node.parentNode != FCK.EditorDocument.documentElement
&& node == node.parentNode.lastChild
&& ( ! FCKListsLib.BlockElements[node.parentNode.tagName.toLowerCase()]
&& ! FCKListsLib.NonEmptyBlockElements[node.parentNode.tagName.toLowerCase()] ) )
node = node.parentNode ;
if ( FCKListsLib.BlockElements[ parentTag ]
|| FCKListsLib.EmptyElements[ parentTag ]
|| node == FCK.EditorDocument.body )
{
// if our parent is a block node, move to the end of our parent.
range.setStart( node, node.childNodes.length ) ;
range.setEnd( node, node.childNodes.length ) ;
}
else
{
// things are a little bit more interesting if our parent is not a block node
// due to the weired ways how Gecko's caret acts...
var stopNode = node.nextSibling ;
// find out the next block/empty element at our grandparent, we'll
// move the caret just before it.
while ( stopNode )
{
if ( stopNode.nodeType != 1 )
{
stopNode = stopNode.nextSibling ;
continue ;
}
var stopTag = stopNode.tagName.toLowerCase() ;
if ( FCKListsLib.BlockElements[stopTag] || FCKListsLib.EmptyElements[stopTag]
|| FCKListsLib.NonEmptyBlockElements[stopTag] )
break ;
stopNode = stopNode.nextSibling ;
}
// note that the dummy marker below is NEEDED, otherwise the caret's behavior will
// be broken in Gecko.
var marker = FCK.EditorDocument.createTextNode( '' ) ;
if ( stopNode )
node.parentNode.insertBefore( marker, stopNode ) ;
else
node.parentNode.appendChild( marker ) ;
range.setStart( marker, 0 ) ;
range.setEnd( marker, 0 ) ;
}
}
selection.removeAllRanges() ;
selection.addRange( range ) ;
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
setTimeout( moveCursor, 1 ) ;
}
this.ExecOnSelectionChangeTimer = function()
{
if ( FCK.LastOnChangeTimer )
window.clearTimeout( FCK.LastOnChangeTimer ) ;
FCK.LastOnChangeTimer = window.setTimeout( FCK.ExecOnSelectionChange, 100 ) ;
}
this.EditorDocument.addEventListener( 'mouseup', this.ExecOnSelectionChange, false ) ;
// On Gecko, firing the "OnSelectionChange" event on every key press started to be too much
// slow. So, a timer has been implemented to solve performance issues when typing to quickly.
this.EditorDocument.addEventListener( 'keyup', this.ExecOnSelectionChangeTimer, false ) ;
this._DblClickListener = function( e )
{
FCK.OnDoubleClick( e.target ) ;
e.stopPropagation() ;
}
this.EditorDocument.addEventListener( 'dblclick', this._DblClickListener, true ) ;
// Record changes for the undo system when there are key down events.
this.EditorDocument.addEventListener( 'keydown', this._KeyDownListener, false ) ;
// Hooks for data object drops
if ( FCKBrowserInfo.IsGecko )
{
this.EditorWindow.addEventListener( 'dragdrop', this._ExecDrop, true ) ;
}
else if ( FCKBrowserInfo.IsSafari )
{
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 ) ;
}
// 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, '<BR>' ) ;
this.InsertHtml( sText ) ;
*/
}
/*
FCK.PasteFromWord = function()
{
// TODO: Implement the "Paste as Plain Text" code.
FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteFromWord, 'dialog/fck_paste.html', 400, 330, 'Word' ) ;
// FCK.CleanAndPaste( FCK.GetClipboardHTML() ) ;
}
*/
FCK.GetClipboardHTML = function()
{
return '' ;
}
FCK.CreateLink = function( url, noUndo )
{
// Creates the array that will be returned. It contains one or more created links (see #220).
var aCreatedLinks = new Array() ;
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 ;
// It may happen that the browser (aka Safari) decides to use the
// URL as the link content to not leave it empty. In this case,
// let's reset it.
if ( sTempUrl == oLink.innerHTML )
oLink.innerHTML = '' ;
aCreatedLinks.push( oLink ) ;
}
}
return aCreatedLinks ;
}
FCK._FillEmptyBlock = function( emptyBlockNode )
{
if ( ! emptyBlockNode || emptyBlockNode.nodeType != 1 )
return ;
var nodeTag = emptyBlockNode.tagName.toLowerCase() ;
if ( nodeTag != 'p' && nodeTag != 'div' )
return ;
if ( emptyBlockNode.firstChild )
return ;
FCKTools.AppendBogusBr( emptyBlockNode ) ;
}
FCK._ExecCheckEmptyBlock = function()
{
FCK._FillEmptyBlock( FCK.EditorDocument.body.firstChild ) ;
var sel = FCK.EditorWindow.getSelection() ;
if ( !sel || sel.rangeCount < 1 )
return ;
var range = sel.getRangeAt( 0 );
FCK._FillEmptyBlock( range.startContainer ) ;
}

View file

@ -0,0 +1,435 @@
/*
* 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 = '<style type="text/css" _fcktemp="true">' ;
if ( FCKConfig.ShowBorders )
sTableBehavior = 'url(' + sBasePath + 'css/behaviors/showtableborders.htc)' ;
// Disable resize handlers.
sStyle += 'INPUT,TEXTAREA,SELECT,.FCK__Anchor,.FCK__PageBreak,.FCK__InputHidden' ;
if ( FCKConfig.DisableObjectResizing )
{
sStyle += ',IMG' ;
sTableBehavior += ' url(' + sBasePath + 'css/behaviors/disablehandles.htc)' ;
}
sStyle += ' { behavior: url(' + sBasePath + 'css/behaviors/disablehandles.htc) ; }' ;
if ( sTableBehavior.length > 0 )
sStyle += 'TABLE { behavior: ' + sTableBehavior + ' ; }' ;
sStyle += '</style>' ;
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()
{
// Don't fire the event if no document is loaded.
if ( FCK.EditorDocument )
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 = '<span id="__fakeFCKRemove__">&nbsp;</span>' + 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 = '<div id="__fakeFCKRemove__">&nbsp;</div>' + 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 <BR>
sText = FCKTools.HTMLEncode( sText ) ;
sText = FCKTools.ProcessLineBreaks( window, FCKConfig, sText ) ;
var closeTagIndex = sText.search( '</p>' ) ;
var startTagIndex = sText.search( '<p>' ) ;
if ( ( closeTagIndex != -1 && startTagIndex != -1 && closeTagIndex < startTagIndex )
|| ( closeTagIndex != -1 && startTagIndex == -1 ) )
{
var prefix = sText.substr( 0, closeTagIndex ) ;
sText = sText.substr( closeTagIndex + 4 ) ;
this.InsertHtml( prefix ) ;
}
// Insert the resulting data in the editor.
FCKUndo.SaveLocked = true ;
this.InsertHtml( sText ) ;
FCKUndo.SaveLocked = false ;
}
}
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:
// <img><img> -> <a><img></a><img> -> <a><img><img></a> 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 <br> 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 ;
}

View file

@ -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 && ( parseFloat( s.match( /msie ([\d|\.]+)/ )[1] ) >= 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) ;

View file

@ -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 = /(<PRE[^>]*>)([\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() ;
}

View file

@ -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' , 480, 250 ) ; break ;
case 'TableProp' : oCommand = new FCKDialogCommand( 'Table' , FCKLang.DlgTableTitle , 'dialog/fck_table.html?Parent', 480, 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 ;
}

View file

@ -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 "<InstanceName>___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).
/<!--[\s\S]*?-->/g ,
// Script tags will also be forced to be protected, otherwise IE will execute them.
/<script[\s\S]*?<\/script>/gi,
// <noscript> tags (get lost in IE and messed up in FF).
/<noscript[\s\S]*?<\/noscript>/gi,
// Protect <object> tags. See #359.
/<object[\s\S]+?<\/object>/gi
] ;
FCKConfig.ProtectedSource.Add = function( regexPattern )
{
this.RegexEntries.AddItem( regexPattern ) ;
}
FCKConfig.ProtectedSource.Protect = function( html )
{
var codeTag = this._CodeTag ;
function _Replace( protectedSource )
{
var index = FCKTempBin.AddElement( protectedSource ) ;
return '<!--{' + codeTag + index + '}-->' ;
}
for ( var i = 0 ; i < this.RegexEntries.length ; i++ )
{
html = html.replace( this.RegexEntries[i], _Replace ) ;
}
return html ;
}
FCKConfig.ProtectedSource.Revert = function( html, clearBin )
{
function _Replace( m, opener, index )
{
var protectedValue = clearBin ? FCKTempBin.RemoveElement( index ) : FCKTempBin.Elements[ index ] ;
// There could be protected source inside another one.
return FCKConfig.ProtectedSource.Revert( protectedValue, clearBin ) ;
}
var regex = new RegExp( "(<|&lt;)!--\\{" + this._CodeTag + "(\\d+)\\}--(>|&gt;)", "g" ) ;
return html.replace( regex, _Replace ) ;
}
// Returns a string with the attributes that must be appended to the body
FCKConfig.GetBodyAttributes = function()
{
var bodyAttributes = '' ;
// Add id and class to the body.
if ( this.BodyId && this.BodyId.length > 0 )
bodyAttributes += ' id="' + this.BodyId + '"' ;
if ( this.BodyClass && this.BodyClass.length > 0 )
bodyAttributes += ' class="' + this.BodyClass + '"' ;
return bodyAttributes ;
}
// Sets the body attributes directly on the node
FCKConfig.ApplyBodyAttributes = function( oBody )
{
// Add ID and Class to the body
if ( this.BodyId && this.BodyId.length > 0 )
oBody.id = FCKConfig.BodyId ;
if ( this.BodyClass && this.BodyClass.length > 0 )
oBody.className += ' ' + FCKConfig.BodyClass ;
}

View file

@ -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 ==
*
* Debug window control and operations.
*/
var FCKDebug = new Object() ;
FCKDebug._GetWindow = function()
{
if ( !this.DebugWindow || this.DebugWindow.closed )
this.DebugWindow = window.open( FCKConfig.BasePath + 'fckdebug.html', 'FCKeditorDebug', 'menubar=no,scrollbars=yes,resizable=yes,location=no,toolbar=no,width=600,height=500', true ) ;
return this.DebugWindow ;
}
FCKDebug.Output = function( message, color, noParse )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().Output( message, color ) ;
}
catch ( e ) {} // Ignore errors
}
FCKDebug.OutputObject = function( anyObject, color )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().OutputObject( anyObject, color ) ;
}
catch ( e ) {} // Ignore errors
}

View file

@ -0,0 +1,38 @@
/*
* 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 ==
*
* Dialog windows operations.
*/
var FCKDialog = new Object() ;
// This method opens a dialog window using the standard dialog template.
FCKDialog.OpenDialog = function( dialogName, dialogTitle, dialogPage, width, height, customValue, parentWindow, resizable )
{
// Setup the dialog info.
var oDialogInfo = new Object() ;
oDialogInfo.Title = dialogTitle ;
oDialogInfo.Page = dialogPage ;
oDialogInfo.Editor = window ;
oDialogInfo.CustomValue = customValue ; // Optional
var sUrl = FCKConfig.BasePath + 'fckdialog.html' ;
this.Show( oDialogInfo, dialogName, sUrl, width, height, parentWindow, resizable ) ;
}

View file

@ -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 ==
*
* Dialog windows operations. (Gecko specific implementations)
*/
FCKDialog.Show = function( dialogInfo, dialogName, pageUrl, dialogWidth, dialogHeight, parentWindow, resizable )
{
var iTop = (FCKConfig.ScreenHeight - dialogHeight) / 2 ;
var iLeft = (FCKConfig.ScreenWidth - dialogWidth) / 2 ;
var sOption = "location=no,menubar=no,toolbar=no,dependent=yes,dialog=yes,minimizable=no,alwaysRaised=yes" +
",resizable=" + ( resizable ? 'yes' : 'no' ) +
",width=" + dialogWidth +
",height=" + dialogHeight +
",top=" + iTop +
",left=" + iLeft ;
if ( !parentWindow )
parentWindow = window ;
FCKFocusManager.Lock() ;
var oWindow = parentWindow.open( '', 'FCKeditorDialog_' + dialogName, sOption, true ) ;
if ( !oWindow )
{
alert( FCKLang.DialogBlocked ) ;
FCKFocusManager.Unlock() ;
return ;
}
oWindow.moveTo( iLeft, iTop ) ;
oWindow.resizeTo( dialogWidth, dialogHeight ) ;
oWindow.focus() ;
oWindow.location.href = pageUrl ;
oWindow.dialogArguments = dialogInfo ;
// On some Gecko browsers (probably over slow connections) the
// "dialogArguments" are not set to the target window so we must
// put it in the opener window so it can be used by the target one.
parentWindow.FCKLastDialogInfo = dialogInfo ;
this.Window = oWindow ;
// Try/Catch must be used to avoid an error when using a frameset
// on a different domain:
// "Permission denied to get property Window.releaseEvents".
try
{
window.top.parent.addEventListener( 'mousedown', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'mouseup', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'click', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'focus', this.CheckFocus, true ) ;
}
catch (e)
{}
}
FCKDialog.CheckFocus = function()
{
// It is strange, but we have to check the FCKDialog existence to avoid a
// random error: "FCKDialog is not defined".
if ( typeof( FCKDialog ) != "object" )
return false ;
if ( FCKDialog.Window && !FCKDialog.Window.closed )
FCKDialog.Window.focus() ;
else
{
// Try/Catch must be used to avoid an error when using a frameset
// on a different domain:
// "Permission denied to get property Window.releaseEvents".
try
{
window.top.parent.removeEventListener( 'onmousedown', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'mouseup', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'click', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'onfocus', FCKDialog.CheckFocus, true ) ;
}
catch (e)
{}
}
return false ;
}

View file

@ -0,0 +1,49 @@
/*
* 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 ==
*
* Dialog windows operations. (IE specific implementations)
*/
FCKDialog.Show = function( dialogInfo, dialogName, pageUrl, dialogWidth, dialogHeight, parentWindow, resizable )
{
if ( !parentWindow )
parentWindow = window ;
var sOptions = 'help:no;scroll:no;status:no' +
';resizable:' + ( resizable ? 'yes' : 'no' ) +
';dialogWidth:' + dialogWidth + 'px' +
';dialogHeight:' + dialogHeight + 'px' ;
FCKFocusManager.Lock() ;
var oReturn = 'B' ;
try
{
dialogInfo.DialogName = dialogName ;
oReturn = parentWindow.showModalDialog( pageUrl, dialogInfo, sOptions ) ;
}
catch( e ) {}
if ( 'B' === oReturn )
alert( FCKLang.DialogBlocked ) ;
FCKFocusManager.Unlock() ;
}

View file

@ -0,0 +1,231 @@
/*
* 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 ==
*
* Advanced document processors.
*/
var FCKDocumentProcessor = new Object() ;
FCKDocumentProcessor._Items = new Array() ;
FCKDocumentProcessor.AppendNew = function()
{
var oNewItem = new Object() ;
this._Items.AddItem( oNewItem ) ;
return oNewItem ;
}
FCKDocumentProcessor.Process = function( document )
{
var oProcessor, i = 0 ;
while( ( oProcessor = this._Items[i++] ) )
oProcessor.ProcessDocument( document ) ;
}
var FCKDocumentProcessor_CreateFakeImage = function( fakeClass, realElement )
{
var oImg = FCK.EditorDocument.createElement( 'IMG' ) ;
oImg.className = fakeClass ;
oImg.src = FCKConfig.FullBasePath + 'images/spacer.gif' ;
oImg.setAttribute( '_fckfakelement', 'true', 0 ) ;
oImg.setAttribute( '_fckrealelement', FCKTempBin.AddElement( realElement ), 0 ) ;
return oImg ;
}
// Link Anchors
if ( FCKBrowserInfo.IsIE || FCKBrowserInfo.IsOpera )
{
var FCKAnchorsProcessor = FCKDocumentProcessor.AppendNew() ;
FCKAnchorsProcessor.ProcessDocument = function( document )
{
var aLinks = document.getElementsByTagName( 'A' ) ;
var oLink ;
var i = aLinks.length - 1 ;
while ( i >= 0 && ( oLink = aLinks[i--] ) )
{
// If it is anchor. Doesn't matter if it's also a link (even better: we show that it's both a link and an anchor)
if ( oLink.name.length > 0 )
{
//if the anchor has some content then we just add a temporary class
if ( oLink.innerHTML !== '' )
{
if ( FCKBrowserInfo.IsIE )
oLink.className += ' FCK__AnchorC' ;
}
else
{
var oImg = FCKDocumentProcessor_CreateFakeImage( 'FCK__Anchor', oLink.cloneNode(true) ) ;
oImg.setAttribute( '_fckanchor', 'true', 0 ) ;
oLink.parentNode.insertBefore( oImg, oLink ) ;
oLink.parentNode.removeChild( oLink ) ;
}
}
}
}
}
// Page Breaks
var FCKPageBreaksProcessor = FCKDocumentProcessor.AppendNew() ;
FCKPageBreaksProcessor.ProcessDocument = function( document )
{
var aDIVs = document.getElementsByTagName( 'DIV' ) ;
var eDIV ;
var i = aDIVs.length - 1 ;
while ( i >= 0 && ( eDIV = aDIVs[i--] ) )
{
if ( eDIV.style.pageBreakAfter == 'always' && eDIV.childNodes.length == 1 && eDIV.childNodes[0].style && eDIV.childNodes[0].style.display == 'none' )
{
var oFakeImage = FCKDocumentProcessor_CreateFakeImage( 'FCK__PageBreak', eDIV.cloneNode(true) ) ;
eDIV.parentNode.insertBefore( oFakeImage, eDIV ) ;
eDIV.parentNode.removeChild( eDIV ) ;
}
}
/*
var aCenters = document.getElementsByTagName( 'CENTER' ) ;
var oCenter ;
var i = aCenters.length - 1 ;
while ( i >= 0 && ( oCenter = aCenters[i--] ) )
{
if ( oCenter.style.pageBreakAfter == 'always' && oCenter.innerHTML.Trim().length == 0 )
{
var oFakeImage = FCKDocumentProcessor_CreateFakeImage( 'FCK__PageBreak', oCenter.cloneNode(true) ) ;
oCenter.parentNode.insertBefore( oFakeImage, oCenter ) ;
oCenter.parentNode.removeChild( oCenter ) ;
}
}
*/
}
// Flash Embeds.
var FCKFlashProcessor = FCKDocumentProcessor.AppendNew() ;
FCKFlashProcessor.ProcessDocument = function( document )
{
/*
Sample code:
This is some <embed src="/UserFiles/Flash/Yellow_Runners.swf"></embed><strong>sample text</strong>. You are&nbsp;<a name="fred"></a> using <a href="http://www.fckeditor.net/">FCKeditor</a>.
*/
var bIsDirty = FCK.IsDirty() ;
var aEmbeds = document.getElementsByTagName( 'EMBED' ) ;
var oEmbed ;
var i = aEmbeds.length - 1 ;
while ( i >= 0 && ( oEmbed = aEmbeds[i--] ) )
{
// IE doesn't return the type attribute with oEmbed.type or oEmbed.getAttribute("type")
// But it turns out that after accessing it then it doesn't gets copied later
var oType = oEmbed.attributes[ 'type' ] ;
// Check the extension and the type. Now it should be enough with just the type
// Opera doesn't return oEmbed.src so oEmbed.src.EndsWith will fail
if ( (oEmbed.src && oEmbed.src.EndsWith( '.swf', true )) || ( oType && oType.nodeValue == 'application/x-shockwave-flash' ) )
{
var oCloned = oEmbed.cloneNode( true ) ;
var oImg = FCKDocumentProcessor_CreateFakeImage( 'FCK__Flash', oCloned ) ;
oImg.setAttribute( '_fckflash', 'true', 0 ) ;
FCKFlashProcessor.RefreshView( oImg, oEmbed ) ;
oEmbed.parentNode.insertBefore( oImg, oEmbed ) ;
oEmbed.parentNode.removeChild( oEmbed ) ;
}
}
// Fix the IsDirty state (#1406).
if ( !bIsDirty )
FCK.ResetIsDirty() ;
}
FCKFlashProcessor.RefreshView = function( placeHolderImage, originalEmbed )
{
if ( originalEmbed.getAttribute( 'width' ) > 0 )
placeHolderImage.style.width = FCKTools.ConvertHtmlSizeToStyle( originalEmbed.getAttribute( 'width' ) ) ;
if ( originalEmbed.getAttribute( 'height' ) > 0 )
placeHolderImage.style.height = FCKTools.ConvertHtmlSizeToStyle( originalEmbed.getAttribute( 'height' ) ) ;
}
FCK.GetRealElement = function( fakeElement )
{
var e = FCKTempBin.Elements[ fakeElement.getAttribute('_fckrealelement') ] ;
if ( fakeElement.getAttribute('_fckflash') )
{
if ( fakeElement.style.width.length > 0 )
e.width = FCKTools.ConvertStyleSizeToHtml( fakeElement.style.width ) ;
if ( fakeElement.style.height.length > 0 )
e.height = FCKTools.ConvertStyleSizeToHtml( fakeElement.style.height ) ;
}
return e ;
}
// HR Processor.
// This is a IE only (tricky) thing. We protect all HR tags before loading them
// (see FCK.ProtectTags). Here we put the HRs back.
if ( FCKBrowserInfo.IsIE )
{
FCKDocumentProcessor.AppendNew().ProcessDocument = function( document )
{
var aHRs = document.getElementsByTagName( 'HR' ) ;
var eHR ;
var i = aHRs.length - 1 ;
while ( i >= 0 && ( eHR = aHRs[i--] ) )
{
// Create the replacement HR.
var newHR = document.createElement( 'hr' ) ;
newHR.mergeAttributes( eHR, true ) ;
// We must insert the new one after it. insertBefore will not work in all cases.
FCKDomTools.InsertAfterNode( eHR, newHR ) ;
eHR.parentNode.removeChild( eHR ) ;
}
}
}
// INPUT:hidden Processor.
FCKDocumentProcessor.AppendNew().ProcessDocument = function( document )
{
var aInputs = document.getElementsByTagName( 'INPUT' ) ;
var oInput ;
var i = aInputs.length - 1 ;
while ( i >= 0 && ( oInput = aInputs[i--] ) )
{
if ( oInput.type == 'hidden' )
{
var oImg = FCKDocumentProcessor_CreateFakeImage( 'FCK__InputHidden', oInput.cloneNode(true) ) ;
oImg.setAttribute( '_fckinputhidden', 'true', 0 ) ;
oInput.parentNode.insertBefore( oImg, oInput ) ;
oInput.parentNode.removeChild( oInput ) ;
}
}
}

View file

@ -0,0 +1,984 @@
/*
* 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 to work with the DOM.
*/
var FCKDomTools =
{
/**
* Move all child nodes from one node to another.
*/
MoveChildren : function( source, target, toTargetStart )
{
if ( source == target )
return ;
var eChild ;
if ( toTargetStart )
{
while ( (eChild = source.lastChild) )
target.insertBefore( source.removeChild( eChild ), target.firstChild ) ;
}
else
{
while ( (eChild = source.firstChild) )
target.appendChild( source.removeChild( eChild ) ) ;
}
},
MoveNode : function( source, target, toTargetStart )
{
if ( toTargetStart )
target.insertBefore( FCKDomTools.RemoveNode( source ), target.firstChild ) ;
else
target.appendChild( FCKDomTools.RemoveNode( source ) ) ;
},
// Remove blank spaces from the beginning and the end of the contents of a node.
TrimNode : function( node )
{
this.LTrimNode( node ) ;
this.RTrimNode( node ) ;
},
LTrimNode : function( node )
{
var eChildNode ;
while ( (eChildNode = node.firstChild) )
{
if ( eChildNode.nodeType == 3 )
{
var sTrimmed = eChildNode.nodeValue.LTrim() ;
var iOriginalLength = eChildNode.nodeValue.length ;
if ( sTrimmed.length == 0 )
{
node.removeChild( eChildNode ) ;
continue ;
}
else if ( sTrimmed.length < iOriginalLength )
{
eChildNode.splitText( iOriginalLength - sTrimmed.length ) ;
node.removeChild( node.firstChild ) ;
}
}
break ;
}
},
RTrimNode : function( node )
{
var eChildNode ;
while ( (eChildNode = node.lastChild) )
{
if ( eChildNode.nodeType == 3 )
{
var sTrimmed = eChildNode.nodeValue.RTrim() ;
var iOriginalLength = eChildNode.nodeValue.length ;
if ( sTrimmed.length == 0 )
{
// If the trimmed text node is empty, just remove it.
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#81).
eChildNode.parentNode.removeChild( eChildNode ) ;
continue ;
}
else if ( sTrimmed.length < iOriginalLength )
{
// If the trimmed text length is less than the original
// length, strip all spaces from the end by splitting
// the text and removing the resulting useless node.
eChildNode.splitText( sTrimmed.length ) ;
// Use "node.lastChild.parentNode" instead of "node" to avoid IE bug (#81).
node.lastChild.parentNode.removeChild( node.lastChild ) ;
}
}
break ;
}
if ( !FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsOpera )
{
eChildNode = node.lastChild ;
if ( eChildNode && eChildNode.nodeType == 1 && eChildNode.nodeName.toLowerCase() == 'br' )
{
// Use "eChildNode.parentNode" instead of "node" to avoid IE bug (#324).
eChildNode.parentNode.removeChild( eChildNode ) ;
}
}
},
RemoveNode : function( node, excludeChildren )
{
if ( excludeChildren )
{
// Move all children before the node.
var eChild ;
while ( (eChild = node.firstChild) )
node.parentNode.insertBefore( node.removeChild( eChild ), node ) ;
}
return node.parentNode.removeChild( node ) ;
},
GetFirstChild : function( node, childNames )
{
// If childNames is a string, transform it in a Array.
if ( typeof ( childNames ) == 'string' )
childNames = [ childNames ] ;
var eChild = node.firstChild ;
while( eChild )
{
if ( eChild.nodeType == 1 && eChild.tagName.Equals.apply( eChild.tagName, childNames ) )
return eChild ;
eChild = eChild.nextSibling ;
}
return null ;
},
GetLastChild : function( node, childNames )
{
// If childNames is a string, transform it in a Array.
if ( typeof ( childNames ) == 'string' )
childNames = [ childNames ] ;
var eChild = node.lastChild ;
while( eChild )
{
if ( eChild.nodeType == 1 && ( !childNames || eChild.tagName.Equals( childNames ) ) )
return eChild ;
eChild = eChild.previousSibling ;
}
return null ;
},
/*
* Gets the previous element (nodeType=1) in the source order. Returns
* "null" If no element is found.
* @param {Object} currentNode The node to start searching from.
* @param {Boolean} ignoreSpaceTextOnly Sets how text nodes will be
* handled. If set to "true", only white spaces text nodes
* will be ignored, while non white space text nodes will stop
* the search, returning null. If "false" or omitted, all
* text nodes are ignored.
* @param {string[]} stopSearchElements An array of element names that
* will cause the search to stop when found, returning null.
* May be omitted (or null).
* @param {string[]} ignoreElements An array of element names that
* must be ignored during the search.
*/
GetPreviousSourceElement : function( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements )
{
if ( !currentNode )
return null ;
if ( stopSearchElements && currentNode.nodeType == 1 && currentNode.nodeName.IEquals( stopSearchElements ) )
return null ;
if ( currentNode.previousSibling )
currentNode = currentNode.previousSibling ;
else
return this.GetPreviousSourceElement( currentNode.parentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
while ( currentNode )
{
if ( currentNode.nodeType == 1 )
{
if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
break ;
if ( !ignoreElements || !currentNode.nodeName.IEquals( ignoreElements ) )
return currentNode ;
}
else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
break ;
if ( currentNode.lastChild )
currentNode = currentNode.lastChild ;
else
return this.GetPreviousSourceElement( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
}
return null ;
},
/*
* Gets the next element (nodeType=1) in the source order. Returns
* "null" If no element is found.
* @param {Object} currentNode The node to start searching from.
* @param {Boolean} ignoreSpaceTextOnly Sets how text nodes will be
* handled. If set to "true", only white spaces text nodes
* will be ignored, while non white space text nodes will stop
* the search, returning null. If "false" or omitted, all
* text nodes are ignored.
* @param {string[]} stopSearchElements An array of element names that
* will cause the search to stop when found, returning null.
* May be omitted (or null).
* @param {string[]} ignoreElements An array of element names that
* must be ignored during the search.
*/
GetNextSourceElement : function( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements, startFromSibling )
{
while( ( currentNode = this.GetNextSourceNode( currentNode, startFromSibling ) ) ) // Only one "=".
{
if ( currentNode.nodeType == 1 )
{
if ( stopSearchElements && currentNode.nodeName.IEquals( stopSearchElements ) )
break ;
if ( ignoreElements && currentNode.nodeName.IEquals( ignoreElements ) )
return this.GetNextSourceElement( currentNode, ignoreSpaceTextOnly, stopSearchElements, ignoreElements ) ;
return currentNode ;
}
else if ( ignoreSpaceTextOnly && currentNode.nodeType == 3 && currentNode.nodeValue.RTrim().length > 0 )
break ;
}
return null ;
},
/*
* Get the next DOM node available in source order.
*/
GetNextSourceNode : function( currentNode, startFromSibling, nodeType, stopSearchNode )
{
if ( !currentNode )
return null ;
var node ;
if ( !startFromSibling && currentNode.firstChild )
node = currentNode.firstChild ;
else
{
if ( stopSearchNode && currentNode == stopSearchNode )
return null ;
node = currentNode.nextSibling ;
if ( !node && ( !stopSearchNode || stopSearchNode != currentNode.parentNode ) )
return this.GetNextSourceNode( currentNode.parentNode, true, nodeType, stopSearchNode ) ;
}
if ( nodeType && node && node.nodeType != nodeType )
return this.GetNextSourceNode( node, false, nodeType, stopSearchNode ) ;
return node ;
},
/*
* Get the next DOM node available in source order.
*/
GetPreviousSourceNode : function( currentNode, startFromSibling, nodeType, stopSearchNode )
{
if ( !currentNode )
return null ;
var node ;
if ( !startFromSibling && currentNode.lastChild )
node = currentNode.lastChild ;
else
{
if ( stopSearchNode && currentNode == stopSearchNode )
return null ;
node = currentNode.previousSibling ;
if ( !node && ( !stopSearchNode || stopSearchNode != currentNode.parentNode ) )
return this.GetPreviousSourceNode( currentNode.parentNode, true, nodeType, stopSearchNode ) ;
}
if ( nodeType && node && node.nodeType != nodeType )
return this.GetPreviousSourceNode( node, false, nodeType, stopSearchNode ) ;
return node ;
},
// Inserts a element after a existing one.
InsertAfterNode : function( existingNode, newNode )
{
return existingNode.parentNode.insertBefore( newNode, existingNode.nextSibling ) ;
},
GetParents : function( node )
{
var parents = new Array() ;
while ( node )
{
parents.unshift( node ) ;
node = node.parentNode ;
}
return parents ;
},
GetCommonParents : function( node1, node2 )
{
var p1 = this.GetParents( node1 ) ;
var p2 = this.GetParents( node2 ) ;
var retval = [] ;
for ( var i = 0 ; i < p1.length ; i++ )
{
if ( p1[i] == p2[i] )
retval.push( p1[i] ) ;
}
return retval ;
},
GetCommonParentNode : function( node1, node2, tagList )
{
var tagMap = {} ;
if ( ! tagList.pop )
tagList = [ tagList ] ;
while ( tagList.length > 0 )
tagMap[tagList.pop().toLowerCase()] = 1 ;
var commonParents = this.GetCommonParents( node1, node2 ) ;
var currentParent = null ;
while ( ( currentParent = commonParents.pop() ) )
{
if ( tagMap[currentParent.nodeName.toLowerCase()] )
return currentParent ;
}
return null ;
},
GetIndexOf : function( node )
{
var currentNode = node.parentNode ? node.parentNode.firstChild : null ;
var currentIndex = -1 ;
while ( currentNode )
{
currentIndex++ ;
if ( currentNode == node )
return currentIndex ;
currentNode = currentNode.nextSibling ;
}
return -1 ;
},
PaddingNode : null,
EnforcePaddingNode : function( doc, tagName )
{
// In IE it can happen when the page is reloaded that doc or doc.body is null, so exit here
try
{
if ( !doc || !doc.body )
return ;
}
catch (e)
{
return ;
}
this.CheckAndRemovePaddingNode( doc, tagName, true ) ;
try
{
if ( doc.body.lastChild && ( doc.body.lastChild.nodeType != 1
|| doc.body.lastChild.tagName.toLowerCase() == tagName.toLowerCase() ) )
return ;
}
catch (e)
{
return ;
}
var node = doc.createElement( tagName ) ;
if ( FCKBrowserInfo.IsGecko && FCKListsLib.NonEmptyBlockElements[ tagName ] )
FCKTools.AppendBogusBr( node ) ;
this.PaddingNode = node ;
if ( doc.body.childNodes.length == 1
&& doc.body.firstChild.nodeType == 1
&& doc.body.firstChild.tagName.toLowerCase() == 'br'
&& ( doc.body.firstChild.getAttribute( '_moz_dirty' ) != null
|| doc.body.firstChild.getAttribute( 'type' ) == '_moz' ) )
doc.body.replaceChild( node, doc.body.firstChild ) ;
else
doc.body.appendChild( node ) ;
},
CheckAndRemovePaddingNode : function( doc, tagName, dontRemove )
{
var paddingNode = this.PaddingNode ;
if ( ! paddingNode )
return ;
// If the padding node is changed, remove its status as a padding node.
try
{
if ( paddingNode.parentNode != doc.body
|| paddingNode.tagName.toLowerCase() != tagName
|| ( paddingNode.childNodes.length > 1 )
|| ( paddingNode.firstChild && paddingNode.firstChild.nodeValue != '\xa0'
&& String(paddingNode.firstChild.tagName).toLowerCase() != 'br' ) )
{
this.PaddingNode = null ;
return ;
}
}
catch (e)
{
this.PaddingNode = null ;
return ;
}
// Now we're sure the padding node exists, and it is unchanged, and it
// isn't the only node in doc.body, remove it.
if ( !dontRemove )
{
if ( paddingNode.parentNode.childNodes.length > 1 )
paddingNode.parentNode.removeChild( paddingNode ) ;
this.PaddingNode = null ;
}
},
HasAttribute : function( element, attributeName )
{
if ( element.hasAttribute )
return element.hasAttribute( attributeName ) ;
else
{
var att = element.attributes[ attributeName ] ;
return ( att != undefined && att.specified ) ;
}
},
/**
* Checks if an element has "specified" attributes.
*/
HasAttributes : function( element )
{
var attributes = element.attributes ;
for ( var i = 0 ; i < attributes.length ; i++ )
{
if ( FCKBrowserInfo.IsIE && attributes[i].nodeName == 'class' )
{
// IE has a strange bug. If calling removeAttribute('className'),
// the attributes collection will still contain the "class"
// attribute, which will be marked as "specified", even if the
// outerHTML of the element is not displaying the class attribute.
// Note : I was not able to reproduce it outside the editor,
// but I've faced it while working on the TC of #1391.
if ( element.className.length > 0 )
return true ;
}
else if ( attributes[i].specified )
return true ;
}
return false ;
},
/**
* Remove an attribute from an element.
*/
RemoveAttribute : function( element, attributeName )
{
if ( FCKBrowserInfo.IsIE && attributeName.toLowerCase() == 'class' )
attributeName = 'className' ;
return element.removeAttribute( attributeName, 0 ) ;
},
GetAttributeValue : function( element, att )
{
var attName = att ;
if ( typeof att == 'string' )
att = element.attributes[ att ] ;
else
attName = att.nodeName ;
if ( att && att.specified )
{
// IE returns "null" for the nodeValue of a "style" attribute.
if ( attName == 'style' )
return element.style.cssText ;
// There are two cases when the nodeValue must be used:
// - for the "class" attribute (all browsers).
// - for events attributes (IE only).
else if ( attName == 'class' || attName.indexOf('on') == 0 )
return att.nodeValue ;
else
{
// Use getAttribute to get its value exactly as it is
// defined.
return element.getAttribute( attName, 2 ) ;
}
}
return null ;
},
/**
* Checks whether one element contains the other.
*/
Contains : function( mainElement, otherElement )
{
// IE supports contains, but only for element nodes.
if ( mainElement.contains && otherElement.nodeType == 1 )
return mainElement.contains( otherElement ) ;
while ( ( otherElement = otherElement.parentNode ) ) // Only one "="
{
if ( otherElement == mainElement )
return true ;
}
return false ;
},
/**
* Breaks a parent element in the position of one of its contained elements.
* For example, in the following case:
* <b>This <i>is some<span /> sample</i> test text</b>
* If element = <span />, we have these results:
* <b>This <i>is some</i><span /><i> sample</i> test text</b> (If parent = <i>)
* <b>This <i>is some</i></b><span /><b<i> sample</i> test text</b> (If parent = <b>)
*/
BreakParent : function( element, parent, reusableRange )
{
var range = reusableRange || new FCKDomRange( FCKTools.GetElementWindow( element ) ) ;
// We'll be extracting part of this element, so let's use our
// range to get the correct piece.
range.SetStart( element, 4 ) ;
range.SetEnd( parent, 4 ) ;
// Extract it.
var docFrag = range.ExtractContents() ;
// Move the element outside the broken element.
range.InsertNode( element.parentNode.removeChild( element ) ) ;
// Re-insert the extracted piece after the element.
docFrag.InsertAfterNode( element ) ;
range.Release( !!reusableRange ) ;
},
/**
* Retrieves a uniquely identifiable tree address of a DOM tree node.
* The tree address returns is an array of integers, with each integer
* indicating a child index from a DOM tree node, starting from
* document.documentElement.
*
* For example, assuming <body> is the second child from <html> (<head>
* being the first), and we'd like to address the third child under the
* fourth child of body, the tree address returned would be:
* [1, 3, 2]
*
* The tree address cannot be used for finding back the DOM tree node once
* the DOM tree structure has been modified.
*/
GetNodeAddress : function( node, normalized )
{
var retval = [] ;
while ( node && node != node.ownerDocument.documentElement )
{
var parentNode = node.parentNode ;
var currentIndex = -1 ;
for( var i = 0 ; i < parentNode.childNodes.length ; i++ )
{
var candidate = parentNode.childNodes[i] ;
if ( normalized === true &&
candidate.nodeType == 3 &&
candidate.previousSibling &&
candidate.previousSibling.nodeType == 3 )
continue;
currentIndex++ ;
if ( parentNode.childNodes[i] == node )
break ;
}
retval.unshift( currentIndex ) ;
node = node.parentNode ;
}
return retval ;
},
/**
* The reverse transformation of FCKDomTools.GetNodeAddress(). This
* function returns the DOM node pointed to by its index address.
*/
GetNodeFromAddress : function( doc, addr, normalized )
{
var cursor = doc.documentElement ;
for ( var i = 0 ; i < addr.length ; i++ )
{
var target = addr[i] ;
if ( ! normalized )
{
cursor = cursor.childNodes[target] ;
continue ;
}
var currentIndex = -1 ;
for (var j = 0 ; j < cursor.childNodes.length ; j++ )
{
var candidate = cursor.childNodes[j] ;
if ( normalized === true &&
candidate.nodeType == 3 &&
candidate.previousSibling &&
candidate.previousSibling.nodeType == 3 )
continue ;
currentIndex++ ;
if ( currentIndex == target )
{
cursor = candidate ;
break ;
}
}
}
return cursor ;
},
CloneElement : function( element )
{
element = element.cloneNode( false ) ;
// The "id" attribute should never be cloned to avoid duplication.
element.removeAttribute( 'id', false ) ;
return element ;
},
ClearElementJSProperty : function( element, attrName )
{
if ( FCKBrowserInfo.IsIE )
element.removeAttribute( attrName ) ;
else
delete element[attrName] ;
},
SetElementMarker : function ( markerObj, element, attrName, value)
{
var id = String( parseInt( Math.random() * 0xfffffff, 10 ) ) ;
element._FCKMarkerId = id ;
element[attrName] = value ;
if ( ! markerObj[id] )
markerObj[id] = { 'element' : element, 'markers' : {} } ;
markerObj[id]['markers'][attrName] = value ;
},
ClearElementMarkers : function( markerObj, element, clearMarkerObj )
{
var id = element._FCKMarkerId ;
if ( ! id )
return ;
this.ClearElementJSProperty( element, '_FCKMarkerId' ) ;
for ( var j in markerObj[id]['markers'] )
this.ClearElementJSProperty( element, j ) ;
if ( clearMarkerObj )
delete markerObj[id] ;
},
ClearAllMarkers : function( markerObj )
{
for ( var i in markerObj )
this.ClearElementMarkers( markerObj, markerObj[i]['element'], true ) ;
},
/**
* Convert a DOM list tree into a data structure that is easier to
* manipulate. This operation should be non-intrusive in the sense that it
* does not change the DOM tree, with the exception that it may add some
* markers to the list item nodes when markerObj is specified.
*/
ListToArray : function( listNode, markerObj, baseArray, baseIndentLevel, grandparentNode )
{
if ( ! listNode.nodeName.IEquals( ['ul', 'ol'] ) )
return [] ;
if ( ! baseIndentLevel )
baseIndentLevel = 0 ;
if ( ! baseArray )
baseArray = [] ;
// Iterate over all list items to get their contents and look for inner lists.
for ( var i = 0 ; i < listNode.childNodes.length ; i++ )
{
var listItem = listNode.childNodes[i] ;
if ( ! listItem.nodeName.IEquals( 'li' ) )
continue ;
var itemObj = { 'parent' : listNode, 'indent' : baseIndentLevel, 'contents' : [] } ;
if ( ! grandparentNode )
{
itemObj.grandparent = listNode.parentNode ;
if ( itemObj.grandparent && itemObj.grandparent.nodeName.IEquals( 'li' ) )
itemObj.grandparent = itemObj.grandparent.parentNode ;
}
else
itemObj.grandparent = grandparentNode ;
if ( markerObj )
this.SetElementMarker( markerObj, listItem, '_FCK_ListArray_Index', baseArray.length ) ;
baseArray.push( itemObj ) ;
for ( var j = 0 ; j < listItem.childNodes.length ; j++ )
{
var child = listItem.childNodes[j] ;
if ( child.nodeName.IEquals( ['ul', 'ol'] ) )
// Note the recursion here, it pushes inner list items with
// +1 indentation in the correct order.
this.ListToArray( child, markerObj, baseArray, baseIndentLevel + 1, itemObj.grandparent ) ;
else
itemObj.contents.push( child ) ;
}
}
return baseArray ;
},
// Convert our internal representation of a list back to a DOM forest.
ArrayToList : function( listArray, markerObj, baseIndex )
{
if ( baseIndex == undefined )
baseIndex = 0 ;
if ( ! listArray || listArray.length < baseIndex + 1 )
return null ;
var doc = listArray[baseIndex].parent.ownerDocument ;
var retval = doc.createDocumentFragment() ;
var rootNode = null ;
var currentIndex = baseIndex ;
var indentLevel = Math.max( listArray[baseIndex].indent, 0 ) ;
var currentListItem = null ;
while ( true )
{
var item = listArray[currentIndex] ;
if ( item.indent == indentLevel )
{
if ( ! rootNode || listArray[currentIndex].parent.nodeName != rootNode.nodeName )
{
rootNode = listArray[currentIndex].parent.cloneNode( false ) ;
retval.appendChild( rootNode ) ;
}
currentListItem = doc.createElement( 'li' ) ;
rootNode.appendChild( currentListItem ) ;
for ( var i = 0 ; i < item.contents.length ; i++ )
currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ;
currentIndex++ ;
}
else if ( item.indent == Math.max( indentLevel, 0 ) + 1 )
{
var listData = this.ArrayToList( listArray, null, currentIndex ) ;
currentListItem.appendChild( listData.listNode ) ;
currentIndex = listData.nextIndex ;
}
else if ( item.indent == -1 && baseIndex == 0 && item.grandparent )
{
var currentListItem ;
if ( item.grandparent.nodeName.IEquals( ['ul', 'ol'] ) )
currentListItem = doc.createElement( 'li' ) ;
else
{
if ( FCKConfig.EnterMode.IEquals( ['div', 'p'] ) && ! item.grandparent.nodeName.IEquals( 'td' ) )
currentListItem = doc.createElement( FCKConfig.EnterMode ) ;
else
currentListItem = doc.createDocumentFragment() ;
}
for ( var i = 0 ; i < item.contents.length ; i++ )
currentListItem.appendChild( item.contents[i].cloneNode( true ) ) ;
if ( currentListItem.nodeType == 11 )
{
if ( currentListItem.lastChild &&
currentListItem.lastChild.getAttribute &&
currentListItem.lastChild.getAttribute( 'type' ) == '_moz' )
currentListItem.removeChild( currentListItem.lastChild );
currentListItem.appendChild( doc.createElement( 'br' ) ) ;
}
if ( currentListItem.nodeName.IEquals( FCKConfig.EnterMode ) && currentListItem.firstChild )
{
this.TrimNode( currentListItem ) ;
if ( FCKListsLib.BlockBoundaries[currentListItem.firstChild.nodeName.toLowerCase()] )
{
var tmp = doc.createDocumentFragment() ;
while ( currentListItem.firstChild )
tmp.appendChild( currentListItem.removeChild( currentListItem.firstChild ) ) ;
currentListItem = tmp ;
}
}
if ( FCKBrowserInfo.IsGeckoLike && currentListItem.nodeName.IEquals( ['div', 'p'] ) )
FCKTools.AppendBogusBr( currentListItem ) ;
retval.appendChild( currentListItem ) ;
rootNode = null ;
currentIndex++ ;
}
else
return null ;
if ( listArray.length <= currentIndex || Math.max( listArray[currentIndex].indent, 0 ) < indentLevel )
{
break ;
}
}
// Clear marker attributes for the new list tree made of cloned nodes, if any.
if ( markerObj )
{
var currentNode = retval.firstChild ;
while ( currentNode )
{
if ( currentNode.nodeType == 1 )
this.ClearElementMarkers( markerObj, currentNode ) ;
currentNode = this.GetNextSourceNode( currentNode ) ;
}
}
return { 'listNode' : retval, 'nextIndex' : currentIndex } ;
},
/**
* Get the next sibling node for a node. If "includeEmpties" is false,
* only element or non empty text nodes are returned.
*/
GetNextSibling : function( node, includeEmpties )
{
node = node.nextSibling ;
while ( node && !includeEmpties && node.nodeType != 1 && ( node.nodeType != 3 || node.nodeValue.length == 0 ) )
node = node.nextSibling ;
return node ;
},
/**
* Get the previous sibling node for a node. If "includeEmpties" is false,
* only element or non empty text nodes are returned.
*/
GetPreviousSibling : function( node, includeEmpties )
{
node = node.previousSibling ;
while ( node && !includeEmpties && node.nodeType != 1 && ( node.nodeType != 3 || node.nodeValue.length == 0 ) )
node = node.previousSibling ;
return node ;
},
/**
* Checks if an element has no "useful" content inside of it
* node tree. No "useful" content means empty text node or a signle empty
* inline node.
* elementCheckCallback may point to a function that returns a boolean
* indicating that a child element must be considered in the element check.
*/
CheckIsEmptyElement : function( element, elementCheckCallback )
{
var child = element.firstChild ;
var elementChild ;
while ( child )
{
if ( child.nodeType == 1 )
{
if ( elementChild || !FCKListsLib.InlineNonEmptyElements[ child.nodeName.toLowerCase() ] )
return false ;
if ( !elementCheckCallback || elementCheckCallback( child ) === true )
elementChild = child ;
}
else if ( child.nodeType == 3 && child.nodeValue.length > 0 )
return false ;
child = child.nextSibling ;
}
return elementChild ? this.CheckIsEmptyElement( elementChild, elementCheckCallback ) : true ;
},
SetElementStyles : function( element, styleDict )
{
var style = element.style ;
for ( var styleName in styleDict )
style[ styleName ] = styleDict[ styleName ] ;
},
GetCurrentElementStyle : function( w, element, attrName )
{
if ( FCKBrowserInfo.IsIE )
return element.currentStyle[attrName] ;
else
return w.getComputedStyle( element, '' )[attrName] ;
},
GetPositionedAncestor : function( w, element )
{
var currentElement = element ;
while ( currentElement != currentElement.ownerDocument.documentElement )
{
if ( this.GetCurrentElementStyle( w, currentElement, 'position' ) != 'static' )
return currentElement ;
currentElement = currentElement.parentNode ;
}
return null ;
},
/**
* Current implementation for ScrollIntoView (due to #1462). We don't have
* a complete implementation here, just the things that fit our needs.
*/
ScrollIntoView : function( element, alignTop )
{
// Get the element window.
var window = FCKTools.GetElementWindow( element ) ;
var windowHeight = FCKTools.GetViewPaneSize( window ).Height ;
// Starts the offset that will be scrolled with the negative value of
// the visible window height.
var offset = windowHeight * -1 ;
// Appends the height it we are about to align the bottoms.
if ( alignTop === false )
{
offset += element.offsetHeight ;
// Consider the margin in the scroll, which is ok for our current
// needs, but needs investigation if we will be using this function
// in other places.
offset += parseInt( this.GetCurrentElementStyle( window, element, 'marginBottom' ) || 0, 10 ) ;
}
// Appends the offsets for the entire element hierarchy.
offset += element.offsetTop ;
while ( ( element = element.offsetParent ) )
offset += element.offsetTop || 0 ;
// Scroll the window to the desired position, if not already visible.
var currentScroll = FCKTools.GetScrollPosition( window ).Y ;
if ( offset > 0 && offset > currentScroll )
window.scrollTo( 0, offset ) ;
}
} ;

View file

@ -0,0 +1,162 @@
/*
* 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 FCKLanguageManager object that is used for language
* operations.
*/
var FCKLanguageManager = FCK.Language =
{
AvailableLanguages :
{
af : 'Afrikaans',
ar : 'Arabic',
bg : 'Bulgarian',
bn : 'Bengali/Bangla',
bs : 'Bosnian',
ca : 'Catalan',
cs : 'Czech',
da : 'Danish',
de : 'German',
el : 'Greek',
en : 'English',
'en-au' : 'English (Australia)',
'en-ca' : 'English (Canadian)',
'en-uk' : 'English (United Kingdom)',
eo : 'Esperanto',
es : 'Spanish',
et : 'Estonian',
eu : 'Basque',
fa : 'Persian',
fi : 'Finnish',
fo : 'Faroese',
fr : 'French',
gl : 'Galician',
he : 'Hebrew',
hi : 'Hindi',
hr : 'Croatian',
hu : 'Hungarian',
it : 'Italian',
ja : 'Japanese',
km : 'Khmer',
ko : 'Korean',
lt : 'Lithuanian',
lv : 'Latvian',
mn : 'Mongolian',
ms : 'Malay',
nb : 'Norwegian Bokmal',
nl : 'Dutch',
no : 'Norwegian',
pl : 'Polish',
pt : 'Portuguese (Portugal)',
'pt-br' : 'Portuguese (Brazil)',
ro : 'Romanian',
ru : 'Russian',
sk : 'Slovak',
sl : 'Slovenian',
sr : 'Serbian (Cyrillic)',
'sr-latn' : 'Serbian (Latin)',
sv : 'Swedish',
th : 'Thai',
tr : 'Turkish',
uk : 'Ukrainian',
vi : 'Vietnamese',
zh : 'Chinese Traditional',
'zh-cn' : 'Chinese Simplified'
},
GetActiveLanguage : function()
{
if ( FCKConfig.AutoDetectLanguage )
{
var sUserLang ;
// IE accepts "navigator.userLanguage" while Gecko "navigator.language".
if ( navigator.userLanguage )
sUserLang = navigator.userLanguage.toLowerCase() ;
else if ( navigator.language )
sUserLang = navigator.language.toLowerCase() ;
else
{
// Firefox 1.0 PR has a bug: it doens't support the "language" property.
return FCKConfig.DefaultLanguage ;
}
// Some language codes are set in 5 characters,
// like "pt-br" for Brazilian Portuguese.
if ( sUserLang.length >= 5 )
{
sUserLang = sUserLang.substr(0,5) ;
if ( this.AvailableLanguages[sUserLang] ) return sUserLang ;
}
// If the user's browser is set to, for example, "pt-br" but only the
// "pt" language file is available then get that file.
if ( sUserLang.length >= 2 )
{
sUserLang = sUserLang.substr(0,2) ;
if ( this.AvailableLanguages[sUserLang] ) return sUserLang ;
}
}
return this.DefaultLanguage ;
},
TranslateElements : function( targetDocument, tag, propertyToSet, encode )
{
var e = targetDocument.getElementsByTagName(tag) ;
var sKey, s ;
for ( var i = 0 ; i < e.length ; i++ )
{
// The extra () is to avoid a warning with strict error checking. This is ok.
if ( (sKey = e[i].getAttribute( 'fckLang' )) )
{
// The extra () is to avoid a warning with strict error checking. This is ok.
if ( (s = FCKLang[ sKey ]) )
{
if ( encode )
s = FCKTools.HTMLEncode( s ) ;
e[i][ propertyToSet ] = s ;
}
}
}
},
TranslatePage : function( targetDocument )
{
this.TranslateElements( targetDocument, 'INPUT', 'value' ) ;
this.TranslateElements( targetDocument, 'SPAN', 'innerHTML' ) ;
this.TranslateElements( targetDocument, 'LABEL', 'innerHTML' ) ;
this.TranslateElements( targetDocument, 'OPTION', 'innerHTML', true ) ;
this.TranslateElements( targetDocument, 'LEGEND', 'innerHTML' ) ;
},
Initialize : function()
{
if ( this.AvailableLanguages[ FCKConfig.DefaultLanguage ] )
this.DefaultLanguage = FCKConfig.DefaultLanguage ;
else
this.DefaultLanguage = 'en' ;
this.ActiveLanguage = new Object() ;
this.ActiveLanguage.Code = this.GetActiveLanguage() ;
this.ActiveLanguage.Name = this.AvailableLanguages[ this.ActiveLanguage.Code ] ;
}
} ;

View file

@ -0,0 +1,152 @@
/*
* 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 ==
*
* Tool object to manage HTML lists items (UL, OL and LI).
*/
var FCKListHandler =
{
OutdentListItem : function( listItem )
{
var eParent = listItem.parentNode ;
// It may happen that a LI is not in a UL or OL (Orphan).
if ( eParent.tagName.toUpperCase().Equals( 'UL','OL' ) )
{
var oDocument = FCKTools.GetElementDocument( listItem ) ;
var oDogFrag = new FCKDocumentFragment( oDocument ) ;
// All children and successive siblings will be moved to a a DocFrag.
var eNextSiblings = oDogFrag.RootNode ;
var eHasLiSibling = false ;
// If we have nested lists inside it, let's move it to the list of siblings.
var eChildList = FCKDomTools.GetFirstChild( listItem, ['UL','OL'] ) ;
if ( eChildList )
{
eHasLiSibling = true ;
var eChild ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while ( (eChild = eChildList.firstChild) )
eNextSiblings.appendChild( eChildList.removeChild( eChild ) ) ;
FCKDomTools.RemoveNode( eChildList ) ;
}
// Move all successive siblings.
var eSibling ;
var eHasSuccessiveLiSibling = false ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while ( (eSibling = listItem.nextSibling) )
{
if ( !eHasLiSibling && eSibling.nodeType == 1 && eSibling.nodeName.toUpperCase() == 'LI' )
eHasSuccessiveLiSibling = eHasLiSibling = true ;
eNextSiblings.appendChild( eSibling.parentNode.removeChild( eSibling ) ) ;
// If a sibling is a incorrectly nested UL or OL, consider only its children.
if ( !eHasSuccessiveLiSibling && eSibling.nodeType == 1 && eSibling.nodeName.toUpperCase().Equals( 'UL','OL' ) )
FCKDomTools.RemoveNode( eSibling, true ) ;
}
// If we are in a list chain.
var sParentParentTag = eParent.parentNode.tagName.toUpperCase() ;
var bWellNested = ( sParentParentTag == 'LI' ) ;
if ( bWellNested || sParentParentTag.Equals( 'UL','OL' ) )
{
if ( eHasLiSibling )
{
var eChildList = eParent.cloneNode( false ) ;
oDogFrag.AppendTo( eChildList ) ;
listItem.appendChild( eChildList ) ;
}
else if ( bWellNested )
oDogFrag.InsertAfterNode( eParent.parentNode ) ;
else
oDogFrag.InsertAfterNode( eParent ) ;
// Move the LI after its parent.parentNode (the upper LI in the hierarchy).
if ( bWellNested )
FCKDomTools.InsertAfterNode( eParent.parentNode, eParent.removeChild( listItem ) ) ;
else
FCKDomTools.InsertAfterNode( eParent, eParent.removeChild( listItem ) ) ;
}
else
{
if ( eHasLiSibling )
{
var eNextList = eParent.cloneNode( false ) ;
oDogFrag.AppendTo( eNextList ) ;
FCKDomTools.InsertAfterNode( eParent, eNextList ) ;
}
var eBlock = oDocument.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
FCKDomTools.MoveChildren( eParent.removeChild( listItem ), eBlock ) ;
FCKDomTools.InsertAfterNode( eParent, eBlock ) ;
if ( FCKConfig.EnterMode == 'br' )
{
// We need the bogus to make it work properly. In Gecko, we
// need it before the new block, on IE, after it.
if ( FCKBrowserInfo.IsGecko )
eBlock.parentNode.insertBefore( FCKTools.CreateBogusBR( oDocument ), eBlock ) ;
else
FCKDomTools.InsertAfterNode( eBlock, FCKTools.CreateBogusBR( oDocument ) ) ;
FCKDomTools.RemoveNode( eBlock, true ) ;
}
}
if ( this.CheckEmptyList( eParent ) )
FCKDomTools.RemoveNode( eParent, true ) ;
}
},
CheckEmptyList : function( listElement )
{
return ( FCKDomTools.GetFirstChild( listElement, 'LI' ) == null ) ;
},
// Check if the list has contents (excluding nested lists).
CheckListHasContents : function( listElement )
{
var eChildNode = listElement.firstChild ;
while ( eChildNode )
{
switch ( eChildNode.nodeType )
{
case 1 :
if ( !eChildNode.nodeName.IEquals( 'UL','LI' ) )
return true ;
break ;
case 3 :
if ( eChildNode.nodeValue.Trim().length > 0 )
return true ;
}
eChildNode = eChildNode.nextSibling ;
}
return false ;
}
} ;

View file

@ -0,0 +1,60 @@
/*
* 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 ==
*
* Library of keys collections.
*
* Test have shown that check for the existence of a key in an object is the
* most efficient list entry check (10x faster that regex). Example:
* if ( FCKListsLib.<ListName>[key] != null )
*/
var FCKListsLib =
{
// We are not handling <ins> and <del> as block elements, for now.
BlockElements : { address:1,blockquote:1,center:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,marquee:1,noscript:1,ol:1,p:1,pre:1,script:1,table:1,ul:1 },
// Block elements that may be filled with &nbsp; if empty.
NonEmptyBlockElements : { p:1,div:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,address:1,pre:1,ol:1,ul:1,li:1,td:1,th:1 },
// Inline elements which MUST have child nodes.
InlineChildReqElements : { abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
// Inline elements which are not marked as empty "Empty" in the XHTML DTD.
InlineNonEmptyElements : { a:1,abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
// Elements marked as empty "Empty" in the XHTML DTD.
EmptyElements : { base:1,col:1,meta:1,link:1,hr:1,br:1,param:1,img:1,area:1,input:1 },
// Elements that may be considered the "Block boundary" in an element path.
PathBlockElements : { address:1,blockquote:1,dl:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,li:1,dt:1,de:1 },
// Elements that may be considered the "Block limit" in an element path.
PathBlockLimitElements : { body:1,div:1,td:1,th:1,caption:1,form:1 },
// Block elements for the Styles System.
StyleBlockElements : { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 },
// Object elements for the Styles System.
StyleObjectElements : { img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1 },
// Elements used to separate block contents.
BlockBoundaries : { p:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,address:1,pre:1,ol:1,ul:1,li:1,dt:1,de:1,table:1,thead:1,tbody:1,tfoot:1,tr:1,th:1,td:1,caption:1,col:1,colgroup:1,blockquote:1,body:1 },
ListBoundaries : { p:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,address:1,pre:1,ol:1,ul:1,li:1,dt:1,de:1,table:1,thead:1,tbody:1,tfoot:1,tr:1,th:1,td:1,caption:1,col:1,colgroup:1,blockquote:1,body:1,br:1 }
} ;

View file

@ -0,0 +1,46 @@
/*
* 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 FCKPlugins object that is responsible for loading the Plugins.
*/
var FCKPlugins = FCK.Plugins = new Object() ;
FCKPlugins.ItemsCount = 0 ;
FCKPlugins.Items = new Object() ;
FCKPlugins.Load = function()
{
var oItems = FCKPlugins.Items ;
// build the plugins collection.
for ( var i = 0 ; i < FCKConfig.Plugins.Items.length ; i++ )
{
var oItem = FCKConfig.Plugins.Items[i] ;
var oPlugin = oItems[ oItem[0] ] = new FCKPlugin( oItem[0], oItem[1], oItem[2] ) ;
FCKPlugins.ItemsCount++ ;
}
// Load all items in the plugins collection.
for ( var s in oItems )
oItems[s].Load() ;
// This is a self destroyable function (must be called once).
FCKPlugins.Load = null ;
}

View file

@ -0,0 +1,97 @@
/*
* 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 ==
*
* These are some Regular Expressions used by the editor.
*/
var FCKRegexLib =
{
// This is the Regular expression used by the SetData method for the "&apos;" entity.
AposEntity : /&apos;/gi ,
// Used by the Styles combo to identify styles that can't be applied to text.
ObjectElements : /^(?:IMG|TABLE|TR|TD|TH|INPUT|SELECT|TEXTAREA|HR|OBJECT|A|UL|OL|LI)$/i ,
// List all named commands (commands that can be interpreted by the browser "execCommand" method.
NamedCommands : /^(?:Cut|Copy|Paste|Print|SelectAll|RemoveFormat|Unlink|Undo|Redo|Bold|Italic|Underline|StrikeThrough|Subscript|Superscript|JustifyLeft|JustifyCenter|JustifyRight|JustifyFull|Outdent|Indent|InsertOrderedList|InsertUnorderedList|InsertHorizontalRule)$/i ,
BeforeBody : /(^[\s\S]*\<body[^\>]*\>)/i,
AfterBody : /(\<\/body\>[\s\S]*$)/i,
// Temporary text used to solve some browser specific limitations.
ToReplace : /___fcktoreplace:([\w]+)/ig ,
// Get the META http-equiv attribute from the tag.
MetaHttpEquiv : /http-equiv\s*=\s*["']?([^"' ]+)/i ,
HasBaseTag : /<base /i ,
HasBodyTag : /<body[\s|>]/i ,
HtmlOpener : /<html\s?[^>]*>/i ,
HeadOpener : /<head\s?[^>]*>/i ,
HeadCloser : /<\/head\s*>/i ,
// Temporary classes (Tables without border, Anchors with content) used in IE
FCK_Class : /\s*FCK__[^ ]*(?=\s+|$)/ ,
// Validate element names (it must be in lowercase).
ElementName : /(^[a-z_:][\w.\-:]*\w$)|(^[a-z_]$)/ ,
// Used in conjunction with the FCKConfig.ForceSimpleAmpersand configuration option.
ForceSimpleAmpersand : /___FCKAmp___/g ,
// Get the closing parts of the tags with no closing tags, like <br/>... gets the "/>" part.
SpaceNoClose : /\/>/g ,
// Empty elements may be <p></p> or even a simple opening <p> (see #211).
EmptyParagraph : /^<(p|div|address|h\d|center)(?=[ >])[^>]*>\s*(<\/\1>)?$/ ,
EmptyOutParagraph : /^<(p|div|address|h\d|center)(?=[ >])[^>]*>(?:\s*|&nbsp;)(<\/\1>)?$/ ,
TagBody : /></ ,
GeckoEntitiesMarker : /#\?-\:/g ,
// We look for the "src" and href attribute with the " or ' or without one of
// them. We have to do all in one, otherwise we will have problems with URLs
// like "thumbnail.php?src=someimage.jpg" (SF-BUG 1554141).
ProtectUrlsImg : /<img(?=\s).*?\ssrc=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi ,
ProtectUrlsA : /<a(?=\s).*?\shref=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi ,
ProtectUrlsArea : /<area(?=\s).*?\shref=((?:(?:\s*)("|').*?\2)|(?:[^"'][^ >]+))/gi ,
Html4DocType : /HTML 4\.0 Transitional/i ,
DocTypeTag : /<!DOCTYPE[^>]*>/i ,
// These regex are used to save the original event attributes in the HTML.
TagsWithEvent : /<[^\>]+ on\w+[\s\r\n]*=[\s\r\n]*?('|")[\s\S]+?\>/g ,
EventAttributes : /\s(on\w+)[\s\r\n]*=[\s\r\n]*?('|")([\s\S]*?)\2/g,
ProtectedEvents : /\s\w+_fckprotectedatt="([^"]+)"/g,
StyleProperties : /\S+\s*:/g,
// [a-zA-Z0-9:]+ seams to be more efficient than [\w:]+
InvalidSelfCloseTags : /(<(?!base|meta|link|hr|br|param|img|area|input)([a-zA-Z0-9:]+)[^>]*)\/>/gi,
// All variables defined in a style attribute or style definition. The variable
// name is returned with $2.
StyleVariableAttName : /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g,
RegExp : /^\/(.*)\/([gim]*)$/
} ;

View file

@ -0,0 +1,42 @@
/*
* 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 ==
*
* Active selection functions.
*/
var FCKSelection = FCK.Selection =
{
GetParentBlock : function()
{
var retval = this.GetParentElement() ;
while ( retval )
{
if ( FCKListsLib.BlockBoundaries[retval.nodeName.toLowerCase()] )
break ;
retval = retval.parentNode ;
}
return retval ;
},
ApplyStyle : function( styleDefinition )
{
FCKStyles.ApplyStyle( new FCKStyle( styleDefinition ) ) ;
}
} ;

View file

@ -0,0 +1,214 @@
/*
* 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 ==
*
* Active selection functions. (Gecko specific implementation)
*/
// Get the selection type (like document.select.type in IE).
FCKSelection.GetType = function()
{
// By default set the type to "Text".
var type = 'Text' ;
// Check if the actual selection is a Control (IMG, TABLE, HR, etc...).
var sel ;
try { sel = FCK.EditorWindow.getSelection() ; } catch (e) {}
if ( sel && sel.rangeCount == 1 )
{
var range = sel.getRangeAt(0) ;
if ( range.startContainer == range.endContainer
&& ( range.endOffset - range.startOffset ) == 1
&& range.startContainer.nodeType == 1
&& FCKListsLib.StyleObjectElements[ range.startContainer.childNodes[ range.startOffset ].nodeName.toLowerCase() ] )
{
type = 'Control' ;
}
}
return type ;
}
// Retrieves the selected element (if any), just in the case that a single
// element (object like and image or a table) is selected.
FCKSelection.GetSelectedElement = function()
{
var selectedElement = null ;
var selection = !!FCK.EditorWindow && FCK.EditorWindow.getSelection() ;
if ( selection && selection.anchorNode && selection.anchorNode.nodeType == 1 )
{
if ( this.GetType() == 'Control' )
{
// This one is good for all browsers, expect Safari Mac.
selectedElement = selection.anchorNode.childNodes[ selection.anchorOffset ] ;
// For Safari (Mac only), the anchor node for a control selection is
// the control itself, which seams logic. FF and Opera use the parent
// as the anchor node, pointing to the control with the offset.
// As FF created the selection "standard", Safari would do better by
// following their steps.
if ( !selectedElement )
selectedElement = selection.anchorNode ;
else if ( selectedElement.nodeType != 1 )
return null ;
}
}
return selectedElement ;
}
FCKSelection.GetParentElement = function()
{
if ( this.GetType() == 'Control' )
return FCKSelection.GetSelectedElement().parentNode ;
else
{
var oSel = FCK.EditorWindow.getSelection() ;
if ( oSel )
{
// make the common case fast - for collapsed/nearly collapsed selections just return anchor.parent.
if ( oSel.anchorNode && oSel.anchorNode == oSel.focusNode )
return oSel.anchorNode.parentNode ;
// looks like we're having a large selection here. To make the behavior same as IE's TextRange.parentElement(),
// we need to find the nearest ancestor node which encapsulates both the beginning and the end of the selection.
// TODO: A simpler logic can be found.
var anchorPath = new FCKElementPath( oSel.anchorNode ) ;
var focusPath = new FCKElementPath( oSel.focusNode ) ;
var deepPath = null ;
var shallowPath = null ;
if ( anchorPath.Elements.length > focusPath.Elements.length )
{
deepPath = anchorPath.Elements ;
shallowPath = focusPath.Elements ;
}
else
{
deepPath = focusPath.Elements ;
shallowPath = anchorPath.Elements ;
}
var deepPathBase = deepPath.length - shallowPath.length ;
for( var i = 0 ; i < shallowPath.length ; i++)
{
if ( deepPath[deepPathBase + i] == shallowPath[i])
return shallowPath[i];
}
return null ;
}
}
return null ;
}
FCKSelection.GetBoundaryParentElement = function( startBoundary )
{
if ( ! FCK.EditorWindow )
return null ;
if ( this.GetType() == 'Control' )
return FCKSelection.GetSelectedElement().parentNode ;
else
{
var oSel = FCK.EditorWindow.getSelection() ;
if ( oSel && oSel.rangeCount > 0 )
{
var range = oSel.getRangeAt( startBoundary ? 0 : ( oSel.rangeCount - 1 ) ) ;
var element = startBoundary ? range.startContainer : range.endContainer ;
return ( element.nodeType == 1 ? element : element.parentNode ) ;
}
}
return null ;
}
FCKSelection.SelectNode = function( element )
{
var oRange = FCK.EditorDocument.createRange() ;
oRange.selectNode( element ) ;
var oSel = FCK.EditorWindow.getSelection() ;
oSel.removeAllRanges() ;
oSel.addRange( oRange ) ;
}
FCKSelection.Collapse = function( toStart )
{
var oSel = FCK.EditorWindow.getSelection() ;
if ( toStart == null || toStart === true )
oSel.collapseToStart() ;
else
oSel.collapseToEnd() ;
}
// The "nodeTagName" parameter must be Upper Case.
FCKSelection.HasAncestorNode = function( nodeTagName )
{
var oContainer = this.GetSelectedElement() ;
if ( ! oContainer && FCK.EditorWindow )
{
try { oContainer = FCK.EditorWindow.getSelection().getRangeAt(0).startContainer ; }
catch(e){}
}
while ( oContainer )
{
if ( oContainer.nodeType == 1 && oContainer.tagName == nodeTagName ) return true ;
oContainer = oContainer.parentNode ;
}
return false ;
}
// The "nodeTagName" parameter must be Upper Case.
FCKSelection.MoveToAncestorNode = function( nodeTagName )
{
var oNode ;
var oContainer = this.GetSelectedElement() ;
if ( ! oContainer )
oContainer = FCK.EditorWindow.getSelection().getRangeAt(0).startContainer ;
while ( oContainer )
{
if ( oContainer.nodeName == nodeTagName )
return oContainer ;
oContainer = oContainer.parentNode ;
}
return null ;
}
FCKSelection.Delete = function()
{
// Gets the actual selection.
var oSel = FCK.EditorWindow.getSelection() ;
// Deletes the actual selection contents.
for ( var i = 0 ; i < oSel.rangeCount ; i++ )
{
oSel.getRangeAt(i).deleteContents() ;
}
return oSel ;
}

View file

@ -0,0 +1,201 @@
/*
* 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 ==
*
* Active selection functions. (IE specific implementation)
*/
// Get the selection type.
FCKSelection.GetType = function()
{
// It is possible that we can still get a text range object even when type=='None' is returned by IE.
// So we'd better check the object returned by createRange() rather than by looking at the type.
try
{
var ieType = FCK.EditorDocument.selection.type ;
if ( ieType == 'Control' || ieType == 'Text' )
return ieType ;
if ( FCK.EditorDocument.selection.createRange().parentElement )
return 'Text' ;
}
catch(e)
{
// Nothing to do, it will return None properly.
}
return 'None' ;
} ;
// Retrieves the selected element (if any), just in the case that a single
// element (object like and image or a table) is selected.
FCKSelection.GetSelectedElement = function()
{
if ( this.GetType() == 'Control' )
{
var oRange = FCK.EditorDocument.selection.createRange() ;
if ( oRange && oRange.item )
return FCK.EditorDocument.selection.createRange().item(0) ;
}
return null ;
} ;
FCKSelection.GetParentElement = function()
{
switch ( this.GetType() )
{
case 'Control' :
var el = FCKSelection.GetSelectedElement() ;
return el ? el.parentElement : null ;
case 'None' :
return null ;
default :
return FCK.EditorDocument.selection.createRange().parentElement() ;
}
} ;
FCKSelection.GetBoundaryParentElement = function( startBoundary )
{
switch ( this.GetType() )
{
case 'Control' :
var el = FCKSelection.GetSelectedElement() ;
return el ? el.parentElement : null ;
case 'None' :
return null ;
default :
var doc = FCK.EditorDocument ;
var range = doc.selection.createRange() ;
range.collapse( startBoundary !== false ) ;
var el = range.parentElement() ;
// It may happen that range is comming from outside "doc", so we
// must check it (#1204).
return FCKTools.GetElementDocument( el ) == doc ? el : null ;
}
} ;
FCKSelection.SelectNode = function( node )
{
FCK.Focus() ;
FCK.EditorDocument.selection.empty() ;
var oRange ;
try
{
// Try to select the node as a control.
oRange = FCK.EditorDocument.body.createControlRange() ;
oRange.addElement( node ) ;
}
catch(e)
{
// If failed, select it as a text range.
oRange = FCK.EditorDocument.body.createTextRange() ;
oRange.moveToElementText( node ) ;
}
oRange.select() ;
} ;
FCKSelection.Collapse = function( toStart )
{
FCK.Focus() ;
if ( this.GetType() == 'Text' )
{
var oRange = FCK.EditorDocument.selection.createRange() ;
oRange.collapse( toStart == null || toStart === true ) ;
oRange.select() ;
}
} ;
// The "nodeTagName" parameter must be Upper Case.
FCKSelection.HasAncestorNode = function( nodeTagName )
{
var oContainer ;
if ( FCK.EditorDocument.selection.type == "Control" )
{
oContainer = this.GetSelectedElement() ;
}
else
{
var oRange = FCK.EditorDocument.selection.createRange() ;
oContainer = oRange.parentElement() ;
}
while ( oContainer )
{
if ( oContainer.tagName == nodeTagName ) return true ;
oContainer = oContainer.parentNode ;
}
return false ;
} ;
// The "nodeTagName" parameter must be UPPER CASE.
FCKSelection.MoveToAncestorNode = function( nodeTagName )
{
var oNode, oRange ;
if ( ! FCK.EditorDocument )
return null ;
if ( FCK.EditorDocument.selection.type == "Control" )
{
oRange = FCK.EditorDocument.selection.createRange() ;
for ( i = 0 ; i < oRange.length ; i++ )
{
if (oRange(i).parentNode)
{
oNode = oRange(i).parentNode ;
break ;
}
}
}
else
{
oRange = FCK.EditorDocument.selection.createRange() ;
oNode = oRange.parentElement() ;
}
while ( oNode && oNode.nodeName != nodeTagName )
oNode = oNode.parentNode ;
return oNode ;
} ;
FCKSelection.Delete = function()
{
// Gets the actual selection.
var oSel = FCK.EditorDocument.selection ;
// Deletes the actual selection contents.
if ( oSel.type.toLowerCase() != "none" )
{
oSel.clear() ;
}
return oSel ;
} ;

View file

@ -0,0 +1,379 @@
/*
* 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 ==
*
* Handles styles in a give document.
*/
var FCKStyles = FCK.Styles =
{
_Callbacks : {},
_ObjectStyles : {},
ApplyStyle : function( style )
{
if ( typeof style == 'string' )
style = this.GetStyles()[ style ] ;
if ( style )
{
if ( style.GetType() == FCK_STYLE_OBJECT )
style.ApplyToObject( FCKSelection.GetSelectedElement() ) ;
else
style.ApplyToSelection( FCK.EditorWindow ) ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
},
RemoveStyle : function( style )
{
if ( typeof style == 'string' )
style = this.GetStyles()[ style ] ;
if ( style )
{
style.RemoveFromSelection( FCK.EditorWindow ) ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
},
/**
* Defines a callback function to be called when the current state of a
* specific style changes.
*/
AttachStyleStateChange : function( styleName, callback, callbackOwner )
{
var callbacks = this._Callbacks[ styleName ] ;
if ( !callbacks )
callbacks = this._Callbacks[ styleName ] = [] ;
callbacks.push( [ callback, callbackOwner ] ) ;
},
CheckSelectionChanges : function()
{
var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
if ( !startElement )
return ;
// Walks the start node parents path, checking all styles that are being listened.
var path = new FCKElementPath( startElement ) ;
var styles = this.GetStyles() ;
for ( var styleName in styles )
{
var callbacks = this._Callbacks[ styleName ] ;
if ( callbacks )
{
var style = styles[ styleName ] ;
var state = style.CheckActive( path ) ;
if ( style._LastState != state )
{
style._LastState = state ;
for ( var i = 0 ; i < callbacks.length ; i++ )
{
var callback = callbacks[i][0] ;
var callbackOwner = callbacks[i][1] ;
callback.call( callbackOwner || window, styleName, state ) ;
}
}
}
}
},
CheckStyleInSelection : function( styleName )
{
return false ;
},
_GetRemoveFormatTagsRegex : function ()
{
var regex = new RegExp( '^(?:' + FCKConfig.RemoveFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) ;
return (this._GetRemoveFormatTagsRegex = function()
{
return regex ;
})
&& regex ;
},
/**
* Remove all styles from the current selection.
* TODO:
* - This is almost a duplication of FCKStyle.RemoveFromRange. We should
* try to merge things.
*/
RemoveAll : function()
{
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
if ( range.CheckIsCollapsed() )
return ;
// Expand the range, if inside inline element boundaries.
range.Expand( 'inline_elements' ) ;
// Get the bookmark nodes.
// Bookmark the range so we can re-select it after processing.
var bookmark = range.CreateBookmark( true ) ;
// The style will be applied within the bookmark boundaries.
var startNode = range.GetBookmarkNode( bookmark, true ) ;
var endNode = range.GetBookmarkNode( bookmark, false ) ;
range.Release( true ) ;
var tagsRegex = this._GetRemoveFormatTagsRegex() ;
// We need to check the selection boundaries (bookmark spans) to break
// the code in a way that we can properly remove partially selected nodes.
// For example, removing a <b> style from
// <b>This is [some text</b> to show <b>the] problem</b>
// ... where [ and ] represent the selection, must result:
// <b>This is </b>[some text to show the]<b> problem</b>
// The strategy is simple, we just break the partial nodes before the
// removal logic, having something that could be represented this way:
// <b>This is </b>[<b>some text</b> to show <b>the</b>]<b> problem</b>
// Let's start checking the start boundary.
var path = new FCKElementPath( startNode ) ;
var pathElements = path.Elements ;
var pathElement ;
for ( var i = 1 ; i < pathElements.length ; i++ )
{
pathElement = pathElements[i] ;
if ( pathElement == path.Block || pathElement == path.BlockLimit )
break ;
// If this element can be removed (even partially).
if ( tagsRegex.test( pathElement.nodeName ) )
FCKDomTools.BreakParent( startNode, pathElement, range ) ;
}
// Now the end boundary.
path = new FCKElementPath( endNode ) ;
pathElements = path.Elements ;
for ( var i = 1 ; i < pathElements.length ; i++ )
{
pathElement = pathElements[i] ;
if ( pathElement == path.Block || pathElement == path.BlockLimit )
break ;
elementName = pathElement.nodeName.toLowerCase() ;
// If this element can be removed (even partially).
if ( tagsRegex.test( pathElement.nodeName ) )
FCKDomTools.BreakParent( endNode, pathElement, range ) ;
}
// Navigate through all nodes between the bookmarks.
var currentNode = FCKDomTools.GetNextSourceNode( startNode, true, 1 ) ;
while ( currentNode )
{
// If we have reached the end of the selection, stop looping.
if ( currentNode == endNode )
break ;
// Cache the next node to be processed. Do it now, because
// currentNode may be removed.
var nextNode = FCKDomTools.GetNextSourceNode( currentNode, false, 1 ) ;
// Remove elements nodes that match with this style rules.
if ( tagsRegex.test( currentNode.nodeName ) )
FCKDomTools.RemoveNode( currentNode, true ) ;
currentNode = nextNode ;
}
range.SelectBookmark( bookmark ) ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
},
GetStyle : function( styleName )
{
return this.GetStyles()[ styleName ] ;
},
GetStyles : function()
{
var styles = this._GetStyles ;
if ( !styles )
{
styles = this._GetStyles = FCKTools.Merge(
this._LoadStylesCore(),
this._LoadStylesCustom(),
this._LoadStylesXml() ) ;
}
return styles ;
},
CheckHasObjectStyle : function( elementName )
{
return !!this._ObjectStyles[ elementName ] ;
},
_LoadStylesCore : function()
{
var styles = {};
var styleDefs = FCKConfig.CoreStyles ;
for ( var styleName in styleDefs )
{
// Core styles are prefixed with _FCK_.
var style = styles[ '_FCK_' + styleName ] = new FCKStyle( styleDefs[ styleName ] ) ;
style.IsCore = true ;
}
return styles ;
},
_LoadStylesCustom : function()
{
var styles = {};
var styleDefs = FCKConfig.CustomStyles ;
if ( styleDefs )
{
for ( var styleName in styleDefs )
{
var style = styles[ styleName ] = new FCKStyle( styleDefs[ styleName ] ) ;
style.Name = styleName ;
}
}
return styles ;
},
_LoadStylesXml : function()
{
var styles = {};
var stylesXmlPath = FCKConfig.StylesXmlPath ;
if ( !stylesXmlPath || stylesXmlPath.length == 0 )
return styles ;
// Load the XML file into a FCKXml object.
var xml = new FCKXml() ;
xml.LoadUrl( stylesXmlPath ) ;
var stylesXmlObj = FCKXml.TransformToObject( xml.SelectSingleNode( 'Styles' ) ) ;
// Get the "Style" nodes defined in the XML file.
var styleNodes = stylesXmlObj.$Style ;
// Check that it did contain some valid nodes
if ( !styleNodes )
return styles ;
// Add each style to our "Styles" collection.
for ( var i = 0 ; i < styleNodes.length ; i++ )
{
var styleNode = styleNodes[i] ;
var element = ( styleNode.element || '' ).toLowerCase() ;
if ( element.length == 0 )
throw( 'The element name is required. Error loading "' + stylesXmlPath + '"' ) ;
var styleDef = {
Element : element,
Attributes : {},
Styles : {},
Overrides : []
} ;
// Get the attributes defined for the style (if any).
var attNodes = styleNode.$Attribute || [] ;
// Add the attributes to the style definition object.
for ( var j = 0 ; j < attNodes.length ; j++ )
{
styleDef.Attributes[ attNodes[j].name ] = attNodes[j].value ;
}
// Get the styles defined for the style (if any).
var cssStyleNodes = styleNode.$Style || [] ;
// Add the attributes to the style definition object.
for ( j = 0 ; j < cssStyleNodes.length ; j++ )
{
styleDef.Styles[ cssStyleNodes[j].name ] = cssStyleNodes[j].value ;
}
// Load override definitions.
var cssStyleOverrideNodes = styleNode.$Override ;
if ( cssStyleOverrideNodes )
{
for ( j = 0 ; j < cssStyleOverrideNodes.length ; j++ )
{
var overrideNode = cssStyleOverrideNodes[j] ;
var overrideDef =
{
Element : overrideNode.element
} ;
var overrideAttNode = overrideNode.$Attribute ;
if ( overrideAttNode )
{
overrideDef.Attributes = {} ;
for ( var k = 0 ; k < overrideAttNode.length ; k++ )
{
var overrideAttValue = overrideAttNode[k].value || null ;
if ( overrideAttValue )
{
// Check if the override attribute value is a regular expression.
var regexMatch = overrideAttValue && FCKRegexLib.RegExp.exec( overrideAttValue ) ;
if ( regexMatch )
overrideAttValue = new RegExp( regexMatch[1], regexMatch[2] || '' ) ;
}
overrideDef.Attributes[ overrideAttNode[k].name ] = overrideAttValue ;
}
}
styleDef.Overrides.push( overrideDef ) ;
}
}
var style = new FCKStyle( styleDef ) ;
style.Name = styleNode.name || element ;
if ( style.GetType() == FCK_STYLE_OBJECT )
this._ObjectStyles[ element ] = true ;
// Add the style to the "Styles" collection using it's name as the key.
styles[ style.Name ] = style ;
}
return styles ;
}
} ;

View file

@ -0,0 +1,858 @@
/*
* 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 ==
*
* Manage table operations.
*/
var FCKTableHandler = new Object() ;
FCKTableHandler.InsertRow = function( insertBefore )
{
// Get the row where the selection is placed in.
var oRow = FCKSelection.MoveToAncestorNode( 'TR' ) ;
if ( !oRow ) return ;
// Create a clone of the row.
var oNewRow = oRow.cloneNode( true ) ;
// Insert the new row (copy) before of it.
oRow.parentNode.insertBefore( oNewRow, oRow ) ;
// Clean one of the rows to produce the illusion of inserting an empty row before or after.
FCKTableHandler.ClearRow( insertBefore ? oNewRow : oRow ) ;
}
FCKTableHandler.DeleteRows = function( row )
{
// If no row has been passed as a parameter,
// then get the row( s ) containing the cells where the selection is placed in.
// If user selected multiple rows ( by selecting multiple cells ), walk
// the selected cell list and delete the rows containing the selected cells
if ( ! row )
{
var aCells = FCKTableHandler.GetSelectedCells() ;
var aRowsToDelete = new Array() ;
//queue up the rows -- it's possible ( and likely ) that we may get duplicates
for ( var i = 0; i < aCells.length; i++ )
{
var oRow = FCKTools.GetElementAscensor( aCells[i],'TR' ) ;
aRowsToDelete[oRow.rowIndex] = oRow ;
}
for ( var i = aRowsToDelete.length; i >= 0; i-- )
{
if ( aRowsToDelete[i] )
FCKTableHandler.DeleteRows( aRowsToDelete[i] );
}
return ;
}
// Get the row's table.
var oTable = FCKTools.GetElementAscensor( row, 'TABLE' ) ;
// If just one row is available then delete the entire table.
if ( oTable.rows.length == 1 )
{
FCKTableHandler.DeleteTable( oTable ) ;
return ;
}
// Delete the row.
row.parentNode.removeChild( row ) ;
}
FCKTableHandler.DeleteTable = function( table )
{
// If no table has been passed as a parameter,
// then get the table where the selection is placed in.
if ( !table )
{
table = FCKSelection.GetSelectedElement() ;
if ( !table || table.tagName != 'TABLE' )
table = FCKSelection.MoveToAncestorNode( 'TABLE' ) ;
}
if ( !table ) return ;
// Delete the table.
FCKSelection.SelectNode( table ) ;
FCKSelection.Collapse();
// if the table is wrapped with a singleton <p> ( or something similar ), remove
// the surrounding tag -- which likely won't show after deletion anyway
if ( table.parentNode.childNodes.length == 1 )
table.parentNode.parentNode.removeChild( table.parentNode );
else
table.parentNode.removeChild( table ) ;
}
FCKTableHandler.InsertColumn = function( insertBefore )
{
// Get the cell where the selection is placed in.
var oCell = null ;
var nodes = this.GetSelectedCells() ;
if ( nodes && nodes.length )
oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
if ( ! oCell )
return ;
// Get the cell's table.
var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
var iIndex = oCell.cellIndex ;
// Loop throw all rows available in the table.
for ( var i = 0 ; i < oTable.rows.length ; i++ )
{
// Get the row.
var oRow = oTable.rows[i] ;
// If the row doens't have enough cells, ignore it.
if ( oRow.cells.length < ( iIndex + 1 ) )
continue ;
oCell = oRow.cells[iIndex].cloneNode(false) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( oCell ) ;
// Get back the currently selected cell.
var oBaseCell = oRow.cells[iIndex] ;
if ( insertBefore )
oRow.insertBefore( oCell, oBaseCell ) ;
else if ( oBaseCell.nextSibling )
oRow.insertBefore( oCell, oBaseCell.nextSibling ) ;
else
oRow.appendChild( oCell ) ;
}
}
FCKTableHandler.DeleteColumns = function( oCell )
{
// if user selected multiple cols ( by selecting multiple cells ), walk
// the selected cell list and delete the rows containing the selected cells
if ( !oCell )
{
var aColsToDelete = FCKTableHandler.GetSelectedCells();
for ( var i = aColsToDelete.length; i >= 0; i-- )
{
if ( aColsToDelete[i] )
FCKTableHandler.DeleteColumns( aColsToDelete[i] );
}
return;
}
if ( !oCell ) return ;
// Get the cell's table.
var oTable = FCKTools.GetElementAscensor( oCell, 'TABLE' ) ;
// Get the cell index.
var iIndex = oCell.cellIndex ;
// Loop throw all rows (from down to up, because it's possible that some
// rows will be deleted).
for ( var i = oTable.rows.length - 1 ; i >= 0 ; i-- )
{
// Get the row.
var oRow = oTable.rows[i] ;
// If the cell to be removed is the first one and the row has just one cell.
if ( iIndex == 0 && oRow.cells.length == 1 )
{
// Remove the entire row.
FCKTableHandler.DeleteRows( oRow ) ;
continue ;
}
// If the cell to be removed exists the delete it.
if ( oRow.cells[iIndex] )
oRow.removeChild( oRow.cells[iIndex] ) ;
}
}
FCKTableHandler.InsertCell = function( cell, insertBefore )
{
// Get the cell where the selection is placed in.
var oCell = null ;
var nodes = this.GetSelectedCells() ;
if ( nodes && nodes.length )
oCell = nodes[ insertBefore ? 0 : ( nodes.length - 1 ) ] ;
if ( ! oCell )
return null ;
// Create the new cell element to be added.
var oNewCell = FCK.EditorDocument.createElement( 'TD' ) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( oNewCell ) ;
if ( !insertBefore && oCell.cellIndex == oCell.parentNode.cells.length - 1 )
oCell.parentNode.appendChild( oNewCell ) ;
else
oCell.parentNode.insertBefore( oNewCell, insertBefore ? oCell : oCell.nextSibling ) ;
return oNewCell ;
}
FCKTableHandler.DeleteCell = function( cell )
{
// If this is the last cell in the row.
if ( cell.parentNode.cells.length == 1 )
{
// Delete the entire row.
FCKTableHandler.DeleteRows( FCKTools.GetElementAscensor( cell, 'TR' ) ) ;
return ;
}
// Delete the cell from the row.
cell.parentNode.removeChild( cell ) ;
}
FCKTableHandler.DeleteCells = function()
{
var aCells = FCKTableHandler.GetSelectedCells() ;
for ( var i = aCells.length - 1 ; i >= 0 ; i-- )
{
FCKTableHandler.DeleteCell( aCells[i] ) ;
}
}
FCKTableHandler._MarkCells = function( cells, label )
{
for ( var i = 0 ; i < cells.length ; i++ )
cells[i][label] = true ;
}
FCKTableHandler._UnmarkCells = function( cells, label )
{
for ( var i = 0 ; i < cells.length ; i++ )
{
if ( FCKBrowserInfo.IsIE )
cells[i].removeAttribute( label ) ;
else
delete cells[i][label] ;
}
}
FCKTableHandler._ReplaceCellsByMarker = function( tableMap, marker, substitute )
{
for ( var i = 0 ; i < tableMap.length ; i++ )
{
for ( var j = 0 ; j < tableMap[i].length ; j++ )
{
if ( tableMap[i][j][marker] )
tableMap[i][j] = substitute ;
}
}
}
FCKTableHandler._GetMarkerGeometry = function( tableMap, rowIdx, colIdx, markerName )
{
var selectionWidth = 0 ;
var selectionHeight = 0 ;
var cellsLeft = 0 ;
var cellsUp = 0 ;
for ( var i = colIdx ; tableMap[rowIdx][i] && tableMap[rowIdx][i][markerName] ; i++ )
selectionWidth++ ;
for ( var i = colIdx - 1 ; tableMap[rowIdx][i] && tableMap[rowIdx][i][markerName] ; i-- )
{
selectionWidth++ ;
cellsLeft++ ;
}
for ( var i = rowIdx ; tableMap[i] && tableMap[i][colIdx] && tableMap[i][colIdx][markerName] ; i++ )
selectionHeight++ ;
for ( var i = rowIdx - 1 ; tableMap[i] && tableMap[i][colIdx] && tableMap[i][colIdx][markerName] ; i-- )
{
selectionHeight++ ;
cellsUp++ ;
}
return { 'width' : selectionWidth, 'height' : selectionHeight, 'x' : cellsLeft, 'y' : cellsUp } ;
}
FCKTableHandler.CheckIsSelectionRectangular = function()
{
// If every row and column in an area on a plane are of the same width and height,
// Then the area is a rectangle.
var cells = FCKTableHandler.GetSelectedCells() ;
if ( cells.length < 1 )
return false ;
this._MarkCells( cells, '_CellSelected' ) ;
var tableMap = this._CreateTableMap( cells[0].parentNode.parentNode ) ;
var rowIdx = cells[0].parentNode.rowIndex ;
var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, cells[0] ) ;
var geometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
var baseColIdx = colIdx - geometry.x ;
var baseRowIdx = rowIdx - geometry.y ;
if ( geometry.width >= geometry.height )
{
for ( colIdx = baseColIdx ; colIdx < baseColIdx + geometry.width ; colIdx++ )
{
rowIdx = baseRowIdx + ( colIdx - baseColIdx ) % geometry.height ;
if ( ! tableMap[rowIdx] || ! tableMap[rowIdx][colIdx] )
{
this._UnmarkCells( cells, '_CellSelected' ) ;
return false ;
}
var g = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
if ( g.width != geometry.width || g.height != geometry.height )
{
this._UnmarkCells( cells, '_CellSelected' ) ;
return false ;
}
}
}
else
{
for ( rowIdx = baseRowIdx ; rowIdx < baseRowIdx + geometry.height ; rowIdx++ )
{
colIdx = baseColIdx + ( rowIdx - baseRowIdx ) % geometry.width ;
if ( ! tableMap[rowIdx] || ! tableMap[rowIdx][colIdx] )
{
this._UnmarkCells( cells, '_CellSelected' ) ;
return false ;
}
var g = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_CellSelected' ) ;
if ( g.width != geometry.width || g.height != geometry.height )
{
this._UnmarkCells( cells, '_CellSelected' ) ;
return false ;
}
}
}
this._UnmarkCells( cells, '_CellSelected' ) ;
return true ;
}
FCKTableHandler.MergeCells = function()
{
// Get all selected cells.
var cells = this.GetSelectedCells() ;
if ( cells.length < 2 )
return ;
// Assume the selected cells are already in a rectangular geometry.
// Because the checking is already done by FCKTableCommand.
var refCell = cells[0] ;
var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
var rowIdx = refCell.parentNode.rowIndex ;
var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
this._MarkCells( cells, '_SelectedCells' ) ;
var selectionGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SelectedCells' ) ;
var baseColIdx = colIdx - selectionGeometry.x ;
var baseRowIdx = rowIdx - selectionGeometry.y ;
var cellContents = refCell.ownerDocument.createDocumentFragment() ;
for ( var i = 0 ; i < selectionGeometry.height ; i++ )
{
var rowChildNodesCount = 0 ;
for ( var j = 0 ; j < selectionGeometry.width ; j++ )
{
var currentCell = tableMap[baseRowIdx + i][baseColIdx + j] ;
while ( currentCell.childNodes.length > 0 )
{
var node = currentCell.removeChild( currentCell.firstChild ) ;
if ( node.nodeType != 1
|| ( node.getAttribute( 'type', 2 ) != '_moz' && node.getAttribute( '_moz_dirty' ) != null ) )
{
cellContents.appendChild( node ) ;
rowChildNodesCount++ ;
}
}
}
if ( rowChildNodesCount > 0 )
cellContents.appendChild( refCell.ownerDocument.createElement( 'br' ) ) ;
}
this._ReplaceCellsByMarker( tableMap, '_SelectedCells', refCell ) ;
this._UnmarkCells( cells, '_SelectedCells' ) ;
this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
refCell.appendChild( cellContents ) ;
if ( FCKBrowserInfo.IsGeckoLike && ( ! refCell.firstChild ) )
FCKTools.AppendBogusBr( refCell ) ;
this._MoveCaretToCell( refCell, false ) ;
}
FCKTableHandler.MergeRight = function()
{
var target = this.GetMergeRightTarget() ;
if ( target == null )
return ;
var refCell = target.refCell ;
var tableMap = target.tableMap ;
var nextCell = target.nextCell ;
var cellContents = FCK.EditorDocument.createDocumentFragment() ;
while ( nextCell && nextCell.childNodes && nextCell.childNodes.length > 0 )
cellContents.appendChild( nextCell.removeChild( nextCell.firstChild ) ) ;
nextCell.parentNode.removeChild( nextCell ) ;
refCell.appendChild( cellContents ) ;
this._MarkCells( [nextCell], '_Replace' ) ;
this._ReplaceCellsByMarker( tableMap, '_Replace', refCell ) ;
this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
this._MoveCaretToCell( refCell, false ) ;
}
FCKTableHandler.MergeDown = function()
{
var target = this.GetMergeDownTarget() ;
if ( target == null )
return ;
var refCell = target.refCell ;
var tableMap = target.tableMap ;
var nextCell = target.nextCell ;
var cellContents = refCell.ownerDocument.createDocumentFragment() ;
while ( nextCell && nextCell.childNodes && nextCell.childNodes.length > 0 )
cellContents.appendChild( nextCell.removeChild( nextCell.firstChild ) ) ;
if ( cellContents.firstChild )
cellContents.insertBefore( nextCell.ownerDocument.createElement( 'br' ), cellContents.firstChild ) ;
refCell.appendChild( cellContents ) ;
this._MarkCells( [nextCell], '_Replace' ) ;
this._ReplaceCellsByMarker( tableMap, '_Replace', refCell ) ;
this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
this._MoveCaretToCell( refCell, false ) ;
}
FCKTableHandler.HorizontalSplitCell = function()
{
var cells = FCKTableHandler.GetSelectedCells() ;
if ( cells.length != 1 )
return ;
var refCell = cells[0] ;
var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
var rowIdx = refCell.parentNode.rowIndex ;
var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
var cellSpan = isNaN( refCell.colSpan ) ? 1 : refCell.colSpan ;
if ( cellSpan > 1 )
{
// Splittng a multi-column cell - original cell gets ceil(colSpan/2) columns,
// new cell gets floor(colSpan/2).
var newCellSpan = Math.ceil( cellSpan / 2 ) ;
var newCell = refCell.ownerDocument.createElement( 'td' ) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( newCell ) ;
var startIdx = colIdx + newCellSpan ;
var endIdx = colIdx + cellSpan ;
var rowSpan = isNaN( refCell.rowSpan ) ? 1 : refCell.rowSpan ;
for ( var r = rowIdx ; r < rowIdx + rowSpan ; r++ )
{
for ( var i = startIdx ; i < endIdx ; i++ )
tableMap[r][i] = newCell ;
}
}
else
{
// Splitting a single-column cell - add a new cell, and expand
// cells crossing the same column.
var newTableMap = [] ;
for ( var i = 0 ; i < tableMap.length ; i++ )
{
var newRow = tableMap[i].slice( 0, colIdx ) ;
if ( tableMap[i].length <= colIdx )
{
newTableMap.push( newRow ) ;
continue ;
}
if ( tableMap[i][colIdx] == refCell )
{
newRow.push( refCell ) ;
newRow.push( refCell.ownerDocument.createElement( 'td' ) ) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( newRow[newRow.length - 1] ) ;
}
else
{
newRow.push( tableMap[i][colIdx] ) ;
newRow.push( tableMap[i][colIdx] ) ;
}
for ( var j = colIdx + 1 ; j < tableMap[i].length ; j++ )
newRow.push( tableMap[i][j] ) ;
newTableMap.push( newRow ) ;
}
tableMap = newTableMap ;
}
this._InstallTableMap( tableMap, refCell.parentNode.parentNode ) ;
}
FCKTableHandler.VerticalSplitCell = function()
{
var cells = FCKTableHandler.GetSelectedCells() ;
if ( cells.length != 1 )
return ;
var currentCell = cells[0] ;
var tableMap = this._CreateTableMap( currentCell.parentNode.parentNode ) ;
var cellIndex = FCKTableHandler._GetCellIndexSpan( tableMap, currentCell.parentNode.rowIndex, currentCell ) ;
var currentRowSpan = currentCell.rowSpan ;
var currentRowIndex = currentCell.parentNode.rowIndex ;
if ( isNaN( currentRowSpan ) )
currentRowSpan = 1 ;
if ( currentRowSpan > 1 )
{
// 1. Set the current cell's rowSpan to 1.
currentCell.rowSpan = Math.ceil( currentRowSpan / 2 ) ;
// 2. Find the appropriate place to insert a new cell at the next row.
var newCellRowIndex = currentRowIndex + Math.ceil( currentRowSpan / 2 ) ;
var insertMarker = null ;
for ( var i = cellIndex+1 ; i < tableMap[newCellRowIndex].length ; i++ )
{
if ( tableMap[newCellRowIndex][i].parentNode.rowIndex == newCellRowIndex )
{
insertMarker = tableMap[newCellRowIndex][i] ;
break ;
}
}
// 3. Insert the new cell to the indicated place, with the appropriate rowSpan, next row.
var newCell = FCK.EditorDocument.createElement( 'td' ) ;
newCell.rowSpan = Math.floor( currentRowSpan / 2 ) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( newCell ) ;
currentCell.parentNode.parentNode.rows[newCellRowIndex].insertBefore( newCell, insertMarker ) ;
}
else
{
// 1. Insert a new row.
var newCellRowIndex = currentRowIndex + 1 ;
var newRow = FCK.EditorDocument.createElement( 'tr' ) ;
currentCell.parentNode.parentNode.insertBefore( newRow, currentCell.parentNode.parentNode.rows[newCellRowIndex] ) ;
// 2. +1 to rowSpan for all cells crossing currentCell's row.
for ( var i = 0 ; i < tableMap[currentRowIndex].length ; )
{
var colSpan = tableMap[currentRowIndex][i].colSpan ;
if ( isNaN( colSpan ) || colSpan < 1 )
colSpan = 1 ;
if ( i == cellIndex )
{
i += colSpan ;
continue ;
}
var rowSpan = tableMap[currentRowIndex][i].rowSpan ;
if ( isNaN( rowSpan ) )
rowSpan = 1 ;
tableMap[currentRowIndex][i].rowSpan = rowSpan + 1 ;
i += colSpan ;
}
// 3. Insert a new cell to new row.
var newCell = FCK.EditorDocument.createElement( 'td' ) ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( newCell ) ;
newRow.appendChild( newCell ) ;
}
}
// Get the cell index from a TableMap.
FCKTableHandler._GetCellIndexSpan = function( tableMap, rowIndex, cell )
{
if ( tableMap.length < rowIndex + 1 )
return null ;
var oRow = tableMap[ rowIndex ] ;
for ( var c = 0 ; c < oRow.length ; c++ )
{
if ( oRow[c] == cell )
return c ;
}
return null ;
}
// Get the cell location from a TableMap. Returns an array with an [x,y] location
FCKTableHandler._GetCellLocation = function( tableMap, cell )
{
for ( var i = 0 ; i < tableMap.length; i++ )
{
for ( var c = 0 ; c < tableMap[i].length ; c++ )
{
if ( tableMap[i][c] == cell ) return [i,c];
}
}
return null ;
}
// Get the cells available in a column of a TableMap.
FCKTableHandler._GetColumnCells = function( tableMap, columnIndex )
{
var aCollCells = new Array() ;
for ( var r = 0 ; r < tableMap.length ; r++ )
{
var oCell = tableMap[r][columnIndex] ;
if ( oCell && ( aCollCells.length == 0 || aCollCells[ aCollCells.length - 1 ] != oCell ) )
aCollCells[ aCollCells.length ] = oCell ;
}
return aCollCells ;
}
// This function is quite hard to explain. It creates a matrix representing all cells in a table.
// The difference here is that the "spanned" cells (colSpan and rowSpan) are duplicated on the matrix
// cells that are "spanned". For example, a row with 3 cells where the second cell has colSpan=2 and rowSpan=3
// will produce a bi-dimensional matrix with the following values (representing the cells):
// Cell1, Cell2, Cell2, Cell 3
// Cell4, Cell2, Cell2, Cell 5
FCKTableHandler._CreateTableMap = function( table )
{
var aRows = table.rows ;
// Row and Column counters.
var r = -1 ;
var aMap = new Array() ;
for ( var i = 0 ; i < aRows.length ; i++ )
{
r++ ;
if ( !aMap[r] )
aMap[r] = new Array() ;
var c = -1 ;
for ( var j = 0 ; j < aRows[i].cells.length ; j++ )
{
var oCell = aRows[i].cells[j] ;
c++ ;
while ( aMap[r][c] )
c++ ;
var iColSpan = isNaN( oCell.colSpan ) ? 1 : oCell.colSpan ;
var iRowSpan = isNaN( oCell.rowSpan ) ? 1 : oCell.rowSpan ;
for ( var rs = 0 ; rs < iRowSpan ; rs++ )
{
if ( !aMap[r + rs] )
aMap[r + rs] = new Array() ;
for ( var cs = 0 ; cs < iColSpan ; cs++ )
{
aMap[r + rs][c + cs] = aRows[i].cells[j] ;
}
}
c += iColSpan - 1 ;
}
}
return aMap ;
}
// This function is the inverse of _CreateTableMap - it takes in a table map and converts it to an HTML table.
FCKTableHandler._InstallTableMap = function( tableMap, table )
{
// Clear the table of all rows first.
while ( table.rows.length > 0 )
{
var row = table.rows[0] ;
row.parentNode.removeChild( row ) ;
}
// Disconnect all the cells in tableMap from their parents, set all colSpan and rowSpan attributes to 1.
for ( var i = 0 ; i < tableMap.length ; i++ )
{
for ( var j = 0 ; j < tableMap[i].length ; j++ )
{
var cell = tableMap[i][j] ;
if ( cell.parentNode )
cell.parentNode.removeChild( cell ) ;
cell.colSpan = cell.rowSpan = 1 ;
}
}
// Scan by rows and set colSpan.
var maxCol = 0 ;
for ( var i = 0 ; i < tableMap.length ; i++ )
{
for ( var j = 0 ; j < tableMap[i].length ; j++ )
{
var cell = tableMap[i][j] ;
if ( ! cell)
continue ;
if ( j > maxCol )
maxCol = j ;
if ( cell._colScanned === true )
continue ;
if ( tableMap[i][j-1] == cell )
cell.colSpan++ ;
if ( tableMap[i][j+1] != cell )
cell._colScanned = true ;
}
}
// Scan by columns and set rowSpan.
for ( var i = 0 ; i <= maxCol ; i++ )
{
for ( var j = 0 ; j < tableMap.length ; j++ )
{
if ( ! tableMap[j] )
continue ;
var cell = tableMap[j][i] ;
if ( ! cell || cell._rowScanned === true )
continue ;
if ( tableMap[j-1] && tableMap[j-1][i] == cell )
cell.rowSpan++ ;
if ( ! tableMap[j+1] || tableMap[j+1][i] != cell )
cell._rowScanned = true ;
}
}
// Clear all temporary flags.
for ( var i = 0 ; i < tableMap.length ; i++ )
{
for ( var j = 0 ; j < tableMap[i].length ; j++)
{
var cell = tableMap[i][j] ;
if ( FCKBrowserInfo.IsIE )
{
cell.removeAttribute( '_colScanned' ) ;
cell.removeAttribute( '_rowScanned' ) ;
}
else
{
delete cell._colScanned ;
delete cell._rowScanned ;
}
}
}
// Insert physical rows and columns to the table.
for ( var i = 0 ; i < tableMap.length ; i++ )
{
var rowObj = table.ownerDocument.createElement( 'tr' ) ;
for ( var j = 0 ; j < tableMap[i].length ; )
{
var cell = tableMap[i][j] ;
if ( tableMap[i-1] && tableMap[i-1][j] == cell )
{
j += cell.colSpan ;
continue ;
}
rowObj.appendChild( cell ) ;
j += cell.colSpan ;
if ( cell.colSpan == 1 )
cell.removeAttribute( 'colspan' ) ;
if ( cell.rowSpan == 1 )
cell.removeAttribute( 'rowspan' ) ;
}
table.appendChild( rowObj ) ;
}
}
FCKTableHandler._MoveCaretToCell = function ( refCell, toStart )
{
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToNodeContents( refCell ) ;
range.Collapse( toStart ) ;
range.Select() ;
}
FCKTableHandler.ClearRow = function( tr )
{
// Get the array of row's cells.
var aCells = tr.cells ;
// Replace the contents of each cell with "nothing".
for ( var i = 0 ; i < aCells.length ; i++ )
{
aCells[i].innerHTML = '' ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( aCells[i] ) ;
}
}
FCKTableHandler.GetMergeRightTarget = function()
{
var cells = this.GetSelectedCells() ;
if ( cells.length != 1 )
return null ;
var refCell = cells[0] ;
var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
var rowIdx = refCell.parentNode.rowIndex ;
var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
var nextColIdx = colIdx + ( isNaN( refCell.colSpan ) ? 1 : refCell.colSpan ) ;
var nextCell = tableMap[rowIdx][nextColIdx] ;
if ( ! nextCell )
return null ;
// The two cells must have the same vertical geometry, otherwise merging does not make sense.
this._MarkCells( [refCell, nextCell], '_SizeTest' ) ;
var refGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SizeTest' ) ;
var nextGeometry = this._GetMarkerGeometry( tableMap, rowIdx, nextColIdx, '_SizeTest' ) ;
this._UnmarkCells( [refCell, nextCell], '_SizeTest' ) ;
if ( refGeometry.height != nextGeometry.height || refGeometry.y != nextGeometry.y )
return null ;
return { 'refCell' : refCell, 'nextCell' : nextCell, 'tableMap' : tableMap } ;
}
FCKTableHandler.GetMergeDownTarget = function()
{
var cells = this.GetSelectedCells() ;
if ( cells.length != 1 )
return null ;
var refCell = cells[0] ;
var tableMap = this._CreateTableMap( refCell.parentNode.parentNode ) ;
var rowIdx = refCell.parentNode.rowIndex ;
var colIdx = this._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
var newRowIdx = rowIdx + ( isNaN( refCell.rowSpan ) ? 1 : refCell.rowSpan ) ;
if ( ! tableMap[newRowIdx] )
return null ;
var nextCell = tableMap[newRowIdx][colIdx] ;
if ( ! nextCell )
return null ;
// The two cells must have the same horizontal geometry, otherwise merging does not makes sense.
this._MarkCells( [refCell, nextCell], '_SizeTest' ) ;
var refGeometry = this._GetMarkerGeometry( tableMap, rowIdx, colIdx, '_SizeTest' ) ;
var nextGeometry = this._GetMarkerGeometry( tableMap, newRowIdx, colIdx, '_SizeTest' ) ;
this._UnmarkCells( [refCell, nextCell], '_SizeTest' ) ;
if ( refGeometry.width != nextGeometry.width || refGeometry.x != nextGeometry.x )
return null ;
return { 'refCell' : refCell, 'nextCell' : nextCell, 'tableMap' : tableMap } ;
}

View file

@ -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 ==
*
* Manage table operations (non-IE).
*/
FCKTableHandler.GetSelectedCells = function()
{
var aCells = new Array() ;
var oSelection = FCK.EditorWindow.getSelection() ;
// If the selection is a text.
if ( oSelection.rangeCount == 1 && oSelection.anchorNode.nodeType == 3 )
{
var oParent = FCKTools.GetElementAscensor( oSelection.anchorNode, 'TD,TH' ) ;
if ( oParent )
aCells[0] = oParent ;
return aCells ;
}
for ( var i = 0 ; i < oSelection.rangeCount ; i++ )
{
var oRange = oSelection.getRangeAt(i) ;
var oCell ;
if ( oRange.startContainer.tagName.Equals( 'TD', 'TH' ) )
oCell = oRange.startContainer ;
else
oCell = oRange.startContainer.childNodes[ oRange.startOffset ] ;
if ( oCell.tagName.Equals( 'TD', 'TH' ) )
aCells[aCells.length] = oCell ;
}
return aCells ;
}

View file

@ -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 ==
*
* Manage table operations (IE specific).
*/
FCKTableHandler.GetSelectedCells = function()
{
if ( FCKSelection.GetType() == 'Control' )
{
var td = FCKSelection.MoveToAncestorNode( 'TD' ) ;
return td ? [ td ] : [] ;
}
var aCells = new Array() ;
var oRange = FCK.EditorDocument.selection.createRange() ;
// var oParent = oRange.parentElement() ;
var oParent = FCKSelection.GetParentElement() ;
if ( oParent && oParent.tagName.Equals( 'TD', 'TH' ) )
aCells[0] = oParent ;
else
{
oParent = FCKSelection.MoveToAncestorNode( 'TABLE' ) ;
if ( oParent )
{
// Loops throw all cells checking if the cell is, or part of it, is inside the selection
// and then add it to the selected cells collection.
for ( var i = 0 ; i < oParent.cells.length ; i++ )
{
var oCellRange = FCK.EditorDocument.body.createTextRange() ;
oCellRange.moveToElementText( oParent.cells[i] ) ;
if ( oRange.inRange( oCellRange )
|| ( oRange.compareEndPoints('StartToStart',oCellRange) >= 0 && oRange.compareEndPoints('StartToEnd',oCellRange) <= 0 )
|| ( oRange.compareEndPoints('EndToStart',oCellRange) >= 0 && oRange.compareEndPoints('EndToEnd',oCellRange) <= 0 ) )
{
aCells[aCells.length] = oParent.cells[i] ;
}
}
}
}
return aCells ;
}

View file

@ -0,0 +1,123 @@
/*
* 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 ==
*
* Toolbar items definitions.
*/
var FCKToolbarItems = new Object() ;
FCKToolbarItems.LoadedItems = new Object() ;
FCKToolbarItems.RegisterItem = function( itemName, item )
{
this.LoadedItems[ itemName ] = item ;
}
FCKToolbarItems.GetItem = function( itemName )
{
var oItem = FCKToolbarItems.LoadedItems[ itemName ] ;
if ( oItem )
return oItem ;
switch ( itemName )
{
case 'Source' : oItem = new FCKToolbarButton( 'Source' , FCKLang.Source, null, FCK_TOOLBARITEM_ICONTEXT, true, true, 1 ) ; break ;
case 'DocProps' : oItem = new FCKToolbarButton( 'DocProps' , FCKLang.DocProps, null, null, null, null, 2 ) ; break ;
case 'Save' : oItem = new FCKToolbarButton( 'Save' , FCKLang.Save, null, null, true, null, 3 ) ; break ;
case 'NewPage' : oItem = new FCKToolbarButton( 'NewPage' , FCKLang.NewPage, null, null, true, null, 4 ) ; break ;
case 'Preview' : oItem = new FCKToolbarButton( 'Preview' , FCKLang.Preview, null, null, true, null, 5 ) ; break ;
case 'Templates' : oItem = new FCKToolbarButton( 'Templates' , FCKLang.Templates, null, null, null, null, 6 ) ; break ;
case 'About' : oItem = new FCKToolbarButton( 'About' , FCKLang.About, null, null, true, null, 47 ) ; break ;
case 'Cut' : oItem = new FCKToolbarButton( 'Cut' , FCKLang.Cut, null, null, false, true, 7 ) ; break ;
case 'Copy' : oItem = new FCKToolbarButton( 'Copy' , FCKLang.Copy, null, null, false, true, 8 ) ; break ;
case 'Paste' : oItem = new FCKToolbarButton( 'Paste' , FCKLang.Paste, null, null, false, true, 9 ) ; break ;
case 'PasteText' : oItem = new FCKToolbarButton( 'PasteText' , FCKLang.PasteText, null, null, false, true, 10 ) ; break ;
case 'PasteWord' : oItem = new FCKToolbarButton( 'PasteWord' , FCKLang.PasteWord, null, null, false, true, 11 ) ; break ;
case 'Print' : oItem = new FCKToolbarButton( 'Print' , FCKLang.Print, null, null, false, true, 12 ) ; break ;
case 'SpellCheck' : oItem = new FCKToolbarButton( 'SpellCheck', FCKLang.SpellCheck, null, null, null, null, 13 ) ; break ;
case 'Undo' : oItem = new FCKToolbarButton( 'Undo' , FCKLang.Undo, null, null, false, true, 14 ) ; break ;
case 'Redo' : oItem = new FCKToolbarButton( 'Redo' , FCKLang.Redo, null, null, false, true, 15 ) ; break ;
case 'SelectAll' : oItem = new FCKToolbarButton( 'SelectAll' , FCKLang.SelectAll, null, null, true, null, 18 ) ; break ;
case 'RemoveFormat' : oItem = new FCKToolbarButton( 'RemoveFormat', FCKLang.RemoveFormat, null, null, false, true, 19 ) ; break ;
case 'FitWindow' : oItem = new FCKToolbarButton( 'FitWindow' , FCKLang.FitWindow, null, null, true, true, 66 ) ; break ;
case 'Bold' : oItem = new FCKToolbarButton( 'Bold' , FCKLang.Bold, null, null, false, true, 20 ) ; break ;
case 'Italic' : oItem = new FCKToolbarButton( 'Italic' , FCKLang.Italic, null, null, false, true, 21 ) ; break ;
case 'Underline' : oItem = new FCKToolbarButton( 'Underline' , FCKLang.Underline, null, null, false, true, 22 ) ; break ;
case 'StrikeThrough' : oItem = new FCKToolbarButton( 'StrikeThrough' , FCKLang.StrikeThrough, null, null, false, true, 23 ) ; break ;
case 'Subscript' : oItem = new FCKToolbarButton( 'Subscript' , FCKLang.Subscript, null, null, false, true, 24 ) ; break ;
case 'Superscript' : oItem = new FCKToolbarButton( 'Superscript' , FCKLang.Superscript, null, null, false, true, 25 ) ; break ;
case 'OrderedList' : oItem = new FCKToolbarButton( 'InsertOrderedList' , FCKLang.NumberedListLbl, FCKLang.NumberedList, null, false, true, 26 ) ; break ;
case 'UnorderedList' : oItem = new FCKToolbarButton( 'InsertUnorderedList' , FCKLang.BulletedListLbl, FCKLang.BulletedList, null, false, true, 27 ) ; break ;
case 'Outdent' : oItem = new FCKToolbarButton( 'Outdent' , FCKLang.DecreaseIndent, null, null, false, true, 28 ) ; break ;
case 'Indent' : oItem = new FCKToolbarButton( 'Indent' , FCKLang.IncreaseIndent, null, null, false, true, 29 ) ; break ;
case 'Blockquote' : oItem = new FCKToolbarButton( 'Blockquote' , FCKLang.Blockquote, null, null, false, true, 73 ) ; break ;
case 'Link' : oItem = new FCKToolbarButton( 'Link' , FCKLang.InsertLinkLbl, FCKLang.InsertLink, null, false, true, 34 ) ; break ;
case 'Unlink' : oItem = new FCKToolbarButton( 'Unlink' , FCKLang.RemoveLink, null, null, false, true, 35 ) ; break ;
case 'Anchor' : oItem = new FCKToolbarButton( 'Anchor' , FCKLang.Anchor, null, null, null, null, 36 ) ; break ;
case 'Image' : oItem = new FCKToolbarButton( 'Image' , FCKLang.InsertImageLbl, FCKLang.InsertImage, null, false, true, 37 ) ; break ;
case 'Flash' : oItem = new FCKToolbarButton( 'Flash' , FCKLang.InsertFlashLbl, FCKLang.InsertFlash, null, false, true, 38 ) ; break ;
case 'Table' : oItem = new FCKToolbarButton( 'Table' , FCKLang.InsertTableLbl, FCKLang.InsertTable, null, false, true, 39 ) ; break ;
case 'SpecialChar' : oItem = new FCKToolbarButton( 'SpecialChar' , FCKLang.InsertSpecialCharLbl, FCKLang.InsertSpecialChar, null, false, true, 42 ) ; break ;
case 'Smiley' : oItem = new FCKToolbarButton( 'Smiley' , FCKLang.InsertSmileyLbl, FCKLang.InsertSmiley, null, false, true, 41 ) ; break ;
case 'PageBreak' : oItem = new FCKToolbarButton( 'PageBreak' , FCKLang.PageBreakLbl, FCKLang.PageBreak, null, false, true, 43 ) ; break ;
case 'Rule' : oItem = new FCKToolbarButton( 'Rule' , FCKLang.InsertLineLbl, FCKLang.InsertLine, null, false, true, 40 ) ; break ;
case 'JustifyLeft' : oItem = new FCKToolbarButton( 'JustifyLeft' , FCKLang.LeftJustify, null, null, false, true, 30 ) ; break ;
case 'JustifyCenter' : oItem = new FCKToolbarButton( 'JustifyCenter' , FCKLang.CenterJustify, null, null, false, true, 31 ) ; break ;
case 'JustifyRight' : oItem = new FCKToolbarButton( 'JustifyRight' , FCKLang.RightJustify, null, null, false, true, 32 ) ; break ;
case 'JustifyFull' : oItem = new FCKToolbarButton( 'JustifyFull' , FCKLang.BlockJustify, null, null, false, true, 33 ) ; break ;
case 'Style' : oItem = new FCKToolbarStyleCombo() ; break ;
case 'FontName' : oItem = new FCKToolbarFontsCombo() ; break ;
case 'FontSize' : oItem = new FCKToolbarFontSizeCombo() ; break ;
case 'FontFormat' : oItem = new FCKToolbarFontFormatCombo() ; break ;
case 'TextColor' : oItem = new FCKToolbarPanelButton( 'TextColor', FCKLang.TextColor, null, null, 45 ) ; break ;
case 'BGColor' : oItem = new FCKToolbarPanelButton( 'BGColor' , FCKLang.BGColor, null, null, 46 ) ; break ;
case 'Find' : oItem = new FCKToolbarButton( 'Find' , FCKLang.Find, null, null, null, null, 16 ) ; break ;
case 'Replace' : oItem = new FCKToolbarButton( 'Replace' , FCKLang.Replace, null, null, null, null, 17 ) ; break ;
case 'Form' : oItem = new FCKToolbarButton( 'Form' , FCKLang.Form, null, null, null, null, 48 ) ; break ;
case 'Checkbox' : oItem = new FCKToolbarButton( 'Checkbox' , FCKLang.Checkbox, null, null, null, null, 49 ) ; break ;
case 'Radio' : oItem = new FCKToolbarButton( 'Radio' , FCKLang.RadioButton, null, null, null, null, 50 ) ; break ;
case 'TextField' : oItem = new FCKToolbarButton( 'TextField' , FCKLang.TextField, null, null, null, null, 51 ) ; break ;
case 'Textarea' : oItem = new FCKToolbarButton( 'Textarea' , FCKLang.Textarea, null, null, null, null, 52 ) ; break ;
case 'HiddenField' : oItem = new FCKToolbarButton( 'HiddenField' , FCKLang.HiddenField, null, null, null, null, 56 ) ; break ;
case 'Button' : oItem = new FCKToolbarButton( 'Button' , FCKLang.Button, null, null, null, null, 54 ) ; break ;
case 'Select' : oItem = new FCKToolbarButton( 'Select' , FCKLang.SelectionField, null, null, null, null, 53 ) ; break ;
case 'ImageButton' : oItem = new FCKToolbarButton( 'ImageButton' , FCKLang.ImageButton, null, null, null, null, 55 ) ; break ;
case 'ShowBlocks' : oItem = new FCKToolbarButton( 'ShowBlocks' , FCKLang.ShowBlocks, null, null, null, true, 72 ) ; break ;
default:
alert( FCKLang.UnknownToolbarItem.replace( /%1/g, itemName ) ) ;
return null ;
}
FCKToolbarItems.LoadedItems[ itemName ] = oItem ;
return oItem ;
}

View file

@ -0,0 +1,373 @@
/*
* 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 FCKToolbarSet object that is used to load and draw the
* toolbar.
*/
function FCKToolbarSet_Create( overhideLocation )
{
var oToolbarSet ;
var sLocation = overhideLocation || FCKConfig.ToolbarLocation ;
switch ( sLocation )
{
case 'In' :
document.getElementById( 'xToolbarRow' ).style.display = '' ;
oToolbarSet = new FCKToolbarSet( document ) ;
break ;
case 'None' :
oToolbarSet = new FCKToolbarSet( document ) ;
break ;
// case 'OutTop' :
// Not supported.
default :
FCK.Events.AttachEvent( 'OnBlur', FCK_OnBlur ) ;
FCK.Events.AttachEvent( 'OnFocus', FCK_OnFocus ) ;
var eToolbarTarget ;
// Out:[TargetWindow]([TargetId])
var oOutMatch = sLocation.match( /^Out:(.+)\((\w+)\)$/ ) ;
if ( oOutMatch )
{
eToolbarTarget = eval( 'parent.' + oOutMatch[1] ).document.getElementById( oOutMatch[2] ) ;
}
else
{
// Out:[TargetId]
oOutMatch = sLocation.match( /^Out:(\w+)$/ ) ;
if ( oOutMatch )
eToolbarTarget = parent.document.getElementById( oOutMatch[1] ) ;
}
if ( !eToolbarTarget )
{
alert( 'Invalid value for "ToolbarLocation"' ) ;
return arguments.callee( 'In' );
}
// If it is a shared toolbar, it may be already available in the target element.
oToolbarSet = eToolbarTarget.__FCKToolbarSet ;
if ( oToolbarSet )
break ;
// Create the IFRAME that will hold the toolbar inside the target element.
var eToolbarIFrame = FCKTools.GetElementDocument( eToolbarTarget ).createElement( 'iframe' ) ;
eToolbarIFrame.src = 'javascript:void(0)' ;
eToolbarIFrame.frameBorder = 0 ;
eToolbarIFrame.width = '100%' ;
eToolbarIFrame.height = '10' ;
eToolbarTarget.appendChild( eToolbarIFrame ) ;
eToolbarIFrame.unselectable = 'on' ;
// Write the basic HTML for the toolbar (copy from the editor main page).
var eTargetDocument = eToolbarIFrame.contentWindow.document ;
// Workaround for Safari 12256. Ticket #63
var sBase = '' ;
if ( FCKBrowserInfo.IsSafari )
sBase = '<base href="' + window.document.location + '">' ;
// Initialize the IFRAME document body.
eTargetDocument.open() ;
eTargetDocument.write( '<html><head>' + sBase + '<script type="text/javascript"> var adjust = function() { window.frameElement.height = document.body.scrollHeight ; }; window.onresize = adjust; window.onload = function () {window.setTimeout( adjust, 0 );}</script></head><body style="overflow: hidden">' + document.getElementById( 'xToolbarSpace' ).innerHTML + '</body></html>' ) ;
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 )
{
var aItems = ( editorInstance ? editorInstance.ToolbarSet : this ).ItemsContextSensitive ;
for ( var i = 0 ; i < aItems.length ; i++ )
aItems[i].RefreshState() ;
}

View file

@ -0,0 +1,621 @@
/*
* 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 )
{
if ( targetWindow.document )
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, '&amp;' ) ;
text = text.replace( /</g, '&lt;' ) ;
text = text.replace( />/g, '&gt;' ) ;
return text ;
}
FCKTools.HTMLDecode = function( text )
{
if ( !text )
return '' ;
text = text.replace( /&gt;/g, '>' ) ;
text = text.replace( /&lt;/g, '<' ) ;
text = text.replace( /&amp;/g, '&' ) ;
return text ;
}
FCKTools._ProcessLineBreaksForPMode = function( oEditor, text, liState, node, strArray )
{
var closeState = 0 ;
var blockStartTag = "<p>" ;
var blockEndTag = "</p>" ;
var lineBreakTag = "<br />" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
closeState = 1 ;
}
// Are we currently inside a <p> 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 = "<div>" ;
var blockEndTag = "</div>" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
closeState = 1 ;
}
// Are we currently inside a <div> 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( "&nbsp;" ) ;
}
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 = "<br />" ;
var blockEndTag = "" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
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 <li> 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 <br> 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 ;
var prevNode = null ;
var curWindow = FCKTools.GetElementWindow( curNode ) ;
while ( curNode && !( curWindow == w && ( curNode == w.document.body || curNode == w.document.documentElement ) ) )
{
x += curNode.offsetLeft - curNode.scrollLeft ;
y += curNode.offsetTop - curNode.scrollTop ;
if ( ! FCKBrowserInfo.IsOpera )
{
var scrollNode = prevNode ;
while ( scrollNode && scrollNode != curNode )
{
x -= scrollNode.scrollLeft ;
y -= scrollNode.scrollTop ;
scrollNode = scrollNode.parentNode ;
}
}
prevNode = curNode ;
if ( curNode.offsetParent )
curNode = curNode.offsetParent ;
else
{
if ( curWindow != w )
{
curNode = curWindow.frameElement ;
prevNode = null ;
if ( curNode )
curWindow = FCKTools.GetElementWindow( curNode ) ;
}
else
curNode = null ;
}
}
// document.body is a special case when it comes to offsetTop and offsetLeft values.
// 1. It matters if document.body itself is a positioned element;
// 2. It matters is when we're in IE and the element has no positioned ancestor.
// Otherwise the values should be ignored.
if ( FCKDomTools.GetCurrentElementStyle( w, w.document.body, 'position') != 'static'
|| ( FCKBrowserInfo.IsIE && FCKDomTools.GetPositionedAncestor( w, node ) == null ) )
{
x += w.document.body.offsetLeft ;
y += w.document.body.offsetTop ;
}
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); } ;
}

View file

@ -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 "<span>My <b>tag</b></span>"
// will be replaced with "My <b>tag</b>".
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 ;
}

View file

@ -0,0 +1,227 @@
/*
* 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 )
{
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() ;
}

View file

@ -0,0 +1,221 @@
/*
* 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.SaveLocked = 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 || this.SaveLocked )
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 ;
}

View file

@ -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 ;
}
})();

View file

@ -0,0 +1,486 @@
/*
* 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( /^<xhtml.*?>/, '<xhtml>' ) ;
// Strip the "XHTML" root node.
sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
// Add a space in the tags with no closing tags, like <br/> -> <br />
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 <br> inside a <pre> 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.nextSibling &&
( 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 <!DOTYPE ... > 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 &amp;. 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 =
{
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 ;
},
area : function( node, htmlNode )
{
var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
if ( sSavedUrl != null )
FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
// IE ignores the "COORDS" and "SHAPE" attribute so we must add it manually.
if ( FCKBrowserInfo.IsIE )
{
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 ;
},
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 ;
},
// 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 ;
},
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 ;
},
// Fix nested <ul> and <ol>.
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 ;
},
pre : function ( node, htmlNode )
{
var firstChild = htmlNode.firstChild ;
if ( firstChild && firstChild.nodeType == 3 )
node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( '\r\n' ) ) ) ;
FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
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 ;
},
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 ;
},
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 ;
},
title : function( node, htmlNode )
{
node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
return node ;
}
} ;
FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;

View file

@ -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 <FCK:meta> element outside head (#1166).
// Save a reference to the XML <head> node, so we can use it for
// orphan <meta>s.
FCKXHtml.TagProcessors['head'] = function( node, htmlNode )
{
FCKXHtml.XML._HeadElement = node ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
// Check whether a <meta> element is outside <head>, 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 ;
}
}

View file

@ -0,0 +1,203 @@
/*
* 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 ) ;
}
}
}
// On very rare cases, IE is loosing the "align" attribute for DIV. (right align and apply bulleted list)
FCKXHtml.TagProcessors['div'] = function( node, htmlNode )
{
if ( htmlNode.align.length > 0 )
FCKXHtml._AppendAttribute( node, 'align', htmlNode.align ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
// IE automatically changes <FONT> tags to <FONT size=+0>.
FCKXHtml.TagProcessors['font'] = function( node, htmlNode )
{
if ( node.attributes.length == 0 )
node = FCKXHtml.XML.createDocumentFragment() ;
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 see the value attribute as an attribute for the <INPUT> 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 ;
}
FCKXHtml.TagProcessors['label'] = function( node, htmlNode )
{
if ( htmlNode.htmlFor.length > 0 )
FCKXHtml._AppendAttribute( node, 'for', htmlNode.htmlFor ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}
// Fix behavior for IE, it doesn't read back the .name on newly created maps
FCKXHtml.TagProcessors['map'] = function( node, htmlNode )
{
if ( ! node.attributes.getNamedItem( 'name' ) )
{
var name = htmlNode.name ;
if ( name )
FCKXHtml._AppendAttribute( node, 'name', name ) ;
}
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
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 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 doens't hold the name attribute as an attribute for the <TEXTAREA> and <SELECT> tags.
FCKXHtml.TagProcessors['textarea'] = FCKXHtml.TagProcessors['select'] = function( node, htmlNode )
{
if ( htmlNode.name )
FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}

View file

@ -0,0 +1,354 @@
/*
* 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 file define the HTML entities handled by the editor.
*/
var FCKXHtmlEntities = new Object() ;
FCKXHtmlEntities.Initialize = function()
{
if ( FCKXHtmlEntities.Entities )
return ;
var sChars = '' ;
var oEntities, e ;
if ( FCKConfig.ProcessHTMLEntities )
{
FCKXHtmlEntities.Entities = {
// Latin-1 Entities
' ':'nbsp',
'¡':'iexcl',
'¢':'cent',
'£':'pound',
'¤':'curren',
'¥':'yen',
'¦':'brvbar',
'§':'sect',
'¨':'uml',
'©':'copy',
'ª':'ordf',
'«':'laquo',
'¬':'not',
'­':'shy',
'®':'reg',
'¯':'macr',
'°':'deg',
'±':'plusmn',
'²':'sup2',
'³':'sup3',
'´':'acute',
'µ':'micro',
'¶':'para',
'·':'middot',
'¸':'cedil',
'¹':'sup1',
'º':'ordm',
'»':'raquo',
'¼':'frac14',
'½':'frac12',
'¾':'frac34',
'¿':'iquest',
'×':'times',
'÷':'divide',
// Symbols
'ƒ':'fnof',
'•':'bull',
'…':'hellip',
'':'prime',
'″':'Prime',
'‾':'oline',
'':'frasl',
'℘':'weierp',
'':'image',
'':'real',
'™':'trade',
'ℵ':'alefsym',
'←':'larr',
'↑':'uarr',
'→':'rarr',
'↓':'darr',
'↔':'harr',
'↵':'crarr',
'⇐':'lArr',
'⇑':'uArr',
'⇒':'rArr',
'⇓':'dArr',
'⇔':'hArr',
'∀':'forall',
'∂':'part',
'∃':'exist',
'∅':'empty',
'∇':'nabla',
'∈':'isin',
'∉':'notin',
'∋':'ni',
'∏':'prod',
'∑':'sum',
'':'minus',
'':'lowast',
'√':'radic',
'∝':'prop',
'∞':'infin',
'∠':'ang',
'∧':'and',
'':'or',
'∩':'cap',
'':'cup',
'∫':'int',
'∴':'there4',
'':'sim',
'≅':'cong',
'≈':'asymp',
'≠':'ne',
'≡':'equiv',
'≤':'le',
'≥':'ge',
'⊂':'sub',
'⊃':'sup',
'⊄':'nsub',
'⊆':'sube',
'⊇':'supe',
'⊕':'oplus',
'⊗':'otimes',
'⊥':'perp',
'⋅':'sdot',
'\u2308':'lceil',
'\u2309':'rceil',
'\u230a':'lfloor',
'\u230b':'rfloor',
'\u2329':'lang',
'\u232a':'rang',
'◊':'loz',
'♠':'spades',
'♣':'clubs',
'♥':'hearts',
'♦':'diams',
// Other Special Characters
'"':'quot',
// '&':'amp', // This entity is automatically handled by the XHTML parser.
// '<':'lt', // This entity is automatically handled by the XHTML parser.
// '>':'gt', // This entity is automatically handled by the XHTML parser.
'ˆ':'circ',
'˜':'tilde',
'':'ensp',
'':'emsp',
'':'thinsp',
'':'zwnj',
'':'zwj',
'':'lrm',
'':'rlm',
'':'ndash',
'—':'mdash',
'':'lsquo',
'':'rsquo',
'':'sbquo',
'“':'ldquo',
'”':'rdquo',
'„':'bdquo',
'†':'dagger',
'‡':'Dagger',
'‰':'permil',
'':'lsaquo',
'':'rsaquo',
'€':'euro'
} ;
// Process Base Entities.
for ( e in FCKXHtmlEntities.Entities )
sChars += e ;
// Include Latin Letters Entities.
if ( FCKConfig.IncludeLatinEntities )
{
oEntities = {
'À':'Agrave',
'Á':'Aacute',
'Â':'Acirc',
'Ã':'Atilde',
'Ä':'Auml',
'Å':'Aring',
'Æ':'AElig',
'Ç':'Ccedil',
'È':'Egrave',
'É':'Eacute',
'Ê':'Ecirc',
'Ë':'Euml',
'Ì':'Igrave',
'Í':'Iacute',
'Î':'Icirc',
'Ï':'Iuml',
'Ð':'ETH',
'Ñ':'Ntilde',
'Ò':'Ograve',
'Ó':'Oacute',
'Ô':'Ocirc',
'Õ':'Otilde',
'Ö':'Ouml',
'Ø':'Oslash',
'Ù':'Ugrave',
'Ú':'Uacute',
'Û':'Ucirc',
'Ü':'Uuml',
'Ý':'Yacute',
'Þ':'THORN',
'ß':'szlig',
'à':'agrave',
'á':'aacute',
'â':'acirc',
'ã':'atilde',
'ä':'auml',
'å':'aring',
'æ':'aelig',
'ç':'ccedil',
'è':'egrave',
'é':'eacute',
'ê':'ecirc',
'ë':'euml',
'ì':'igrave',
'í':'iacute',
'î':'icirc',
'ï':'iuml',
'ð':'eth',
'ñ':'ntilde',
'ò':'ograve',
'ó':'oacute',
'ô':'ocirc',
'õ':'otilde',
'ö':'ouml',
'ø':'oslash',
'ù':'ugrave',
'ú':'uacute',
'û':'ucirc',
'ü':'uuml',
'ý':'yacute',
'þ':'thorn',
'ÿ':'yuml',
'Œ':'OElig',
'œ':'oelig',
'Š':'Scaron',
'š':'scaron',
'Ÿ':'Yuml'
} ;
for ( e in oEntities )
{
FCKXHtmlEntities.Entities[ e ] = oEntities[ e ] ;
sChars += e ;
}
oEntities = null ;
}
// Include Greek Letters Entities.
if ( FCKConfig.IncludeGreekEntities )
{
oEntities = {
'Α':'Alpha',
'Β':'Beta',
'Γ':'Gamma',
'Δ':'Delta',
'Ε':'Epsilon',
'Ζ':'Zeta',
'Η':'Eta',
'Θ':'Theta',
'Ι':'Iota',
'Κ':'Kappa',
'Λ':'Lambda',
'Μ':'Mu',
'Ν':'Nu',
'Ξ':'Xi',
'Ο':'Omicron',
'Π':'Pi',
'Ρ':'Rho',
'Σ':'Sigma',
'Τ':'Tau',
'Υ':'Upsilon',
'Φ':'Phi',
'Χ':'Chi',
'Ψ':'Psi',
'Ω':'Omega',
'α':'alpha',
'β':'beta',
'γ':'gamma',
'δ':'delta',
'ε':'epsilon',
'ζ':'zeta',
'η':'eta',
'θ':'theta',
'ι':'iota',
'κ':'kappa',
'λ':'lambda',
'μ':'mu',
'ν':'nu',
'ξ':'xi',
'ο':'omicron',
'π':'pi',
'ρ':'rho',
'ς':'sigmaf',
'σ':'sigma',
'τ':'tau',
'υ':'upsilon',
'φ':'phi',
'χ':'chi',
'ψ':'psi',
'ω':'omega',
'\u03d1':'thetasym',
'\u03d2':'upsih',
'\u03d6':'piv'
} ;
for ( e in oEntities )
{
FCKXHtmlEntities.Entities[ e ] = oEntities[ e ] ;
sChars += e ;
}
oEntities = null ;
}
}
else
{
FCKXHtmlEntities.Entities = {} ;
// Even if we are not processing the entities, we must render the &nbsp;
// correctly. As we don't want HTML entities, let's use its numeric
// representation (&#160).
sChars = ' ' ;
}
// Create the Regex used to find entities in the text.
var sRegexPattern = '[' + sChars + ']' ;
if ( FCKConfig.ProcessNumericEntities )
sRegexPattern = '[^ -~]|' + sRegexPattern ;
var sAdditional = FCKConfig.AdditionalNumericEntities ;
if ( sAdditional && sAdditional.length > 0 )
sRegexPattern += '|' + FCKConfig.AdditionalNumericEntities ;
FCKXHtmlEntities.EntitiesRegex = new RegExp( sRegexPattern, 'g' ) ;
}

View file

@ -0,0 +1,15 @@
<public:component lightweight="true">
<script language="javascript">
function CancelEvent()
{
return false ;
}
this.onresizestart = CancelEvent ;
this.onbeforeeditfocus = CancelEvent ;
</script>
</public:component>

View file

@ -0,0 +1,36 @@
<public:component lightweight="true">
<public:attach event="oncontentready" onevent="ShowBorders()" />
<public:attach event="onpropertychange" onevent="OnPropertyChange()" />
<script language="javascript">
var oClassRegex = /\s*FCK__ShowTableBorders/ ;
function ShowBorders()
{
if ( this.border == 0 )
{
if ( !oClassRegex.test( this.className ) )
this.className += ' FCK__ShowTableBorders' ;
}
else
{
if ( oClassRegex.test( this.className ) )
{
this.className = this.className.replace( oClassRegex, '' ) ;
if ( this.className.length == 0 )
this.removeAttribute( 'className', 0 ) ;
}
}
}
function OnPropertyChange()
{
if ( event.propertyName == 'border' || event.propertyName == 'className' )
ShowBorders.call(this) ;
}
</script>
</public:component>

View file

@ -0,0 +1,92 @@
/*
* 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 is the default CSS file used by the editor area. It defines the
* initial font of the editor and background color.
*
* A user can configure the editor to use another CSS file. Just change
* the value of the FCKConfig.EditorAreaCSS key in the configuration
* file.
*/
/*
The "body" styles should match your editor web site, mainly regarding
background color and font family and size.
*/
body
{
background-color: #ffffff;
padding: 5px 5px 5px 5px;
margin: 0px;
}
body, td
{
font-family: Arial, Verdana, sans-serif;
font-size: 12px;
}
a[href]
{
color: -moz-hyperlinktext !important; /* For Firefox... mark as important, otherwise it becomes black */
text-decoration: -moz-anchor-decoration; /* For Firefox 3, otherwise no underline will be used */
}
/*
Just uncomment the following block if you want to avoid spaces between
paragraphs. Remember to apply the same style in your output front end page.
*/
/*
p, ul, li
{
margin-top: 0px;
margin-bottom: 0px;
}
*/
/*
The following are some sample styles used in the "Styles" toolbar command.
You should instead remove them, and include the styles used by the site
you are using the editor in.
*/
.Bold
{
font-weight: bold;
}
.Title
{
font-weight: bold;
font-size: 18px;
color: #cc3300;
}
.Code
{
border: #8b4513 1px solid;
padding-right: 5px;
padding-left: 5px;
color: #000066;
font-family: 'Courier New' , Monospace;
background-color: #ff9933;
}

View file

@ -0,0 +1,182 @@
/*
* 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 CSS Style Sheet defines rules used by the editor for its internal use.
*/
/* Fix to allow putting the caret at the end of the content in Firefox if
clicking below the content. */
html
{
min-height: 100%;
}
table.FCK__ShowTableBorders, table.FCK__ShowTableBorders td, table.FCK__ShowTableBorders th
{
border: #d3d3d3 1px solid;
}
form
{
border: 1px dotted #FF0000;
padding: 2px;
}
.FCK__Flash
{
border: #a9a9a9 1px solid;
background-position: center center;
background-image: url(images/fck_flashlogo.gif);
background-repeat: no-repeat;
width: 80px;
height: 80px;
}
/* Empty anchors images */
.FCK__Anchor
{
border: 1px dotted #00F;
background-position: center center;
background-image: url(images/fck_anchor.gif);
background-repeat: no-repeat;
width: 16px;
height: 15px;
vertical-align: middle;
}
/* Anchors with content */
.FCK__AnchorC
{
border: 1px dotted #00F;
background-position: 1px center;
background-image: url(images/fck_anchor.gif);
background-repeat: no-repeat;
padding-left: 18px;
}
/* Any anchor for non-IE, if we combine it with the previous rule IE ignores all. */
a[name]
{
border: 1px dotted #00F;
background-position: 0 center;
background-image: url(images/fck_anchor.gif);
background-repeat: no-repeat;
padding-left: 18px;
}
.FCK__PageBreak
{
background-position: center center;
background-image: url(images/fck_pagebreak.gif);
background-repeat: no-repeat;
clear: both;
display: block;
float: none;
width: 100%;
border-top: #999999 1px dotted;
border-bottom: #999999 1px dotted;
border-right: 0px;
border-left: 0px;
height: 5px;
}
/* Hidden fields */
.FCK__InputHidden
{
width: 19px;
height: 18px;
background-image: url(images/fck_hiddenfield.gif);
background-repeat: no-repeat;
vertical-align: text-bottom;
background-position: center center;
}
.FCK__ShowBlocks p,
.FCK__ShowBlocks div,
.FCK__ShowBlocks pre,
.FCK__ShowBlocks address,
.FCK__ShowBlocks blockquote,
.FCK__ShowBlocks h1,
.FCK__ShowBlocks h2,
.FCK__ShowBlocks h3,
.FCK__ShowBlocks h4,
.FCK__ShowBlocks h5,
.FCK__ShowBlocks h6
{
background-repeat: no-repeat;
border: 1px dotted gray;
padding-top: 8px;
padding-left: 8px;
}
.FCK__ShowBlocks p
{
background-image: url(images/block_p.png);
}
.FCK__ShowBlocks div
{
background-image: url(images/block_div.png);
}
.FCK__ShowBlocks pre
{
background-image: url(images/block_pre.png);
}
.FCK__ShowBlocks address
{
background-image: url(images/block_address.png);
}
.FCK__ShowBlocks blockquote
{
background-image: url(images/block_blockquote.png);
}
.FCK__ShowBlocks h1
{
background-image: url(images/block_h1.png);
}
.FCK__ShowBlocks h2
{
background-image: url(images/block_h2.png);
}
.FCK__ShowBlocks h3
{
background-image: url(images/block_h3.png);
}
.FCK__ShowBlocks h4
{
background-image: url(images/block_h4.png);
}
.FCK__ShowBlocks h5
{
background-image: url(images/block_h5.png);
}
.FCK__ShowBlocks h6
{
background-image: url(images/block_h6.png);
}

Some files were not shown because too many files have changed in this diff Show more