Added FCK

Monotone-Parent: 2bb0c651a5f3ed0338d78594fd2f6f2ced5e171e
Monotone-Revision: 6734e3a43a98dff1324a7329b27decda3bfe1ebc

Monotone-Author: crobert@inverse.ca
Monotone-Date: 2009-06-23T17:41:38
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
C Robert 2009-06-23 17:41:38 +00:00
parent ebff1411c5
commit a373c28da8
467 changed files with 83409 additions and 0 deletions

View File

@ -0,0 +1,223 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKContextMenu Class: renders an control a context menu.
*/
var FCKContextMenu = function( parentWindow, langDir )
{
this.CtrlDisable = false ;
var oPanel = this._Panel = new FCKPanel( parentWindow ) ;
oPanel.AppendStyleSheet( FCKConfig.SkinEditorCSS ) ;
oPanel.IsContextMenu = true ;
// The FCKTools.DisableSelection doesn't seems to work to avoid dragging of the icons in Mozilla
// so we stop the start of the dragging
if ( FCKBrowserInfo.IsGecko )
oPanel.Document.addEventListener( 'draggesture', function(e) {e.preventDefault(); return false;}, true ) ;
var oMenuBlock = this._MenuBlock = new FCKMenuBlock() ;
oMenuBlock.Panel = oPanel ;
oMenuBlock.OnClick = FCKTools.CreateEventListener( FCKContextMenu_MenuBlock_OnClick, this ) ;
this._Redraw = true ;
}
FCKContextMenu.prototype.SetMouseClickWindow = function( mouseClickWindow )
{
if ( !FCKBrowserInfo.IsIE )
{
this._Document = mouseClickWindow.document ;
if ( FCKBrowserInfo.IsOpera && !( 'oncontextmenu' in document.createElement('foo') ) )
{
this._Document.addEventListener( 'mousedown', FCKContextMenu_Document_OnMouseDown, false ) ;
this._Document.addEventListener( 'mouseup', FCKContextMenu_Document_OnMouseUp, false ) ;
}
this._Document.addEventListener( 'contextmenu', FCKContextMenu_Document_OnContextMenu, false ) ;
}
}
/**
The customData parameter is just a value that will be send to the command that is executed,
so it's possible to reuse the same command for several items just by assigning different data for each one.
*/
FCKContextMenu.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
{
var oItem = this._MenuBlock.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
this._Redraw = true ;
return oItem ;
}
FCKContextMenu.prototype.AddSeparator = function()
{
this._MenuBlock.AddSeparator() ;
this._Redraw = true ;
}
FCKContextMenu.prototype.RemoveAllItems = function()
{
this._MenuBlock.RemoveAllItems() ;
this._Redraw = true ;
}
FCKContextMenu.prototype.AttachToElement = function( element )
{
if ( FCKBrowserInfo.IsIE )
FCKTools.AddEventListenerEx( element, 'contextmenu', FCKContextMenu_AttachedElement_OnContextMenu, this ) ;
else
element._FCKContextMenu = this ;
}
function FCKContextMenu_Document_OnContextMenu( e )
{
if ( FCKConfig.BrowserContextMenu )
return true ;
var el = e.target ;
while ( el )
{
if ( el._FCKContextMenu )
{
if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
return true ;
FCKTools.CancelEvent( e ) ;
FCKContextMenu_AttachedElement_OnContextMenu( e, el._FCKContextMenu, el ) ;
return false ;
}
el = el.parentNode ;
}
return true ;
}
var FCKContextMenu_OverrideButton ;
function FCKContextMenu_Document_OnMouseDown( e )
{
if( !e || e.button != 2 )
return false ;
if ( FCKConfig.BrowserContextMenu )
return true ;
var el = e.target ;
while ( el )
{
if ( el._FCKContextMenu )
{
if ( el._FCKContextMenu.CtrlDisable && ( e.ctrlKey || e.metaKey ) )
return true ;
var overrideButton = FCKContextMenu_OverrideButton ;
if( !overrideButton )
{
var doc = FCKTools.GetElementDocument( e.target ) ;
overrideButton = FCKContextMenu_OverrideButton = doc.createElement('input') ;
overrideButton.type = 'button' ;
var buttonHolder = doc.createElement('p') ;
doc.body.appendChild( buttonHolder ) ;
buttonHolder.appendChild( overrideButton ) ;
}
overrideButton.style.cssText = 'position:absolute;top:' + ( e.clientY - 2 ) +
'px;left:' + ( e.clientX - 2 ) +
'px;width:5px;height:5px;opacity:0.01' ;
}
el = el.parentNode ;
}
return false ;
}
function FCKContextMenu_Document_OnMouseUp( e )
{
if ( FCKConfig.BrowserContextMenu )
return true ;
var overrideButton = FCKContextMenu_OverrideButton ;
if ( overrideButton )
{
var parent = overrideButton.parentNode ;
parent.parentNode.removeChild( parent ) ;
FCKContextMenu_OverrideButton = undefined ;
if( e && e.button == 2 )
{
FCKContextMenu_Document_OnContextMenu( e ) ;
return false ;
}
}
return true ;
}
function FCKContextMenu_AttachedElement_OnContextMenu( ev, fckContextMenu, el )
{
if ( ( fckContextMenu.CtrlDisable && ( ev.ctrlKey || ev.metaKey ) ) || FCKConfig.BrowserContextMenu )
return true ;
var eTarget = el || this ;
if ( fckContextMenu.OnBeforeOpen )
fckContextMenu.OnBeforeOpen.call( fckContextMenu, eTarget ) ;
if ( fckContextMenu._MenuBlock.Count() == 0 )
return false ;
if ( fckContextMenu._Redraw )
{
fckContextMenu._MenuBlock.Create( fckContextMenu._Panel.MainNode ) ;
fckContextMenu._Redraw = false ;
}
// This will avoid that the content of the context menu can be dragged in IE
// as the content of the panel is recreated we need to do it every time
FCKTools.DisableSelection( fckContextMenu._Panel.Document.body ) ;
var x = 0 ;
var y = 0 ;
if ( FCKBrowserInfo.IsIE )
{
x = ev.screenX ;
y = ev.screenY ;
}
else if ( FCKBrowserInfo.IsSafari )
{
x = ev.clientX ;
y = ev.clientY ;
}
else
{
x = ev.pageX ;
y = ev.pageY ;
}
fckContextMenu._Panel.Show( x, y, ev.currentTarget || null ) ;
return false ;
}
function FCKContextMenu_MenuBlock_OnClick( menuItem, contextMenu )
{
contextMenu._Panel.Hide() ;
FCKTools.RunFunction( contextMenu.OnItemClick, contextMenu, menuItem ) ;
}

View File

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

View File

@ -0,0 +1,53 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This is a generic Document Fragment object. It is not intended to provide
* the W3C implementation, but is a way to fix the missing of a real Document
* Fragment in IE (where document.createDocumentFragment() returns a normal
* document instead), giving a standard interface for it.
* (IE Implementation)
*/
var FCKDocumentFragment = function( parentDocument, baseDocFrag )
{
this.RootNode = baseDocFrag || parentDocument.createDocumentFragment() ;
}
FCKDocumentFragment.prototype =
{
// Append the contents of this Document Fragment to another element.
AppendTo : function( targetNode )
{
targetNode.appendChild( this.RootNode ) ;
},
AppendHtml : function( html )
{
var eTmpDiv = this.RootNode.ownerDocument.createElement( 'div' ) ;
eTmpDiv.innerHTML = html ;
FCKDomTools.MoveChildren( eTmpDiv, this.RootNode ) ;
},
InsertAfterNode : function( existingNode )
{
FCKDomTools.InsertAfterNode( existingNode, this.RootNode ) ;
}
}

View File

@ -0,0 +1,58 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This is a generic Document Fragment object. It is not intended to provide
* the W3C implementation, but is a way to fix the missing of a real Document
* Fragment in IE (where document.createDocumentFragment() returns a normal
* document instead), giving a standard interface for it.
* (IE Implementation)
*/
var FCKDocumentFragment = function( parentDocument )
{
this._Document = parentDocument ;
this.RootNode = parentDocument.createElement( 'div' ) ;
}
// Append the contents of this Document Fragment to another node.
FCKDocumentFragment.prototype =
{
AppendTo : function( targetNode )
{
FCKDomTools.MoveChildren( this.RootNode, targetNode ) ;
},
AppendHtml : function( html )
{
var eTmpDiv = this._Document.createElement( 'div' ) ;
eTmpDiv.innerHTML = html ;
FCKDomTools.MoveChildren( eTmpDiv, this.RootNode ) ;
},
InsertAfterNode : function( existingNode )
{
var eRoot = this.RootNode ;
var eLast ;
while( ( eLast = eRoot.lastChild ) )
FCKDomTools.InsertAfterNode( existingNode, eRoot.removeChild( eLast ) ) ;
}
} ;

View File

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

View File

@ -0,0 +1,104 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Class for working with a selection range, much like the W3C DOM Range, but
* it is not intended to be an implementation of the W3C interface.
* (Gecko Implementation)
*/
FCKDomRange.prototype.MoveToSelection = function()
{
this.Release( true ) ;
var oSel = this.Window.getSelection() ;
if ( oSel && oSel.rangeCount > 0 )
{
this._Range = FCKW3CRange.CreateFromRange( this.Window.document, oSel.getRangeAt(0) ) ;
this._UpdateElementInfo() ;
}
else
if ( this.Window.document )
this.MoveToElementStart( this.Window.document.body ) ;
}
FCKDomRange.prototype.Select = function()
{
var oRange = this._Range ;
if ( oRange )
{
var startContainer = oRange.startContainer ;
// If we have a collapsed range, inside an empty element, we must add
// something to it, otherwise the caret will not be visible.
if ( oRange.collapsed && startContainer.nodeType == 1 && startContainer.childNodes.length == 0 )
startContainer.appendChild( oRange._Document.createTextNode('') ) ;
var oDocRange = this.Window.document.createRange() ;
oDocRange.setStart( startContainer, oRange.startOffset ) ;
try
{
oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
}
catch ( e )
{
// There is a bug in Firefox implementation (it would be too easy
// otherwise). The new start can't be after the end (W3C says it can).
// So, let's create a new range and collapse it to the desired point.
if ( e.toString().Contains( 'NS_ERROR_ILLEGAL_VALUE' ) )
{
oRange.collapse( true ) ;
oDocRange.setEnd( oRange.endContainer, oRange.endOffset ) ;
}
else
throw( e ) ;
}
var oSel = this.Window.getSelection() ;
oSel.removeAllRanges() ;
// We must add a clone otherwise Firefox will have rendering issues.
oSel.addRange( oDocRange ) ;
}
}
// Not compatible with bookmark created with CreateBookmark2.
// The bookmark nodes will be deleted from the document.
FCKDomRange.prototype.SelectBookmark = function( bookmark )
{
var domRange = this.Window.document.createRange() ;
var startNode = this.GetBookmarkNode( bookmark, true ) ;
var endNode = this.GetBookmarkNode( bookmark, false ) ;
domRange.setStart( startNode.parentNode, FCKDomTools.GetIndexOf( startNode ) ) ;
FCKDomTools.RemoveNode( startNode ) ;
if ( endNode )
{
domRange.setEnd( endNode.parentNode, FCKDomTools.GetIndexOf( endNode ) ) ;
FCKDomTools.RemoveNode( endNode ) ;
}
var selection = this.Window.getSelection() ;
selection.removeAllRanges() ;
selection.addRange( domRange ) ;
}

View File

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

View File

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

View File

@ -0,0 +1,368 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKEditingArea Class: renders an editable area.
*/
/**
* @constructor
* @param {String} targetElement The element that will hold the editing area. Any child element present in the target will be deleted.
*/
var FCKEditingArea = function( targetElement )
{
this.TargetElement = targetElement ;
this.Mode = FCK_EDITMODE_WYSIWYG ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKEditingArea_Cleanup ) ;
}
/**
* @param {String} html The complete HTML for the page, including DOCTYPE and the <html> tag.
*/
FCKEditingArea.prototype.Start = function( html, secondCall )
{
var eTargetElement = this.TargetElement ;
var oTargetDocument = FCKTools.GetElementDocument( eTargetElement ) ;
// Remove all child nodes from the target.
while( eTargetElement.firstChild )
eTargetElement.removeChild( eTargetElement.firstChild ) ;
if ( this.Mode == FCK_EDITMODE_WYSIWYG )
{
// For FF, document.domain must be set only when different, otherwhise
// we'll strangely have "Permission denied" issues.
if ( FCK_IS_CUSTOM_DOMAIN )
html = '<script>document.domain="' + FCK_RUNTIME_DOMAIN + '";</script>' + html ;
// IE has a bug with the <base> tag... it must have a </base> closer,
// otherwise the all successive tags will be set as children nodes of the <base>.
if ( FCKBrowserInfo.IsIE )
html = html.replace( /(<base[^>]*?)\s*\/?>(?!\s*<\/base>)/gi, '$1></base>' ) ;
else if ( !secondCall )
{
// Gecko moves some tags out of the body to the head, so we must use
// innerHTML to set the body contents (SF BUG 1526154).
// Extract the BODY contents from the html.
var oMatchBefore = html.match( FCKRegexLib.BeforeBody ) ;
var oMatchAfter = html.match( FCKRegexLib.AfterBody ) ;
if ( oMatchBefore && oMatchAfter )
{
var sBody = html.substr( oMatchBefore[1].length,
html.length - oMatchBefore[1].length - oMatchAfter[1].length ) ; // This is the BODY tag contents.
html =
oMatchBefore[1] + // This is the HTML until the <body...> tag, inclusive.
'&nbsp;' +
oMatchAfter[1] ; // This is the HTML from the </body> tag, inclusive.
// If nothing in the body, place a BOGUS tag so the cursor will appear.
if ( FCKBrowserInfo.IsGecko && ( sBody.length == 0 || FCKRegexLib.EmptyParagraph.test( sBody ) ) )
sBody = '<br type="_moz">' ;
this._BodyHTML = sBody ;
}
else
this._BodyHTML = html ; // Invalid HTML input.
}
// Create the editing area IFRAME.
var oIFrame = this.IFrame = oTargetDocument.createElement( 'iframe' ) ;
// IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
// See #1055.
var sOverrideError = '<script type="text/javascript" _fcktemp="true">window.onerror=function(){return true;};</script>' ;
oIFrame.frameBorder = 0 ;
oIFrame.style.width = oIFrame.style.height = '100%' ;
if ( FCK_IS_CUSTOM_DOMAIN && FCKBrowserInfo.IsIE )
{
window._FCKHtmlToLoad = html.replace( /<head>/i, '<head>' + sOverrideError ) ;
oIFrame.src = 'javascript:void( (function(){' +
'document.open() ;' +
'document.domain="' + document.domain + '" ;' +
'document.write( window.parent._FCKHtmlToLoad );' +
'document.close() ;' +
'window.parent._FCKHtmlToLoad = null ;' +
'})() )' ;
}
else if ( !FCKBrowserInfo.IsGecko )
{
// Firefox will render the tables inside the body in Quirks mode if the
// source of the iframe is set to javascript. see #515
oIFrame.src = 'javascript:void(0)' ;
}
// Append the new IFRAME to the target. For IE, it must be done after
// setting the "src", to avoid the "secure/unsecure" message under HTTPS.
eTargetElement.appendChild( oIFrame ) ;
// Get the window and document objects used to interact with the newly created IFRAME.
this.Window = oIFrame.contentWindow ;
// IE: Avoid JavaScript errors thrown by the editing are source (like tags events).
// TODO: This error handler is not being fired.
// this.Window.onerror = function() { alert( 'Error!' ) ; return true ; }
if ( !FCK_IS_CUSTOM_DOMAIN || !FCKBrowserInfo.IsIE )
{
var oDoc = this.Window.document ;
oDoc.open() ;
oDoc.write( html.replace( /<head>/i, '<head>' + sOverrideError ) ) ;
oDoc.close() ;
}
if ( FCKBrowserInfo.IsAIR )
FCKAdobeAIR.EditingArea_Start( oDoc, html ) ;
// Firefox 1.0.x is buggy... ohh yes... so let's do it two times and it
// will magically work.
if ( FCKBrowserInfo.IsGecko10 && !secondCall )
{
this.Start( html, true ) ;
return ;
}
if ( oIFrame.readyState && oIFrame.readyState != 'completed' )
{
var editArea = this ;
// Using a IE alternative for DOMContentLoaded, similar to the
// solution proposed at http://javascript.nwbox.com/IEContentLoaded/
setTimeout( function()
{
try
{
editArea.Window.document.documentElement.doScroll("left") ;
}
catch(e)
{
setTimeout( arguments.callee, 0 ) ;
return ;
}
editArea.Window._FCKEditingArea = editArea ;
FCKEditingArea_CompleteStart.call( editArea.Window ) ;
}, 0 ) ;
}
else
{
this.Window._FCKEditingArea = this ;
// FF 1.0.x is buggy... we must wait a lot to enable editing because
// sometimes the content simply disappears, for example when pasting
// "bla1!<img src='some_url'>!bla2" in the source and then switching
// back to design.
if ( FCKBrowserInfo.IsGecko10 )
this.Window.setTimeout( FCKEditingArea_CompleteStart, 500 ) ;
else
FCKEditingArea_CompleteStart.call( this.Window ) ;
}
}
else
{
var eTextarea = this.Textarea = oTargetDocument.createElement( 'textarea' ) ;
eTextarea.className = 'SourceField' ;
eTextarea.dir = 'ltr' ;
FCKDomTools.SetElementStyles( eTextarea,
{
width : '100%',
height : '100%',
border : 'none',
resize : 'none',
outline : 'none'
} ) ;
eTargetElement.appendChild( eTextarea ) ;
eTextarea.value = html ;
// Fire the "OnLoad" event.
FCKTools.RunFunction( this.OnLoad ) ;
}
}
// "this" here is FCKEditingArea.Window
function FCKEditingArea_CompleteStart()
{
// On Firefox, the DOM takes a little to become available. So we must wait for it in a loop.
if ( !this.document.body )
{
this.setTimeout( FCKEditingArea_CompleteStart, 50 ) ;
return ;
}
var oEditorArea = this._FCKEditingArea ;
// Save this reference to be re-used later.
oEditorArea.Document = oEditorArea.Window.document ;
oEditorArea.MakeEditable() ;
// Fire the "OnLoad" event.
FCKTools.RunFunction( oEditorArea.OnLoad ) ;
}
FCKEditingArea.prototype.MakeEditable = function()
{
var oDoc = this.Document ;
if ( FCKBrowserInfo.IsIE )
{
// Kludge for #141 and #523
oDoc.body.disabled = true ;
oDoc.body.contentEditable = true ;
oDoc.body.removeAttribute( "disabled" ) ;
/* The following commands don't throw errors, but have no effect.
oDoc.execCommand( 'AutoDetect', false, false ) ;
oDoc.execCommand( 'KeepSelection', false, true ) ;
*/
}
else
{
try
{
// Disable Firefox 2 Spell Checker.
oDoc.body.spellcheck = ( this.FFSpellChecker !== false ) ;
if ( this._BodyHTML )
{
oDoc.body.innerHTML = this._BodyHTML ;
oDoc.body.offsetLeft ; // Don't remove, this is a hack to fix Opera 9.50, see #2264.
this._BodyHTML = null ;
}
oDoc.designMode = 'on' ;
// Tell Gecko (Firefox 1.5+) to enable or not live resizing of objects (by Alfonso Martinez)
oDoc.execCommand( 'enableObjectResizing', false, !FCKConfig.DisableObjectResizing ) ;
// Disable the standard table editing features of Firefox.
oDoc.execCommand( 'enableInlineTableEditing', false, !FCKConfig.DisableFFTableHandles ) ;
}
catch (e)
{
// In Firefox if the iframe is initially hidden it can't be set to designMode and it raises an exception
// So we set up a DOM Mutation event Listener on the HTML, as it will raise several events when the document is visible again
FCKTools.AddEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
}
}
}
// This function processes the notifications of the DOM Mutation event on the document
// We use it to know that the document will be ready to be editable again (or we hope so)
function FCKEditingArea_Document_AttributeNodeModified( evt )
{
var editingArea = evt.currentTarget.contentWindow._FCKEditingArea ;
// We want to run our function after the events no longer fire, so we can know that it's a stable situation
if ( editingArea._timer )
window.clearTimeout( editingArea._timer ) ;
editingArea._timer = FCKTools.SetTimeout( FCKEditingArea_MakeEditableByMutation, 1000, editingArea ) ;
}
// This function ideally should be called after the document is visible, it does clean up of the
// mutation tracking and tries again to make the area editable.
function FCKEditingArea_MakeEditableByMutation()
{
// Clean up
delete this._timer ;
// Now we don't want to keep on getting this event
FCKTools.RemoveEventListener( this.Window.frameElement, 'DOMAttrModified', FCKEditingArea_Document_AttributeNodeModified ) ;
// Let's try now to set the editing area editable
// If it fails it will set up the Mutation Listener again automatically
this.MakeEditable() ;
}
FCKEditingArea.prototype.Focus = function()
{
try
{
if ( this.Mode == FCK_EDITMODE_WYSIWYG )
{
if ( FCKBrowserInfo.IsIE )
this._FocusIE() ;
else
this.Window.focus() ;
}
else
{
var oDoc = FCKTools.GetElementDocument( this.Textarea ) ;
if ( (!oDoc.hasFocus || oDoc.hasFocus() ) && oDoc.activeElement == this.Textarea )
return ;
this.Textarea.focus() ;
}
}
catch(e) {}
}
FCKEditingArea.prototype._FocusIE = function()
{
// In IE it can happen that the document is in theory focused but the
// active element is outside of it.
this.Document.body.setActive() ;
this.Window.focus() ;
// Kludge for #141... yet more code to workaround IE bugs
var range = this.Document.selection.createRange() ;
var parentNode = range.parentElement() ;
var parentTag = parentNode.nodeName.toLowerCase() ;
// Only apply the fix when in a block, and the block is empty.
if ( parentNode.childNodes.length > 0 ||
!( FCKListsLib.BlockElements[parentTag] ||
FCKListsLib.NonEmptyBlockElements[parentTag] ) )
{
return ;
}
// Force the selection to happen, in this way we guarantee the focus will
// be there.
range = new FCKDomRange( this.Window ) ;
range.MoveToElementEditStart( parentNode ) ;
range.Select() ;
}
function FCKEditingArea_Cleanup()
{
if ( this.Document )
this.Document.body.innerHTML = "" ;
this.TargetElement = null ;
this.IFrame = null ;
this.Document = null ;
this.Textarea = null ;
if ( this.Window )
{
this.Window._FCKEditingArea = null ;
this.Window = null ;
}
}

