initial commit

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,359 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Component that creates floating panels. It is used by many
* other components, like the toolbar items, context menu, etc...
*/
var FCKPanel = function( parentWindow )
{
this.IsRTL = ( FCKLang.Dir == 'rtl' ) ;
this.IsContextMenu = false ;
this._LockCounter = 0 ;
this._Window = parentWindow || window ;
var oDocument ;
if ( FCKBrowserInfo.IsIE )
{
// Create the Popup that will hold the panel.
this._Popup = this._Window.createPopup() ;
oDocument = this.Document = this._Popup.document ;
FCK.IECleanup.AddItem( this, FCKPanel_Cleanup ) ;
}
else
{
var oIFrame = this._IFrame = this._Window.document.createElement('iframe') ;
oIFrame.src = 'javascript:void(0)' ;
oIFrame.allowTransparency = true ;
oIFrame.frameBorder = '0' ;
oIFrame.scrolling = 'no' ;
oIFrame.width = oIFrame.height = 0 ;
FCKDomTools.SetElementStyles( oIFrame,
{
position : 'absolute',
zIndex : FCKConfig.FloatingPanelsZIndex
} ) ;
if ( this._Window == window.parent && window.frameElement )
{
var scrollPos = null ;
if ( FCKBrowserInfo.IsGecko && FCK && FCK.EditorDocument )
scrollPos = [ FCK.EditorDocument.body.scrollLeft, FCK.EditorDocument.body.scrollTop ] ;
window.frameElement.parentNode.insertBefore( oIFrame, window.frameElement ) ;
if ( scrollPos )
{
var restoreFunc = function()
{
FCK.EditorDocument.body.scrollLeft = scrollPos[0] ;
FCK.EditorDocument.body.scrollTop = scrollPos[1] ;
}
setTimeout( restoreFunc, 500 ) ;
}
}
else
this._Window.document.body.appendChild( oIFrame ) ;
var oIFrameWindow = oIFrame.contentWindow ;
oDocument = this.Document = oIFrameWindow.document ;
// Workaround for Safari 12256. Ticket #63
var sBase = '' ;
if ( FCKBrowserInfo.IsSafari )
sBase = '<base href="' + window.document.location + '">' ;
// Initialize the IFRAME document body.
oDocument.open() ;
oDocument.write( '<html><head>' + sBase + '<\/head><body style="margin:0px;padding:0px;"><\/body><\/html>' ) ;
oDocument.close() ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'focus', FCKPanel_Window_OnFocus, this ) ;
FCKTools.AddEventListenerEx( oIFrameWindow, 'blur', FCKPanel_Window_OnBlur, this ) ;
}
oDocument.dir = FCKLang.Dir ;
FCKTools.AddEventListener( oDocument, 'contextmenu', FCKTools.CancelEvent ) ;
// Create the main DIV that is used as the panel base.
this.MainNode = oDocument.body.appendChild( oDocument.createElement('DIV') ) ;
// The "float" property must be set so Firefox calculates the size correctly.
this.MainNode.style.cssFloat = this.IsRTL ? 'right' : 'left' ;
}
FCKPanel.prototype.AppendStyleSheet = function( styleSheet )
{
FCKTools.AppendStyleSheet( this.Document, styleSheet ) ;
}
FCKPanel.prototype.Preload = function( x, y, relElement )
{
// The offsetWidth and offsetHeight properties are not available if the
// element is not visible. So we must "show" the popup with no size to
// be able to use that values in the second call (IE only).
if ( this._Popup )
this._Popup.show( x, y, 0, 0, relElement ) ;
}
FCKPanel.prototype.Show = function( x, y, relElement, width, height )
{
var iMainWidth ;
var eMainNode = this.MainNode ;
if ( this._Popup )
{
// The offsetWidth and offsetHeight properties are not available if the
// element is not visible. So we must "show" the popup with no size to
// be able to use that values in the second call.
this._Popup.show( x, y, 0, 0, relElement ) ;
// The following lines must be place after the above "show", otherwise it
// doesn't has the desired effect.
FCKDomTools.SetElementStyles( eMainNode,
{
width : width ? width + 'px' : '',
height : height ? height + 'px' : ''
} ) ;
iMainWidth = eMainNode.offsetWidth ;
if ( this.IsRTL )
{
if ( this.IsContextMenu )
x = x - iMainWidth + 1 ;
else if ( relElement )
x = ( x * -1 ) + relElement.offsetWidth - iMainWidth ;
}
// Second call: Show the Popup at the specified location, with the correct size.
this._Popup.show( x, y, iMainWidth, eMainNode.offsetHeight, relElement ) ;
if ( this.OnHide )
{
if ( this._Timer )
CheckPopupOnHide.call( this, true ) ;
this._Timer = FCKTools.SetInterval( CheckPopupOnHide, 100, this ) ;
}
}
else
{
// Do not fire OnBlur while the panel is opened.
if ( typeof( FCK.ToolbarSet.CurrentInstance.FocusManager ) != 'undefined' )
FCK.ToolbarSet.CurrentInstance.FocusManager.Lock() ;
if ( this.ParentPanel )
{
this.ParentPanel.Lock() ;
// Due to a bug on FF3, we must ensure that the parent panel will
// blur (#1584).
FCKPanel_Window_OnBlur( null, this.ParentPanel ) ;
}
// Be sure we'll not have more than one Panel opened at the same time.
if ( FCKPanel._OpenedPanel )
FCKPanel._OpenedPanel.Hide() ;
FCKDomTools.SetElementStyles( eMainNode,
{
width : width ? width + 'px' : '',
height : height ? height + 'px' : ''
} ) ;
iMainWidth = eMainNode.offsetWidth ;
if ( !width ) this._IFrame.width = 1 ;
if ( !height ) this._IFrame.height = 1 ;
// This is weird... but with Firefox, we must get the offsetWidth before
// setting the _IFrame size (which returns "0"), and then after that,
// to return the correct width. Remove the first step and it will not
// work when the editor is in RTL.
//
// The "|| eMainNode.firstChild.offsetWidth" part has been added
// for Opera compatibility (see #570).
iMainWidth = eMainNode.offsetWidth || eMainNode.firstChild.offsetWidth ;
// Base the popup coordinates upon the coordinates of relElement.
var oPos = FCKTools.GetDocumentPosition( this._Window,
relElement.nodeType == 9 ?
( FCKTools.IsStrictMode( relElement ) ? relElement.documentElement : relElement.body ) :
relElement ) ;
// Minus the offsets provided by any positioned parent element of the panel iframe.
var positionedAncestor = FCKDomTools.GetPositionedAncestor( FCKTools.GetElementWindow( this._IFrame ), this._IFrame.parentNode ) ;
if ( positionedAncestor )
{
var nPos = FCKTools.GetDocumentPosition( FCKTools.GetElementWindow( positionedAncestor ), positionedAncestor ) ;
oPos.x -= nPos.x ;
oPos.y -= nPos.y ;
}
if ( this.IsRTL && !this.IsContextMenu )
x = ( x * -1 ) ;
x += oPos.x ;
y += oPos.y ;
if ( this.IsRTL )
{
if ( this.IsContextMenu )
x = x - iMainWidth + 1 ;
else if ( relElement )
x = x + relElement.offsetWidth - iMainWidth ;
}
else
{
var oViewPaneSize = FCKTools.GetViewPaneSize( this._Window ) ;
var oScrollPosition = FCKTools.GetScrollPosition( this._Window ) ;
var iViewPaneHeight = oViewPaneSize.Height + oScrollPosition.Y ;
var iViewPaneWidth = oViewPaneSize.Width + oScrollPosition.X ;
if ( ( x + iMainWidth ) > iViewPaneWidth )
x -= x + iMainWidth - iViewPaneWidth ;
if ( ( y + eMainNode.offsetHeight ) > iViewPaneHeight )
y -= y + eMainNode.offsetHeight - iViewPaneHeight ;
}
if ( x < 0 )
x = 0 ;
// Set the context menu DIV in the specified location.
FCKDomTools.SetElementStyles( this._IFrame,
{
left : x + 'px',
top : y + 'px'
} ) ;
var iWidth = iMainWidth ;
var iHeight = eMainNode.offsetHeight ;
this._IFrame.width = iWidth ;
this._IFrame.height = iHeight ;
// Move the focus to the IFRAME so we catch the "onblur".
this._IFrame.contentWindow.focus() ;
FCKPanel._OpenedPanel = this ;
}
this._IsOpened = true ;
FCKTools.RunFunction( this.OnShow, this ) ;
}
FCKPanel.prototype.Hide = function( ignoreOnHide )
{
if ( this._Popup )
this._Popup.hide() ;
else
{
if ( !this._IsOpened || this._LockCounter > 0 )
return ;
// Enable the editor to fire the "OnBlur".
if ( typeof( FCKFocusManager ) != 'undefined' )
FCKFocusManager.Unlock() ;
// It is better to set the sizes to 0, otherwise Firefox would have
// rendering problems.
this._IFrame.width = this._IFrame.height = 0 ;
this._IsOpened = false ;
if ( this.ParentPanel )
this.ParentPanel.Unlock() ;
if ( !ignoreOnHide )
FCKTools.RunFunction( this.OnHide, this ) ;
}
}
FCKPanel.prototype.CheckIsOpened = function()
{
if ( this._Popup )
return this._Popup.isOpen ;
else
return this._IsOpened ;
}
FCKPanel.prototype.CreateChildPanel = function()
{
var oWindow = this._Popup ? FCKTools.GetDocumentWindow( this.Document ) : this._Window ;
var oChildPanel = new FCKPanel( oWindow ) ;
oChildPanel.ParentPanel = this ;
return oChildPanel ;
}
FCKPanel.prototype.Lock = function()
{
this._LockCounter++ ;
}
FCKPanel.prototype.Unlock = function()
{
if ( --this._LockCounter == 0 && !this.HasFocus )
this.Hide() ;
}
/* Events */
function FCKPanel_Window_OnFocus( e, panel )
{
panel.HasFocus = true ;
}
function FCKPanel_Window_OnBlur( e, panel )
{
panel.HasFocus = false ;
if ( panel._LockCounter == 0 )
FCKTools.RunFunction( panel.Hide, panel ) ;
}
function CheckPopupOnHide( forceHide )
{
if ( forceHide || !this._Popup.isOpen )
{
window.clearInterval( this._Timer ) ;
this._Timer = null ;
FCKTools.RunFunction( this.OnHide, this ) ;
}
}
function FCKPanel_Cleanup()
{
this._Popup = null ;
this._Window = null ;
this.Document = null ;
this.MainNode = null ;
}

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,87 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* FCKXml Class: class to load and manipulate XML files.
*/
FCKXml.prototype =
{
LoadUrl : function( urlToCall )
{
this.Error = false ;
var oFCKXml = this ;
var oXmlHttp = FCKTools.CreateXmlObject( 'XmlHttp' ) ;
oXmlHttp.open( "GET", urlToCall, false ) ;
oXmlHttp.send( null ) ;
if ( oXmlHttp.status == 200 || oXmlHttp.status == 304 )
this.DOMDocument = oXmlHttp.responseXML ;
else if ( oXmlHttp.status == 0 && oXmlHttp.readyState == 4 )
this.DOMDocument = oXmlHttp.responseXML ;
else
this.DOMDocument = null ;
if ( this.DOMDocument == null || this.DOMDocument.firstChild == null )
{
this.Error = true ;
if (window.confirm( 'Error loading "' + urlToCall + '"\r\nDo you want to see more info?' ) )
alert( 'URL requested: "' + urlToCall + '"\r\n' +
'Server response:\r\nStatus: ' + oXmlHttp.status + '\r\n' +
'Response text:\r\n' + oXmlHttp.responseText ) ;
}
},
SelectNodes : function( xpath, contextNode )
{
if ( this.Error )
return new Array() ;
var aNodeArray = new Array();
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), XPathResult.ORDERED_NODE_ITERATOR_TYPE, null) ;
if ( xPathResult )
{
var oNode = xPathResult.iterateNext() ;
while( oNode )
{
aNodeArray[aNodeArray.length] = oNode ;
oNode = xPathResult.iterateNext();
}
}
return aNodeArray ;
},
SelectSingleNode : function( xpath, contextNode )
{
if ( this.Error )
return null ;
var xPathResult = this.DOMDocument.evaluate( xpath, contextNode ? contextNode : this.DOMDocument,
this.DOMDocument.createNSResolver(this.DOMDocument.documentElement), 9, null);
if ( xPathResult && xPathResult.singleNodeValue )
return xPathResult.singleNodeValue ;
else
return null ;
}
} ;

View file

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