View File

@ -0,0 +1,89 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Manages the DOM ascensors element list of a specific DOM node
* (limited to body, inclusive).
*/
var FCKElementPath = function( lastNode )
{
var eBlock = null ;
var eBlockLimit = null ;
var aElements = new Array() ;
var e = lastNode ;
while ( e )
{
if ( e.nodeType == 1 )
{
if ( !this.LastElement )
this.LastElement = e ;
var sElementName = e.nodeName.toLowerCase() ;
if ( FCKBrowserInfo.IsIE && e.scopeName != 'HTML' )
sElementName = e.scopeName.toLowerCase() + ':' + sElementName ;
if ( !eBlockLimit )
{
if ( !eBlock && FCKListsLib.PathBlockElements[ sElementName ] != null )
eBlock = e ;
if ( FCKListsLib.PathBlockLimitElements[ sElementName ] != null )
{
// DIV is considered the Block, if no block is available (#525)
// and if it doesn't contain other blocks.
if ( !eBlock && sElementName == 'div' && !FCKElementPath._CheckHasBlock( e ) )
eBlock = e ;
else
eBlockLimit = e ;
}
}
aElements.push( e ) ;
if ( sElementName == 'body' )
break ;
}
e = e.parentNode ;
}
this.Block = eBlock ;
this.BlockLimit = eBlockLimit ;
this.Elements = aElements ;
}
/**
* Check if an element contains any block element.
*/
FCKElementPath._CheckHasBlock = function( element )
{
var childNodes = element.childNodes ;
for ( var i = 0, count = childNodes.length ; i < count ; i++ )
{
var child = childNodes[i] ;
if ( child.nodeType == 1 && FCKListsLib.BlockElements[ child.nodeName.toLowerCase() ] )
return true ;
}
return false ;
}

View File

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

View File

@ -0,0 +1,71 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKEvents Class: used to handle events is a advanced way.
*/
var FCKEvents = function( eventsOwner )
{
this.Owner = eventsOwner ;
this._RegisteredEvents = new Object() ;
}
FCKEvents.prototype.AttachEvent = function( eventName, functionPointer )
{
var aTargets ;
if ( !( aTargets = this._RegisteredEvents[ eventName ] ) )
this._RegisteredEvents[ eventName ] = [ functionPointer ] ;
else
{
// Check that the event handler isn't already registered with the same listener
// It doesn't detect function pointers belonging to an object (at least in Gecko)
if ( aTargets.IndexOf( functionPointer ) == -1 )
aTargets.push( functionPointer ) ;
}
}
FCKEvents.prototype.FireEvent = function( eventName, params )
{
var bReturnValue = true ;
var oCalls = this._RegisteredEvents[ eventName ] ;
if ( oCalls )
{
for ( var i = 0 ; i < oCalls.length ; i++ )
{
try
{
bReturnValue = ( oCalls[ i ]( this.Owner, params ) && bReturnValue ) ;
}
catch(e)
{
// Ignore the following error. It may happen if pointing to a
// script not anymore available (#934):
// -2146823277 = Can't execute code from a freed script
if ( e.number != -2146823277 )
throw e ;
}
}
}
return bReturnValue ;
}

View File

@ -0,0 +1,142 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This class can be used to interate through nodes inside a range.
*
* During interation, the provided range can become invalid, due to document
* mutations, so CreateBookmark() used to restore it after processing, if
* needed.
*/
var FCKHtmlIterator = function( source )
{
this._sourceHtml = source ;
}
FCKHtmlIterator.prototype =
{
Next : function()
{
var sourceHtml = this._sourceHtml ;
if ( sourceHtml == null )
return null ;
var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ;
var isTag = false ;
var value = "" ;
if ( match )
{
if ( match.index > 0 )
{
value = sourceHtml.substr( 0, match.index ) ;
this._sourceHtml = sourceHtml.substr( match.index ) ;
}
else
{
isTag = true ;
value = match[0] ;
this._sourceHtml = sourceHtml.substr( match[0].length ) ;
}
}
else
{
value = sourceHtml ;
this._sourceHtml = null ;
}
return { 'isTag' : isTag, 'value' : value } ;
},
Each : function( func )
{
var chunk ;
while ( ( chunk = this.Next() ) )
func( chunk.isTag, chunk.value ) ;
}
} ;
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This class can be used to interate through nodes inside a range.
*
* During interation, the provided range can become invalid, due to document
* mutations, so CreateBookmark() used to restore it after processing, if
* needed.
*/
var FCKHtmlIterator = function( source )
{
this._sourceHtml = source ;
}
FCKHtmlIterator.prototype =
{
Next : function()
{
var sourceHtml = this._sourceHtml ;
if ( sourceHtml == null )
return null ;
var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ;
var isTag = false ;
var value = "" ;
if ( match )
{
if ( match.index > 0 )
{
value = sourceHtml.substr( 0, match.index ) ;
this._sourceHtml = sourceHtml.substr( match.index ) ;
}
else
{
isTag = true ;
value = match[0] ;
this._sourceHtml = sourceHtml.substr( match[0].length ) ;
}
}
else
{
value = sourceHtml ;
this._sourceHtml = null ;
}
return { 'isTag' : isTag, 'value' : value } ;
},
Each : function( func )
{
var chunk ;
while ( ( chunk = this.Next() ) )
func( chunk.isTag, chunk.value ) ;
}
} ;

View File

@ -0,0 +1,103 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKIcon Class: renders an icon from a single image, a strip or even a
* spacer.
*/
var FCKIcon = function( iconPathOrStripInfoArray )
{
var sTypeOf = iconPathOrStripInfoArray ? typeof( iconPathOrStripInfoArray ) : 'undefined' ;
switch ( sTypeOf )
{
case 'number' :
this.Path = FCKConfig.SkinPath + 'fck_strip.gif' ;
this.Size = 16 ;
this.Position = iconPathOrStripInfoArray ;
break ;
case 'undefined' :
this.Path = FCK_SPACER_PATH ;
break ;
case 'string' :
this.Path = iconPathOrStripInfoArray ;
break ;
default :
// It is an array in the format [ StripFilePath, IconSize, IconPosition ]
this.Path = iconPathOrStripInfoArray[0] ;
this.Size = iconPathOrStripInfoArray[1] ;
this.Position = iconPathOrStripInfoArray[2] ;
}
}
FCKIcon.prototype.CreateIconElement = function( document )
{
var eIcon, eIconImage ;
if ( this.Position ) // It is using an icons strip image.
{
var sPos = '-' + ( ( this.Position - 1 ) * this.Size ) + 'px' ;
if ( FCKBrowserInfo.IsIE )
{
// <div class="TB_Button_Image"><img src="strip.gif" style="top:-16px"></div>
eIcon = document.createElement( 'DIV' ) ;
eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
eIconImage.src = this.Path ;
eIconImage.style.top = sPos ;
}
else
{
// <img class="TB_Button_Image" src="spacer.gif" style="background-position: 0px -16px;background-image: url(strip.gif);">
eIcon = document.createElement( 'IMG' ) ;
eIcon.src = FCK_SPACER_PATH ;
eIcon.style.backgroundPosition = '0px ' + sPos ;
eIcon.style.backgroundImage = 'url("' + this.Path + '")' ;
}
}
else // It is using a single icon image.
{
if ( FCKBrowserInfo.IsIE )
{
// IE makes the button 1px higher if using the <img> directly, so we
// are changing to the <div> system to clip the image correctly.
eIcon = document.createElement( 'DIV' ) ;
eIconImage = eIcon.appendChild( document.createElement( 'IMG' ) ) ;
eIconImage.src = this.Path ? this.Path : FCK_SPACER_PATH ;
}
else
{
// This is not working well with IE. See notes above.
// <img class="TB_Button_Image" src="smiley.gif">
eIcon = document.createElement( 'IMG' ) ;
eIcon.src = this.Path ? this.Path : FCK_SPACER_PATH ;
}
}
eIcon.className = 'TB_Button_Image' ;
return eIcon ;
}

View File

@ -0,0 +1,68 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKIECleanup Class: a generic class used as a tool to remove IE leaks.
*/
var FCKIECleanup = function( attachWindow )
{
// If the attachWindow already have a cleanup object, just use that one.
if ( attachWindow._FCKCleanupObj )
this.Items = attachWindow._FCKCleanupObj.Items ;
else
{
this.Items = new Array() ;
attachWindow._FCKCleanupObj = this ;
FCKTools.AddEventListenerEx( attachWindow, 'unload', FCKIECleanup_Cleanup ) ;
// attachWindow.attachEvent( 'onunload', FCKIECleanup_Cleanup ) ;
}
}
FCKIECleanup.prototype.AddItem = function( dirtyItem, cleanupFunction )
{
this.Items.push( [ dirtyItem, cleanupFunction ] ) ;
}
function FCKIECleanup_Cleanup()
{
if ( !this._FCKCleanupObj || ( FCKConfig.MsWebBrowserControlCompat && !window.FCKUnloadFlag ) )
return ;
var aItems = this._FCKCleanupObj.Items ;
while ( aItems.length > 0 )
{
// It is important to remove from the end to the beginning (pop()),
// because of the order things get created in the editor. In the code,
// elements in deeper position in the DOM are placed at the end of the
// cleanup function, so we must cleanup then first, otherwise IE could
// throw some crazy memory errors (IE bug).
var oItem = aItems.pop() ;
if ( oItem )
oItem[1].call( oItem[0] ) ;
}
this._FCKCleanupObj = null ;
if ( CollectGarbage )
CollectGarbage() ;
}

View File

@ -0,0 +1,64 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Preload a list of images, firing an event when complete.
*/
var FCKImagePreloader = function()
{
this._Images = new Array() ;
}
FCKImagePreloader.prototype =
{
AddImages : function( images )
{
if ( typeof( images ) == 'string' )
images = images.split( ';' ) ;
this._Images = this._Images.concat( images ) ;
},
Start : function()
{
var aImages = this._Images ;
this._PreloadCount = aImages.length ;
for ( var i = 0 ; i < aImages.length ; i++ )
{
var eImg = document.createElement( 'img' ) ;
FCKTools.AddEventListenerEx( eImg, 'load', _FCKImagePreloader_OnImage, this ) ;
FCKTools.AddEventListenerEx( eImg, 'error', _FCKImagePreloader_OnImage, this ) ;
eImg.src = aImages[i] ;
_FCKImagePreloader_ImageCache.push( eImg ) ;
}
}
};
// All preloaded images must be placed in a global array, otherwise the preload
// magic will not happen.
var _FCKImagePreloader_ImageCache = new Array() ;
function _FCKImagePreloader_OnImage( ev, imagePreloader )
{
if ( (--imagePreloader._PreloadCount) == 0 && imagePreloader.OnComplete )
imagePreloader.OnComplete() ;
}

View File

@ -0,0 +1,141 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Control keyboard keystroke combinations.
*/
var FCKKeystrokeHandler = function( cancelCtrlDefaults )
{
this.Keystrokes = new Object() ;
this.CancelCtrlDefaults = ( cancelCtrlDefaults !== false ) ;
}
/*
* Listen to keystroke events in an element or DOM document object.
* @target: The element or document to listen to keystroke events.
*/
FCKKeystrokeHandler.prototype.AttachToElement = function( target )
{
// For newer browsers, it is enough to listen to the keydown event only.
// Some browsers instead, don't cancel key events in the keydown, but in the
// keypress. So we must do a longer trip in those cases.
FCKTools.AddEventListenerEx( target, 'keydown', _FCKKeystrokeHandler_OnKeyDown, this ) ;
if ( FCKBrowserInfo.IsGecko10 || FCKBrowserInfo.IsOpera || ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac ) )
FCKTools.AddEventListenerEx( target, 'keypress', _FCKKeystrokeHandler_OnKeyPress, this ) ;
}
/*
* Sets a list of keystrokes. It can receive either a single array or "n"
* arguments, each one being an array of 1 or 2 elemenst. The first element
* is the keystroke combination, and the second is the value to assign to it.
* If the second element is missing, the keystroke definition is removed.
*/
FCKKeystrokeHandler.prototype.SetKeystrokes = function()
{
// Look through the arguments.
for ( var i = 0 ; i < arguments.length ; i++ )
{
var keyDef = arguments[i] ;
// If the configuration for the keystrokes is missing some element or has any extra comma
// this item won't be valid, so skip it and keep on processing.
if ( !keyDef )
continue ;
if ( typeof( keyDef[0] ) == 'object' ) // It is an array with arrays defining the keystrokes.
this.SetKeystrokes.apply( this, keyDef ) ;
else
{
if ( keyDef.length == 1 ) // If it has only one element, remove the keystroke.
delete this.Keystrokes[ keyDef[0] ] ;
else // Otherwise add it.
this.Keystrokes[ keyDef[0] ] = keyDef[1] === true ? true : keyDef ;
}
}
}
function _FCKKeystrokeHandler_OnKeyDown( ev, keystrokeHandler )
{
// Get the key code.
var keystroke = ev.keyCode || ev.which ;
// Combine it with the CTRL, SHIFT and ALT states.
var keyModifiers = 0 ;
if ( ev.ctrlKey || ev.metaKey )
keyModifiers += CTRL ;
if ( ev.shiftKey )
keyModifiers += SHIFT ;
if ( ev.altKey )
keyModifiers += ALT ;
var keyCombination = keystroke + keyModifiers ;
var cancelIt = keystrokeHandler._CancelIt = false ;
// Look for its definition availability.
var keystrokeValue = keystrokeHandler.Keystrokes[ keyCombination ] ;
// FCKDebug.Output( 'KeyDown: ' + keyCombination + ' - Value: ' + keystrokeValue ) ;
// If the keystroke is defined
if ( keystrokeValue )
{
// If the keystroke has been explicitly set to "true" OR calling the
// "OnKeystroke" event, it doesn't return "true", the default behavior
// must be preserved.
if ( keystrokeValue === true || !( keystrokeHandler.OnKeystroke && keystrokeHandler.OnKeystroke.apply( keystrokeHandler, keystrokeValue ) ) )
return true ;
cancelIt = true ;
}
// By default, it will cancel all combinations with the CTRL key only (except positioning keys).
if ( cancelIt || ( keystrokeHandler.CancelCtrlDefaults && keyModifiers == CTRL && ( keystroke < 33 || keystroke > 40 ) ) )
{
keystrokeHandler._CancelIt = true ;
if ( ev.preventDefault )
return ev.preventDefault() ;
ev.returnValue = false ;
ev.cancelBubble = true ;
return false ;
}
return true ;
}
function _FCKKeystrokeHandler_OnKeyPress( ev, keystrokeHandler )
{
if ( keystrokeHandler._CancelIt )
{
// FCKDebug.Output( 'KeyPress Cancel', 'Red') ;
if ( ev.preventDefault )
return ev.preventDefault() ;
return false ;
}
return true ;
}

View File

@ -0,0 +1,153 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Renders a list of menu items.
*/
var FCKMenuBlock = function()
{
this._Items = new Array() ;
}
FCKMenuBlock.prototype.Count = function()
{
return this._Items.length ;
}
FCKMenuBlock.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
{
var oItem = new FCKMenuItem( this, name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
oItem.OnClick = FCKTools.CreateEventListener( FCKMenuBlock_Item_OnClick, this ) ;
oItem.OnActivate = FCKTools.CreateEventListener( FCKMenuBlock_Item_OnActivate, this ) ;
this._Items.push( oItem ) ;
return oItem ;
}
FCKMenuBlock.prototype.AddSeparator = function()
{
this._Items.push( new FCKMenuSeparator() ) ;
}
FCKMenuBlock.prototype.RemoveAllItems = function()
{
this._Items = new Array() ;
var eItemsTable = this._ItemsTable ;
if ( eItemsTable )
{
while ( eItemsTable.rows.length > 0 )
eItemsTable.deleteRow( 0 ) ;
}
}
FCKMenuBlock.prototype.Create = function( parentElement )
{
if ( !this._ItemsTable )
{
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKMenuBlock_Cleanup ) ;
this._Window = FCKTools.GetElementWindow( parentElement ) ;
var oDoc = FCKTools.GetElementDocument( parentElement ) ;
var eTable = parentElement.appendChild( oDoc.createElement( 'table' ) ) ;
eTable.cellPadding = 0 ;
eTable.cellSpacing = 0 ;
FCKTools.DisableSelection( eTable ) ;
var oMainElement = eTable.insertRow(-1).insertCell(-1) ;
oMainElement.className = 'MN_Menu' ;
var eItemsTable = this._ItemsTable = oMainElement.appendChild( oDoc.createElement( 'table' ) ) ;
eItemsTable.cellPadding = 0 ;
eItemsTable.cellSpacing = 0 ;
}
for ( var i = 0 ; i < this._Items.length ; i++ )
this._Items[i].Create( this._ItemsTable ) ;
}
/* Events */
function FCKMenuBlock_Item_OnClick( clickedItem, menuBlock )
{
if ( menuBlock.Hide )
menuBlock.Hide() ;
FCKTools.RunFunction( menuBlock.OnClick, menuBlock, [ clickedItem ] ) ;
}
function FCKMenuBlock_Item_OnActivate( menuBlock )
{
var oActiveItem = menuBlock._ActiveItem ;
if ( oActiveItem && oActiveItem != this )
{
// Set the focus to this menu block window (to fire OnBlur on opened panels).
if ( !FCKBrowserInfo.IsIE && oActiveItem.HasSubMenu && !this.HasSubMenu )
{
menuBlock._Window.focus() ;
// Due to the event model provided by Opera, we need to set
// HasFocus here as the above focus() call will not fire the focus
// event in the panel immediately (#1200).
menuBlock.Panel.HasFocus = true ;
}
oActiveItem.Deactivate() ;
}
menuBlock._ActiveItem = this ;
}
function FCKMenuBlock_Cleanup()
{
this._Window = null ;
this._ItemsTable = null ;
}
// ################# //
var FCKMenuSeparator = function()
{}
FCKMenuSeparator.prototype.Create = function( parentTable )
{
var oDoc = FCKTools.GetElementDocument( parentTable ) ;
var r = parentTable.insertRow(-1) ;
var eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator MN_Icon' ;
eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator' ;
eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
eCell = r.insertCell(-1) ;
eCell.className = 'MN_Separator' ;
eCell.appendChild( oDoc.createElement( 'DIV' ) ).className = 'MN_Separator_Line' ;
}

View File

@ -0,0 +1,54 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This class is a menu block that behaves like a panel. It's a mix of the
* FCKMenuBlock and FCKPanel classes.
*/
var FCKMenuBlockPanel = function()
{
// Call the "base" constructor.
FCKMenuBlock.call( this ) ;
}
FCKMenuBlockPanel.prototype = new FCKMenuBlock() ;
// Override the create method.
FCKMenuBlockPanel.prototype.Create = function()
{
var oPanel = this.Panel = ( this.Parent && this.Parent.Panel ? this.Parent.Panel.CreateChildPanel() : new FCKPanel() ) ;
oPanel.AppendStyleSheet( FCKConfig.SkinEditorCSS ) ;
// Call the "base" implementation.
FCKMenuBlock.prototype.Create.call( this, oPanel.MainNode ) ;
}
FCKMenuBlockPanel.prototype.Show = function( x, y, relElement )
{
if ( !this.Panel.CheckIsOpened() )
this.Panel.Show( x, y, relElement ) ;
}
FCKMenuBlockPanel.prototype.Hide = function()
{
if ( this.Panel.CheckIsOpened() )
this.Panel.Hide() ;
}

View File

@ -0,0 +1,161 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines and renders a menu items in a menu block.
*/
var FCKMenuItem = function( parentMenuBlock, name, label, iconPathOrStripInfoArray, isDisabled, customData )
{
this.Name = name ;
this.Label = label || name ;
this.IsDisabled = isDisabled ;
this.Icon = new FCKIcon( iconPathOrStripInfoArray ) ;
this.SubMenu = new FCKMenuBlockPanel() ;
this.SubMenu.Parent = parentMenuBlock ;
this.SubMenu.OnClick = FCKTools.CreateEventListener( FCKMenuItem_SubMenu_OnClick, this ) ;
this.CustomData = customData ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKMenuItem_Cleanup ) ;
}
FCKMenuItem.prototype.AddItem = function( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData )
{
this.HasSubMenu = true ;
return this.SubMenu.AddItem( name, label, iconPathOrStripInfoArrayOrIndex, isDisabled, customData ) ;
}
FCKMenuItem.prototype.AddSeparator = function()
{
this.SubMenu.AddSeparator() ;
}
FCKMenuItem.prototype.Create = function( parentTable )
{
var bHasSubMenu = this.HasSubMenu ;
var oDoc = FCKTools.GetElementDocument( parentTable ) ;
// Add a row in the table to hold the menu item.
var r = this.MainElement = parentTable.insertRow(-1) ;
r.className = this.IsDisabled ? 'MN_Item_Disabled' : 'MN_Item' ;
// Set the row behavior.
if ( !this.IsDisabled )
{
FCKTools.AddEventListenerEx( r, 'mouseover', FCKMenuItem_OnMouseOver, [ this ] ) ;
FCKTools.AddEventListenerEx( r, 'click', FCKMenuItem_OnClick, [ this ] ) ;
if ( !bHasSubMenu )
FCKTools.AddEventListenerEx( r, 'mouseout', FCKMenuItem_OnMouseOut, [ this ] ) ;
}
// Create the icon cell.
var eCell = r.insertCell(-1) ;
eCell.className = 'MN_Icon' ;
eCell.appendChild( this.Icon.CreateIconElement( oDoc ) ) ;
// Create the label cell.
eCell = r.insertCell(-1) ;
eCell.className = 'MN_Label' ;
eCell.noWrap = true ;
eCell.appendChild( oDoc.createTextNode( this.Label ) ) ;
// Create the arrow cell and setup the sub menu panel (if needed).
eCell = r.insertCell(-1) ;
if ( bHasSubMenu )
{
eCell.className = 'MN_Arrow' ;
// The arrow is a fixed size image.
var eArrowImg = eCell.appendChild( oDoc.createElement( 'IMG' ) ) ;
eArrowImg.src = FCK_IMAGES_PATH + 'arrow_' + FCKLang.Dir + '.gif' ;
eArrowImg.width = 4 ;
eArrowImg.height = 7 ;
this.SubMenu.Create() ;
this.SubMenu.Panel.OnHide = FCKTools.CreateEventListener( FCKMenuItem_SubMenu_OnHide, this ) ;
}
}
FCKMenuItem.prototype.Activate = function()
{
this.MainElement.className = 'MN_Item_Over' ;
if ( this.HasSubMenu )
{
// Show the child menu block. The ( +2, -2 ) correction is done because
// of the padding in the skin. It is not a good solution because one
// could change the skin and so the final result would not be accurate.
// For now it is ok because we are controlling the skin.
this.SubMenu.Show( this.MainElement.offsetWidth + 2, -2, this.MainElement ) ;
}
FCKTools.RunFunction( this.OnActivate, this ) ;
}
FCKMenuItem.prototype.Deactivate = function()
{
this.MainElement.className = 'MN_Item' ;
if ( this.HasSubMenu )
this.SubMenu.Hide() ;
}
/* Events */
function FCKMenuItem_SubMenu_OnClick( clickedItem, listeningItem )
{
FCKTools.RunFunction( listeningItem.OnClick, listeningItem, [ clickedItem ] ) ;
}
function FCKMenuItem_SubMenu_OnHide( menuItem )
{
menuItem.Deactivate() ;
}
function FCKMenuItem_OnClick( ev, menuItem )
{
if ( menuItem.HasSubMenu )
menuItem.Activate() ;
else
{
menuItem.Deactivate() ;
FCKTools.RunFunction( menuItem.OnClick, menuItem, [ menuItem ] ) ;
}
}
function FCKMenuItem_OnMouseOver( ev, menuItem )
{
menuItem.Activate() ;
}
function FCKMenuItem_OnMouseOut( ev, menuItem )
{
menuItem.Deactivate() ;
}
function FCKMenuItem_Cleanup()
{
this.MainElement = null ;
}

View File

@ -0,0 +1,463 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Component that creates floating panels. It is used by many
* other components, like the toolbar items, context menu, etc...
*/
var FCKPanel = function( parentWindow )
{
this.IsRTL = ( FCKLang.Dir == 'rtl' ) ;
this.IsContextMenu = false ;
this._LockCounter = 0 ;
this._Window = parentWindow || window ;
var oDocument ;
if ( FCKBrowserInfo.IsIE )
{
// Create the Popup that will hold the panel.
// The popup has to be created before playing with domain hacks, see #1666.
this._Popup = this._Window.createPopup() ;
// this._Window cannot be accessed while playing with domain hacks, but local variable is ok.
// See #1666.
var pDoc = this._Window.document ;
// This is a trick to IE6 (not IE7). The original domain must be set
// before creating the popup, so we are able to take a refence to the
// document inside of it, and the set the proper domain for it. (#123)
if ( FCK_IS_CUSTOM_DOMAIN && !FCKBrowserInfo.IsIE7 )
{
pDoc.domain = FCK_ORIGINAL_DOMAIN ;
document.domain = FCK_ORIGINAL_DOMAIN ;
}
oDocument = this.Document = this._Popup.document ;
// Set the proper domain inside the popup.
if ( FCK_IS_CUSTOM_DOMAIN )
{
oDocument.domain = FCK_RUNTIME_DOMAIN ;
pDoc.domain = FCK_RUNTIME_DOMAIN ;
document.domain = FCK_RUNTIME_DOMAIN ;
}
FCK.IECleanup.AddItem( this, FCKPanel_Cleanup ) ;
}
else
{
var oIFrame = this._IFrame = this._Window.document.createElement('iframe') ;
FCKTools.ResetStyles( oIFrame );
oIFrame.src = 'javascript:void(0)' ;
oIFrame.allowTransparency = true ;
oIFrame.frameBorder = '0' ;
oIFrame.scrolling = 'no' ;
oIFrame.style.width = oIFrame.style.height = '0px' ;
FCKDomTools.SetElementStyles( oIFrame,
{
position : 'absolute',
zIndex : FCKConfig.FloatingPanelsZIndex
} ) ;
this._Window.document.body.appendChild( oIFrame ) ;
var oIFrameWindow = oIFrame.contentWindow ;
oDocument = this.Document = oIFrameWindow.document ;
// Workaround for Safari 12256. Ticket #63
var sBase = '' ;
if ( FCKBrowserInfo.IsSafari )
sBase = '<base href="' + window.document.location + '">' ;
// Initialize the IFRAME document body.
oDocument.open() ;
oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ;
oDocument.close() ;
if( FCKBrowserInfo.IsAIR )
FCKAdobeAIR.Panel_Contructor( oDocument, window.document.location ) ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'blur', FCKPanel_Window_OnBlur, this ) ;
}
oDocument.dir = FCKLang.Dir ;
FCKTools.AddEventListener( oDocument, 'contextmenu', FCKTools.CancelEvent ) ;
// Create the main DIV that is used as the panel base.
this.MainNode = oDocument.body.appendChild( oDocument.createElement('DIV') ) ;
// The "float" property must be set so Firefox calculates the size correctly.
this.MainNode.style.cssFloat = this.IsRTL ? 'right' : 'left' ;
}
FCKPanel.prototype.AppendStyleSheet = function( styleSheet )
{
FCKTools.AppendStyleSheet( this.Document, styleSheet ) ;
}
FCKPanel.prototype.Preload = function( x, y, relElement )
{
// The offsetWidth and offsetHeight properties are not available if the
// element is not visible. So we must "show" the popup with no size to
// be able to use that values in the second call (IE only).
if ( this._Popup )
this._Popup.show( x, y, 0, 0, relElement ) ;
}
// Workaround for IE7 problem. See #1982
// Submenus are restricted to the size of its parent, so we increase it as needed.
// Returns true if the panel has been repositioned
FCKPanel.prototype.ResizeForSubpanel = function( panel, width, height )
{
if ( !FCKBrowserInfo.IsIE7 )
return false ;
if ( !this._Popup.isOpen )
{
this.Subpanel = null ;
return false ;
}
// If we are resetting the extra space
if ( width == 0 && height == 0 )
{
// Another subpanel is being shown, so we must not shrink back
if (this.Subpanel !== panel)
return false ;
// Reset values.
// We leave the IncreasedY untouched to avoid vertical movement of the
// menu if the submenu is higher than the main menu.
this.Subpanel = null ;
this.IncreasedX = 0 ;
}
else
{
this.Subpanel = panel ;
// If the panel has already been increased enough, get out
if ( ( this.IncreasedX >= width ) && ( this.IncreasedY >= height ) )
return false ;
this.IncreasedX = Math.max( this.IncreasedX, width ) ;
this.IncreasedY = Math.max( this.IncreasedY, height ) ;
}
var x = this.ShowRect.x ;
var w = this.IncreasedX ;
if ( this.IsRTL )
x = x - w ;
// Horizontally increase as needed (sum of widths).
// Vertically, use only the maximum of this menu or the submenu
var finalWidth = this.ShowRect.w + w ;
var finalHeight = Math.max( this.ShowRect.h, this.IncreasedY ) ;
if ( this.ParentPanel )
this.ParentPanel.ResizeForSubpanel( this, finalWidth, finalHeight ) ;
this._Popup.show( x, this.ShowRect.y, finalWidth, finalHeight, this.RelativeElement ) ;
return this.IsRTL ;
}
FCKPanel.prototype.Show = function( x, y, relElement, width, height )
{
var iMainWidth ;
var eMainNode = this.MainNode ;
if ( this._Popup )
{
// The offsetWidth and offsetHeight properties are not available if the
// element is not visible. So we must "show" the popup with no size to
// be able to use that values in the second call.
this._Popup.show( x, y, 0, 0, relElement ) ;
// The following lines must be place after the above "show", otherwise it
// doesn't has the desired effect.
FCKDomTools.SetElementStyles( eMainNode,
{
width : width ? width + 'px' : '',
height : height ? height + 'px' : ''
} ) ;
iMainWidth = eMainNode.offsetWidth ;
if ( FCKBrowserInfo.IsIE7 )
{
if (this.ParentPanel && this.ParentPanel.ResizeForSubpanel(this, iMainWidth, eMainNode.offsetHeight) )
{
// As the parent has moved, allow the browser to update its internal data, so the new position is correct.
FCKTools.RunFunction( this.Show, this, [x, y, relElement] ) ;
return ;
}
}
if ( this.IsRTL )
{
if ( this.IsContextMenu )
x = x - iMainWidth + 1 ;
else if ( relElement )
x = ( x * -1 ) + relElement.offsetWidth - iMainWidth ;
}
if ( FCKBrowserInfo.IsIE7 )
{
// Store the values that will be used by the ResizeForSubpanel function
this.ShowRect = {x:x, y:y, w:iMainWidth, h:eMainNode.offsetHeight} ;
this.IncreasedX = 0 ;
this.IncreasedY = 0 ;
this.RelativeElement = relElement ;
}
// Second call: Show the Popup at the specified location, with the correct size.
this._Popup.show( x, y, iMainWidth, eMainNode.offsetHeight, relElement ) ;
if ( this.OnHide )
{
if ( this._Timer )
CheckPopupOnHide.call( this, true ) ;
this._Timer = FCKTools.SetInterval( CheckPopupOnHide, 100, this ) ;
}
}
else
{
// Do not fire OnBlur while the panel is opened.
if ( typeof( FCK.ToolbarSet.CurrentInstance.FocusManager ) != 'undefined' )
FCK.ToolbarSet.CurrentInstance.FocusManager.Lock() ;
if ( this.ParentPanel )
{
this.ParentPanel.Lock() ;
// Due to a bug on FF3, we must ensure that the parent panel will
// blur (#1584).
FCKPanel_Window_OnBlur( null, this.ParentPanel ) ;
}
// Toggle the iframe scrolling attribute to prevent the panel
// scrollbars from disappearing in FF Mac. (#191)
if ( FCKBrowserInfo.IsGecko && FCKBrowserInfo.IsMac )
{
this._IFrame.scrolling = '' ;
FCKTools.RunFunction( function(){ this._IFrame.scrolling = 'no'; }, this ) ;
}
// Be sure we'll not have more than one Panel opened at the same time.
// Do not unlock focus manager here because we're displaying another floating panel
// instead of returning the editor to a "no panel" state (Bug #1514).
if ( FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel &&
FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel != this )
FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel.Hide( false, true ) ;
FCKDomTools.SetElementStyles( eMainNode,
{
width : width ? width + 'px' : '',
height : height ? height + 'px' : ''
} ) ;
iMainWidth = eMainNode.offsetWidth ;
if ( !width ) this._IFrame.width = 1 ;
if ( !height ) this._IFrame.height = 1 ;
// This is weird... but with Firefox, we must get the offsetWidth before
// setting the _IFrame size (which returns "0"), and then after that,
// to return the correct width. Remove the first step and it will not
// work when the editor is in RTL.
//
// The "|| eMainNode.firstChild.offsetWidth" part has been added
// for Opera compatibility (see #570).
iMainWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
// Base the popup coordinates upon the coordinates of relElement.
var oPos = FCKTools.GetDocumentPosition( this._Window,
relElement.nodeType == 9 ?
( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :
relElement ) ;
// Minus the offsets provided by any positioned parent element of the panel iframe.
var positionedAncestor = FCKDomTools.GetPositionedAncestor( this._IFrame.parentNode ) ;
if ( positionedAncestor )
{
var nPos = FCKTools.GetDocumentPosition( FCKTools.GetElementWindow( positionedAncestor ), positionedAncestor ) ;
oPos.x -= nPos.x ;
oPos.y -= nPos.y ;
}
if ( this.IsRTL && !this.IsContextMenu )
x = ( x * -1 ) ;
x += oPos.x ;
y += oPos.y ;
if ( this.IsRTL )
{
if ( this.IsContextMenu )
x = x - iMainWidth + 1 ;
else if ( relElement )
x = x + relElement.offsetWidth - iMainWidth ;
}
else
{
var oViewPaneSize = FCKTools.GetViewPaneSize( this._Window ) ;
var oScrollPosition = FCKTools.GetScrollPosition( this._Window ) ;
var iViewPaneHeight = oViewPaneSize.Height + oScrollPosition.Y ;
var iViewPaneWidth = oViewPaneSize.Width + oScrollPosition.X ;
if ( ( x + iMainWidth ) > iViewPaneWidth )
x -= x + iMainWidth - iViewPaneWidth ;
if ( ( y + eMainNode.offsetHeight ) > iViewPaneHeight )
y -= y + eMainNode.offsetHeight - iViewPaneHeight ;
}
// Set the context menu DIV in the specified location.
FCKDomTools.SetElementStyles( this._IFrame,
{
left : x + 'px',
top : y + 'px'
} ) ;
// Move the focus to the IFRAME so we catch the "onblur".
this._IFrame.contentWindow.focus() ;
this._IsOpened = true ;
var me = this ;
this._resizeTimer = setTimeout( function()
{
var iWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
var iHeight = eMainNode.offsetHeight ;
me._IFrame.style.width = iWidth + 'px' ;
me._IFrame.style.height = iHeight + 'px' ;
}, 0 ) ;
FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'FCKPanel' )._OpenedPanel = this ;
}
FCKTools.RunFunction( this.OnShow, this ) ;
}
FCKPanel.prototype.Hide = function( ignoreOnHide, ignoreFocusManagerUnlock )
{
if ( this._Popup )
this._Popup.hide() ;
else
{
if ( !this._IsOpened || this._LockCounter > 0 )
return ;
// Enable the editor to fire the "OnBlur".
if ( typeof( FCKFocusManager ) != 'undefined' && !ignoreFocusManagerUnlock )
FCKFocusManager.Unlock() ;
// It is better to set the sizes to 0, otherwise Firefox would have
// rendering problems.
this._IFrame.style.width = this._IFrame.style.height = '0px' ;
this._IsOpened = false ;
if ( this._resizeTimer )
{
clearTimeout( this._resizeTimer ) ;
this._resizeTimer = null ;
}
if ( this.ParentPanel )
this.ParentPanel.Unlock() ;
if ( !ignoreOnHide )
FCKTools.RunFunction( this.OnHide, this ) ;
}
}
FCKPanel.prototype.CheckIsOpened = function()
{
if ( this._Popup )
return this._Popup.isOpen ;
else
return this._IsOpened ;
}
FCKPanel.prototype.CreateChildPanel = function()
{
var oWindow = this._Popup ? FCKTools.GetDocumentWindow( this.Document ) : this._Window ;
var oChildPanel = new FCKPanel( oWindow ) ;
oChildPanel.ParentPanel = this ;
return oChildPanel ;
}
FCKPanel.prototype.Lock = function()
{
this._LockCounter++ ;
}
FCKPanel.prototype.Unlock = function()
{
if ( --this._LockCounter == 0 && !this.HasFocus )
this.Hide() ;
}
/* Events */
function FCKPanel_Window_OnFocus( e, panel )
{
panel.HasFocus = true ;
}
function FCKPanel_Window_OnBlur( e, panel )
{
panel.HasFocus = false ;
if ( panel._LockCounter == 0 )
FCKTools.RunFunction( panel.Hide, panel ) ;
}
function CheckPopupOnHide( forceHide )
{
if ( forceHide || !this._Popup.isOpen )
{
window.clearInterval( this._Timer ) ;
this._Timer = null ;
if (this._Popup && this.ParentPanel && !forceHide)
this.ParentPanel.ResizeForSubpanel(this, 0, 0) ;
FCKTools.RunFunction( this.OnHide, this ) ;
}
}
function FCKPanel_Cleanup()
{
this._Popup = null ;
this._Window = null ;
this.Document = null ;
this.MainNode = null ;
this.RelativeElement = null ;
}

View File

@ -0,0 +1,56 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKPlugin Class: Represents a single plugin.
*/
var FCKPlugin = function( name, availableLangs, basePath )
{
this.Name = name ;
this.BasePath = basePath ? basePath : FCKConfig.PluginsPath ;
this.Path = this.BasePath + name + '/' ;
if ( !availableLangs || availableLangs.length == 0 )
this.AvailableLangs = new Array() ;
else
this.AvailableLangs = availableLangs.split(',') ;
}
FCKPlugin.prototype.Load = function()
{
// Load the language file, if defined.
if ( this.AvailableLangs.length > 0 )
{
var sLang ;
// Check if the plugin has the language file for the active language.
if ( this.AvailableLangs.IndexOf( FCKLanguageManager.ActiveLanguage.Code ) >= 0 )
sLang = FCKLanguageManager.ActiveLanguage.Code ;
else
// Load the default language file (first one) if the current one is not available.
sLang = this.AvailableLangs[0] ;
// Add the main plugin script.
LoadScript( this.Path + 'lang/' + sLang + '.js' ) ;
}
// Add the main plugin script.
LoadScript( this.Path + 'fckplugin.js' ) ;
}

View File

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

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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbar Class: represents a toolbar in the toolbarset. It is a group of
* toolbar items.
*/
var FCKToolbar = function()
{
this.Items = new Array() ;
}
FCKToolbar.prototype.AddItem = function( item )
{
return this.Items[ this.Items.length ] = item ;
}
FCKToolbar.prototype.AddButton = function( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state )
{
if ( typeof( iconPathOrStripInfoArrayOrIndex ) == 'number' )
iconPathOrStripInfoArrayOrIndex = [ this.DefaultIconsStrip, this.DefaultIconSize, iconPathOrStripInfoArrayOrIndex ] ;
var oButton = new FCKToolbarButtonUI( name, label, tooltip, iconPathOrStripInfoArrayOrIndex, style, state ) ;
oButton._FCKToolbar = this ;
oButton.OnClick = FCKToolbar_OnItemClick ;
return this.AddItem( oButton ) ;
}
function FCKToolbar_OnItemClick( item )
{
var oToolbar = item._FCKToolbar ;
if ( oToolbar.OnItemClick )
oToolbar.OnItemClick( oToolbar, item ) ;
}
FCKToolbar.prototype.AddSeparator = function()
{
this.AddItem( new FCKToolbarSeparator() ) ;
}
FCKToolbar.prototype.Create = function( parentElement )
{
var oDoc = FCKTools.GetElementDocument( parentElement ) ;
var e = oDoc.createElement( 'table' ) ;
e.className = 'TB_Toolbar' ;
e.style.styleFloat = e.style.cssFloat = ( FCKLang.Dir == 'ltr' ? 'left' : 'right' ) ;
e.dir = FCKLang.Dir ;
e.cellPadding = 0 ;
e.cellSpacing = 0 ;
var targetRow = e.insertRow(-1) ;
// Insert the start cell.
var eCell ;
if ( !this.HideStart )
{
eCell = targetRow.insertCell(-1) ;
eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_Start' ;
}
for ( var i = 0 ; i < this.Items.length ; i++ )
{
this.Items[i].Create( targetRow.insertCell(-1) ) ;
}
// Insert the ending cell.
if ( !this.HideEnd )
{
eCell = targetRow.insertCell(-1) ;
eCell.appendChild( oDoc.createElement( 'div' ) ).className = 'TB_End' ;
}
parentElement.appendChild( e ) ;
}
var FCKToolbarSeparator = function()
{}
FCKToolbarSeparator.prototype.Create = function( parentElement )
{
FCKTools.AppendElement( parentElement, 'div' ).className = 'TB_Separator' ;
}

View File

@ -0,0 +1,36 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarBreak Class: breaks the toolbars.
* It makes it possible to force the toolbar to break to a new line.
* This is the Gecko specific implementation.
*/
var FCKToolbarBreak = function()
{}
FCKToolbarBreak.prototype.Create = function( targetElement )
{
var oBreakDiv = targetElement.ownerDocument.createElement( 'div' ) ;
oBreakDiv.style.clear = oBreakDiv.style.cssFloat = FCKLang.Dir == 'rtl' ? 'right' : 'left' ;
targetElement.appendChild( oBreakDiv ) ;
}

View File

@ -0,0 +1,38 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarBreak Class: breaks the toolbars.
* It makes it possible to force the toolbar to break to a new line.
* This is the IE specific implementation.
*/
var FCKToolbarBreak = function()
{}
FCKToolbarBreak.prototype.Create = function( targetElement )
{
var oBreakDiv = FCKTools.GetElementDocument( targetElement ).createElement( 'div' ) ;
oBreakDiv.className = 'TB_Break' ;
oBreakDiv.style.clear = FCKLang.Dir == 'rtl' ? 'left' : 'right' ;
targetElement.appendChild( oBreakDiv ) ;
}

View File

@ -0,0 +1,81 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarButton Class: represents a button in the toolbar.
*/
var FCKToolbarButton = function( commandName, label, tooltip, style, sourceView, contextSensitive, icon )
{
this.CommandName = commandName ;
this.Label = label ;
this.Tooltip = tooltip ;
this.Style = style ;
this.SourceView = sourceView ? true : false ;
this.ContextSensitive = contextSensitive ? true : false ;
if ( icon == null )
this.IconPath = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
else if ( typeof( icon ) == 'number' )
this.IconPath = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
else
this.IconPath = icon ;
}
FCKToolbarButton.prototype.Create = function( targetElement )
{
this._UIButton = new FCKToolbarButtonUI( this.CommandName, this.Label, this.Tooltip, this.IconPath, this.Style ) ;
this._UIButton.OnClick = this.Click ;
this._UIButton._ToolbarButton = this ;
this._UIButton.Create( targetElement ) ;
}
FCKToolbarButton.prototype.RefreshState = function()
{
var uiButton = this._UIButton ;
if ( !uiButton )
return ;
// Gets the actual state.
var eState = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
// If there are no state changes than do nothing and return.
if ( eState == uiButton.State ) return ;
// Sets the actual state.
uiButton.ChangeState( eState ) ;
}
FCKToolbarButton.prototype.Click = function()
{
var oToolbarButton = this._ToolbarButton || this ;
FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oToolbarButton.CommandName ).Execute() ;
}
FCKToolbarButton.prototype.Enable = function()
{
this.RefreshState() ;
}
FCKToolbarButton.prototype.Disable = function()
{
// Sets the actual state.
this._UIButton.ChangeState( FCK_TRISTATE_DISABLED ) ;
}

View File

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

View File

@ -0,0 +1,139 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontFormatCombo = function( tooltip, style )
{
if ( tooltip === false )
return ;
this.CommandName = 'FontFormat' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.NormalLabel = 'Normal' ;
this.PanelWidth = 190 ;
this.DefaultLabel = FCKConfig.DefaultFontFormatLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontFormatCombo.prototype = new FCKToolbarStyleCombo( false ) ;
FCKToolbarFontFormatCombo.prototype.GetLabel = function()
{
return FCKLang.FontFormat ;
}
FCKToolbarFontFormatCombo.prototype.GetStyles = function()
{
var styles = {} ;
// Get the format names from the language file.
var aNames = FCKLang['FontFormats'].split(';') ;
var oNames = {
p : aNames[0],
pre : aNames[1],
address : aNames[2],
h1 : aNames[3],
h2 : aNames[4],
h3 : aNames[5],
h4 : aNames[6],
h5 : aNames[7],
h6 : aNames[8],
div : aNames[9] || ( aNames[0] + ' (DIV)')
} ;
// Get the available formats from the configuration file.
var elements = FCKConfig.FontFormats.split(';') ;
for ( var i = 0 ; i < elements.length ; i++ )
{
var elementName = elements[ i ] ;
var style = FCKStyles.GetStyle( '_FCK_' + elementName ) ;
if ( style )
{
style.Label = oNames[ elementName ] ;
styles[ '_FCK_' + elementName ] = style ;
}
else
alert( "The FCKConfig.CoreStyles['" + elementName + "'] setting was not found. Please check the fckconfig.js file" ) ;
}
return styles ;
}
FCKToolbarFontFormatCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
{
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var blockElement = path.Block ;
if ( blockElement )
{
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( blockElement ) )
{
targetSpecialCombo.SetLabel( style.Label ) ;
return ;
}
}
}
}
targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
}
FCKToolbarFontFormatCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var blockElement = path.Block ;
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( blockElement ) )
{
targetSpecialCombo.SelectItem( item ) ;
return ;
}
}
}
}

View File

@ -0,0 +1,98 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontsCombo = function( tooltip, style )
{
this.CommandName = 'FontName' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultFontLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontsCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
FCKToolbarFontsCombo.prototype.GetLabel = function()
{
return FCKLang.Font ;
}
FCKToolbarFontsCombo.prototype.GetStyles = function()
{
var baseStyle = FCKStyles.GetStyle( '_FCK_FontFace' ) ;
if ( !baseStyle )
{
alert( "The FCKConfig.CoreStyles['Size'] setting was not found. Please check the fckconfig.js file" ) ;
return {} ;
}
var styles = {} ;
var fonts = FCKConfig.FontNames.split(';') ;
for ( var i = 0 ; i < fonts.length ; i++ )
{
var fontParts = fonts[i].split('/') ;
var font = fontParts[0] ;
var caption = fontParts[1] || font ;
var style = FCKTools.CloneObject( baseStyle ) ;
style.SetVariable( 'Font', font ) ;
style.Label = caption ;
styles[ caption ] = style ;
}
return styles ;
}
FCKToolbarFontsCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement = FCKSelection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckActive( path ) )
{
targetSpecialCombo.SelectItem( item ) ;
return ;
}
}
}
}

View File

@ -0,0 +1,76 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarFontSizeCombo = function( tooltip, style )
{
this.CommandName = 'FontSize' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultFontSizeLabel || '' ;
this.FieldWidth = 70 ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarFontSizeCombo.prototype = new FCKToolbarFontFormatCombo( false ) ;
FCKToolbarFontSizeCombo.prototype.GetLabel = function()
{
return FCKLang.FontSize ;
}
FCKToolbarFontSizeCombo.prototype.GetStyles = function()
{
var baseStyle = FCKStyles.GetStyle( '_FCK_Size' ) ;
if ( !baseStyle )
{
alert( "The FCKConfig.CoreStyles['FontFace'] setting was not found. Please check the fckconfig.js file" ) ;
return {} ;
}
var styles = {} ;
var fonts = FCKConfig.FontSizes.split(';') ;
for ( var i = 0 ; i < fonts.length ; i++ )
{
var fontParts = fonts[i].split('/') ;
var font = fontParts[0] ;
var caption = fontParts[1] || font ;
var style = FCKTools.CloneObject( baseStyle ) ;
style.SetVariable( 'Size', font ) ;
style.Label = caption ;
styles[ caption ] = style ;
}
return styles ;
}
FCKToolbarFontSizeCombo.prototype.RefreshActiveItems = FCKToolbarStyleCombo.prototype.RefreshActiveItems ;
FCKToolbarFontSizeCombo.prototype.StyleCombo_OnBeforeClick = FCKToolbarFontsCombo.prototype.StyleCombo_OnBeforeClick ;

View File

@ -0,0 +1,103 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarPanelButton Class: represents a special button in the toolbar
* that shows a panel when pressed.
*/
var FCKToolbarPanelButton = function( commandName, label, tooltip, style, icon )
{
this.CommandName = commandName ;
var oIcon ;
if ( icon == null )
oIcon = FCKConfig.SkinPath + 'toolbar/' + commandName.toLowerCase() + '.gif' ;
else if ( typeof( icon ) == 'number' )
oIcon = [ FCKConfig.SkinPath + 'fck_strip.gif', 16, icon ] ;
var oUIButton = this._UIButton = new FCKToolbarButtonUI( commandName, label, tooltip, oIcon, style ) ;
oUIButton._FCKToolbarPanelButton = this ;
oUIButton.ShowArrow = true ;
oUIButton.OnClick = FCKToolbarPanelButton_OnButtonClick ;
}
FCKToolbarPanelButton.prototype.TypeName = 'FCKToolbarPanelButton' ;
FCKToolbarPanelButton.prototype.Create = function( parentElement )
{
parentElement.className += 'Menu' ;
this._UIButton.Create( parentElement ) ;
var oPanel = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName )._Panel ;
this.RegisterPanel( oPanel ) ;
}
FCKToolbarPanelButton.prototype.RegisterPanel = function( oPanel )
{
if ( oPanel._FCKToolbarPanelButton )
return ;
oPanel._FCKToolbarPanelButton = this ;
var eLineDiv = oPanel.Document.body.appendChild( oPanel.Document.createElement( 'div' ) ) ;
eLineDiv.style.position = 'absolute' ;
eLineDiv.style.top = '0px' ;
var eLine = oPanel._FCKToolbarPanelButtonLineDiv = eLineDiv.appendChild( oPanel.Document.createElement( 'IMG' ) ) ;
eLine.className = 'TB_ConnectionLine' ;
eLine.style.position = 'absolute' ;
// eLine.style.backgroundColor = 'Red' ;
eLine.src = FCK_SPACER_PATH ;
oPanel.OnHide = FCKToolbarPanelButton_OnPanelHide ;
}
/*
Events
*/
function FCKToolbarPanelButton_OnButtonClick( toolbarButton )
{
var oButton = this._FCKToolbarPanelButton ;
var e = oButton._UIButton.MainElement ;
oButton._UIButton.ChangeState( FCK_TRISTATE_ON ) ;
// oButton.LineImg.style.width = ( e.offsetWidth - 2 ) + 'px' ;
var oCommand = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( oButton.CommandName ) ;
var oPanel = oCommand._Panel ;
oPanel._FCKToolbarPanelButtonLineDiv.style.width = ( e.offsetWidth - 2 ) + 'px' ;
oCommand.Execute( 0, e.offsetHeight - 1, e ) ; // -1 to be over the border
}
function FCKToolbarPanelButton_OnPanelHide()
{
var oMenuButton = this._FCKToolbarPanelButton ;
oMenuButton._UIButton.ChangeState( FCK_TRISTATE_OFF ) ;
}
// The Panel Button works like a normal button so the refresh state functions
// defined for the normal button can be reused here.
FCKToolbarPanelButton.prototype.RefreshState = FCKToolbarButton.prototype.RefreshState ;
FCKToolbarPanelButton.prototype.Enable = FCKToolbarButton.prototype.Enable ;
FCKToolbarPanelButton.prototype.Disable = FCKToolbarButton.prototype.Disable ;

View File

@ -0,0 +1,146 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarSpecialCombo Class: This is a "abstract" base class to be used
* by the special combo toolbar elements like font name, font size, paragraph format, etc...
*
* The following properties and methods must be implemented when inheriting from
* this class:
* - Property: CommandName [ The command name to be executed ]
* - Method: GetLabel() [ Returns the label ]
* - CreateItems( targetSpecialCombo ) [ Add all items in the special combo ]
*/
var FCKToolbarSpecialCombo = function()
{
this.SourceView = false ;
this.ContextSensitive = true ;
this.FieldWidth = null ;
this.PanelWidth = null ;
this.PanelMaxHeight = null ;
//this._LastValue = null ;
}
FCKToolbarSpecialCombo.prototype.DefaultLabel = '' ;
function FCKToolbarSpecialCombo_OnSelect( itemId, item )
{
FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).Execute( itemId, item ) ;
}
FCKToolbarSpecialCombo.prototype.Create = function( targetElement )
{
this._Combo = new FCKSpecialCombo( this.GetLabel(), this.FieldWidth, this.PanelWidth, this.PanelMaxHeight, FCKBrowserInfo.IsIE ? window : FCKTools.GetElementWindow( targetElement ).parent ) ;
/*
this._Combo.FieldWidth = this.FieldWidth != null ? this.FieldWidth : 100 ;
this._Combo.PanelWidth = this.PanelWidth != null ? this.PanelWidth : 150 ;
this._Combo.PanelMaxHeight = this.PanelMaxHeight != null ? this.PanelMaxHeight : 150 ;
*/
//this._Combo.Command.Name = this.Command.Name;
// this._Combo.Label = this.Label ;
this._Combo.Tooltip = this.Tooltip ;
this._Combo.Style = this.Style ;
this.CreateItems( this._Combo ) ;
this._Combo.Create( targetElement ) ;
this._Combo.CommandName = this.CommandName ;
this._Combo.OnSelect = FCKToolbarSpecialCombo_OnSelect ;
}
function FCKToolbarSpecialCombo_RefreshActiveItems( combo, value )
{
combo.DeselectAll() ;
combo.SelectItem( value ) ;
combo.SetLabelById( value ) ;
}
FCKToolbarSpecialCombo.prototype.RefreshState = function()
{
// Gets the actual state.
var eState ;
// if ( FCK.EditMode == FCK_EDITMODE_SOURCE && ! this.SourceView )
// eState = FCK_TRISTATE_DISABLED ;
// else
// {
var sValue = FCK.ToolbarSet.CurrentInstance.Commands.GetCommand( this.CommandName ).GetState() ;
// FCKDebug.Output( 'RefreshState of Special Combo "' + this.TypeOf + '" - State: ' + sValue ) ;
if ( sValue != FCK_TRISTATE_DISABLED )
{
eState = FCK_TRISTATE_ON ;
if ( this.RefreshActiveItems )
this.RefreshActiveItems( this._Combo, sValue ) ;
else
{
if ( this._LastValue !== sValue)
{
this._LastValue = sValue ;
if ( !sValue || sValue.length == 0 )
{
this._Combo.DeselectAll() ;
this._Combo.SetLabel( this.DefaultLabel ) ;
}
else
FCKToolbarSpecialCombo_RefreshActiveItems( this._Combo, sValue ) ;
}
}
}
else
eState = FCK_TRISTATE_DISABLED ;
// }
// If there are no state changes then do nothing and return.
if ( eState == this.State ) return ;
if ( eState == FCK_TRISTATE_DISABLED )
{
this._Combo.DeselectAll() ;
this._Combo.SetLabel( '' ) ;
}
// Sets the actual state.
this.State = eState ;
// Updates the graphical state.
this._Combo.SetEnabled( eState != FCK_TRISTATE_DISABLED ) ;
}
FCKToolbarSpecialCombo.prototype.Enable = function()
{
this.RefreshState() ;
}
FCKToolbarSpecialCombo.prototype.Disable = function()
{
this.State = FCK_TRISTATE_DISABLED ;
this._Combo.DeselectAll() ;
this._Combo.SetLabel( '' ) ;
this._Combo.SetEnabled( false ) ;
}

View File

@ -0,0 +1,200 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKToolbarPanelButton Class: Handles the Fonts combo selector.
*/
var FCKToolbarStyleCombo = function( tooltip, style )
{
if ( tooltip === false )
return ;
this.CommandName = 'Style' ;
this.Label = this.GetLabel() ;
this.Tooltip = tooltip ? tooltip : this.Label ;
this.Style = style ? style : FCK_TOOLBARITEM_ICONTEXT ;
this.DefaultLabel = FCKConfig.DefaultStyleLabel || '' ;
}
// Inherit from FCKToolbarSpecialCombo.
FCKToolbarStyleCombo.prototype = new FCKToolbarSpecialCombo ;
FCKToolbarStyleCombo.prototype.GetLabel = function()
{
return FCKLang.Style ;
}
FCKToolbarStyleCombo.prototype.GetStyles = function()
{
var styles = {} ;
var allStyles = FCK.ToolbarSet.CurrentInstance.Styles.GetStyles() ;
for ( var styleName in allStyles )
{
var style = allStyles[ styleName ] ;
if ( !style.IsCore )
styles[ styleName ] = style ;
}
return styles ;
}
FCKToolbarStyleCombo.prototype.CreateItems = function( targetSpecialCombo )
{
var targetDoc = targetSpecialCombo._Panel.Document ;
// Add the Editor Area CSS to the panel so the style classes are previewed correctly.
FCKTools.AppendStyleSheet( targetDoc, FCKConfig.ToolbarComboPreviewCSS ) ;
FCKTools.AppendStyleString( targetDoc, FCKConfig.EditorAreaStyles ) ;
targetDoc.body.className += ' ForceBaseFont' ;
// Add ID and Class to the body.
FCKConfig.ApplyBodyAttributes( targetDoc.body ) ;
// Get the styles list.
var styles = this.GetStyles() ;
for ( var styleName in styles )
{
var style = styles[ styleName ] ;
// Object type styles have no preview.
var caption = style.GetType() == FCK_STYLE_OBJECT ?
styleName :
FCKToolbarStyleCombo_BuildPreview( style, style.Label || styleName ) ;
var item = targetSpecialCombo.AddItem( styleName, caption ) ;
item.Style = style ;
}
// We must prepare the list before showing it.
targetSpecialCombo.OnBeforeClick = this.StyleCombo_OnBeforeClick ;
}
FCKToolbarStyleCombo.prototype.RefreshActiveItems = function( targetSpecialCombo )
{
var startElement = FCK.ToolbarSet.CurrentInstance.Selection.GetBoundaryParentElement( true ) ;
if ( startElement )
{
var path = new FCKElementPath( startElement ) ;
var elements = path.Elements ;
for ( var e = 0 ; e < elements.length ; e++ )
{
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( style.CheckElementRemovable( elements[ e ], true ) )
{
targetSpecialCombo.SetLabel( style.Label || style.Name ) ;
return ;
}
}
}
}
targetSpecialCombo.SetLabel( this.DefaultLabel ) ;
}
FCKToolbarStyleCombo.prototype.StyleCombo_OnBeforeClick = function( targetSpecialCombo )
{
// Two things are done here:
// - In a control selection, get the element name, so we'll display styles
// for that element only.
// - Select the styles that are active for the current selection.
// Clear the current selection.
targetSpecialCombo.DeselectAll() ;
var startElement ;
var path ;
var tagName ;
var selection = FCK.ToolbarSet.CurrentInstance.Selection ;
if ( selection.GetType() == 'Control' )
{
startElement = selection.GetSelectedElement() ;
tagName = startElement.nodeName.toLowerCase() ;
}
else
{
startElement = selection.GetBoundaryParentElement( true ) ;
path = new FCKElementPath( startElement ) ;
}
for ( var i in targetSpecialCombo.Items )
{
var item = targetSpecialCombo.Items[i] ;
var style = item.Style ;
if ( ( tagName && style.Element == tagName ) || ( !tagName && style.GetType() != FCK_STYLE_OBJECT ) )
{
item.style.display = '' ;
if ( ( path && style.CheckActive( path ) ) || ( !path && style.CheckElementRemovable( startElement, true ) ) )
targetSpecialCombo.SelectItem( style.Name ) ;
}
else
item.style.display = 'none' ;
}
}
function FCKToolbarStyleCombo_BuildPreview( style, caption )
{
var styleType = style.GetType() ;
var html = [] ;
if ( styleType == FCK_STYLE_BLOCK )
html.push( '<div class="BaseFont">' ) ;
var elementName = style.Element ;
// Avoid <bdo> in the preview.
if ( elementName == 'bdo' )
elementName = 'span' ;
html = [ '<', elementName ] ;
// Assign all defined attributes.
var attribs = style._StyleDesc.Attributes ;
if ( attribs )
{
for ( var att in attribs )
{
html.push( ' ', att, '="', style.GetFinalAttributeValue( att ), '"' ) ;
}
}
// Assign the style attribute.
if ( style._GetStyleText().length > 0 )
html.push( ' style="', style.GetFinalStyleValue(), '"' ) ;
html.push( '>', caption, '</', elementName, '>' ) ;
if ( styleType == FCK_STYLE_BLOCK )
html.push( '</div>' ) ;
return html.join( '' ) ;
}

View File

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

View File

@ -0,0 +1,108 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKXml Class: class to load and manipulate XML files.
* (IE specific implementation)
*/
var FCKXml = function()
{
this.Error = false ;
}
FCKXml.GetAttribute = function( node, attName, defaultValue )
{
var attNode = node.attributes.getNamedItem( attName ) ;
return attNode ? attNode.value : defaultValue ;
}
/**
* Transforms a XML element node in a JavaScript object. Attributes defined for
* the element will be available as properties, as long as child element
* nodes, but the later will generate arrays with property names prefixed with "$".
*
* For example, the following XML element:
*
* <SomeNode name="Test" key="2">
* <MyChild id="10">
* <OtherLevel name="Level 3" />
* </MyChild>
* <MyChild id="25" />
* <AnotherChild price="499" />
* </SomeNode>
*
* ... results in the following object:
*
* {
* name : "Test",
* key : "2",
* $MyChild :
* [
* {
* id : "10",
* $OtherLevel :
* {
* name : "Level 3"
* }
* },
* {
* id : "25"
* }
* ],
* $AnotherChild :
* [
* {
* price : "499"
* }
* ]
* }
*/
FCKXml.TransformToObject = function( element )
{
if ( !element )
return null ;
var obj = {} ;
var attributes = element.attributes ;
for ( var i = 0 ; i < attributes.length ; i++ )
{
var att = attributes[i] ;
obj[ att.name ] = att.value ;
}
var childNodes = element.childNodes ;
for ( i = 0 ; i < childNodes.length ; i++ )
{
var child = childNodes[i] ;
if ( child.nodeType == 1 )
{
var childName = '$' + child.nodeName ;
var childList = obj[ childName ] ;
if ( !childList )
childList = obj[ childName ] = [] ;
childList.push( this.TransformToObject( child ) ) ;
}
}
return obj ;
}

View File

@ -0,0 +1,106 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKXml Class: class to load and manipulate XML files.
*/
FCKXml.prototype =
{
LoadUrl : function( urlToCall )
{
this.Error = false ;
var oXml ;
var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
oXmlHttp.open( 'GET', urlToCall, false ) ;
oXmlHttp.send( null ) ;
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 || ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 ) )
{
oXml = oXmlHttp.responseXML ;
// #1426: Fallback if responseXML isn't set for some
// reason (e.g. improperly configured web server)
if ( !oXml )
oXml = (new DOMParser()).parseFromString( oXmlHttp.responseText, 'text/xml' ) ;
}
else
oXml = null ;
if ( oXml )
{
// Try to access something on it.
try
{
var test = oXml.firstChild ;
}
catch (e)
{
// If document.domain has been changed (#123), we'll have a security
// error at this point. The workaround here is parsing the responseText:
// http://alexander.kirk.at/2006/07/27/firefox-15-xmlhttprequest-reqresponsexml-and-documentdomain/
oXml = (new DOMParser()).parseFromString( oXmlHttp.responseText, 'text/xml' ) ;
}
}
if ( !oXml || !oXml.firstChild )
{
this.Error = true ;
if ( window.confirm( 'Error loading "' + urlToCall + '" (HTTP Status: ' + oXmlHttp.status + ').\r\nDo you want to see the server response dump?' ) )
alert( oXmlHttp.responseText ) ;
}
this.DOMDocument = oXml ;
},
SelectNodes : function( xpath, contextNode )
{
if ( this.Error )
return new Array() ;
var aNodeArray = new Array();
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ;
if ( xPathResult )
{
var oNode = xPathResult.iterateNext() ;
while( oNode )
{
aNodeArray[aNodeArray.length] = oNode ;
oNode = xPathResult.iterateNext();
}
}
return aNodeArray ;
},
SelectSingleNode : function( xpath, contextNode )
{
if ( this.Error )
return null ;
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), 9, null);
if ( xPathResult && xPathResult.singleNodeValue )
return xPathResult.singleNodeValue ;
else
return null ;
}
} ;

View File

@ -0,0 +1,93 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKXml Class: class to load and manipulate XML files.
* (IE specific implementation)
*/
FCKXml.prototype =
{
LoadUrl : function( urlToCall )
{
this.Error = false ;
var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
if ( !oXmlHttp )
{
this.Error = true ;
return ;
}
oXmlHttp.open( "GET", urlToCall, false ) ;
oXmlHttp.send( null ) ;
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 || ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 ) )
{
this.DOMDocument = oXmlHttp.responseXML ;
// #1426: Fallback if responseXML isn't set for some
// reason (e.g. improperly configured web server)
if ( !this.DOMDocument || this.DOMDocument.firstChild == null )
{
this.DOMDocument = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
this.DOMDocument.async = false ;
this.DOMDocument.resolveExternals = false ;
this.DOMDocument.loadXML( oXmlHttp.responseText ) ;
}
}
else
{
this.DOMDocument = null ;
}
if ( this.DOMDocument == null || this.DOMDocument.firstChild == null )
{
this.Error = true ;
if (window.confirm( 'Error loading "' + urlToCall + '"\r\nDo you want to see more info?' ) )
alert( 'URL requested: "' + urlToCall + '"\r\n' +
'Server response:\r\nStatus: ' + oXmlHttp.status + '\r\n' +
'Response text:\r\n' + oXmlHttp.responseText ) ;
}
},
SelectNodes : function( xpath, contextNode )
{
if ( this.Error )
return new Array() ;
if ( contextNode )
return contextNode.selectNodes( xpath ) ;
else
return this.DOMDocument.selectNodes( xpath ) ;
},
SelectSingleNode : function( xpath, contextNode )
{
if ( this.Error )
return null ;
if ( contextNode )
return contextNode.selectSingleNode( xpath ) ;
else
return this.DOMDocument.selectSingleNode( xpath ) ;
}
} ;

View File

@ -0,0 +1,634 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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, customValue )
{
this.Name = name ;
this.Title = title ;
this.Url = url ;
this.Width = width ;
this.Height = height ;
this.CustomValue = customValue ;
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, this.CustomValue, null, this.Resizable ) ;
}
FCKDialogCommand.prototype.GetState = function()
{
if ( this.GetStateFunction )
return this.GetStateFunction( this.GetStateParam ) ;
else
return FCK.EditMode == FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}
// 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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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() ;
oRange.InsertNode( oFakeImage ) ;
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
}
FCKPageBreakCommand.prototype.GetState = function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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 ;
}
var FCKVisitLinkCommand = function()
{
this.Name = 'VisitLink';
}
FCKVisitLinkCommand.prototype =
{
GetState : function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
var state = FCK.GetNamedCommandState( 'Unlink' ) ;
if ( state == FCK_TRISTATE_OFF )
{
var el = FCKSelection.MoveToAncestorNode( 'A' ) ;
if ( !el.href )
state = FCK_TRISTATE_DISABLED ;
}
return state ;
},
Execute : function()
{
var el = FCKSelection.MoveToAncestorNode( 'A' ) ;
var url = el.getAttribute( '_fcksavedurl' ) || el.getAttribute( 'href', 2 ) ;
// Check if it's a full URL.
// If not full URL, we'll need to apply the BaseHref setting.
if ( ! /:\/\//.test( url ) )
{
var baseHref = FCKConfig.BaseHref ;
var parentWindow = FCK.GetInstanceObject( 'parent' ) ;
if ( !baseHref )
{
baseHref = parentWindow.document.location.href ;
baseHref = baseHref.substring( 0, baseHref.lastIndexOf( '/' ) + 1 ) ;
}
if ( /^\//.test( url ) )
{
try
{
baseHref = baseHref.match( /^.*:\/\/+[^\/]+/ )[0] ;
}
catch ( e )
{
baseHref = parentWindow.document.location.protocol + '://' + parentWindow.parent.document.location.host ;
}
}
url = baseHref + url ;
}
if ( !window.open( url, '_blank' ) )
alert( FCKLang.VisitLinkBlocked ) ;
}
} ;
// 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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return FCK.GetNamedCommandState( 'Paste' ) ;
}
} ;
// FCKRuleCommand
var FCKRuleCommand = function()
{
this.Name = 'Rule' ;
}
FCKRuleCommand.prototype =
{
Execute : function()
{
FCKUndo.SaveUndoStep() ;
FCK.InsertElement( 'hr' ) ;
},
GetState : function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return FCK.GetNamedCommandState( 'InsertHorizontalRule' ) ;
}
} ;
// FCKCutCopyCommand
var FCKCutCopyCommand = function( isCut )
{
this.Name = isCut ? 'Cut' : 'Copy' ;
}
FCKCutCopyCommand.prototype =
{
Execute : function()
{
var enabled = false ;
if ( FCKBrowserInfo.IsIE )
{
// The following seems to be the only reliable way to detect that
// cut/copy is enabled in IE. It will fire the oncut/oncopy event
// only if the security settings enabled the command to execute.
var onEvent = function()
{
enabled = true ;
} ;
var eventName = 'on' + this.Name.toLowerCase() ;
FCK.EditorDocument.body.attachEvent( eventName, onEvent ) ;
FCK.ExecuteNamedCommand( this.Name ) ;
FCK.EditorDocument.body.detachEvent( eventName, onEvent ) ;
}
else
{
try
{
// Other browsers throw an error if the command is disabled.
FCK.ExecuteNamedCommand( this.Name ) ;
enabled = true ;
}
catch(e){}
}
if ( !enabled )
alert( FCKLang[ 'PasteError' + this.Name ] ) ;
},
GetState : function()
{
// Strangely, the Cut command happens to have the correct states for
// both Copy and Cut in all browsers.
return FCK.EditMode != FCK_EDITMODE_WYSIWYG ?
FCK_TRISTATE_DISABLED :
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return FCK.GetNamedCommandState( 'Unlink') ;
}
};
var FCKDeleteDivCommand = function()
{
}
FCKDeleteDivCommand.prototype =
{
GetState : function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
var node = FCKSelection.GetParentElement() ;
var path = new FCKElementPath( node ) ;
return path.BlockLimit && path.BlockLimit.nodeName.IEquals( 'div' ) ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
},
Execute : function()
{
// Create an undo snapshot before doing anything.
FCKUndo.SaveUndoStep() ;
// Find out the nodes to delete.
var nodes = FCKDomTools.GetSelectedDivContainers() ;
// Remember the current selection position.
var range = new FCKDomRange( FCK.EditorWindow ) ;
range.MoveToSelection() ;
var bookmark = range.CreateBookmark() ;
// Delete the container DIV node.
for ( var i = 0 ; i < nodes.length ; i++)
FCKDomTools.RemoveNode( nodes[i], true ) ;
// Restore selection.
range.MoveToBookmark( bookmark ) ;
range.Select() ;
}
} ;
// FCKRuleCommand
var FCKNbsp = function()
{
this.Name = 'Non Breaking Space' ;
}
FCKNbsp.prototype =
{
Execute : function()
{
FCK.InsertHtml( '&nbsp;' ) ;
},
GetState : function()
{
return ( FCK.EditMode != FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_DISABLED : FCK_TRISTATE_OFF ) ;
}
} ;

View File

@ -0,0 +1,281 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 )
{
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() ;
}
// The common parent must not be the following tags: table, tbody, tr, ol, ul.
while ( commonParent.nodeName.IEquals( 'table', 'tbody', 'tr', 'ol', 'ul' ) )
commonParent = commonParent.parentNode ;
// Reconstruct the block list to be processed such that all resulting blocks
// satisfy parentNode == commonParent.
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 = FCKTools.GetElementDocument( block ).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 = [] ;
var elementMarkers = {} ;
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 ;
}
// Remember the blocks that were recorded down in the moveOutNodes array
// to prevent duplicates.
if ( bqParent && bqChild && !bqChild._fckblockquotemoveout )
{
moveOutNodes.push( bqChild ) ;
FCKDomTools.SetElementMarker( elementMarkers, bqChild, '_fckblockquotemoveout', true ) ;
}
}
FCKDomTools.ClearAllMarkers( elementMarkers ) ;
var movedNodes = [] ;
var processedBlockquoteBlocks = [], elementMarkers = {} ;
var noBlockLeft = function( bqBlock )
{
for ( var i = 0 ; i < bqBlock.childNodes.length ; i++ )
{
if ( FCKListsLib.BlockElements[ bqBlock.childNodes[i].nodeName.toLowerCase() ] )
return false ;
}
return true ;
} ;
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 ) ;
else if ( node == node.parentNode.lastChild )
bqBlock.parentNode.insertBefore( bqBlock.removeChild( node ), bqBlock.nextSibling ) ;
else
FCKDomTools.BreakParent( node, node.parentNode, range ) ;
// Remember the blockquote node so we can clear it later (if it becomes empty).
if ( !bqBlock._fckbqprocessed )
{
processedBlockquoteBlocks.push( bqBlock ) ;
FCKDomTools.SetElementMarker( elementMarkers, bqBlock, '_fckbqprocessed', true );
}
movedNodes.push( node ) ;
}
// Clear blockquote nodes that have become empty.
for ( var i = processedBlockquoteBlocks.length - 1 ; i >= 0 ; i-- )
{
var bqBlock = processedBlockquoteBlocks[i] ;
if ( noBlockLeft( bqBlock ) )
FCKDomTools.RemoveNode( bqBlock ) ;
}
FCKDomTools.ClearAllMarkers( elementMarkers ) ;
if ( FCKConfig.EnterMode.IEquals( 'br' ) )
{
while ( movedNodes.length )
{
var node = movedNodes.shift() ;
var firstTime = true ;
if ( node.nodeName.IEquals( 'div' ) )
{
var docFrag = FCKTools.GetElementDocument( node ).createDocumentFragment() ;
var needBeginBr = firstTime && node.previousSibling &&
!FCKListsLib.BlockBoundaries[node.previousSibling.nodeName.toLowerCase()] ;
if ( firstTime && needBeginBr )
docFrag.appendChild( FCKTools.GetElementDocument( node ).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( FCKTools.GetElementDocument( node ).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,61 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return this.IsActive ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ;
},
_OnStyleStateChange : function( styleName, isActive )
{
this.IsActive = isActive ;
}
};

View File

@ -0,0 +1,213 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ;
// Save the current selection and scroll position.
var oRange, oEditorScrollPos ;
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
{
oRange = new FCKDomRange( FCK.EditorWindow ) ;
oRange.MoveToSelection() ;
oEditorScrollPos = FCKTools.GetScrollPosition( FCK.EditorWindow ) ;
}
else
{
var eTextarea = FCK.EditingArea.Textarea ;
oRange = !FCKBrowserInfo.IsIE && [ eTextarea.selectionStart, eTextarea.selectionEnd ] ;
oEditorScrollPos = [ eTextarea.scrollLeft, eTextarea.scrollTop ] ;
}
// 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";
eEditorFrame.offsetLeft ; // Kludge for Safari 3.1 browser bug, do not remove. See #2066.
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() ;
// Restore the selection and scroll position of inside the document.
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
{
oRange.Select() ;
FCK.EditorWindow.scrollTo( oEditorScrollPos.X, oEditorScrollPos.Y ) ;
}
else
{
if ( !FCKBrowserInfo.IsIE )
{
eTextarea.selectionStart = oRange[0] ;
eTextarea.selectionEnd = oRange[1] ;
}
eTextarea.scrollLeft = oEditorScrollPos[0] ;
eTextarea.scrollTop = oEditorScrollPos[1] ;
}
}
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,282 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ) ;
iterator.EnforceRealBlocks = true ;
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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] || null ;
case 'center' :
return classes[1] || null ;
case 'right' :
return classes[2] || null ;
case 'justify' :
return classes[3] || null ;
}
}
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 = FCKSelection.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 = FCKTools.GetElementDocument( groupObj.root ).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 = FCKTools.GetElementDocument( groupObj.root ) ;
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,39 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return FCK.GetNamedCommandState( this.Name ) ;
}

View File

@ -0,0 +1,40 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return FCK.GetNamedCommandState( 'Paste' ) ;
}

View File

@ -0,0 +1,40 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || 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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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,94 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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' ;
if ( FCKBrowserInfo.IsIE )
{
try
{
FCK.EditorDocument.selection.createRange().select() ;
}
catch ( e )
{}
}
else
{
var focus = FCK.EditorWindow.getSelection().focusNode ;
if ( focus )
{
if ( focus.nodeType != 1 )
focus = focus.parentNode ;
FCKDomTools.ScrollIntoView( focus, false ) ;
}
}
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,49 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKStyleCommand Class: represents the "Spell Check" command.
* (Gecko specific implementation)
*/
var FCKSpellCheckCommand = function()
{
this.Name = 'SpellCheck' ;
this.IsEnabled = ( FCKConfig.SpellChecker != 'ieSpell' ) ;
}
FCKSpellCheckCommand.prototype.Execute = function()
{
switch ( FCKConfig.SpellChecker )
{
case 'SpellerPages' :
FCKDialog.OpenDialog( 'FCKDialog_SpellCheck', 'Spell Check', 'dialog/fck_spellerpages.html', 440, 480 ) ;
break;
case 'WSC' :
FCKDialog.OpenDialog( 'FCKDialog_SpellCheck', 'Spell Check', 'wsc/w.html', 530, 480 ) ;
}
}
FCKSpellCheckCommand.prototype.GetState = function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
return this.IsEnabled ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}

View File

@ -0,0 +1,72 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKStyleCommand Class: represents the "Spell Check" command.
* (IE specific implementation)
*/
var FCKSpellCheckCommand = function()
{
this.Name = 'SpellCheck' ;
this.IsEnabled = true ;
}
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 ;
case 'WSC' :
FCKDialog.OpenDialog( 'FCKDialog_SpellCheck', 'Spell Check', 'wsc/w.html', 530, 480 ) ;
}
}
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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.EditMode != FCK_EDITMODE_WYSIWYG || !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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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,201 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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.SkinEditorCSS ) ;
this._Panel.MainNode.className = 'FCK_Panel' ;
this._CreatePanelBody( this._Panel.Document, this._Panel.MainNode ) ;
FCK.ToolbarSet.ToolbarItems.GetItem( this.Name ).RegisterPanel( this._Panel ) ;
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()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
return FCK_TRISTATE_DISABLED ;
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', 410, 320,
FCKTools.Bind( command, 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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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,179 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 =
'window.FCKeditorAPI = {' +
'Version : "2.6.4",' +
'VersionBuild : "21629",' +
'Instances : window.FCKeditorAPI && window.FCKeditorAPI.Instances || {},' +
'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 : window.FCKeditorAPI && window.FCKeditorAPI._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.IsAIR )
{
FCKAdobeAIR.FCKeditorAPI_Evaluate( oParentWindow, sScript ) ;
}
else if ( FCKBrowserInfo.IsSafari )
{
// oParentWindow.eval in Safari 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 ;
// The __Instances properly has been changed to the public Instances,
// but we should still have the "deprecated" version of it.
FCKeditorAPI.__Instances = FCKeditorAPI.Instances ;
}
// 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.FCKConfig && FCKConfig.MsWebBrowserControlCompat
&& !window.FCKUnloadFlag )
return ;
delete FCKeditorAPI.Instances[ FCK.Name ] ;
}
function FCKeditorAPI_ConfirmCleanup()
{
if ( window.FCKConfig && FCKConfig.MsWebBrowserControlCompat )
window.FCKUnloadFlag = true ;
}
FCKTools.AddEventListener( window, 'unload', FCKeditorAPI_Cleanup ) ;
FCKTools.AddEventListener( window, 'beforeunload', FCKeditorAPI_ConfirmCleanup) ;

View File

@ -0,0 +1,159 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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.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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This is a 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 ;
FCKScriptLoader._LoadedScripts[ scriptName ] = true ;
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._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','FCKDomRange'], 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,345 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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() ;
menu.AddItem( 'VisitLink', FCKLang.VisitLink ) ;
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 ) ;
}
}} ;
case 'DivContainer':
return {
AddItems : function( menu, tag, tagName )
{
var currentBlocks = FCKDomTools.GetSelectedDivContainers() ;
if ( currentBlocks.length > 0 )
{
menu.AddSeparator() ;
menu.AddItem( 'EditDiv', FCKLang.EditDiv, 75 ) ;
menu.AddItem( 'DeleteDiv', FCKLang.DeleteDiv, 76 ) ;
}
}} ;
}
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 )
{
// IE might work incorrectly if we refocus the editor #798
if ( !FCKBrowserInfo.IsIE )
FCK.Focus() ;
FCKCommands.GetCommand( item.Name ).Execute( item.CustomData ) ;
}

View File

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

View File

@ -0,0 +1,456 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Creation and initialization of the "FCK" object. This is the main
* object that represents an editor instance.
* (IE specific implementations)
*/
FCK.Description = "FCKeditor for Internet Explorer 5.5+" ;
FCK._GetBehaviorsStyle = function()
{
if ( !FCK._BehaviorsStyle )
{
var sBasePath = FCKConfig.BasePath ;
var sTableBehavior = '' ;
var sStyle ;
// The behaviors should be pointed using the BasePath 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.IsSelectionChangeLocked && FCK.EditorDocument )
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
function Doc_OnDrop()
{
if ( FCK.MouseDownFlag )
{
FCK.MouseDownFlag = false ;
return ;
}
if ( FCKConfig.ForcePasteAsPlainText )
{
var evt = FCK.EditorWindow.event ;
if ( FCK._CheckIsPastingEnabled() || FCKConfig.ShowDropDialog )
FCK.PasteAsPlainText( evt.dataTransfer.getData( 'Text' ) ) ;
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 ) ;
this.EditorDocument.attachEvent("onbeforedeactivate", function(){ FCKSelection.Save() ; } ) ;
// Catch cursor selection changes.
this.EditorDocument.attachEvent("onselectionchange", Doc_OnSelectionChange ) ;
FCKTools.AddEventListener( FCK.EditorDocument, 'mousedown', Doc_OnMouseDown ) ;
}
FCK.InsertHtml = function( html )
{
html = FCKConfig.ProtectedSource.Protect( html ) ;
html = FCK.ProtectEvents( html ) ;
html = FCK.ProtectUrls( html ) ;
html = FCK.ProtectTags( html ) ;
// FCK.Focus() ;
FCKSelection.Restore() ;
FCK.EditorWindow.focus() ;
FCKUndo.SaveUndoStep() ;
// Gets the actual selection.
var oSel = FCKSelection.GetSelection() ;
// 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__" style="display:none;">fakeFCKRemove</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 ;
}
function _FCK_RemoveDisabledAtt()
{
this.removeAttribute( 'disabled' ) ;
}
function Doc_OnMouseDown( evt )
{
var e = evt.srcElement ;
// Radio buttons and checkboxes should not be allowed to be triggered in IE
// in editable mode. Otherwise the whole browser window may be locked by
// the buttons. (#1782)
if ( e.nodeName.IEquals( 'input' ) && e.type.IEquals( ['radio', 'checkbox'] ) && !e.disabled )
{
e.disabled = true ;
FCKTools.SetTimeout( _FCK_RemoveDisabledAtt, 1, e ) ;
}
}

View File

@ -0,0 +1,61 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Contains browser detection information.
*/
var s = navigator.userAgent.toLowerCase() ;
var FCKBrowserInfo =
{
IsIE : /*@cc_on!@*/false,
IsIE7 : /*@cc_on!@*/false && ( parseInt( s.match( /msie (\d+)/ )[1], 10 ) >= 7 ),
IsIE6 : /*@cc_on!@*/false && ( parseInt( s.match( /msie (\d+)/ )[1], 10 ) >= 6 ),
IsSafari : s.Contains(' applewebkit/'), // Read "IsWebKit"
IsOpera : !!window.opera,
IsAIR : s.Contains(' adobeair/'),
IsMac : s.Contains('macintosh')
} ;
// Completes the browser info with further Gecko information.
(function( browserInfo )
{
browserInfo.IsGecko = ( navigator.product == 'Gecko' ) && !browserInfo.IsSafari && !browserInfo.IsOpera ;
browserInfo.IsGeckoLike = ( browserInfo.IsGecko || browserInfo.IsSafari || browserInfo.IsOpera ) ;
if ( browserInfo.IsGecko )
{
var geckoMatch = s.match( /rv:(\d+\.\d+)/ ) ;
var geckoVersion = geckoMatch && parseFloat( geckoMatch[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).
if ( geckoVersion )
{
browserInfo.IsGecko10 = ( geckoVersion < 1.8 ) ;
browserInfo.IsGecko19 = ( geckoVersion > 1.8 ) ;
}
}
})(FCKBrowserInfo) ;

View File

@ -0,0 +1,100 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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|DL|DT|DD|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|DL|DT|DD|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|DL)[ \/\>]/i ;
oRegex.DecreaseIndent = /^\<\/(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR|UL|OL|DL)[ \>]/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.push( data ) - 1 ) + 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,172 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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, 380, 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, 300 ) ; break ;
case 'Unlink' : oCommand = new FCKUnlinkCommand() ; break ;
case 'VisitLink' : oCommand = new FCKVisitLinkCommand() ; break ;
case 'Anchor' : oCommand = new FCKDialogCommand( 'Anchor' , FCKLang.DlgAnchorTitle , 'dialog/fck_anchor.html' , 370, 160 ) ; break ;
case 'AnchorDelete' : oCommand = new FCKAnchorDeleteCommand() ; break ;
case 'BulletedList' : oCommand = new FCKDialogCommand( 'BulletedList', FCKLang.BulletedListProp , 'dialog/fck_listprop.html?UL' , 370, 160 ) ; break ;
case 'NumberedList' : oCommand = new FCKDialogCommand( 'NumberedList', FCKLang.NumberedListProp , 'dialog/fck_listprop.html?OL' , 370, 160 ) ; break ;
case 'About' : oCommand = new FCKDialogCommand( 'About' , FCKLang.About , 'dialog/fck_about.html' , 420, 330, function(){ return FCK_TRISTATE_OFF ; } ) ; break ;
case 'Find' : oCommand = new FCKDialogCommand( 'Find' , FCKLang.DlgFindAndReplaceTitle, 'dialog/fck_replace.html' , 340, 230, null, null, 'Find' ) ; break ;
case 'Replace' : oCommand = new FCKDialogCommand( 'Replace' , FCKLang.DlgFindAndReplaceTitle, 'dialog/fck_replace.html' , 340, 230, null, null, 'Replace' ) ; break ;
case 'Image' : oCommand = new FCKDialogCommand( 'Image' , FCKLang.DlgImgTitle , 'dialog/fck_image.html' , 450, 390 ) ; break ;
case 'Flash' : oCommand = new FCKDialogCommand( 'Flash' , FCKLang.DlgFlashTitle , 'dialog/fck_flash.html' , 450, 390 ) ; break ;
case 'SpecialChar' : oCommand = new FCKDialogCommand( 'SpecialChar', FCKLang.DlgSpecialCharTitle , 'dialog/fck_specialchar.html' , 400, 290 ) ; 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, 240 ) ; 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 'Nbsp' : oCommand = new FCKNbsp() ; 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 'CreateDiv' : oCommand = new FCKDialogCommand( 'CreateDiv', FCKLang.CreateDiv, 'dialog/fck_div.html', 380, 210, null, null, true ) ; break ;
case 'EditDiv' : oCommand = new FCKDialogCommand( 'EditDiv', FCKLang.EditDiv, 'dialog/fck_div.html', 380, 210, null, null, false ) ; break ;
case 'DeleteDiv' : oCommand = new FCKDeleteDivCommand() ; 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, 210 ) ; break ;
case 'Checkbox' : oCommand = new FCKDialogCommand( 'Checkbox' , FCKLang.Checkbox , 'dialog/fck_checkbox.html' , 380, 200 ) ; break ;
case 'Radio' : oCommand = new FCKDialogCommand( 'Radio' , FCKLang.RadioButton , 'dialog/fck_radiobutton.html' , 380, 200 ) ; break ;
case 'TextField' : oCommand = new FCKDialogCommand( 'TextField' , FCKLang.TextField , 'dialog/fck_textfield.html' , 380, 210 ) ; break ;
case 'Textarea' : oCommand = new FCKDialogCommand( 'Textarea' , FCKLang.Textarea , 'dialog/fck_textarea.html' , 380, 210 ) ; break ;
case 'HiddenField' : oCommand = new FCKDialogCommand( 'HiddenField', FCKLang.HiddenField , 'dialog/fck_hiddenfield.html' , 380, 190 ) ; break ;
case 'Button' : oCommand = new FCKDialogCommand( 'Button' , FCKLang.Button , 'dialog/fck_button.html' , 380, 210 ) ; break ;
case 'Select' : oCommand = new FCKDialogCommand( 'Select' , FCKLang.SelectionField, 'dialog/fck_select.html' , 400, 340 ) ; break ;
case 'ImageButton' : oCommand = new FCKDialogCommand( 'ImageButton', FCKLang.ImageButton , 'dialog/fck_image.html?ImageButton', 450, 390 ) ; 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 FCKCutCopyCommand( false ) ; break ;
case 'Cut' : oCommand = new FCKCutCopyCommand( true ) ; 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,237 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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) ;
}
else
FCKConfig.BasePath = document.location.protocol + '//' + document.location.host +
document.location.pathname.substring( 0, document.location.pathname.lastIndexOf( '/' ) + 1) ;
FCKConfig.FullBasePath = 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 += '/' ;
// If no ToolbarComboPreviewCSS, point it to EditorAreaCSS.
var sComboPreviewCSS = oConfig.ToolbarComboPreviewCSS ;
if ( !sComboPreviewCSS || sComboPreviewCSS.length == 0 )
oConfig.ToolbarComboPreviewCSS = oConfig.EditorAreaCSS ;
// Turn the attributes that will be removed in the RemoveFormat from a string to an array
oConfig.RemoveAttributesArray = (oConfig.RemoveAttributes || '').split( ',' );
if ( !FCKConfig.SkinEditorCSS || FCKConfig.SkinEditorCSS.length == 0 )
FCKConfig.SkinEditorCSS = FCKConfig.SkinPath + 'fck_editor.css' ;
if ( !FCKConfig.SkinDialogCSS || FCKConfig.SkinDialogCSS.length == 0 )
FCKConfig.SkinDialogCSS = FCKConfig.SkinPath + 'fck_dialog.css' ;
}
// 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.push( [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
] ;
FCKConfig.ProtectedSource.Add = function( regexPattern )
{
this.RegexEntries.push( 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,59 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Debug window control and operations.
*/
// Public function defined here must be declared in fckdebug_empty.js.
var FCKDebug =
{
Output : function( message, color, noParse )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().Output( message, color, noParse ) ;
}
catch ( e ) {} // Ignore errors
},
OutputObject : function( anyObject, color )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().OutputObject( anyObject, color ) ;
}
catch ( e ) {} // Ignore errors
},
_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 ;
}
} ;

View File

@ -0,0 +1,31 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Debug window control and operations (empty for the compressed files - #2043).
*/
var FCKDebug =
{
Output : function()
{},
OutputObject : function()
{}
} ;

View File

@ -0,0 +1,239 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Dialog windows operations.
*/
var FCKDialog = ( function()
{
var topDialog ;
var baseZIndex ;
var cover ;
// The document that holds the dialog.
var topWindow = window.parent ;
while ( topWindow.parent && topWindow.parent != topWindow )
{
try
{
if ( topWindow.parent.document.domain != document.domain )
break ;
if ( topWindow.parent.document.getElementsByTagName( 'frameset' ).length > 0 )
break ;
}
catch ( e )
{
break ;
}
topWindow = topWindow.parent ;
}
var topDocument = topWindow.document ;
var getZIndex = function()
{
if ( !baseZIndex )
baseZIndex = FCKConfig.FloatingPanelsZIndex + 999 ;
return ++baseZIndex ;
}
// TODO : This logic is not actually working when reducing the window, only
// when enlarging it.
var resizeHandler = function()
{
if ( !cover )
return ;
var relElement = FCKTools.IsStrictMode( topDocument ) ? topDocument.documentElement : topDocument.body ;
FCKDomTools.SetElementStyles( cover,
{
'width' : Math.max( relElement.scrollWidth,
relElement.clientWidth,
topDocument.scrollWidth || 0 ) - 1 + 'px',
'height' : Math.max( relElement.scrollHeight,
relElement.clientHeight,
topDocument.scrollHeight || 0 ) - 1 + 'px'
} ) ;
}
return {
/**
* Opens a dialog window using the standard dialog template.
*/
OpenDialog : function( dialogName, dialogTitle, dialogPage, width, height, customValue, parentWindow, resizable )
{
if ( !topDialog )
this.DisplayMainCover() ;
// Setup the dialog info to be passed to the dialog.
var dialogInfo =
{
Title : dialogTitle,
Page : dialogPage,
Editor : window,
CustomValue : customValue, // Optional
TopWindow : topWindow
}
FCK.ToolbarSet.CurrentInstance.Selection.Save( true ) ;
// Calculate the dialog position, centering it on the screen.
var viewSize = FCKTools.GetViewPaneSize( topWindow ) ;
var scrollPosition = { 'X' : 0, 'Y' : 0 } ;
var useAbsolutePosition = FCKBrowserInfo.IsIE && ( !FCKBrowserInfo.IsIE7 || !FCKTools.IsStrictMode( topWindow.document ) ) ;
if ( useAbsolutePosition )
scrollPosition = FCKTools.GetScrollPosition( topWindow ) ;
var iTop = Math.max( scrollPosition.Y + ( viewSize.Height - height - 20 ) / 2, 0 ) ;
var iLeft = Math.max( scrollPosition.X + ( viewSize.Width - width - 20 ) / 2, 0 ) ;
// Setup the IFRAME that will hold the dialog.
var dialog = topDocument.createElement( 'iframe' ) ;
FCKTools.ResetStyles( dialog ) ;
dialog.src = FCKConfig.BasePath + 'fckdialog.html' ;
// Dummy URL for testing whether the code in fckdialog.js alone leaks memory.
// dialog.src = 'about:blank';
dialog.frameBorder = 0 ;
dialog.allowTransparency = true ;
FCKDomTools.SetElementStyles( dialog,
{
'position' : ( useAbsolutePosition ) ? 'absolute' : 'fixed',
'top' : iTop + 'px',
'left' : iLeft + 'px',
'width' : width + 'px',
'height' : height + 'px',
'zIndex' : getZIndex()
} ) ;
// Save the dialog info to be used by the dialog page once loaded.
dialog._DialogArguments = dialogInfo ;
// Append the IFRAME to the target document.
topDocument.body.appendChild( dialog ) ;
// Keep record of the dialog's parent/child relationships.
dialog._ParentDialog = topDialog ;
topDialog = dialog ;
},
/**
* (For internal use)
* Called when the top dialog is closed.
*/
OnDialogClose : function( dialogWindow )
{
var dialog = dialogWindow.frameElement ;
FCKDomTools.RemoveNode( dialog ) ;
if ( dialog._ParentDialog ) // Nested Dialog.
{
topDialog = dialog._ParentDialog ;
dialog._ParentDialog.contentWindow.SetEnabled( true ) ;
}
else // First Dialog.
{
// Set the Focus in the browser, so the "OnBlur" event is not
// fired. In IE, there is no need to do that because the dialog
// already moved the selection to the editing area before
// closing (EnsureSelection). Also, the Focus() call here
// causes memory leak on IE7 (weird).
if ( !FCKBrowserInfo.IsIE )
FCK.Focus() ;
this.HideMainCover() ;
// Bug #1918: Assigning topDialog = null directly causes IE6 to crash.
setTimeout( function(){ topDialog = null ; }, 0 ) ;
// Release the previously saved selection.
FCK.ToolbarSet.CurrentInstance.Selection.Release() ;
}
},
DisplayMainCover : function()
{
// Setup the DIV that will be used to cover.
cover = topDocument.createElement( 'div' ) ;
FCKTools.ResetStyles( cover ) ;
FCKDomTools.SetElementStyles( cover,
{
'position' : 'absolute',
'zIndex' : getZIndex(),
'top' : '0px',
'left' : '0px',
'backgroundColor' : FCKConfig.BackgroundBlockerColor
} ) ;
FCKDomTools.SetOpacity( cover, FCKConfig.BackgroundBlockerOpacity ) ;
// For IE6-, we need to fill the cover with a transparent IFRAME,
// to properly block <select> fields.
if ( FCKBrowserInfo.IsIE && !FCKBrowserInfo.IsIE7 )
{
var iframe = topDocument.createElement( 'iframe' ) ;
FCKTools.ResetStyles( iframe ) ;
iframe.hideFocus = true ;
iframe.frameBorder = 0 ;
iframe.src = FCKTools.GetVoidUrl() ;
FCKDomTools.SetElementStyles( iframe,
{
'width' : '100%',
'height' : '100%',
'position' : 'absolute',
'left' : '0px',
'top' : '0px',
'filter' : 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'
} ) ;
cover.appendChild( iframe ) ;
}
// We need to manually adjust the cover size on resize.
FCKTools.AddEventListener( topWindow, 'resize', resizeHandler ) ;
resizeHandler() ;
topDocument.body.appendChild( cover ) ;
FCKFocusManager.Lock() ;
// Prevent the user from refocusing the disabled
// editing window by pressing Tab. (Bug #2065)
var el = FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'frameElement' ) ;
el._fck_originalTabIndex = el.tabIndex ;
el.tabIndex = -1 ;
},
HideMainCover : function()
{
FCKDomTools.RemoveNode( cover ) ;
FCKFocusManager.Unlock() ;
// Revert the tab index hack. (Bug #2065)
var el = FCK.ToolbarSet.CurrentInstance.GetInstanceObject( 'frameElement' ) ;
el.tabIndex = el._fck_originalTabIndex ;
FCKDomTools.ClearElementJSProperty( el, '_fck_originalTabIndex' ) ;
},
GetCover : function()
{
return cover ;
}
} ;
} )() ;

View File

@ -0,0 +1,270 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Advanced document processors.
*/
var FCKDocumentProcessor = new Object() ;
FCKDocumentProcessor._Items = new Array() ;
FCKDocumentProcessor.AppendNew = function()
{
var oNewItem = new Object() ;
this._Items.push( oNewItem ) ;
return oNewItem ;
}
FCKDocumentProcessor.Process = function( document )
{
var bIsDirty = FCK.IsDirty() ;
var oProcessor, i = 0 ;
while( ( oProcessor = this._Items[i++] ) )
oProcessor.ProcessDocument( document ) ;
if ( !bIsDirty )
FCK.ResetIsDirty() ;
}
var FCKDocumentProcessor_CreateFakeImage = function( fakeClass, realElement )
{
var oImg = FCKTools.GetElementDocument( realElement ).createElement( 'IMG' ) ;
oImg.className = fakeClass ;
oImg.src = FCKConfig.BasePath + '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 ) ;
}
}
*/
}
// EMBED and OBJECT tags.
var FCKEmbedAndObjectProcessor = (function()
{
var customProcessors = [] ;
var processElement = function( el )
{
var clone = el.cloneNode( true ) ;
var replaceElement ;
var fakeImg = replaceElement = FCKDocumentProcessor_CreateFakeImage( 'FCK__UnknownObject', clone ) ;
FCKEmbedAndObjectProcessor.RefreshView( fakeImg, el ) ;
for ( var i = 0 ; i < customProcessors.length ; i++ )
replaceElement = customProcessors[i]( el, replaceElement ) || replaceElement ;
if ( replaceElement != fakeImg )
FCKTempBin.RemoveElement( fakeImg.getAttribute( '_fckrealelement' ) ) ;
el.parentNode.replaceChild( replaceElement, el ) ;
}
var processElementsByName = function( elementName, doc )
{
var aObjects = doc.getElementsByTagName( elementName );
for ( var i = aObjects.length - 1 ; i >= 0 ; i-- )
processElement( aObjects[i] ) ;
}
var processObjectAndEmbed = function( doc )
{
processElementsByName( 'object', doc );
processElementsByName( 'embed', doc );
}
return FCKTools.Merge( FCKDocumentProcessor.AppendNew(),
{
ProcessDocument : function( doc )
{
// Firefox 3 would sometimes throw an unknown exception while accessing EMBEDs and OBJECTs
// without the setTimeout().
if ( FCKBrowserInfo.IsGecko )
FCKTools.RunFunction( processObjectAndEmbed, this, [ doc ] ) ;
else
processObjectAndEmbed( doc ) ;
},
RefreshView : function( placeHolder, original )
{
if ( original.getAttribute( 'width' ) > 0 )
placeHolder.style.width = FCKTools.ConvertHtmlSizeToStyle( original.getAttribute( 'width' ) ) ;
if ( original.getAttribute( 'height' ) > 0 )
placeHolder.style.height = FCKTools.ConvertHtmlSizeToStyle( original.getAttribute( 'height' ) ) ;
},
AddCustomHandler : function( func )
{
customProcessors.push( func ) ;
}
} ) ;
} )() ;
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 ) ;
}
}
}
// Flash handler.
FCKEmbedAndObjectProcessor.AddCustomHandler( function( el, fakeImg )
{
if ( ! ( el.nodeName.IEquals( 'embed' ) && ( el.type == 'application/x-shockwave-flash' || /\.swf($|#|\?)/i.test( el.src ) ) ) )
return ;
fakeImg.className = 'FCK__Flash' ;
fakeImg.setAttribute( '_fckflash', 'true', 0 );
} ) ;
// Buggy <span class="Apple-style-span"> tags added by Safari.
if ( FCKBrowserInfo.IsSafari )
{
FCKDocumentProcessor.AppendNew().ProcessDocument = function( doc )
{
var spans = doc.getElementsByClassName ?
doc.getElementsByClassName( 'Apple-style-span' ) :
Array.prototype.filter.call(
doc.getElementsByTagName( 'span' ),
function( item ){ return item.className == 'Apple-style-span' ; }
) ;
for ( var i = spans.length - 1 ; i >= 0 ; i-- )
FCKDomTools.RemoveNode( spans[i], true ) ;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,165 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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',
'fr-ca' : 'French (Canada)',
gl : 'Galician',
gu : 'Gujarati',
he : 'Hebrew',
hi : 'Hindi',
hr : 'Croatian',
hu : 'Hungarian',
is : 'Icelandic',
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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,63 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 that accept text nodes, but are not possible to edit in the browser.
NonEditableElements : { button:1,option:1,script:1,iframe:1,textarea:1,object:1,embed:1,map:1,applet: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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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,100 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ,
HtmlDocType : /DTD HTML/ ,
// 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]*)$/,
HtmlTag : /<[^\s<>](?:"[^"]*"|'[^']*'|[^<])*>/
} ;

View File

@ -0,0 +1,42 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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,228 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 = this.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 selection = !!FCK.EditorWindow && this.GetSelection() ;
if ( !selection || selection.rangeCount < 1 )
return null ;
var range = selection.getRangeAt( 0 ) ;
if ( range.startContainer != range.endContainer || range.startContainer.nodeType != 1 || range.startOffset != range.endOffset - 1 )
return null ;
var node = range.startContainer.childNodes[ range.startOffset ] ;
if ( node.nodeType != 1 )
return null ;
return node ;
}
FCKSelection.GetParentElement = function()
{
if ( this.GetType() == 'Control' )
return FCKSelection.GetSelectedElement().parentNode ;
else
{
var oSel = this.GetSelection() ;
if ( oSel )
{
// if anchorNode == focusNode, see if the selection is text only or including nodes.
// if text only, return the parent node.
// if the selection includes DOM nodes, then the anchorNode is the nearest container.
if ( oSel.anchorNode && oSel.anchorNode == oSel.focusNode )
{
var oRange = oSel.getRangeAt( 0 ) ;
if ( oRange.collapsed || oRange.startContainer.nodeType == 3 )
return oSel.anchorNode.parentNode ;
else
return oSel.anchorNode ;
}
// 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 = this.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 = this.GetSelection() ;
oSel.removeAllRanges() ;
oSel.addRange( oRange ) ;
}
FCKSelection.Collapse = function( toStart )
{
var oSel = this.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 = this.GetSelection().getRangeAt(0).startContainer ; }
catch(e){}
}
while ( oContainer )
{
if ( oContainer.nodeType == 1 && oContainer.nodeName.IEquals( 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 = this.GetSelection().getRangeAt(0).startContainer ;
while ( oContainer )
{
if ( oContainer.nodeName.IEquals( nodeTagName ) )
return oContainer ;
oContainer = oContainer.parentNode ;
}
return null ;
}
FCKSelection.Delete = function()
{
// Gets the actual selection.
var oSel = this.GetSelection() ;
// Deletes the actual selection contents.
for ( var i = 0 ; i < oSel.rangeCount ; i++ )
{
oSel.getRangeAt(i).deleteContents() ;
}
return oSel ;
}
/**
* Returns the native selection object.
*/
FCKSelection.GetSelection = function()
{
return FCK.EditorWindow.getSelection() ;
}
// The following are IE only features (we don't need then in other browsers
// currently).
FCKSelection.Save = function()
{}
FCKSelection.Restore = function()
{}
FCKSelection.Release = function()
{}

View File

@ -0,0 +1,287 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 = FCKSelection.GetSelection().type ;
if ( ieType == 'Control' || ieType == 'Text' )
return ieType ;
if ( this.GetSelection().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 = this.GetSelection().createRange() ;
if ( oRange && oRange.item )
return this.GetSelection().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 this.GetSelection().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() ;
this.GetSelection().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 = this.GetSelection().createRange() ;
oRange.collapse( toStart == null || toStart === true ) ;
oRange.select() ;
}
} ;
// The "nodeTagName" parameter must be Upper Case.
FCKSelection.HasAncestorNode = function( nodeTagName )
{
var oContainer ;
if ( this.GetSelection().type == "Control" )
{
oContainer = this.GetSelectedElement() ;
}
else
{
var oRange = this.GetSelection().createRange() ;
oContainer = oRange.parentElement() ;
}
while ( oContainer )
{
if ( oContainer.nodeName.IEquals( nodeTagName ) ) return true ;
oContainer = oContainer.parentNode ;
}
return false ;
} ;
// The "nodeTagName" parameter must be UPPER CASE.
// It can be also an array of names
FCKSelection.MoveToAncestorNode = function( nodeTagName )
{
var oNode, oRange ;
if ( ! FCK.EditorDocument )
return null ;
if ( this.GetSelection().type == "Control" )
{
oRange = this.GetSelection().createRange() ;
for ( i = 0 ; i < oRange.length ; i++ )
{
if (oRange(i).parentNode)
{
oNode = oRange(i).parentNode ;
break ;
}
}
}
else
{
oRange = this.GetSelection().createRange() ;
oNode = oRange.parentElement() ;
}
while ( oNode && !oNode.nodeName.Equals( nodeTagName ) )
oNode = oNode.parentNode ;
return oNode ;
} ;
FCKSelection.Delete = function()
{
// Gets the actual selection.
var oSel = this.GetSelection() ;
// Deletes the actual selection contents.
if ( oSel.type.toLowerCase() != "none" )
{
oSel.clear() ;
}
return oSel ;
} ;
/**
* Returns the native selection object.
*/
FCKSelection.GetSelection = function()
{
this.Restore() ;
return FCK.EditorDocument.selection ;
}
FCKSelection.Save = function( lock )
{
var editorDocument = FCK.EditorDocument ;
if ( !editorDocument )
return ;
// Avoid saving again a selection while a dialog is open #2616
if ( this.locked )
return ;
this.locked = !!lock ;
var selection = editorDocument.selection ;
var range ;
if ( selection )
{
// The call might fail if the document doesn't have the focus (#1801),
// but we don't want to modify the current selection (#2495) with a call to FCK.Focus() ;
try {
range = selection.createRange() ;
}
catch(e) {}
// Ensure that the range comes from the editor document.
if ( range )
{
if ( range.parentElement && FCKTools.GetElementDocument( range.parentElement() ) != editorDocument )
range = null ;
else if ( range.item && FCKTools.GetElementDocument( range.item(0) )!= editorDocument )
range = null ;
}
}
this.SelectionData = range ;
}
FCKSelection._GetSelectionDocument = function( selection )
{
var range = selection.createRange() ;
if ( !range )
return null;
else if ( range.item )
return FCKTools.GetElementDocument( range.item( 0 ) ) ;
else
return FCKTools.GetElementDocument( range.parentElement() ) ;
}
FCKSelection.Restore = function()
{
if ( this.SelectionData )
{
FCK.IsSelectionChangeLocked = true ;
try
{
// Don't repeat the restore process if the editor document is already selected.
if ( String( this._GetSelectionDocument( FCK.EditorDocument.selection ).body.contentEditable ) == 'true' )
{
FCK.IsSelectionChangeLocked = false ;
return ;
}
this.SelectionData.select() ;
}
catch ( e ) {}
FCK.IsSelectionChangeLocked = false ;
}
}
FCKSelection.Release = function()
{
this.locked = false ;
delete this.SelectionData ;
}

View File

@ -0,0 +1,381 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ( state != ( style._LastState || null ) )
{
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 ) ;
else
FCKDomTools.RemoveAttributes( currentNode, FCKConfig.RemoveAttributesArray );
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,863 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 = aCells[i].parentNode ;
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 through 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 doesn'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] ;
oRow.insertBefore( oCell, ( insertBefore ? oBaseCell : oBaseCell.nextSibling ) ) ;
}
}
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( cell.parentNode ) ;
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++ )
{
FCKDomTools.ClearElementJSProperty(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 ;
// Check if the selected cells are all in the same table section (thead, tfoot or tbody)
for (var i = 0; i < cells.length; i++)
{
if ( cells[i].parentNode.parentNode != cells[0].parentNode.parentNode )
return false ;
}
this._MarkCells( cells, '_CellSelected' ) ;
var tableMap = this._CreateTableMap( cells[0] ) ;
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 ) ;
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 = FCKTools.GetElementDocument( refCell ).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( FCK.EditorDocument.createElement( 'br' ) ) ;
}
this._ReplaceCellsByMarker( tableMap, '_SelectedCells', refCell ) ;
this._UnmarkCells( cells, '_SelectedCells' ) ;
this._InstallTableMap( tableMap, refCell.parentNode.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.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 = FCKTools.GetElementDocument( refCell ).createDocumentFragment() ;
while ( nextCell && nextCell.childNodes && nextCell.childNodes.length > 0 )
cellContents.appendChild( nextCell.removeChild( nextCell.firstChild ) ) ;
if ( cellContents.firstChild )
cellContents.insertBefore( FCK.EditorDocument.createElement( 'br' ), cellContents.firstChild ) ;
refCell.appendChild( cellContents ) ;
this._MarkCells( [nextCell], '_Replace' ) ;
this._ReplaceCellsByMarker( tableMap, '_Replace', refCell ) ;
this._InstallTableMap( tableMap, refCell.parentNode.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 ) ;
var rowIdx = refCell.parentNode.rowIndex ;
var colIdx = FCKTableHandler._GetCellIndexSpan( tableMap, rowIdx, refCell ) ;
var cellSpan = isNaN( refCell.colSpan ) ? 1 : refCell.colSpan ;
if ( cellSpan > 1 )
{
// Splitting 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 = FCK.EditorDocument.createElement( refCell.nodeName ) ;
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( FCK.EditorDocument.createElement( refCell.nodeName ) ) ;
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.parentNode ) ;
}
FCKTableHandler.VerticalSplitCell = function()
{
var cells = FCKTableHandler.GetSelectedCells() ;
if ( cells.length != 1 )
return ;
var currentCell = cells[0] ;
var tableMap = this._CreateTableMap( currentCell ) ;
var currentRowIndex = currentCell.parentNode.rowIndex ;
var cellIndex = FCKTableHandler._GetCellIndexSpan( tableMap, currentRowIndex, currentCell ) ;
// Save current cell colSpan
var currentColSpan = isNaN( currentCell.colSpan ) ? 1 : currentCell.colSpan ;
var currentRowSpan = currentCell.rowSpan ;
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 oRow = tableMap[newCellRowIndex] ;
var insertMarker = null ;
for ( var i = cellIndex+1 ; i < oRow.length ; i++ )
{
if ( oRow[i].parentNode.rowIndex == newCellRowIndex )
{
insertMarker = oRow[i] ;
break ;
}
}
// 3. Insert the new cell to the indicated place, with the appropriate rowSpan and colSpan, next row.
var newCell = FCK.EditorDocument.createElement( currentCell.nodeName ) ;
newCell.rowSpan = Math.floor( currentRowSpan / 2 ) ;
if ( currentColSpan > 1 )
newCell.colSpan = currentColSpan ;
if ( FCKBrowserInfo.IsGeckoLike )
FCKTools.AppendBogusBr( newCell ) ;
currentCell.parentNode.parentNode.parentNode.rows[newCellRowIndex].insertBefore( newCell, insertMarker ) ;
}
else
{
// 1. Insert a new row.
var newSectionRowIdx = currentCell.parentNode.sectionRowIndex + 1 ;
var newRow = FCK.EditorDocument.createElement( 'tr' ) ;
var tSection = currentCell.parentNode.parentNode ;
if ( tSection.rows.length > newSectionRowIdx )
tSection.insertBefore( newRow, tSection.rows[newSectionRowIdx] ) ;
else
tSection.appendChild( newRow ) ;
// 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. Set colSpan on the new cell.
var newCell = FCK.EditorDocument.createElement( currentCell.nodeName ) ;
if ( currentColSpan > 1 )
newCell.colSpan = currentColSpan ;
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 ;
}
// 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, Cell3
// Cell4, Cell2, Cell2, Cell5
// Cell6, Cell2, Cell2, Cell7
FCKTableHandler._CreateTableMap = function( refCell )
{
var table = (refCell.nodeName == 'TABLE' ? refCell : refCell.parentNode.parentNode.parentNode ) ;
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 )
{
// Workaround for #1917 : MSIE will always report a cell's rowSpan as 1 as long
// as the cell is not attached to a row. So we'll need an alternative attribute
// for storing the calculated rowSpan in IE.
var rowSpanAttr = FCKBrowserInfo.IsIE ? "_fckrowspan" : "rowSpan" ;
// 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[rowSpanAttr] = 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[rowSpanAttr]++ ;
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] ;
FCKDomTools.ClearElementJSProperty(cell, '_colScanned' ) ;
FCKDomTools.ClearElementJSProperty(cell, '_rowScanned' ) ;
}
}
// Insert physical rows and columns to the table.
for ( var i = 0 ; i < tableMap.length ; i++ )
{
var rowObj = FCK.EditorDocument.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 ) ;
if ( rowSpanAttr != 'rowSpan' )
{
cell.rowSpan = cell[rowSpanAttr] ;
cell.removeAttribute( rowSpanAttr ) ;
}
j += cell.colSpan ;
if ( cell.colSpan == 1 )
cell.removeAttribute( 'colspan' ) ;
if ( cell.rowSpan == 1 )
cell.removeAttribute( 'rowspan' ) ;
}
if ( FCKBrowserInfo.IsIE )
{
table.rows[i].replaceNode( rowObj ) ;
}
else
{
table.rows[i].innerHTML = '' ;
FCKDomTools.MoveChildren( rowObj, table.rows[i] ) ;
}
}
}
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 ) ;
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 ) ;
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 ;
// Check if the selected cells are both in the same table section (thead, tfoot or tbody).
if ( refCell.parentNode.parentNode != nextCell.parentNode.parentNode )
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Manage table operations (non-IE).
*/
FCKTableHandler.GetSelectedCells = function()
{
var aCells = new Array() ;
var oSelection = FCKSelection.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.nodeName.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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Manage table operations (IE specific).
*/
FCKTableHandler.GetSelectedCells = function()
{
if ( FCKSelection.GetType() == 'Control' )
{
var td = FCKSelection.MoveToAncestorNode( ['TD', 'TH'] ) ;
return td ? [ td ] : [] ;
}
var aCells = new Array() ;
var oRange = FCKSelection.GetSelection().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,124 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 'CreateDiv' : oItem = new FCKToolbarButton( 'CreateDiv' , FCKLang.CreateDiv, null, null, false, true, 74 ) ; 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,399 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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 )
{
if ( FCKBrowserInfo.IsAIR )
FCKAdobeAIR.ToolbarSet_GetOutElement( window, oOutMatch ) ;
else
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 = window.onload = '
+ 'function(){' // poll scrollHeight until it no longer changes for 1 sec.
+ 'var timer = null;'
+ 'var lastHeight = -1;'
+ 'var lastChange = 0;'
+ 'var poller = function(){'
+ 'var currentHeight = document.body.scrollHeight || 0;'
+ 'var currentTime = (new Date()).getTime();'
+ 'if (currentHeight != lastHeight){'
+ 'lastChange = currentTime;'
+ 'adjust();'
+ 'lastHeight = document.body.scrollHeight;'
+ '}'
+ 'if (lastChange < currentTime - 1000) clearInterval(timer);'
+ '};'
+ 'timer = setInterval(poller, 100);'
+ '}'
+ '</script></head><body style="overflow: hidden">' + document.getElementById( 'xToolbarSpace' ).innerHTML + '</body></html>' ) ;
eTargetDocument.close() ;
if( FCKBrowserInfo.IsAIR )
FCKAdobeAIR.ToolbarSet_InitOutFrame( eTargetDocument ) ;
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.SkinEditorCSS ) ;
oToolbarSet = eToolbarTarget.__FCKToolbarSet = new FCKToolbarSet( eTargetDocument ) ;
oToolbarSet._IFrame = eToolbarIFrame ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( eToolbarTarget, FCKToolbarSet_Target_Cleanup ) ;
}
oToolbarSet.CurrentInstance = FCK ;
if ( !oToolbarSet.ToolbarItems )
oToolbarSet.ToolbarItems = FCKToolbarItems ;
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,749 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 ;
}
/**
* Fixes relative URL entries defined inside CSS styles by appending a prefix
* to them.
* @param (String) cssStyles The CSS styles definition possibly containing url()
* paths.
* @param (String) urlFixPrefix The prefix to append to relative URLs.
*/
FCKTools.FixCssUrls = function( urlFixPrefix, cssStyles )
{
if ( !urlFixPrefix || urlFixPrefix.length == 0 )
return cssStyles ;
return cssStyles.replace( /url\s*\(([\s'"]*)(.*?)([\s"']*)\)/g, function( match, opener, path, closer )
{
if ( /^\/|^\w?:/.test( path ) )
return match ;
else
return 'url(' + opener + urlFixPrefix + path + closer + ')' ;
} ) ;
}
FCKTools._GetUrlFixedCss = function( cssStyles, urlFixPrefix )
{
var match = cssStyles.match( /^([^|]+)\|([\s\S]*)/ ) ;
if ( match )
return FCKTools.FixCssUrls( match[1], match[2] ) ;
else
return cssStyles ;
}
/**
* Appends a <link css> or <style> element to the document.
* @param (Object) documentElement The DOM document object to which append the
* stylesheet.
* @param (Variant) cssFileOrDef A String pointing to the CSS file URL or an
* Array with many CSS file URLs or the CSS definitions for the <style>
* element.
* @return {Array} An array containing all elements created in the target
* document. It may include <link> or <style> elements, depending on the
* value passed with cssFileOrDef.
*/
FCKTools.AppendStyleSheet = function( domDocument, cssFileOrArrayOrDef )
{
if ( !cssFileOrArrayOrDef )
return [] ;
if ( typeof( cssFileOrArrayOrDef ) == 'string' )
{
// Test if the passed argument is an URL.
if ( /[\\\/\.][^{}]*$/.test( cssFileOrArrayOrDef ) )
{
// The string may have several URLs separated by comma.
return this.AppendStyleSheet( domDocument, cssFileOrArrayOrDef.split(',') ) ;
}
else
return [ this.AppendStyleString( domDocument, FCKTools._GetUrlFixedCss( cssFileOrArrayOrDef ) ) ] ;
}
else
{
var styles = [] ;
for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ )
styles.push( this._AppendStyleSheet( domDocument, cssFileOrArrayOrDef[i] ) ) ;
return styles ;
}
}
FCKTools.GetStyleHtml = (function()
{
var getStyle = function( styleDef, markTemp )
{
if ( styleDef.length == 0 )
return '' ;
var temp = markTemp ? ' _fcktemp="true"' : '' ;
return '<' + 'style type="text/css"' + temp + '>' + styleDef + '<' + '/style>' ;
}
var getLink = function( cssFileUrl, markTemp )
{
if ( cssFileUrl.length == 0 )
return '' ;
var temp = markTemp ? ' _fcktemp="true"' : '' ;
return '<' + 'link href="' + cssFileUrl + '" type="text/css" rel="stylesheet" ' + temp + '/>' ;
}
return function( cssFileOrArrayOrDef, markTemp )
{
if ( !cssFileOrArrayOrDef )
return '' ;
if ( typeof( cssFileOrArrayOrDef ) == 'string' )
{
// Test if the passed argument is an URL.
if ( /[\\\/\.][^{}]*$/.test( cssFileOrArrayOrDef ) )
{
// The string may have several URLs separated by comma.
return this.GetStyleHtml( cssFileOrArrayOrDef.split(','), markTemp ) ;
}
else
return getStyle( this._GetUrlFixedCss( cssFileOrArrayOrDef ), markTemp ) ;
}
else
{
var html = '' ;
for ( var i = 0 ; i < cssFileOrArrayOrDef.length ; i++ )
html += getLink( cssFileOrArrayOrDef[i], markTemp ) ;
return html ;
}
}
})() ;
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 for that browser.
return ( 'CSS1Compat' == ( document.compatMode || ( FCKBrowserInfo.IsSafari ? 'CSS1Compat' : null ) ) ) ;
}
// 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 = curNode.contentWindow.parent ;
}
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.document.body, 'position') != 'static'
|| ( FCKBrowserInfo.IsIE && FCKDomTools.GetPositionedAncestor( 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 ;
}
/**
* Binding the "this" reference to an object for a function.
*/
FCKTools.Bind = function( subject, func )
{
return function(){ return func.apply( subject, arguments ) ; } ;
}
/**
* Retrieve the correct "empty iframe" URL for the current browser, which
* causes the minimum fuzz (e.g. security warnings in HTTPS, DNS error in
* IE5.5, etc.) for that browser, making the iframe ready to DOM use whithout
* having to loading an external file.
*/
FCKTools.GetVoidUrl = function()
{
if ( FCK_IS_CUSTOM_DOMAIN )
return "javascript: void( function(){" +
"document.open();" +
"document.write('<html><head><title></title></head><body></body></html>');" +
"document.domain = '" + FCK_RUNTIME_DOMAIN + "';" +
"document.close();" +
"}() ) ;";
if ( FCKBrowserInfo.IsIE )
{
if ( FCKBrowserInfo.IsIE7 || !FCKBrowserInfo.IsIE6 )
return "" ; // IE7+ / IE5.5
else
return "javascript: '';" ; // IE6+
}
return "javascript: void(0);" ; // All other browsers.
}
FCKTools.ResetStyles = function( element )
{
element.style.cssText = 'margin:0;' +
'padding:0;' +
'border:0;' +
'background-color:transparent;' +
'background-image:none;' ;
}

View File

@ -0,0 +1,282 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 if ( FCKBrowserInfo.IsSafari )
element.style.KhtmlUserSelect = 'none' ; // WebKit 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 )
{
if ( !cssStyles )
return null ;
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' :
// Originaly, we were had the following here:
// return document.implementation.createDocument( '', '', null ) ;
// But that doesn't work if we're running under domain relaxation mode, so we need a workaround.
// See http://ajaxian.com/archives/xml-messages-with-cross-domain-json about the trick we're using.
var doc = ( new DOMParser() ).parseFromString( '<tmp></tmp>', 'text/xml' ) ;
FCKDomTools.RemoveNode( doc.firstChild ) ;
return doc ;
}
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 targetWindow.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,234 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* 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 )
{
if ( !cssStyles )
return null ;
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' :
// Try the native XMLHttpRequest introduced with IE7.
if ( document.location.protocol != 'file:' )
try { return new XMLHttpRequest() ; } catch (e) {}
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,223 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*/
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()
{
FCKSelection.Restore() ;
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-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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,534 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKXHtml object, responsible for the XHTML operations.
*/
var FCKXHtml = new Object() ;
FCKXHtml.CurrentJobNum = 0 ;
FCKXHtml.GetXHTML = function( node, includeNode, format )
{
FCKDomTools.CheckAndRemovePaddingNode( FCKTools.GetElementDocument( node ), 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() ;
// According to the doctype set the proper end for self-closing tags
// HTML: <br>
// XHTML: Add a space, like <br/> -> <br />
if (FCKConfig.DocType.length > 0 && FCKRegexLib.HtmlDocType.test( FCKConfig.DocType ) )
sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, '>');
else
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.hasAttribute('_moz_editor_bogus_node') || htmlNode.getAttribute( 'type' ) == '_moz' ) )
{
if ( htmlNode.nextSibling )
return false ;
else
{
htmlNode.removeAttribute( '_moz_editor_bogus_node' ) ;
htmlNode.removeAttribute( 'type' ) ;
}
}
// 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.push( item ) - 1 ) ;
}
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 ) ;
// Bug #768 : If the width and height are defined inline CSS,
// don't define it again in the HTML attributes.
if ( htmlNode.style.width )
node.removeAttribute( 'width' ) ;
if ( htmlNode.style.height )
node.removeAttribute( 'height' ) ;
return node ;
},
// Fix orphaned <li> nodes (Bug #503).
li : function( node, htmlNode, targetNode )
{
// If the XML parent node is already a <ul> or <ol>, then add the <li> as usual.
if ( targetNode.nodeName.IEquals( ['ul', 'ol'] ) )
return FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
var newTarget = FCKXHtml.XML.createElement( 'ul' ) ;
// Reset the _fckxhtmljob so the HTML node is processed again.
htmlNode._fckxhtmljob = null ;
// Loop through all sibling LIs, adding them to the <ul>.
do
{
FCKXHtml._AppendNode( newTarget, htmlNode ) ;
// Look for the next element following this <li>.
do
{
htmlNode = FCKDomTools.GetNextSibling( htmlNode ) ;
} while ( htmlNode && htmlNode.nodeType == 3 && htmlNode.nodeValue.Trim().length == 0 )
} while ( htmlNode && htmlNode.nodeName.toLowerCase() == 'li' )
return newTarget ;
},
// 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,114 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKXHtml object, responsible for the XHTML operations.
* Gecko specific.
*/
FCKXHtml._GetMainXmlString = function()
{
return ( new XMLSerializer() ).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 ;
}
}
if ( FCKBrowserInfo.IsGecko )
{
// #2162, some Firefox extensions might add references to internal links
FCKXHtml.TagProcessors['link'] = function( node, htmlNode )
{
if ( htmlNode.href.substr(0, 9).toLowerCase() == 'chrome://' )
return false ;
return node ;
}
}

View File

@ -0,0 +1,213 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines 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,
bHasStyle ;
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' )
{
// Just mark it to do it later in this function.
bHasStyle = true ;
continue ;
}
// 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 ) ;
}
}
// IE loses the style attribute in JavaScript-created elements tags. (#2390)
if ( bHasStyle || htmlNode.style.cssText.length > 0 )
{
var data = FCKTools.ProtectFormStyles( htmlNode ) ;
var sStyleValue = htmlNode.style.cssText.replace( FCKRegexLib.StyleProperties, FCKTools.ToLowerCase ) ;
FCKTools.RestoreFormStyles( htmlNode, data ) ;
this._AppendAttribute( node, 'style', sStyleValue ) ;
}
}
// 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,357 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This 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', // Opera and Safari don't encode it in their implementation
'ˆ':'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 = {
'>':'gt' // Opera and Safari don't encode it in their implementation
} ;
sChars = '>';
// 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,114 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This is 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;
}
/**
* Uncomment the following block, or only selected lines if appropriate,
* if you have some style items that would break the styles combo box.
* You can also write other CSS overrides inside the style block below
* as needed and they will be applied to inside the style combo only.
*/
/*
.SC_Item *, .SC_ItemSelected *
{
margin: 0px !important;
padding: 0px !important;
text-indent: 0px !important;
clip: auto !important;
position: static !important;
}
*/
/**
* 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;
}
.quote {
border-left: 2px solid blue ! important;
margin-left: 3px ! important;
padding-left: 3px ! important;
}

View File

@ -0,0 +1,199 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* This CSS Style Sheet defines rules used by the editor for its internal use.
*/
/* #########
* WARNING
* #########
* When changing this file, the minified version of it must be updated in the
* fckeditor.html file (see FCK_InternalCSS).
*/
/* 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;
}
.FCK__UnknownObject
{
border: #a9a9a9 1px solid;
background-position: center center;
background-image: url(images/fck_plugin.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