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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,325 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCK.ContextMenu object that is responsible for all
* Context Menu operations in the editing area.
*/
FCK.ContextMenu = new Object() ;
FCK.ContextMenu.Listeners = new Array() ;
FCK.ContextMenu.RegisterListener = function( listener )
{
if ( listener )
this.Listeners.push( listener ) ;
}
function FCK_ContextMenu_Init()
{
var oInnerContextMenu = FCK.ContextMenu._InnerContextMenu = new FCKContextMenu( FCKBrowserInfo.IsIE ? window : window.parent, FCKLang.Dir ) ;
oInnerContextMenu.CtrlDisable = FCKConfig.BrowserContextMenuOnCtrl ;
oInnerContextMenu.OnBeforeOpen = FCK_ContextMenu_OnBeforeOpen ;
oInnerContextMenu.OnItemClick = FCK_ContextMenu_OnItemClick ;
// Get the registering function.
var oMenu = FCK.ContextMenu ;
// Register all configured context menu listeners.
for ( var i = 0 ; i < FCKConfig.ContextMenu.length ; i++ )
oMenu.RegisterListener( FCK_ContextMenu_GetListener( FCKConfig.ContextMenu[i] ) ) ;
}
function FCK_ContextMenu_GetListener( listenerName )
{
switch ( listenerName )
{
case 'Generic' :
return {
AddItems : function( menu, tag, tagName )
{
menu.AddItem( 'Cut' , FCKLang.Cut , 7, FCKCommands.GetCommand( 'Cut' ).GetState() == FCK_TRISTATE_DISABLED ) ;
menu.AddItem( 'Copy' , FCKLang.Copy , 8, FCKCommands.GetCommand( 'Copy' ).GetState() == FCK_TRISTATE_DISABLED ) ;
menu.AddItem( 'Paste' , FCKLang.Paste , 9, FCKCommands.GetCommand( 'Paste' ).GetState() == FCK_TRISTATE_DISABLED ) ;
}} ;
case 'Table' :
return {
AddItems : function( menu, tag, tagName )
{
var bIsTable = ( tagName == 'TABLE' ) ;
var bIsCell = ( !bIsTable && FCKSelection.HasAncestorNode( 'TABLE' ) ) ;
if ( bIsCell )
{
menu.AddSeparator() ;
var oItem = menu.AddItem( 'Cell' , FCKLang.CellCM ) ;
oItem.AddItem( 'TableInsertCellBefore' , FCKLang.InsertCellBefore, 69 ) ;
oItem.AddItem( 'TableInsertCellAfter' , FCKLang.InsertCellAfter, 58 ) ;
oItem.AddItem( 'TableDeleteCells' , FCKLang.DeleteCells, 59 ) ;
if ( FCKBrowserInfo.IsGecko )
oItem.AddItem( 'TableMergeCells' , FCKLang.MergeCells, 60,
FCKCommands.GetCommand( 'TableMergeCells' ).GetState() == FCK_TRISTATE_DISABLED ) ;
else
{
oItem.AddItem( 'TableMergeRight' , FCKLang.MergeRight, 60,
FCKCommands.GetCommand( 'TableMergeRight' ).GetState() == FCK_TRISTATE_DISABLED ) ;
oItem.AddItem( 'TableMergeDown' , FCKLang.MergeDown, 60,
FCKCommands.GetCommand( 'TableMergeDown' ).GetState() == FCK_TRISTATE_DISABLED ) ;
}
oItem.AddItem( 'TableHorizontalSplitCell' , FCKLang.HorizontalSplitCell, 61,
FCKCommands.GetCommand( 'TableHorizontalSplitCell' ).GetState() == FCK_TRISTATE_DISABLED ) ;
oItem.AddItem( 'TableVerticalSplitCell' , FCKLang.VerticalSplitCell, 61,
FCKCommands.GetCommand( 'TableVerticalSplitCell' ).GetState() == FCK_TRISTATE_DISABLED ) ;
oItem.AddSeparator() ;
oItem.AddItem( 'TableCellProp' , FCKLang.CellProperties, 57,
FCKCommands.GetCommand( 'TableCellProp' ).GetState() == FCK_TRISTATE_DISABLED ) ;
menu.AddSeparator() ;
oItem = menu.AddItem( 'Row' , FCKLang.RowCM ) ;
oItem.AddItem( 'TableInsertRowBefore' , FCKLang.InsertRowBefore, 70 ) ;
oItem.AddItem( 'TableInsertRowAfter' , FCKLang.InsertRowAfter, 62 ) ;
oItem.AddItem( 'TableDeleteRows' , FCKLang.DeleteRows, 63 ) ;
menu.AddSeparator() ;
oItem = menu.AddItem( 'Column' , FCKLang.ColumnCM ) ;
oItem.AddItem( 'TableInsertColumnBefore', FCKLang.InsertColumnBefore, 71 ) ;
oItem.AddItem( 'TableInsertColumnAfter' , FCKLang.InsertColumnAfter, 64 ) ;
oItem.AddItem( 'TableDeleteColumns' , FCKLang.DeleteColumns, 65 ) ;
}
if ( bIsTable || bIsCell )
{
menu.AddSeparator() ;
menu.AddItem( 'TableDelete' , FCKLang.TableDelete ) ;
menu.AddItem( 'TableProp' , FCKLang.TableProperties, 39 ) ;
}
}} ;
case 'Link' :
return {
AddItems : function( menu, tag, tagName )
{
var bInsideLink = ( tagName == 'A' || FCKSelection.HasAncestorNode( 'A' ) ) ;
if ( bInsideLink || FCK.GetNamedCommandState( 'Unlink' ) != FCK_TRISTATE_DISABLED )
{
// Go up to the anchor to test its properties
var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
var bIsAnchor = ( oLink && oLink.name.length > 0 && oLink.href.length == 0 ) ;
// If it isn't a link then don't add the Link context menu
if ( bIsAnchor )
return ;
menu.AddSeparator() ;
if ( bInsideLink )
menu.AddItem( 'Link', FCKLang.EditLink , 34 ) ;
menu.AddItem( 'Unlink' , FCKLang.RemoveLink , 35 ) ;
}
}} ;
case 'Image' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'IMG' && !tag.getAttribute( '_fckfakelement' ) )
{
menu.AddSeparator() ;
menu.AddItem( 'Image', FCKLang.ImageProperties, 37 ) ;
}
}} ;
case 'Anchor' :
return {
AddItems : function( menu, tag, tagName )
{
// Go up to the anchor to test its properties
var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
var bIsAnchor = ( oLink && oLink.name.length > 0 ) ;
if ( bIsAnchor || ( tagName == 'IMG' && tag.getAttribute( '_fckanchor' ) ) )
{
menu.AddSeparator() ;
menu.AddItem( 'Anchor', FCKLang.AnchorProp, 36 ) ;
menu.AddItem( 'AnchorDelete', FCKLang.AnchorDelete ) ;
}
}} ;
case 'Flash' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'IMG' && tag.getAttribute( '_fckflash' ) )
{
menu.AddSeparator() ;
menu.AddItem( 'Flash', FCKLang.FlashProperties, 38 ) ;
}
}} ;
case 'Form' :
return {
AddItems : function( menu, tag, tagName )
{
if ( FCKSelection.HasAncestorNode('FORM') )
{
menu.AddSeparator() ;
menu.AddItem( 'Form', FCKLang.FormProp, 48 ) ;
}
}} ;
case 'Checkbox' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'INPUT' && tag.type == 'checkbox' )
{
menu.AddSeparator() ;
menu.AddItem( 'Checkbox', FCKLang.CheckboxProp, 49 ) ;
}
}} ;
case 'Radio' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'INPUT' && tag.type == 'radio' )
{
menu.AddSeparator() ;
menu.AddItem( 'Radio', FCKLang.RadioButtonProp, 50 ) ;
}
}} ;
case 'TextField' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'INPUT' && ( tag.type == 'text' || tag.type == 'password' ) )
{
menu.AddSeparator() ;
menu.AddItem( 'TextField', FCKLang.TextFieldProp, 51 ) ;
}
}} ;
case 'HiddenField' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'IMG' && tag.getAttribute( '_fckinputhidden' ) )
{
menu.AddSeparator() ;
menu.AddItem( 'HiddenField', FCKLang.HiddenFieldProp, 56 ) ;
}
}} ;
case 'ImageButton' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'INPUT' && tag.type == 'image' )
{
menu.AddSeparator() ;
menu.AddItem( 'ImageButton', FCKLang.ImageButtonProp, 55 ) ;
}
}} ;
case 'Button' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'INPUT' && ( tag.type == 'button' || tag.type == 'submit' || tag.type == 'reset' ) )
{
menu.AddSeparator() ;
menu.AddItem( 'Button', FCKLang.ButtonProp, 54 ) ;
}
}} ;
case 'Select' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'SELECT' )
{
menu.AddSeparator() ;
menu.AddItem( 'Select', FCKLang.SelectionFieldProp, 53 ) ;
}
}} ;
case 'Textarea' :
return {
AddItems : function( menu, tag, tagName )
{
if ( tagName == 'TEXTAREA' )
{
menu.AddSeparator() ;
menu.AddItem( 'Textarea', FCKLang.TextareaProp, 52 ) ;
}
}} ;
case 'BulletedList' :
return {
AddItems : function( menu, tag, tagName )
{
if ( FCKSelection.HasAncestorNode('UL') )
{
menu.AddSeparator() ;
menu.AddItem( 'BulletedList', FCKLang.BulletedListProp, 27 ) ;
}
}} ;
case 'NumberedList' :
return {
AddItems : function( menu, tag, tagName )
{
if ( FCKSelection.HasAncestorNode('OL') )
{
menu.AddSeparator() ;
menu.AddItem( 'NumberedList', FCKLang.NumberedListProp, 26 ) ;
}
}} ;
}
return null ;
}
function FCK_ContextMenu_OnBeforeOpen()
{
// Update the UI.
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
// Get the actual selected tag (if any).
var oTag, sTagName ;
// The extra () is to avoid a warning with strict error checking. This is ok.
if ( (oTag = FCKSelection.GetSelectedElement()) )
sTagName = oTag.tagName ;
// Cleanup the current menu items.
var oMenu = FCK.ContextMenu._InnerContextMenu ;
oMenu.RemoveAllItems() ;
// Loop through the listeners.
var aListeners = FCK.ContextMenu.Listeners ;
for ( var i = 0 ; i < aListeners.length ; i++ )
aListeners[i].AddItems( oMenu, oTag, sTagName ) ;
}
function FCK_ContextMenu_OnItemClick( item )
{
FCK.Focus() ;
FCKCommands.GetCommand( item.Name ).Execute() ;
}

View file

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

View file

@ -0,0 +1,435 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Creation and initialization of the "FCK" object. This is the main
* object that represents an editor instance.
* (IE specific implementations)
*/
FCK.Description = "FCKeditor for Internet Explorer 5.5+" ;
FCK._GetBehaviorsStyle = function()
{
if ( !FCK._BehaviorsStyle )
{
var sBasePath = FCKConfig.FullBasePath ;
var sTableBehavior = '' ;
var sStyle ;
// The behaviors should be pointed using the FullBasePath to avoid security
// errors when using a different BaseHref.
sStyle = '<style type="text/css" _fcktemp="true">' ;
if ( FCKConfig.ShowBorders )
sTableBehavior = 'url(' + sBasePath + 'css/behaviors/showtableborders.htc)' ;
// Disable resize handlers.
sStyle += 'INPUT,TEXTAREA,SELECT,.FCK__Anchor,.FCK__PageBreak,.FCK__InputHidden' ;
if ( FCKConfig.DisableObjectResizing )
{
sStyle += ',IMG' ;
sTableBehavior += ' url(' + sBasePath + 'css/behaviors/disablehandles.htc)' ;
}
sStyle += ' { behavior: url(' + sBasePath + 'css/behaviors/disablehandles.htc) ; }' ;
if ( sTableBehavior.length > 0 )
sStyle += 'TABLE { behavior: ' + sTableBehavior + ' ; }' ;
sStyle += '</style>' ;
FCK._BehaviorsStyle = sStyle ;
}
return FCK._BehaviorsStyle ;
}
function Doc_OnMouseUp()
{
if ( FCK.EditorWindow.event.srcElement.tagName == 'HTML' )
{
FCK.Focus() ;
FCK.EditorWindow.event.cancelBubble = true ;
FCK.EditorWindow.event.returnValue = false ;
}
}
function Doc_OnPaste()
{
var body = FCK.EditorDocument.body ;
body.detachEvent( 'onpaste', Doc_OnPaste ) ;
var ret = FCK.Paste( !FCKConfig.ForcePasteAsPlainText && !FCKConfig.AutoDetectPasteFromWord ) ;
body.attachEvent( 'onpaste', Doc_OnPaste ) ;
return ret ;
}
function Doc_OnDblClick()
{
FCK.OnDoubleClick( FCK.EditorWindow.event.srcElement ) ;
FCK.EditorWindow.event.cancelBubble = true ;
}
function Doc_OnSelectionChange()
{
// Don't fire the event if no document is loaded.
if ( FCK.EditorDocument )
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
function Doc_OnDrop()
{
if ( FCK.MouseDownFlag )
{
FCK.MouseDownFlag = false ;
return ;
}
var evt = FCK.EditorWindow.event ;
if ( FCKConfig.ForcePasteAsPlainText )
{
if ( FCK._CheckIsPastingEnabled() || FCKConfig.ShowDropDialog )
FCK.PasteAsPlainText( evt.dataTransfer.getData( 'Text' ) ) ;
}
else
{
if ( FCKConfig.ShowDropDialog )
FCKTools.RunFunction( FCKDialog.OpenDialog,
FCKDialog, ['FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security'] ) ;
}
evt.returnValue = false ;
evt.cancelBubble = true ;
}
FCK.InitializeBehaviors = function( dontReturn )
{
// Set the focus to the editable area when clicking in the document area.
// TODO: The cursor must be positioned at the end.
this.EditorDocument.attachEvent( 'onmouseup', Doc_OnMouseUp ) ;
// Intercept pasting operations
this.EditorDocument.body.attachEvent( 'onpaste', Doc_OnPaste ) ;
// Intercept drop operations
this.EditorDocument.body.attachEvent( 'ondrop', Doc_OnDrop ) ;
// Reset the context menu.
FCK.ContextMenu._InnerContextMenu.AttachToElement( FCK.EditorDocument.body ) ;
this.EditorDocument.attachEvent("onkeydown", FCK._KeyDownListener ) ;
this.EditorDocument.attachEvent("ondblclick", Doc_OnDblClick ) ;
// Catch cursor selection changes.
this.EditorDocument.attachEvent("onselectionchange", Doc_OnSelectionChange ) ;
}
FCK.InsertHtml = function( html )
{
html = FCKConfig.ProtectedSource.Protect( html ) ;
html = FCK.ProtectEvents( html ) ;
html = FCK.ProtectUrls( html ) ;
html = FCK.ProtectTags( html ) ;
// FCK.Focus() ;
FCK.EditorWindow.focus() ;
FCKUndo.SaveUndoStep() ;
// Gets the actual selection.
var oSel = FCK.EditorDocument.selection ;
// Deletes the actual selection contents.
if ( oSel.type.toLowerCase() == 'control' )
oSel.clear() ;
// Using the following trick, any comment in the beginning of the HTML will
// be preserved.
html = '<span id="__fakeFCKRemove__">&nbsp;</span>' + html ;
// Insert the HTML.
oSel.createRange().pasteHTML( html ) ;
// Remove the fake node
FCK.EditorDocument.getElementById('__fakeFCKRemove__').removeNode( true ) ;
FCKDocumentProcessor.Process( FCK.EditorDocument ) ;
// For some strange reason the SaveUndoStep() call doesn't activate the undo button at the first InsertHtml() call.
this.Events.FireEvent( "OnSelectionChange" ) ;
}
FCK.SetInnerHtml = function( html ) // IE Only
{
var oDoc = FCK.EditorDocument ;
// Using the following trick, any comment in the beginning of the HTML will
// be preserved.
oDoc.body.innerHTML = '<div id="__fakeFCKRemove__">&nbsp;</div>' + html ;
oDoc.getElementById('__fakeFCKRemove__').removeNode( true ) ;
}
function FCK_PreloadImages()
{
var oPreloader = new FCKImagePreloader() ;
// Add the configured images.
oPreloader.AddImages( FCKConfig.PreloadImages ) ;
// Add the skin icons strip.
oPreloader.AddImages( FCKConfig.SkinPath + 'fck_strip.gif' ) ;
oPreloader.OnComplete = LoadToolbarSetup ;
oPreloader.Start() ;
}
// Disable the context menu in the editor (outside the editing area).
function Document_OnContextMenu()
{
return ( event.srcElement._FCKShowContextMenu == true ) ;
}
document.oncontextmenu = Document_OnContextMenu ;
function FCK_Cleanup()
{
this.LinkedField = null ;
this.EditorWindow = null ;
this.EditorDocument = null ;
}
FCK._ExecPaste = function()
{
// As we call ExecuteNamedCommand('Paste'), it would enter in a loop. So, let's use a semaphore.
if ( FCK._PasteIsRunning )
return true ;
if ( FCKConfig.ForcePasteAsPlainText )
{
FCK.PasteAsPlainText() ;
return false ;
}
var sHTML = FCK._CheckIsPastingEnabled( true ) ;
if ( sHTML === false )
FCKTools.RunFunction( FCKDialog.OpenDialog, FCKDialog, ['FCKDialog_Paste', FCKLang.Paste, 'dialog/fck_paste.html', 400, 330, 'Security'] ) ;
else
{
if ( FCKConfig.AutoDetectPasteFromWord && sHTML.length > 0 )
{
var re = /<\w[^>]*(( class="?MsoNormal"?)|(="mso-))/gi ;
if ( re.test( sHTML ) )
{
if ( confirm( FCKLang.PasteWordConfirm ) )
{
FCK.PasteFromWord() ;
return false ;
}
}
}
// Instead of inserting the retrieved HTML, let's leave the OS work for us,
// by calling FCK.ExecuteNamedCommand( 'Paste' ). It could give better results.
// Enable the semaphore to avoid a loop.
FCK._PasteIsRunning = true ;
FCK.ExecuteNamedCommand( 'Paste' ) ;
// Removes the semaphore.
delete FCK._PasteIsRunning ;
}
// Let's always make a custom implementation (return false), otherwise
// the new Keyboard Handler may conflict with this code, and the CTRL+V code
// could result in a simple "V" being pasted.
return false ;
}
FCK.PasteAsPlainText = function( forceText )
{
if ( !FCK._CheckIsPastingEnabled() )
{
FCKDialog.OpenDialog( 'FCKDialog_Paste', FCKLang.PasteAsText, 'dialog/fck_paste.html', 400, 330, 'PlainText' ) ;
return ;
}
// Get the data available in the clipboard in text format.
var sText = null ;
if ( ! forceText )
sText = clipboardData.getData("Text") ;
else
sText = forceText ;
if ( sText && sText.length > 0 )
{
// Replace the carriage returns with <BR>
sText = FCKTools.HTMLEncode( sText ) ;
sText = FCKTools.ProcessLineBreaks( window, FCKConfig, sText ) ;
var closeTagIndex = sText.search( '</p>' ) ;
var startTagIndex = sText.search( '<p>' ) ;
if ( ( closeTagIndex != -1 && startTagIndex != -1 && closeTagIndex < startTagIndex )
|| ( closeTagIndex != -1 && startTagIndex == -1 ) )
{
var prefix = sText.substr( 0, closeTagIndex ) ;
sText = sText.substr( closeTagIndex + 4 ) ;
this.InsertHtml( prefix ) ;
}
// Insert the resulting data in the editor.
FCKUndo.SaveLocked = true ;
this.InsertHtml( sText ) ;
FCKUndo.SaveLocked = false ;
}
}
FCK._CheckIsPastingEnabled = function( returnContents )
{
// The following seams to be the only reliable way to check is script
// pasting operations are enabled in the security settings of IE6 and IE7.
// It adds a little bit of overhead to the check, but so far that's the
// only way, mainly because of IE7.
FCK._PasteIsEnabled = false ;
document.body.attachEvent( 'onpaste', FCK_CheckPasting_Listener ) ;
// The execCommand in GetClipboardHTML will fire the "onpaste", only if the
// security settings are enabled.
var oReturn = FCK.GetClipboardHTML() ;
document.body.detachEvent( 'onpaste', FCK_CheckPasting_Listener ) ;
if ( FCK._PasteIsEnabled )
{
if ( !returnContents )
oReturn = true ;
}
else
oReturn = false ;
delete FCK._PasteIsEnabled ;
return oReturn ;
}
function FCK_CheckPasting_Listener()
{
FCK._PasteIsEnabled = true ;
}
FCK.GetClipboardHTML = function()
{
var oDiv = document.getElementById( '___FCKHiddenDiv' ) ;
if ( !oDiv )
{
oDiv = document.createElement( 'DIV' ) ;
oDiv.id = '___FCKHiddenDiv' ;
var oDivStyle = oDiv.style ;
oDivStyle.position = 'absolute' ;
oDivStyle.visibility = oDivStyle.overflow = 'hidden' ;
oDivStyle.width = oDivStyle.height = 1 ;
document.body.appendChild( oDiv ) ;
}
oDiv.innerHTML = '' ;
var oTextRange = document.body.createTextRange() ;
oTextRange.moveToElementText( oDiv ) ;
oTextRange.execCommand( 'Paste' ) ;
var sData = oDiv.innerHTML ;
oDiv.innerHTML = '' ;
return sData ;
}
FCK.CreateLink = function( url, noUndo )
{
// Creates the array that will be returned. It contains one or more created links (see #220).
var aCreatedLinks = new Array() ;
// Remove any existing link in the selection.
FCK.ExecuteNamedCommand( 'Unlink', null, false, !!noUndo ) ;
if ( url.length > 0 )
{
// If there are several images, and you try to link each one, all the images get inside the link:
// <img><img> -> <a><img></a><img> -> <a><img><img></a> due to the call to 'CreateLink' (bug in IE)
if (FCKSelection.GetType() == 'Control')
{
// Create a link
var oLink = this.EditorDocument.createElement( 'A' ) ;
oLink.href = url ;
// Get the selected object
var oControl = FCKSelection.GetSelectedElement() ;
// Put the link just before the object
oControl.parentNode.insertBefore(oLink, oControl) ;
// Move the object inside the link
oControl.parentNode.removeChild( oControl ) ;
oLink.appendChild( oControl ) ;
return [ oLink ] ;
}
// Generate a temporary name for the link.
var sTempUrl = 'javascript:void(0);/*' + ( new Date().getTime() ) + '*/' ;
// Use the internal "CreateLink" command to create the link.
FCK.ExecuteNamedCommand( 'CreateLink', sTempUrl, false, !!noUndo ) ;
// Look for the just create link.
var oLinks = this.EditorDocument.links ;
for ( i = 0 ; i < oLinks.length ; i++ )
{
var oLink = oLinks[i] ;
// Check it this a newly created link.
// getAttribute must be used. oLink.url may cause problems with IE7 (#555).
if ( oLink.getAttribute( 'href', 2 ) == sTempUrl )
{
var sInnerHtml = oLink.innerHTML ; // Save the innerHTML (IE changes it if it is like an URL).
oLink.href = url ;
oLink.innerHTML = sInnerHtml ; // Restore the innerHTML.
// If the last child is a <br> move it outside the link or it
// will be too easy to select this link again #388.
var oLastChild = oLink.lastChild ;
if ( oLastChild && oLastChild.nodeName == 'BR' )
{
// Move the BR after the link.
FCKDomTools.InsertAfterNode( oLink, oLink.removeChild( oLastChild ) ) ;
}
aCreatedLinks.push( oLink ) ;
}
}
}
return aCreatedLinks ;
}

View file

@ -0,0 +1,59 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Contains browser detection information.
*/
var s = navigator.userAgent.toLowerCase() ;
var FCKBrowserInfo =
{
IsIE : /*@cc_on!@*/false,
IsIE7 : /*@cc_on!@*/false && ( parseFloat( s.match( /msie ([\d|\.]+)/ )[1] ) >= 7 ),
IsGecko : s.Contains('gecko/'),
IsSafari : s.Contains(' applewebkit/'), // Read "IsWebKit"
IsOpera : !!window.opera,
IsMac : s.Contains('macintosh')
} ;
// Completes the browser info with further Gecko information.
(function( browserInfo )
{
browserInfo.IsGeckoLike = ( browserInfo.IsGecko || browserInfo.IsSafari || browserInfo.IsOpera ) ;
if ( browserInfo.IsGecko )
{
var geckoVersion = s.match( /gecko\/(\d+)/ )[1] ;
// Actually "10" refers to Gecko versions before Firefox 1.5, when
// Gecko 1.8 (build 20051111) has been released.
// Some browser (like Mozilla 1.7.13) may have a Gecko build greater
// than 20051111, so we must also check for the revision number not to
// be 1.7 (we are assuming that rv < 1.7 will not have build > 20051111).
// TODO: Future versions may consider the rv number only, but it is
// still to check that all Gecko based browser present the rv number.
browserInfo.IsGecko10 = ( ( geckoVersion < 20051111 ) || ( /rv:1\.7/.test(s) ) ) ;
browserInfo.IsGecko19 = /rv:1\.9/.test(s) ;
}
else
browserInfo.IsGecko10 = false ;
})(FCKBrowserInfo) ;

View file

@ -0,0 +1,100 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Format the HTML.
*/
var FCKCodeFormatter = new Object() ;
FCKCodeFormatter.Init = function()
{
var oRegex = this.Regex = new Object() ;
// Regex for line breaks.
oRegex.BlocksOpener = /\<(P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|TITLE|META|LINK|BASE|SCRIPT|LINK|TD|TH|AREA|OPTION)[^\>]*\>/gi ;
oRegex.BlocksCloser = /\<\/(P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|TITLE|META|LINK|BASE|SCRIPT|LINK|TD|TH|AREA|OPTION)[^\>]*\>/gi ;
oRegex.NewLineTags = /\<(BR|HR)[^\>]*\>/gi ;
oRegex.MainTags = /\<\/?(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR)[^\>]*\>/gi ;
oRegex.LineSplitter = /\s*\n+\s*/g ;
// Regex for indentation.
oRegex.IncreaseIndent = /^\<(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR|UL|OL)[ \/\>]/i ;
oRegex.DecreaseIndent = /^\<\/(HTML|HEAD|BODY|FORM|TABLE|TBODY|THEAD|TR|UL|OL)[ \>]/i ;
oRegex.FormatIndentatorRemove = new RegExp( '^' + FCKConfig.FormatIndentator ) ;
oRegex.ProtectedTags = /(<PRE[^>]*>)([\s\S]*?)(<\/PRE>)/gi ;
}
FCKCodeFormatter._ProtectData = function( outer, opener, data, closer )
{
return opener + '___FCKpd___' + FCKCodeFormatter.ProtectedData.AddItem( data ) + closer ;
}
FCKCodeFormatter.Format = function( html )
{
if ( !this.Regex )
this.Init() ;
// Protected content that remain untouched during the
// process go in the following array.
FCKCodeFormatter.ProtectedData = new Array() ;
var sFormatted = html.replace( this.Regex.ProtectedTags, FCKCodeFormatter._ProtectData ) ;
// Line breaks.
sFormatted = sFormatted.replace( this.Regex.BlocksOpener, '\n$&' ) ;
sFormatted = sFormatted.replace( this.Regex.BlocksCloser, '$&\n' ) ;
sFormatted = sFormatted.replace( this.Regex.NewLineTags, '$&\n' ) ;
sFormatted = sFormatted.replace( this.Regex.MainTags, '\n$&\n' ) ;
// Indentation.
var sIndentation = '' ;
var asLines = sFormatted.split( this.Regex.LineSplitter ) ;
sFormatted = '' ;
for ( var i = 0 ; i < asLines.length ; i++ )
{
var sLine = asLines[i] ;
if ( sLine.length == 0 )
continue ;
if ( this.Regex.DecreaseIndent.test( sLine ) )
sIndentation = sIndentation.replace( this.Regex.FormatIndentatorRemove, '' ) ;
sFormatted += sIndentation + sLine + '\n' ;
if ( this.Regex.IncreaseIndent.test( sLine ) )
sIndentation += FCKConfig.FormatIndentator ;
}
// Now we put back the protected data.
for ( var j = 0 ; j < FCKCodeFormatter.ProtectedData.length ; j++ )
{
var oRegex = new RegExp( '___FCKpd___' + j ) ;
sFormatted = sFormatted.replace( oRegex, FCKCodeFormatter.ProtectedData[j].replace( /\$/g, '$$$$' ) ) ;
}
return sFormatted.Trim() ;
}

View file

@ -0,0 +1,167 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Define all commands available in the editor.
*/
var FCKCommands = FCK.Commands = new Object() ;
FCKCommands.LoadedCommands = new Object() ;
FCKCommands.RegisterCommand = function( commandName, command )
{
this.LoadedCommands[ commandName ] = command ;
}
FCKCommands.GetCommand = function( commandName )
{
var oCommand = FCKCommands.LoadedCommands[ commandName ] ;
if ( oCommand )
return oCommand ;
switch ( commandName )
{
case 'Bold' :
case 'Italic' :
case 'Underline' :
case 'StrikeThrough':
case 'Subscript' :
case 'Superscript' : oCommand = new FCKCoreStyleCommand( commandName ) ; break ;
case 'RemoveFormat' : oCommand = new FCKRemoveFormatCommand() ; break ;
case 'DocProps' : oCommand = new FCKDialogCommand( 'DocProps' , FCKLang.DocProps , 'dialog/fck_docprops.html' , 400, 390, FCKCommands.GetFullPageState ) ; break ;
case 'Templates' : oCommand = new FCKDialogCommand( 'Templates' , FCKLang.DlgTemplatesTitle , 'dialog/fck_template.html' , 380, 450 ) ; break ;
case 'Link' : oCommand = new FCKDialogCommand( 'Link' , FCKLang.DlgLnkWindowTitle , 'dialog/fck_link.html' , 400, 330 ) ; break ;
case 'Unlink' : oCommand = new FCKUnlinkCommand() ; break ;
case 'Anchor' : oCommand = new FCKDialogCommand( 'Anchor' , FCKLang.DlgAnchorTitle , 'dialog/fck_anchor.html' , 370, 170 ) ; break ;
case 'AnchorDelete' : oCommand = new FCKAnchorDeleteCommand() ; break ;
case 'BulletedList' : oCommand = new FCKDialogCommand( 'BulletedList', FCKLang.BulletedListProp , 'dialog/fck_listprop.html?UL' , 370, 170 ) ; break ;
case 'NumberedList' : oCommand = new FCKDialogCommand( 'NumberedList', FCKLang.NumberedListProp , 'dialog/fck_listprop.html?OL' , 370, 170 ) ; break ;
case 'About' : oCommand = new FCKDialogCommand( 'About' , FCKLang.About , 'dialog/fck_about.html' , 400, 330 ) ; break ;
case 'Find' : oCommand = new FCKDialogCommand( 'Find' , FCKLang.DlgFindAndReplaceTitle , 'dialog/fck_replace.html' , 340, 250 ) ; break ;
case 'Replace' : oCommand = new FCKDialogCommand( 'Replace' , FCKLang.DlgFindAndReplaceTitle , 'dialog/fck_replace.html' , 340, 250 ) ; break ;
case 'Image' : oCommand = new FCKDialogCommand( 'Image' , FCKLang.DlgImgTitle , 'dialog/fck_image.html' , 450, 400 ) ; break ;
case 'Flash' : oCommand = new FCKDialogCommand( 'Flash' , FCKLang.DlgFlashTitle , 'dialog/fck_flash.html' , 450, 400 ) ; break ;
case 'SpecialChar' : oCommand = new FCKDialogCommand( 'SpecialChar', FCKLang.DlgSpecialCharTitle , 'dialog/fck_specialchar.html' , 400, 320 ) ; break ;
case 'Smiley' : oCommand = new FCKDialogCommand( 'Smiley' , FCKLang.DlgSmileyTitle , 'dialog/fck_smiley.html' , FCKConfig.SmileyWindowWidth, FCKConfig.SmileyWindowHeight ) ; break ;
case 'Table' : oCommand = new FCKDialogCommand( 'Table' , FCKLang.DlgTableTitle , 'dialog/fck_table.html' , 480, 250 ) ; break ;
case 'TableProp' : oCommand = new FCKDialogCommand( 'Table' , FCKLang.DlgTableTitle , 'dialog/fck_table.html?Parent', 480, 250 ) ; break ;
case 'TableCellProp': oCommand = new FCKDialogCommand( 'TableCell' , FCKLang.DlgCellTitle , 'dialog/fck_tablecell.html' , 550, 250 ) ; break ;
case 'Style' : oCommand = new FCKStyleCommand() ; break ;
case 'FontName' : oCommand = new FCKFontNameCommand() ; break ;
case 'FontSize' : oCommand = new FCKFontSizeCommand() ; break ;
case 'FontFormat' : oCommand = new FCKFormatBlockCommand() ; break ;
case 'Source' : oCommand = new FCKSourceCommand() ; break ;
case 'Preview' : oCommand = new FCKPreviewCommand() ; break ;
case 'Save' : oCommand = new FCKSaveCommand() ; break ;
case 'NewPage' : oCommand = new FCKNewPageCommand() ; break ;
case 'PageBreak' : oCommand = new FCKPageBreakCommand() ; break ;
case 'Rule' : oCommand = new FCKRuleCommand() ; break ;
case 'TextColor' : oCommand = new FCKTextColorCommand('ForeColor') ; break ;
case 'BGColor' : oCommand = new FCKTextColorCommand('BackColor') ; break ;
case 'Paste' : oCommand = new FCKPasteCommand() ; break ;
case 'PasteText' : oCommand = new FCKPastePlainTextCommand() ; break ;
case 'PasteWord' : oCommand = new FCKPasteWordCommand() ; break ;
case 'JustifyLeft' : oCommand = new FCKJustifyCommand( 'left' ) ; break ;
case 'JustifyCenter' : oCommand = new FCKJustifyCommand( 'center' ) ; break ;
case 'JustifyRight' : oCommand = new FCKJustifyCommand( 'right' ) ; break ;
case 'JustifyFull' : oCommand = new FCKJustifyCommand( 'justify' ) ; break ;
case 'Indent' : oCommand = new FCKIndentCommand( 'indent', FCKConfig.IndentLength ) ; break ;
case 'Outdent' : oCommand = new FCKIndentCommand( 'outdent', FCKConfig.IndentLength * -1 ) ; break ;
case 'Blockquote' : oCommand = new FCKBlockQuoteCommand() ; break ;
case 'TableInsertRowAfter' : oCommand = new FCKTableCommand('TableInsertRowAfter') ; break ;
case 'TableInsertRowBefore' : oCommand = new FCKTableCommand('TableInsertRowBefore') ; break ;
case 'TableDeleteRows' : oCommand = new FCKTableCommand('TableDeleteRows') ; break ;
case 'TableInsertColumnAfter' : oCommand = new FCKTableCommand('TableInsertColumnAfter') ; break ;
case 'TableInsertColumnBefore' : oCommand = new FCKTableCommand('TableInsertColumnBefore') ; break ;
case 'TableDeleteColumns' : oCommand = new FCKTableCommand('TableDeleteColumns') ; break ;
case 'TableInsertCellAfter' : oCommand = new FCKTableCommand('TableInsertCellAfter') ; break ;
case 'TableInsertCellBefore' : oCommand = new FCKTableCommand('TableInsertCellBefore') ; break ;
case 'TableDeleteCells' : oCommand = new FCKTableCommand('TableDeleteCells') ; break ;
case 'TableMergeCells' : oCommand = new FCKTableCommand('TableMergeCells') ; break ;
case 'TableMergeRight' : oCommand = new FCKTableCommand('TableMergeRight') ; break ;
case 'TableMergeDown' : oCommand = new FCKTableCommand('TableMergeDown') ; break ;
case 'TableHorizontalSplitCell' : oCommand = new FCKTableCommand('TableHorizontalSplitCell') ; break ;
case 'TableVerticalSplitCell' : oCommand = new FCKTableCommand('TableVerticalSplitCell') ; break ;
case 'TableDelete' : oCommand = new FCKTableCommand('TableDelete') ; break ;
case 'Form' : oCommand = new FCKDialogCommand( 'Form' , FCKLang.Form , 'dialog/fck_form.html' , 380, 230 ) ; break ;
case 'Checkbox' : oCommand = new FCKDialogCommand( 'Checkbox' , FCKLang.Checkbox , 'dialog/fck_checkbox.html' , 380, 230 ) ; break ;
case 'Radio' : oCommand = new FCKDialogCommand( 'Radio' , FCKLang.RadioButton , 'dialog/fck_radiobutton.html' , 380, 230 ) ; break ;
case 'TextField' : oCommand = new FCKDialogCommand( 'TextField' , FCKLang.TextField , 'dialog/fck_textfield.html' , 380, 230 ) ; break ;
case 'Textarea' : oCommand = new FCKDialogCommand( 'Textarea' , FCKLang.Textarea , 'dialog/fck_textarea.html' , 380, 230 ) ; break ;
case 'HiddenField' : oCommand = new FCKDialogCommand( 'HiddenField', FCKLang.HiddenField , 'dialog/fck_hiddenfield.html' , 380, 230 ) ; break ;
case 'Button' : oCommand = new FCKDialogCommand( 'Button' , FCKLang.Button , 'dialog/fck_button.html' , 380, 230 ) ; break ;
case 'Select' : oCommand = new FCKDialogCommand( 'Select' , FCKLang.SelectionField, 'dialog/fck_select.html' , 400, 380 ) ; break ;
case 'ImageButton' : oCommand = new FCKDialogCommand( 'ImageButton', FCKLang.ImageButton , 'dialog/fck_image.html?ImageButton', 450, 400 ) ; break ;
case 'SpellCheck' : oCommand = new FCKSpellCheckCommand() ; break ;
case 'FitWindow' : oCommand = new FCKFitWindow() ; break ;
case 'Undo' : oCommand = new FCKUndoCommand() ; break ;
case 'Redo' : oCommand = new FCKRedoCommand() ; break ;
case 'Copy' : oCommand = new FCKCopyCommand() ; break ;
case 'SelectAll' : oCommand = new FCKSelectAllCommand() ; break ;
case 'InsertOrderedList' : oCommand = new FCKListCommand( 'insertorderedlist', 'ol' ) ; break ;
case 'InsertUnorderedList' : oCommand = new FCKListCommand( 'insertunorderedlist', 'ul' ) ; break ;
case 'ShowBlocks' : oCommand = new FCKShowBlockCommand( 'ShowBlocks', FCKConfig.StartupShowBlocks ? FCK_TRISTATE_ON : FCK_TRISTATE_OFF ) ; break ;
// Generic Undefined command (usually used when a command is under development).
case 'Undefined' : oCommand = new FCKUndefinedCommand() ; break ;
// By default we assume that it is a named command.
default:
if ( FCKRegexLib.NamedCommands.test( commandName ) )
oCommand = new FCKNamedCommand( commandName ) ;
else
{
alert( FCKLang.UnknownCommand.replace( /%1/g, commandName ) ) ;
return null ;
}
}
FCKCommands.LoadedCommands[ commandName ] = oCommand ;
return oCommand ;
}
// Gets the state of the "Document Properties" button. It must be enabled only
// when "Full Page" editing is available.
FCKCommands.GetFullPageState = function()
{
return FCKConfig.FullPage ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
}
FCKCommands.GetBooleanState = function( isDisabled )
{
return isDisabled ? FCK_TRISTATE_DISABLED : FCK_TRISTATE_OFF ;
}

View file

@ -0,0 +1,239 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Creates and initializes the FCKConfig object.
*/
var FCKConfig = FCK.Config = new Object() ;
/*
For the next major version (probably 3.0) we should move all this stuff to
another dedicated object and leave FCKConfig as a holder object for settings only).
*/
// Editor Base Path
if ( document.location.protocol == 'file:' )
{
FCKConfig.BasePath = decodeURIComponent( document.location.pathname.substr(1) ) ;
FCKConfig.BasePath = FCKConfig.BasePath.replace( /\\/gi, '/' ) ;
// The way to address local files is different according to the OS.
// In Windows it is file:// but in MacOs it is file:/// so let's get it automatically
var sFullProtocol = document.location.href.match( /^(file\:\/{2,3})/ )[1] ;
// #945 Opera does strange things with files loaded from the disk, and it fails in Mac to load xml files
if ( FCKBrowserInfo.IsOpera )
sFullProtocol += 'localhost/' ;
FCKConfig.BasePath = sFullProtocol + FCKConfig.BasePath.substring( 0, FCKConfig.BasePath.lastIndexOf( '/' ) + 1) ;
FCKConfig.FullBasePath = FCKConfig.BasePath ;
}
else
{
FCKConfig.BasePath = document.location.pathname.substring( 0, document.location.pathname.lastIndexOf( '/' ) + 1) ;
FCKConfig.FullBasePath = document.location.protocol + '//' + document.location.host + FCKConfig.BasePath ;
}
FCKConfig.EditorPath = FCKConfig.BasePath.replace( /editor\/$/, '' ) ;
// There is a bug in Gecko. If the editor is hidden on startup, an error is
// thrown when trying to get the screen dimensions.
try
{
FCKConfig.ScreenWidth = screen.width ;
FCKConfig.ScreenHeight = screen.height ;
}
catch (e)
{
FCKConfig.ScreenWidth = 800 ;
FCKConfig.ScreenHeight = 600 ;
}
// Override the actual configuration values with the values passed throw the
// hidden field "<InstanceName>___Config".
FCKConfig.ProcessHiddenField = function()
{
this.PageConfig = new Object() ;
// Get the hidden field.
var oConfigField = window.parent.document.getElementById( FCK.Name + '___Config' ) ;
// Do nothing if the config field was not defined.
if ( ! oConfigField ) return ;
var aCouples = oConfigField.value.split('&') ;
for ( var i = 0 ; i < aCouples.length ; i++ )
{
if ( aCouples[i].length == 0 )
continue ;
var aConfig = aCouples[i].split( '=' ) ;
var sKey = decodeURIComponent( aConfig[0] ) ;
var sVal = decodeURIComponent( aConfig[1] ) ;
if ( sKey == 'CustomConfigurationsPath' ) // The Custom Config File path must be loaded immediately.
FCKConfig[ sKey ] = sVal ;
else if ( sVal.toLowerCase() == "true" ) // If it is a boolean TRUE.
this.PageConfig[ sKey ] = true ;
else if ( sVal.toLowerCase() == "false" ) // If it is a boolean FALSE.
this.PageConfig[ sKey ] = false ;
else if ( sVal.length > 0 && !isNaN( sVal ) ) // If it is a number.
this.PageConfig[ sKey ] = parseInt( sVal, 10 ) ;
else // In any other case it is a string.
this.PageConfig[ sKey ] = sVal ;
}
}
function FCKConfig_LoadPageConfig()
{
var oPageConfig = FCKConfig.PageConfig ;
for ( var sKey in oPageConfig )
FCKConfig[ sKey ] = oPageConfig[ sKey ] ;
}
function FCKConfig_PreProcess()
{
var oConfig = FCKConfig ;
// Force debug mode if fckdebug=true in the QueryString (main page).
if ( oConfig.AllowQueryStringDebug )
{
try
{
if ( (/fckdebug=true/i).test( window.top.location.search ) )
oConfig.Debug = true ;
}
catch (e) { /* Ignore it. Much probably we are inside a FRAME where the "top" is in another domain (security error). */ }
}
// Certifies that the "PluginsPath" configuration ends with a slash.
if ( !oConfig.PluginsPath.EndsWith('/') )
oConfig.PluginsPath += '/' ;
// EditorAreaCSS accepts a single path string, a list of paths separated by
// a comma or and array of paths.
// In the string cases, transform it in an array.
if ( typeof( oConfig.EditorAreaCSS ) == 'string' )
oConfig.EditorAreaCSS = oConfig.EditorAreaCSS.split(',') ;
var sComboPreviewCSS = oConfig.ToolbarComboPreviewCSS ;
if ( !sComboPreviewCSS || sComboPreviewCSS.length == 0 )
oConfig.ToolbarComboPreviewCSS = oConfig.EditorAreaCSS ;
else if ( typeof( sComboPreviewCSS ) == 'string' )
oConfig.ToolbarComboPreviewCSS = [ sComboPreviewCSS ] ;
}
// Define toolbar sets collection.
FCKConfig.ToolbarSets = new Object() ;
// Defines the plugins collection.
FCKConfig.Plugins = new Object() ;
FCKConfig.Plugins.Items = new Array() ;
FCKConfig.Plugins.Add = function( name, langs, path )
{
FCKConfig.Plugins.Items.AddItem( [name, langs, path] ) ;
}
// FCKConfig.ProtectedSource: object that holds a collection of Regular
// Expressions that defined parts of the raw HTML that must remain untouched
// like custom tags, scripts, server side code, etc...
FCKConfig.ProtectedSource = new Object() ;
// Generates a string used to identify and locate the Protected Tags comments.
FCKConfig.ProtectedSource._CodeTag = (new Date()).valueOf() ;
// Initialize the regex array with the default ones.
FCKConfig.ProtectedSource.RegexEntries = [
// First of any other protection, we must protect all comments to avoid
// loosing them (of course, IE related).
/<!--[\s\S]*?-->/g ,
// Script tags will also be forced to be protected, otherwise IE will execute them.
/<script[\s\S]*?<\/script>/gi,
// <noscript> tags (get lost in IE and messed up in FF).
/<noscript[\s\S]*?<\/noscript>/gi,
// Protect <object> tags. See #359.
/<object[\s\S]+?<\/object>/gi
] ;
FCKConfig.ProtectedSource.Add = function( regexPattern )
{
this.RegexEntries.AddItem( regexPattern ) ;
}
FCKConfig.ProtectedSource.Protect = function( html )
{
var codeTag = this._CodeTag ;
function _Replace( protectedSource )
{
var index = FCKTempBin.AddElement( protectedSource ) ;
return '<!--{' + codeTag + index + '}-->' ;
}
for ( var i = 0 ; i < this.RegexEntries.length ; i++ )
{
html = html.replace( this.RegexEntries[i], _Replace ) ;
}
return html ;
}
FCKConfig.ProtectedSource.Revert = function( html, clearBin )
{
function _Replace( m, opener, index )
{
var protectedValue = clearBin ? FCKTempBin.RemoveElement( index ) : FCKTempBin.Elements[ index ] ;
// There could be protected source inside another one.
return FCKConfig.ProtectedSource.Revert( protectedValue, clearBin ) ;
}
var regex = new RegExp( "(<|&lt;)!--\\{" + this._CodeTag + "(\\d+)\\}--(>|&gt;)", "g" ) ;
return html.replace( regex, _Replace ) ;
}
// Returns a string with the attributes that must be appended to the body
FCKConfig.GetBodyAttributes = function()
{
var bodyAttributes = '' ;
// Add id and class to the body.
if ( this.BodyId && this.BodyId.length > 0 )
bodyAttributes += ' id="' + this.BodyId + '"' ;
if ( this.BodyClass && this.BodyClass.length > 0 )
bodyAttributes += ' class="' + this.BodyClass + '"' ;
return bodyAttributes ;
}
// Sets the body attributes directly on the node
FCKConfig.ApplyBodyAttributes = function( oBody )
{
// Add ID and Class to the body
if ( this.BodyId && this.BodyId.length > 0 )
oBody.id = FCKConfig.BodyId ;
if ( this.BodyClass && this.BodyClass.length > 0 )
oBody.className += ' ' + FCKConfig.BodyClass ;
}

View file

@ -0,0 +1,56 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Debug window control and operations.
*/
var FCKDebug = new Object() ;
FCKDebug._GetWindow = function()
{
if ( !this.DebugWindow || this.DebugWindow.closed )
this.DebugWindow = window.open( FCKConfig.BasePath + 'fckdebug.html', 'FCKeditorDebug', 'menubar=no,scrollbars=yes,resizable=yes,location=no,toolbar=no,width=600,height=500', true ) ;
return this.DebugWindow ;
}
FCKDebug.Output = function( message, color, noParse )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().Output( message, color ) ;
}
catch ( e ) {} // Ignore errors
}
FCKDebug.OutputObject = function( anyObject, color )
{
if ( ! FCKConfig.Debug )
return ;
try
{
this._GetWindow().OutputObject( anyObject, color ) ;
}
catch ( e ) {} // Ignore errors
}

View file

@ -0,0 +1,38 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Dialog windows operations.
*/
var FCKDialog = new Object() ;
// This method opens a dialog window using the standard dialog template.
FCKDialog.OpenDialog = function( dialogName, dialogTitle, dialogPage, width, height, customValue, parentWindow, resizable )
{
// Setup the dialog info.
var oDialogInfo = new Object() ;
oDialogInfo.Title = dialogTitle ;
oDialogInfo.Page = dialogPage ;
oDialogInfo.Editor = window ;
oDialogInfo.CustomValue = customValue ; // Optional
var sUrl = FCKConfig.BasePath + 'fckdialog.html' ;
this.Show( oDialogInfo, dialogName, sUrl, width, height, parentWindow, resizable ) ;
}

View file

@ -0,0 +1,103 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Dialog windows operations. (Gecko specific implementations)
*/
FCKDialog.Show = function( dialogInfo, dialogName, pageUrl, dialogWidth, dialogHeight, parentWindow, resizable )
{
var iTop = (FCKConfig.ScreenHeight - dialogHeight) / 2 ;
var iLeft = (FCKConfig.ScreenWidth - dialogWidth) / 2 ;
var sOption = "location=no,menubar=no,toolbar=no,dependent=yes,dialog=yes,minimizable=no,alwaysRaised=yes" +
",resizable=" + ( resizable ? 'yes' : 'no' ) +
",width=" + dialogWidth +
",height=" + dialogHeight +
",top=" + iTop +
",left=" + iLeft ;
if ( !parentWindow )
parentWindow = window ;
FCKFocusManager.Lock() ;
var oWindow = parentWindow.open( '', 'FCKeditorDialog_' + dialogName, sOption, true ) ;
if ( !oWindow )
{
alert( FCKLang.DialogBlocked ) ;
FCKFocusManager.Unlock() ;
return ;
}
oWindow.moveTo( iLeft, iTop ) ;
oWindow.resizeTo( dialogWidth, dialogHeight ) ;
oWindow.focus() ;
oWindow.location.href = pageUrl ;
oWindow.dialogArguments = dialogInfo ;
// On some Gecko browsers (probably over slow connections) the
// "dialogArguments" are not set to the target window so we must
// put it in the opener window so it can be used by the target one.
parentWindow.FCKLastDialogInfo = dialogInfo ;
this.Window = oWindow ;
// Try/Catch must be used to avoid an error when using a frameset
// on a different domain:
// "Permission denied to get property Window.releaseEvents".
try
{
window.top.parent.addEventListener( 'mousedown', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'mouseup', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'click', this.CheckFocus, true ) ;
window.top.parent.addEventListener( 'focus', this.CheckFocus, true ) ;
}
catch (e)
{}
}
FCKDialog.CheckFocus = function()
{
// It is strange, but we have to check the FCKDialog existence to avoid a
// random error: "FCKDialog is not defined".
if ( typeof( FCKDialog ) != "object" )
return false ;
if ( FCKDialog.Window && !FCKDialog.Window.closed )
FCKDialog.Window.focus() ;
else
{
// Try/Catch must be used to avoid an error when using a frameset
// on a different domain:
// "Permission denied to get property Window.releaseEvents".
try
{
window.top.parent.removeEventListener( 'onmousedown', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'mouseup', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'click', FCKDialog.CheckFocus, true ) ;
window.top.parent.removeEventListener( 'onfocus', FCKDialog.CheckFocus, true ) ;
}
catch (e)
{}
}
return false ;
}

View file

@ -0,0 +1,49 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Dialog windows operations. (IE specific implementations)
*/
FCKDialog.Show = function( dialogInfo, dialogName, pageUrl, dialogWidth, dialogHeight, parentWindow, resizable )
{
if ( !parentWindow )
parentWindow = window ;
var sOptions = 'help:no;scroll:no;status:no' +
';resizable:' + ( resizable ? 'yes' : 'no' ) +
';dialogWidth:' + dialogWidth + 'px' +
';dialogHeight:' + dialogHeight + 'px' ;
FCKFocusManager.Lock() ;
var oReturn = 'B' ;
try
{
dialogInfo.DialogName = dialogName ;
oReturn = parentWindow.showModalDialog( pageUrl, dialogInfo, sOptions ) ;
}
catch( e ) {}
if ( 'B' === oReturn )
alert( FCKLang.DialogBlocked ) ;
FCKFocusManager.Unlock() ;
}

View file

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

View file

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

View file

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

View file

@ -0,0 +1,152 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Tool object to manage HTML lists items (UL, OL and LI).
*/
var FCKListHandler =
{
OutdentListItem : function( listItem )
{
var eParent = listItem.parentNode ;
// It may happen that a LI is not in a UL or OL (Orphan).
if ( eParent.tagName.toUpperCase().Equals( 'UL','OL' ) )
{
var oDocument = FCKTools.GetElementDocument( listItem ) ;
var oDogFrag = new FCKDocumentFragment( oDocument ) ;
// All children and successive siblings will be moved to a a DocFrag.
var eNextSiblings = oDogFrag.RootNode ;
var eHasLiSibling = false ;
// If we have nested lists inside it, let's move it to the list of siblings.
var eChildList = FCKDomTools.GetFirstChild( listItem, ['UL','OL'] ) ;
if ( eChildList )
{
eHasLiSibling = true ;
var eChild ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while ( (eChild = eChildList.firstChild) )
eNextSiblings.appendChild( eChildList.removeChild( eChild ) ) ;
FCKDomTools.RemoveNode( eChildList ) ;
}
// Move all successive siblings.
var eSibling ;
var eHasSuccessiveLiSibling = false ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while ( (eSibling = listItem.nextSibling) )
{
if ( !eHasLiSibling && eSibling.nodeType == 1 && eSibling.nodeName.toUpperCase() == 'LI' )
eHasSuccessiveLiSibling = eHasLiSibling = true ;
eNextSiblings.appendChild( eSibling.parentNode.removeChild( eSibling ) ) ;
// If a sibling is a incorrectly nested UL or OL, consider only its children.
if ( !eHasSuccessiveLiSibling && eSibling.nodeType == 1 && eSibling.nodeName.toUpperCase().Equals( 'UL','OL' ) )
FCKDomTools.RemoveNode( eSibling, true ) ;
}
// If we are in a list chain.
var sParentParentTag = eParent.parentNode.tagName.toUpperCase() ;
var bWellNested = ( sParentParentTag == 'LI' ) ;
if ( bWellNested || sParentParentTag.Equals( 'UL','OL' ) )
{
if ( eHasLiSibling )
{
var eChildList = eParent.cloneNode( false ) ;
oDogFrag.AppendTo( eChildList ) ;
listItem.appendChild( eChildList ) ;
}
else if ( bWellNested )
oDogFrag.InsertAfterNode( eParent.parentNode ) ;
else
oDogFrag.InsertAfterNode( eParent ) ;
// Move the LI after its parent.parentNode (the upper LI in the hierarchy).
if ( bWellNested )
FCKDomTools.InsertAfterNode( eParent.parentNode, eParent.removeChild( listItem ) ) ;
else
FCKDomTools.InsertAfterNode( eParent, eParent.removeChild( listItem ) ) ;
}
else
{
if ( eHasLiSibling )
{
var eNextList = eParent.cloneNode( false ) ;
oDogFrag.AppendTo( eNextList ) ;
FCKDomTools.InsertAfterNode( eParent, eNextList ) ;
}
var eBlock = oDocument.createElement( FCKConfig.EnterMode == 'p' ? 'p' : 'div' ) ;
FCKDomTools.MoveChildren( eParent.removeChild( listItem ), eBlock ) ;
FCKDomTools.InsertAfterNode( eParent, eBlock ) ;
if ( FCKConfig.EnterMode == 'br' )
{
// We need the bogus to make it work properly. In Gecko, we
// need it before the new block, on IE, after it.
if ( FCKBrowserInfo.IsGecko )
eBlock.parentNode.insertBefore( FCKTools.CreateBogusBR( oDocument ), eBlock ) ;
else
FCKDomTools.InsertAfterNode( eBlock, FCKTools.CreateBogusBR( oDocument ) ) ;
FCKDomTools.RemoveNode( eBlock, true ) ;
}
}
if ( this.CheckEmptyList( eParent ) )
FCKDomTools.RemoveNode( eParent, true ) ;
}
},
CheckEmptyList : function( listElement )
{
return ( FCKDomTools.GetFirstChild( listElement, 'LI' ) == null ) ;
},
// Check if the list has contents (excluding nested lists).
CheckListHasContents : function( listElement )
{
var eChildNode = listElement.firstChild ;
while ( eChildNode )
{
switch ( eChildNode.nodeType )
{
case 1 :
if ( !eChildNode.nodeName.IEquals( 'UL','LI' ) )
return true ;
break ;
case 3 :
if ( eChildNode.nodeValue.Trim().length > 0 )
return true ;
}
eChildNode = eChildNode.nextSibling ;
}
return false ;
}
} ;

View file

@ -0,0 +1,60 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Library of keys collections.
*
* Test have shown that check for the existence of a key in an object is the
* most efficient list entry check (10x faster that regex). Example:
* if ( FCKListsLib.<ListName>[key] != null )
*/
var FCKListsLib =
{
// We are not handling <ins> and <del> as block elements, for now.
BlockElements : { address:1,blockquote:1,center:1,div:1,dl:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,marquee:1,noscript:1,ol:1,p:1,pre:1,script:1,table:1,ul:1 },
// Block elements that may be filled with &nbsp; if empty.
NonEmptyBlockElements : { p:1,div:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,address:1,pre:1,ol:1,ul:1,li:1,td:1,th:1 },
// Inline elements which MUST have child nodes.
InlineChildReqElements : { abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
// Inline elements which are not marked as empty "Empty" in the XHTML DTD.
InlineNonEmptyElements : { a:1,abbr:1,acronym:1,b:1,bdo:1,big:1,cite:1,code:1,del:1,dfn:1,em:1,font:1,i:1,ins:1,label:1,kbd:1,q:1,samp:1,small:1,span:1,strike:1,strong:1,sub:1,sup:1,tt:1,u:1,'var':1 },
// Elements marked as empty "Empty" in the XHTML DTD.
EmptyElements : { base:1,col:1,meta:1,link:1,hr:1,br:1,param:1,img:1,area:1,input:1 },
// Elements that may be considered the "Block boundary" in an element path.
PathBlockElements : { address:1,blockquote:1,dl:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1,li:1,dt:1,de:1 },
// Elements that may be considered the "Block limit" in an element path.
PathBlockLimitElements : { body:1,div:1,td:1,th:1,caption:1,form:1 },
// Block elements for the Styles System.
StyleBlockElements : { address:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,p:1,pre:1 },
// Object elements for the Styles System.
StyleObjectElements : { img:1,hr:1,li:1,table:1,tr:1,td:1,embed:1,object:1,ol:1,ul:1 },
// Elements used to separate block contents.
BlockBoundaries : { p:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,address:1,pre:1,ol:1,ul:1,li:1,dt:1,de:1,table:1,thead:1,tbody:1,tfoot:1,tr:1,th:1,td:1,caption:1,col:1,colgroup:1,blockquote:1,body:1 },
ListBoundaries : { p:1,div:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,hr:1,address:1,pre:1,ol:1,ul:1,li:1,dt:1,de:1,table:1,thead:1,tbody:1,tfoot:1,tr:1,th:1,td:1,caption:1,col:1,colgroup:1,blockquote:1,body:1,br:1 }
} ;

View file

@ -0,0 +1,46 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKPlugins object that is responsible for loading the Plugins.
*/
var FCKPlugins = FCK.Plugins = new Object() ;
FCKPlugins.ItemsCount = 0 ;
FCKPlugins.Items = new Object() ;
FCKPlugins.Load = function()
{
var oItems = FCKPlugins.Items ;
// build the plugins collection.
for ( var i = 0 ; i < FCKConfig.Plugins.Items.length ; i++ )
{
var oItem = FCKConfig.Plugins.Items[i] ;
var oPlugin = oItems[ oItem[0] ] = new FCKPlugin( oItem[0], oItem[1], oItem[2] ) ;
FCKPlugins.ItemsCount++ ;
}
// Load all items in the plugins collection.
for ( var s in oItems )
oItems[s].Load() ;
// This is a self destroyable function (must be called once).
FCKPlugins.Load = null ;
}

View file

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

View file

@ -0,0 +1,42 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Active selection functions.
*/
var FCKSelection = FCK.Selection =
{
GetParentBlock : function()
{
var retval = this.GetParentElement() ;
while ( retval )
{
if ( FCKListsLib.BlockBoundaries[retval.nodeName.toLowerCase()] )
break ;
retval = retval.parentNode ;
}
return retval ;
},
ApplyStyle : function( styleDefinition )
{
FCKStyles.ApplyStyle( new FCKStyle( styleDefinition ) ) ;
}
} ;

View file

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

View file

@ -0,0 +1,201 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Active selection functions. (IE specific implementation)
*/
// Get the selection type.
FCKSelection.GetType = function()
{
// It is possible that we can still get a text range object even when type=='None' is returned by IE.
// So we'd better check the object returned by createRange() rather than by looking at the type.
try
{
var ieType = FCK.EditorDocument.selection.type ;
if ( ieType == 'Control' || ieType == 'Text' )
return ieType ;
if ( FCK.EditorDocument.selection.createRange().parentElement )
return 'Text' ;
}
catch(e)
{
// Nothing to do, it will return None properly.
}
return 'None' ;
} ;
// Retrieves the selected element (if any), just in the case that a single
// element (object like and image or a table) is selected.
FCKSelection.GetSelectedElement = function()
{
if ( this.GetType() == 'Control' )
{
var oRange = FCK.EditorDocument.selection.createRange() ;
if ( oRange && oRange.item )
return FCK.EditorDocument.selection.createRange().item(0) ;
}
return null ;
} ;
FCKSelection.GetParentElement = function()
{
switch ( this.GetType() )
{
case 'Control' :
var el = FCKSelection.GetSelectedElement() ;
return el ? el.parentElement : null ;
case 'None' :
return null ;
default :
return FCK.EditorDocument.selection.createRange().parentElement() ;
}
} ;
FCKSelection.GetBoundaryParentElement = function( startBoundary )
{
switch ( this.GetType() )
{
case 'Control' :
var el = FCKSelection.GetSelectedElement() ;
return el ? el.parentElement : null ;
case 'None' :
return null ;
default :
var doc = FCK.EditorDocument ;
var range = doc.selection.createRange() ;
range.collapse( startBoundary !== false ) ;
var el = range.parentElement() ;
// It may happen that range is comming from outside "doc", so we
// must check it (#1204).
return FCKTools.GetElementDocument( el ) == doc ? el : null ;
}
} ;
FCKSelection.SelectNode = function( node )
{
FCK.Focus() ;
FCK.EditorDocument.selection.empty() ;
var oRange ;
try
{
// Try to select the node as a control.
oRange = FCK.EditorDocument.body.createControlRange() ;
oRange.addElement( node ) ;
}
catch(e)
{
// If failed, select it as a text range.
oRange = FCK.EditorDocument.body.createTextRange() ;
oRange.moveToElementText( node ) ;
}
oRange.select() ;
} ;
FCKSelection.Collapse = function( toStart )
{
FCK.Focus() ;
if ( this.GetType() == 'Text' )
{
var oRange = FCK.EditorDocument.selection.createRange() ;
oRange.collapse( toStart == null || toStart === true ) ;
oRange.select() ;
}
} ;
// The "nodeTagName" parameter must be Upper Case.
FCKSelection.HasAncestorNode = function( nodeTagName )
{
var oContainer ;
if ( FCK.EditorDocument.selection.type == "Control" )
{
oContainer = this.GetSelectedElement() ;
}
else
{
var oRange = FCK.EditorDocument.selection.createRange() ;
oContainer = oRange.parentElement() ;
}
while ( oContainer )
{
if ( oContainer.tagName == nodeTagName ) return true ;
oContainer = oContainer.parentNode ;
}
return false ;
} ;
// The "nodeTagName" parameter must be UPPER CASE.
FCKSelection.MoveToAncestorNode = function( nodeTagName )
{
var oNode, oRange ;
if ( ! FCK.EditorDocument )
return null ;
if ( FCK.EditorDocument.selection.type == "Control" )
{
oRange = FCK.EditorDocument.selection.createRange() ;
for ( i = 0 ; i < oRange.length ; i++ )
{
if (oRange(i).parentNode)
{
oNode = oRange(i).parentNode ;
break ;
}
}
}
else
{
oRange = FCK.EditorDocument.selection.createRange() ;
oNode = oRange.parentElement() ;
}
while ( oNode && oNode.nodeName != nodeTagName )
oNode = oNode.parentNode ;
return oNode ;
} ;
FCKSelection.Delete = function()
{
// Gets the actual selection.
var oSel = FCK.EditorDocument.selection ;
// Deletes the actual selection contents.
if ( oSel.type.toLowerCase() != "none" )
{
oSel.clear() ;
}
return oSel ;
} ;

View file

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

View file

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

View file

@ -0,0 +1,56 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Manage table operations (non-IE).
*/
FCKTableHandler.GetSelectedCells = function()
{
var aCells = new Array() ;
var oSelection = FCK.EditorWindow.getSelection() ;
// If the selection is a text.
if ( oSelection.rangeCount == 1 && oSelection.anchorNode.nodeType == 3 )
{
var oParent = FCKTools.GetElementAscensor( oSelection.anchorNode, 'TD,TH' ) ;
if ( oParent )
aCells[0] = oParent ;
return aCells ;
}
for ( var i = 0 ; i < oSelection.rangeCount ; i++ )
{
var oRange = oSelection.getRangeAt(i) ;
var oCell ;
if ( oRange.startContainer.tagName.Equals( 'TD', 'TH' ) )
oCell = oRange.startContainer ;
else
oCell = oRange.startContainer.childNodes[ oRange.startOffset ] ;
if ( oCell.tagName.Equals( 'TD', 'TH' ) )
aCells[aCells.length] = oCell ;
}
return aCells ;
}

View file

@ -0,0 +1,64 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Manage table operations (IE specific).
*/
FCKTableHandler.GetSelectedCells = function()
{
if ( FCKSelection.GetType() == 'Control' )
{
var td = FCKSelection.MoveToAncestorNode( 'TD' ) ;
return td ? [ td ] : [] ;
}
var aCells = new Array() ;
var oRange = FCK.EditorDocument.selection.createRange() ;
// var oParent = oRange.parentElement() ;
var oParent = FCKSelection.GetParentElement() ;
if ( oParent && oParent.tagName.Equals( 'TD', 'TH' ) )
aCells[0] = oParent ;
else
{
oParent = FCKSelection.MoveToAncestorNode( 'TABLE' ) ;
if ( oParent )
{
// Loops throw all cells checking if the cell is, or part of it, is inside the selection
// and then add it to the selected cells collection.
for ( var i = 0 ; i < oParent.cells.length ; i++ )
{
var oCellRange = FCK.EditorDocument.body.createTextRange() ;
oCellRange.moveToElementText( oParent.cells[i] ) ;
if ( oRange.inRange( oCellRange )
|| ( oRange.compareEndPoints('StartToStart',oCellRange) >= 0 && oRange.compareEndPoints('StartToEnd',oCellRange) <= 0 )
|| ( oRange.compareEndPoints('EndToStart',oCellRange) >= 0 && oRange.compareEndPoints('EndToEnd',oCellRange) <= 0 ) )
{
aCells[aCells.length] = oParent.cells[i] ;
}
}
}
}
return aCells ;
}

View file

@ -0,0 +1,123 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Toolbar items definitions.
*/
var FCKToolbarItems = new Object() ;
FCKToolbarItems.LoadedItems = new Object() ;
FCKToolbarItems.RegisterItem = function( itemName, item )
{
this.LoadedItems[ itemName ] = item ;
}
FCKToolbarItems.GetItem = function( itemName )
{
var oItem = FCKToolbarItems.LoadedItems[ itemName ] ;
if ( oItem )
return oItem ;
switch ( itemName )
{
case 'Source' : oItem = new FCKToolbarButton( 'Source' , FCKLang.Source, null, FCK_TOOLBARITEM_ICONTEXT, true, true, 1 ) ; break ;
case 'DocProps' : oItem = new FCKToolbarButton( 'DocProps' , FCKLang.DocProps, null, null, null, null, 2 ) ; break ;
case 'Save' : oItem = new FCKToolbarButton( 'Save' , FCKLang.Save, null, null, true, null, 3 ) ; break ;
case 'NewPage' : oItem = new FCKToolbarButton( 'NewPage' , FCKLang.NewPage, null, null, true, null, 4 ) ; break ;
case 'Preview' : oItem = new FCKToolbarButton( 'Preview' , FCKLang.Preview, null, null, true, null, 5 ) ; break ;
case 'Templates' : oItem = new FCKToolbarButton( 'Templates' , FCKLang.Templates, null, null, null, null, 6 ) ; break ;
case 'About' : oItem = new FCKToolbarButton( 'About' , FCKLang.About, null, null, true, null, 47 ) ; break ;
case 'Cut' : oItem = new FCKToolbarButton( 'Cut' , FCKLang.Cut, null, null, false, true, 7 ) ; break ;
case 'Copy' : oItem = new FCKToolbarButton( 'Copy' , FCKLang.Copy, null, null, false, true, 8 ) ; break ;
case 'Paste' : oItem = new FCKToolbarButton( 'Paste' , FCKLang.Paste, null, null, false, true, 9 ) ; break ;
case 'PasteText' : oItem = new FCKToolbarButton( 'PasteText' , FCKLang.PasteText, null, null, false, true, 10 ) ; break ;
case 'PasteWord' : oItem = new FCKToolbarButton( 'PasteWord' , FCKLang.PasteWord, null, null, false, true, 11 ) ; break ;
case 'Print' : oItem = new FCKToolbarButton( 'Print' , FCKLang.Print, null, null, false, true, 12 ) ; break ;
case 'SpellCheck' : oItem = new FCKToolbarButton( 'SpellCheck', FCKLang.SpellCheck, null, null, null, null, 13 ) ; break ;
case 'Undo' : oItem = new FCKToolbarButton( 'Undo' , FCKLang.Undo, null, null, false, true, 14 ) ; break ;
case 'Redo' : oItem = new FCKToolbarButton( 'Redo' , FCKLang.Redo, null, null, false, true, 15 ) ; break ;
case 'SelectAll' : oItem = new FCKToolbarButton( 'SelectAll' , FCKLang.SelectAll, null, null, true, null, 18 ) ; break ;
case 'RemoveFormat' : oItem = new FCKToolbarButton( 'RemoveFormat', FCKLang.RemoveFormat, null, null, false, true, 19 ) ; break ;
case 'FitWindow' : oItem = new FCKToolbarButton( 'FitWindow' , FCKLang.FitWindow, null, null, true, true, 66 ) ; break ;
case 'Bold' : oItem = new FCKToolbarButton( 'Bold' , FCKLang.Bold, null, null, false, true, 20 ) ; break ;
case 'Italic' : oItem = new FCKToolbarButton( 'Italic' , FCKLang.Italic, null, null, false, true, 21 ) ; break ;
case 'Underline' : oItem = new FCKToolbarButton( 'Underline' , FCKLang.Underline, null, null, false, true, 22 ) ; break ;
case 'StrikeThrough' : oItem = new FCKToolbarButton( 'StrikeThrough' , FCKLang.StrikeThrough, null, null, false, true, 23 ) ; break ;
case 'Subscript' : oItem = new FCKToolbarButton( 'Subscript' , FCKLang.Subscript, null, null, false, true, 24 ) ; break ;
case 'Superscript' : oItem = new FCKToolbarButton( 'Superscript' , FCKLang.Superscript, null, null, false, true, 25 ) ; break ;
case 'OrderedList' : oItem = new FCKToolbarButton( 'InsertOrderedList' , FCKLang.NumberedListLbl, FCKLang.NumberedList, null, false, true, 26 ) ; break ;
case 'UnorderedList' : oItem = new FCKToolbarButton( 'InsertUnorderedList' , FCKLang.BulletedListLbl, FCKLang.BulletedList, null, false, true, 27 ) ; break ;
case 'Outdent' : oItem = new FCKToolbarButton( 'Outdent' , FCKLang.DecreaseIndent, null, null, false, true, 28 ) ; break ;
case 'Indent' : oItem = new FCKToolbarButton( 'Indent' , FCKLang.IncreaseIndent, null, null, false, true, 29 ) ; break ;
case 'Blockquote' : oItem = new FCKToolbarButton( 'Blockquote' , FCKLang.Blockquote, null, null, false, true, 73 ) ; break ;
case 'Link' : oItem = new FCKToolbarButton( 'Link' , FCKLang.InsertLinkLbl, FCKLang.InsertLink, null, false, true, 34 ) ; break ;
case 'Unlink' : oItem = new FCKToolbarButton( 'Unlink' , FCKLang.RemoveLink, null, null, false, true, 35 ) ; break ;
case 'Anchor' : oItem = new FCKToolbarButton( 'Anchor' , FCKLang.Anchor, null, null, null, null, 36 ) ; break ;
case 'Image' : oItem = new FCKToolbarButton( 'Image' , FCKLang.InsertImageLbl, FCKLang.InsertImage, null, false, true, 37 ) ; break ;
case 'Flash' : oItem = new FCKToolbarButton( 'Flash' , FCKLang.InsertFlashLbl, FCKLang.InsertFlash, null, false, true, 38 ) ; break ;
case 'Table' : oItem = new FCKToolbarButton( 'Table' , FCKLang.InsertTableLbl, FCKLang.InsertTable, null, false, true, 39 ) ; break ;
case 'SpecialChar' : oItem = new FCKToolbarButton( 'SpecialChar' , FCKLang.InsertSpecialCharLbl, FCKLang.InsertSpecialChar, null, false, true, 42 ) ; break ;
case 'Smiley' : oItem = new FCKToolbarButton( 'Smiley' , FCKLang.InsertSmileyLbl, FCKLang.InsertSmiley, null, false, true, 41 ) ; break ;
case 'PageBreak' : oItem = new FCKToolbarButton( 'PageBreak' , FCKLang.PageBreakLbl, FCKLang.PageBreak, null, false, true, 43 ) ; break ;
case 'Rule' : oItem = new FCKToolbarButton( 'Rule' , FCKLang.InsertLineLbl, FCKLang.InsertLine, null, false, true, 40 ) ; break ;
case 'JustifyLeft' : oItem = new FCKToolbarButton( 'JustifyLeft' , FCKLang.LeftJustify, null, null, false, true, 30 ) ; break ;
case 'JustifyCenter' : oItem = new FCKToolbarButton( 'JustifyCenter' , FCKLang.CenterJustify, null, null, false, true, 31 ) ; break ;
case 'JustifyRight' : oItem = new FCKToolbarButton( 'JustifyRight' , FCKLang.RightJustify, null, null, false, true, 32 ) ; break ;
case 'JustifyFull' : oItem = new FCKToolbarButton( 'JustifyFull' , FCKLang.BlockJustify, null, null, false, true, 33 ) ; break ;
case 'Style' : oItem = new FCKToolbarStyleCombo() ; break ;
case 'FontName' : oItem = new FCKToolbarFontsCombo() ; break ;
case 'FontSize' : oItem = new FCKToolbarFontSizeCombo() ; break ;
case 'FontFormat' : oItem = new FCKToolbarFontFormatCombo() ; break ;
case 'TextColor' : oItem = new FCKToolbarPanelButton( 'TextColor', FCKLang.TextColor, null, null, 45 ) ; break ;
case 'BGColor' : oItem = new FCKToolbarPanelButton( 'BGColor' , FCKLang.BGColor, null, null, 46 ) ; break ;
case 'Find' : oItem = new FCKToolbarButton( 'Find' , FCKLang.Find, null, null, null, null, 16 ) ; break ;
case 'Replace' : oItem = new FCKToolbarButton( 'Replace' , FCKLang.Replace, null, null, null, null, 17 ) ; break ;
case 'Form' : oItem = new FCKToolbarButton( 'Form' , FCKLang.Form, null, null, null, null, 48 ) ; break ;
case 'Checkbox' : oItem = new FCKToolbarButton( 'Checkbox' , FCKLang.Checkbox, null, null, null, null, 49 ) ; break ;
case 'Radio' : oItem = new FCKToolbarButton( 'Radio' , FCKLang.RadioButton, null, null, null, null, 50 ) ; break ;
case 'TextField' : oItem = new FCKToolbarButton( 'TextField' , FCKLang.TextField, null, null, null, null, 51 ) ; break ;
case 'Textarea' : oItem = new FCKToolbarButton( 'Textarea' , FCKLang.Textarea, null, null, null, null, 52 ) ; break ;
case 'HiddenField' : oItem = new FCKToolbarButton( 'HiddenField' , FCKLang.HiddenField, null, null, null, null, 56 ) ; break ;
case 'Button' : oItem = new FCKToolbarButton( 'Button' , FCKLang.Button, null, null, null, null, 54 ) ; break ;
case 'Select' : oItem = new FCKToolbarButton( 'Select' , FCKLang.SelectionField, null, null, null, null, 53 ) ; break ;
case 'ImageButton' : oItem = new FCKToolbarButton( 'ImageButton' , FCKLang.ImageButton, null, null, null, null, 55 ) ; break ;
case 'ShowBlocks' : oItem = new FCKToolbarButton( 'ShowBlocks' , FCKLang.ShowBlocks, null, null, null, true, 72 ) ; break ;
default:
alert( FCKLang.UnknownToolbarItem.replace( /%1/g, itemName ) ) ;
return null ;
}
FCKToolbarItems.LoadedItems[ itemName ] = oItem ;
return oItem ;
}

View file

@ -0,0 +1,373 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKToolbarSet object that is used to load and draw the
* toolbar.
*/
function FCKToolbarSet_Create( overhideLocation )
{
var oToolbarSet ;
var sLocation = overhideLocation || FCKConfig.ToolbarLocation ;
switch ( sLocation )
{
case 'In' :
document.getElementById( 'xToolbarRow' ).style.display = '' ;
oToolbarSet = new FCKToolbarSet( document ) ;
break ;
case 'None' :
oToolbarSet = new FCKToolbarSet( document ) ;
break ;
// case 'OutTop' :
// Not supported.
default :
FCK.Events.AttachEvent( 'OnBlur', FCK_OnBlur ) ;
FCK.Events.AttachEvent( 'OnFocus', FCK_OnFocus ) ;
var eToolbarTarget ;
// Out:[TargetWindow]([TargetId])
var oOutMatch = sLocation.match( /^Out:(.+)\((\w+)\)$/ ) ;
if ( oOutMatch )
{
eToolbarTarget = eval( 'parent.' + oOutMatch[1] ).document.getElementById( oOutMatch[2] ) ;
}
else
{
// Out:[TargetId]
oOutMatch = sLocation.match( /^Out:(\w+)$/ ) ;
if ( oOutMatch )
eToolbarTarget = parent.document.getElementById( oOutMatch[1] ) ;
}
if ( !eToolbarTarget )
{
alert( 'Invalid value for "ToolbarLocation"' ) ;
return arguments.callee( 'In' );
}
// If it is a shared toolbar, it may be already available in the target element.
oToolbarSet = eToolbarTarget.__FCKToolbarSet ;
if ( oToolbarSet )
break ;
// Create the IFRAME that will hold the toolbar inside the target element.
var eToolbarIFrame = FCKTools.GetElementDocument( eToolbarTarget ).createElement( 'iframe' ) ;
eToolbarIFrame.src = 'javascript:void(0)' ;
eToolbarIFrame.frameBorder = 0 ;
eToolbarIFrame.width = '100%' ;
eToolbarIFrame.height = '10' ;
eToolbarTarget.appendChild( eToolbarIFrame ) ;
eToolbarIFrame.unselectable = 'on' ;
// Write the basic HTML for the toolbar (copy from the editor main page).
var eTargetDocument = eToolbarIFrame.contentWindow.document ;
// Workaround for Safari 12256. Ticket #63
var sBase = '' ;
if ( FCKBrowserInfo.IsSafari )
sBase = '<base href="' + window.document.location + '">' ;
// Initialize the IFRAME document body.
eTargetDocument.open() ;
eTargetDocument.write( '<html><head>' + sBase + '<script type="text/javascript"> var adjust = function() { window.frameElement.height = document.body.scrollHeight ; }; window.onresize = adjust; window.onload = function () {window.setTimeout( adjust, 0 );}</script></head><body style="overflow: hidden">' + document.getElementById( 'xToolbarSpace' ).innerHTML + '</body></html>' ) ;
eTargetDocument.close() ;
FCKTools.AddEventListener( eTargetDocument, 'contextmenu', FCKTools.CancelEvent ) ;
// Load external resources (must be done here, otherwise Firefox will not
// have the document DOM ready to be used right away.
FCKTools.AppendStyleSheet( eTargetDocument, FCKConfig.SkinPath + 'fck_editor.css' ) ;
oToolbarSet = eToolbarTarget.__FCKToolbarSet = new FCKToolbarSet( eTargetDocument ) ;
oToolbarSet._IFrame = eToolbarIFrame ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( eToolbarTarget, FCKToolbarSet_Target_Cleanup ) ;
}
oToolbarSet.CurrentInstance = FCK ;
FCK.AttachToOnSelectionChange( oToolbarSet.RefreshItemsState ) ;
return oToolbarSet ;
}
function FCK_OnBlur( editorInstance )
{
var eToolbarSet = editorInstance.ToolbarSet ;
if ( eToolbarSet.CurrentInstance == editorInstance )
eToolbarSet.Disable() ;
}
function FCK_OnFocus( editorInstance )
{
var oToolbarset = editorInstance.ToolbarSet ;
var oInstance = editorInstance || FCK ;
// Unregister the toolbar window from the current instance.
oToolbarset.CurrentInstance.FocusManager.RemoveWindow( oToolbarset._IFrame.contentWindow ) ;
// Set the new current instance.
oToolbarset.CurrentInstance = oInstance ;
// Register the toolbar window in the current instance.
oInstance.FocusManager.AddWindow( oToolbarset._IFrame.contentWindow, true ) ;
oToolbarset.Enable() ;
}
function FCKToolbarSet_Cleanup()
{
this._TargetElement = null ;
this._IFrame = null ;
}
function FCKToolbarSet_Target_Cleanup()
{
this.__FCKToolbarSet = null ;
}
var FCKToolbarSet = function( targetDocument )
{
this._Document = targetDocument ;
// Get the element that will hold the elements structure.
this._TargetElement = targetDocument.getElementById( 'xToolbar' ) ;
// Setup the expand and collapse handlers.
var eExpandHandle = targetDocument.getElementById( 'xExpandHandle' ) ;
var eCollapseHandle = targetDocument.getElementById( 'xCollapseHandle' ) ;
eExpandHandle.title = FCKLang.ToolbarExpand ;
FCKTools.AddEventListener( eExpandHandle, 'click', FCKToolbarSet_Expand_OnClick ) ;
eCollapseHandle.title = FCKLang.ToolbarCollapse ;
FCKTools.AddEventListener( eCollapseHandle, 'click', FCKToolbarSet_Collapse_OnClick ) ;
// Set the toolbar state at startup.
if ( !FCKConfig.ToolbarCanCollapse || FCKConfig.ToolbarStartExpanded )
this.Expand() ;
else
this.Collapse() ;
// Enable/disable the collapse handler
eCollapseHandle.style.display = FCKConfig.ToolbarCanCollapse ? '' : 'none' ;
if ( FCKConfig.ToolbarCanCollapse )
eCollapseHandle.style.display = '' ;
else
targetDocument.getElementById( 'xTBLeftBorder' ).style.display = '' ;
// Set the default properties.
this.Toolbars = new Array() ;
this.IsLoaded = false ;
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( this, FCKToolbarSet_Cleanup ) ;
}
function FCKToolbarSet_Expand_OnClick()
{
FCK.ToolbarSet.Expand() ;
}
function FCKToolbarSet_Collapse_OnClick()
{
FCK.ToolbarSet.Collapse() ;
}
FCKToolbarSet.prototype.Expand = function()
{
this._ChangeVisibility( false ) ;
}
FCKToolbarSet.prototype.Collapse = function()
{
this._ChangeVisibility( true ) ;
}
FCKToolbarSet.prototype._ChangeVisibility = function( collapse )
{
this._Document.getElementById( 'xCollapsed' ).style.display = collapse ? '' : 'none' ;
this._Document.getElementById( 'xExpanded' ).style.display = collapse ? 'none' : '' ;
if ( FCKBrowserInfo.IsGecko )
{
// I had to use "setTimeout" because Gecko was not responding in a right
// way when calling window.onresize() directly.
FCKTools.RunFunction( window.onresize ) ;
}
}
FCKToolbarSet.prototype.Load = function( toolbarSetName )
{
this.Name = toolbarSetName ;
this.Items = new Array() ;
// Reset the array of toolbar items that are active only on WYSIWYG mode.
this.ItemsWysiwygOnly = new Array() ;
// Reset the array of toolbar items that are sensitive to the cursor position.
this.ItemsContextSensitive = new Array() ;
// Cleanup the target element.
this._TargetElement.innerHTML = '' ;
var ToolbarSet = FCKConfig.ToolbarSets[toolbarSetName] ;
if ( !ToolbarSet )
{
alert( FCKLang.UnknownToolbarSet.replace( /%1/g, toolbarSetName ) ) ;
return ;
}
this.Toolbars = new Array() ;
for ( var x = 0 ; x < ToolbarSet.length ; x++ )
{
var oToolbarItems = ToolbarSet[x] ;
// If the configuration for the toolbar is missing some element or has any extra comma
// this item won't be valid, so skip it and keep on processing.
if ( !oToolbarItems )
continue ;
var oToolbar ;
if ( typeof( oToolbarItems ) == 'string' )
{
if ( oToolbarItems == '/' )
oToolbar = new FCKToolbarBreak() ;
}
else
{
oToolbar = new FCKToolbar() ;
for ( var j = 0 ; j < oToolbarItems.length ; j++ )
{
var sItem = oToolbarItems[j] ;
if ( sItem == '-')
oToolbar.AddSeparator() ;
else
{
var oItem = FCKToolbarItems.GetItem( sItem ) ;
if ( oItem )
{
oToolbar.AddItem( oItem ) ;
this.Items.push( oItem ) ;
if ( !oItem.SourceView )
this.ItemsWysiwygOnly.push( oItem ) ;
if ( oItem.ContextSensitive )
this.ItemsContextSensitive.push( oItem ) ;
}
}
}
// oToolbar.AddTerminator() ;
}
oToolbar.Create( this._TargetElement ) ;
this.Toolbars[ this.Toolbars.length ] = oToolbar ;
}
FCKTools.DisableSelection( this._Document.getElementById( 'xCollapseHandle' ).parentNode ) ;
if ( FCK.Status != FCK_STATUS_COMPLETE )
FCK.Events.AttachEvent( 'OnStatusChange', this.RefreshModeState ) ;
else
this.RefreshModeState() ;
this.IsLoaded = true ;
this.IsEnabled = true ;
FCKTools.RunFunction( this.OnLoad ) ;
}
FCKToolbarSet.prototype.Enable = function()
{
if ( this.IsEnabled )
return ;
this.IsEnabled = true ;
var aItems = this.Items ;
for ( var i = 0 ; i < aItems.length ; i++ )
aItems[i].RefreshState() ;
}
FCKToolbarSet.prototype.Disable = function()
{
if ( !this.IsEnabled )
return ;
this.IsEnabled = false ;
var aItems = this.Items ;
for ( var i = 0 ; i < aItems.length ; i++ )
aItems[i].Disable() ;
}
FCKToolbarSet.prototype.RefreshModeState = function( editorInstance )
{
if ( FCK.Status != FCK_STATUS_COMPLETE )
return ;
var oToolbarSet = editorInstance ? editorInstance.ToolbarSet : this ;
var aItems = oToolbarSet.ItemsWysiwygOnly ;
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
{
// Enable all buttons that are available on WYSIWYG mode only.
for ( var i = 0 ; i < aItems.length ; i++ )
aItems[i].Enable() ;
// Refresh the buttons state.
oToolbarSet.RefreshItemsState( editorInstance ) ;
}
else
{
// Refresh the buttons state.
oToolbarSet.RefreshItemsState( editorInstance ) ;
// Disable all buttons that are available on WYSIWYG mode only.
for ( var j = 0 ; j < aItems.length ; j++ )
aItems[j].Disable() ;
}
}
FCKToolbarSet.prototype.RefreshItemsState = function( editorInstance )
{
var aItems = ( editorInstance ? editorInstance.ToolbarSet : this ).ItemsContextSensitive ;
for ( var i = 0 ; i < aItems.length ; i++ )
aItems[i].RefreshState() ;
}

View file

@ -0,0 +1,621 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Utility functions.
*/
var FCKTools = new Object() ;
FCKTools.CreateBogusBR = function( targetDocument )
{
var eBR = targetDocument.createElement( 'br' ) ;
// eBR.setAttribute( '_moz_editor_bogus_node', 'TRUE' ) ;
eBR.setAttribute( 'type', '_moz' ) ;
return eBR ;
}
// Returns a reference to the appended style sheet or an array with all the appended references
FCKTools.AppendStyleSheet = function( documentElement, cssFileUrlOrArray )
{
if ( typeof( cssFileUrlOrArray ) == 'string' )
return this._AppendStyleSheet( documentElement, cssFileUrlOrArray ) ;
else
{
var aStyleSheeArray = new Array() ;
for ( var i = 0 ; i < cssFileUrlOrArray.length ; i++ )
aStyleSheeArray.push(this._AppendStyleSheet( documentElement, cssFileUrlOrArray[i] ) ) ;
return aStyleSheeArray ;
}
}
FCKTools.AppendStyleString = function ( documentElement, cssStyles )
{
this._AppendStyleString( documentElement, cssStyles ) ;
}
FCKTools.GetElementDocument = function ( element )
{
return element.ownerDocument || element.document ;
}
// Get the window object where the element is placed in.
FCKTools.GetElementWindow = function( element )
{
return this.GetDocumentWindow( this.GetElementDocument( element ) ) ;
}
FCKTools.GetDocumentWindow = function( document )
{
// With Safari, there is not way to retrieve the window from the document, so we must fix it.
if ( FCKBrowserInfo.IsSafari && !document.parentWindow )
this.FixDocumentParentWindow( window.top ) ;
return document.parentWindow || document.defaultView ;
}
/*
This is a Safari specific function that fix the reference to the parent
window from the document object.
*/
FCKTools.FixDocumentParentWindow = function( targetWindow )
{
if ( targetWindow.document )
targetWindow.document.parentWindow = targetWindow ;
for ( var i = 0 ; i < targetWindow.frames.length ; i++ )
FCKTools.FixDocumentParentWindow( targetWindow.frames[i] ) ;
}
FCKTools.HTMLEncode = function( text )
{
if ( !text )
return '' ;
text = text.replace( /&/g, '&amp;' ) ;
text = text.replace( /</g, '&lt;' ) ;
text = text.replace( />/g, '&gt;' ) ;
return text ;
}
FCKTools.HTMLDecode = function( text )
{
if ( !text )
return '' ;
text = text.replace( /&gt;/g, '>' ) ;
text = text.replace( /&lt;/g, '<' ) ;
text = text.replace( /&amp;/g, '&' ) ;
return text ;
}
FCKTools._ProcessLineBreaksForPMode = function( oEditor, text, liState, node, strArray )
{
var closeState = 0 ;
var blockStartTag = "<p>" ;
var blockEndTag = "</p>" ;
var lineBreakTag = "<br />" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
closeState = 1 ;
}
// Are we currently inside a <p> tag now?
// If yes, close it at the next double line break.
while ( node && node != oEditor.FCK.EditorDocument.body )
{
if ( node.tagName.toLowerCase() == 'p' )
{
closeState = 1 ;
break;
}
node = node.parentNode ;
}
for ( var i = 0 ; i < text.length ; i++ )
{
var c = text.charAt( i ) ;
if ( c == '\r' )
continue ;
if ( c != '\n' )
{
strArray.push( c ) ;
continue ;
}
// Now we have encountered a line break.
// Check if the next character is also a line break.
var n = text.charAt( i + 1 ) ;
if ( n == '\r' )
{
i++ ;
n = text.charAt( i + 1 ) ;
}
if ( n == '\n' )
{
i++ ; // ignore next character - we have already processed it.
if ( closeState )
strArray.push( blockEndTag ) ;
strArray.push( blockStartTag ) ;
closeState = 1 ;
}
else
strArray.push( lineBreakTag ) ;
}
}
FCKTools._ProcessLineBreaksForDivMode = function( oEditor, text, liState, node, strArray )
{
var closeState = 0 ;
var blockStartTag = "<div>" ;
var blockEndTag = "</div>" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
closeState = 1 ;
}
// Are we currently inside a <div> tag now?
// If yes, close it at the next double line break.
while ( node && node != oEditor.FCK.EditorDocument.body )
{
if ( node.tagName.toLowerCase() == 'div' )
{
closeState = 1 ;
break ;
}
node = node.parentNode ;
}
for ( var i = 0 ; i < text.length ; i++ )
{
var c = text.charAt( i ) ;
if ( c == '\r' )
continue ;
if ( c != '\n' )
{
strArray.push( c ) ;
continue ;
}
if ( closeState )
{
if ( strArray[ strArray.length - 1 ] == blockStartTag )
{
// A div tag must have some contents inside for it to be visible.
strArray.push( "&nbsp;" ) ;
}
strArray.push( blockEndTag ) ;
}
strArray.push( blockStartTag ) ;
closeState = 1 ;
}
if ( closeState )
strArray.push( blockEndTag ) ;
}
FCKTools._ProcessLineBreaksForBrMode = function( oEditor, text, liState, node, strArray )
{
var closeState = 0 ;
var blockStartTag = "<br />" ;
var blockEndTag = "" ;
if ( liState )
{
blockStartTag = "<li>" ;
blockEndTag = "</li>" ;
closeState = 1 ;
}
for ( var i = 0 ; i < text.length ; i++ )
{
var c = text.charAt( i ) ;
if ( c == '\r' )
continue ;
if ( c != '\n' )
{
strArray.push( c ) ;
continue ;
}
if ( closeState && blockEndTag.length )
strArray.push ( blockEndTag ) ;
strArray.push( blockStartTag ) ;
closeState = 1 ;
}
}
FCKTools.ProcessLineBreaks = function( oEditor, oConfig, text )
{
var enterMode = oConfig.EnterMode.toLowerCase() ;
var strArray = [] ;
// Is the caret or selection inside an <li> tag now?
var liState = 0 ;
var range = new oEditor.FCKDomRange( oEditor.FCK.EditorWindow ) ;
range.MoveToSelection() ;
var node = range._Range.startContainer ;
while ( node && node.nodeType != 1 )
node = node.parentNode ;
if ( node && node.tagName.toLowerCase() == 'li' )
liState = 1 ;
if ( enterMode == 'p' )
this._ProcessLineBreaksForPMode( oEditor, text, liState, node, strArray ) ;
else if ( enterMode == 'div' )
this._ProcessLineBreaksForDivMode( oEditor, text, liState, node, strArray ) ;
else if ( enterMode == 'br' )
this._ProcessLineBreaksForBrMode( oEditor, text, liState, node, strArray ) ;
return strArray.join( "" ) ;
}
/**
* Adds an option to a SELECT element.
*/
FCKTools.AddSelectOption = function( selectElement, optionText, optionValue )
{
var oOption = FCKTools.GetElementDocument( selectElement ).createElement( "OPTION" ) ;
oOption.text = optionText ;
oOption.value = optionValue ;
selectElement.options.add(oOption) ;
return oOption ;
}
FCKTools.RunFunction = function( func, thisObject, paramsArray, timerWindow )
{
if ( func )
this.SetTimeout( func, 0, thisObject, paramsArray, timerWindow ) ;
}
FCKTools.SetTimeout = function( func, milliseconds, thisObject, paramsArray, timerWindow )
{
return ( timerWindow || window ).setTimeout(
function()
{
if ( paramsArray )
func.apply( thisObject, [].concat( paramsArray ) ) ;
else
func.apply( thisObject ) ;
},
milliseconds ) ;
}
FCKTools.SetInterval = function( func, milliseconds, thisObject, paramsArray, timerWindow )
{
return ( timerWindow || window ).setInterval(
function()
{
func.apply( thisObject, paramsArray || [] ) ;
},
milliseconds ) ;
}
FCKTools.ConvertStyleSizeToHtml = function( size )
{
return size.EndsWith( '%' ) ? size : parseInt( size, 10 ) ;
}
FCKTools.ConvertHtmlSizeToStyle = function( size )
{
return size.EndsWith( '%' ) ? size : ( size + 'px' ) ;
}
// START iCM MODIFICATIONS
// Amended to accept a list of one or more ascensor tag names
// Amended to check the element itself before working back up through the parent hierarchy
FCKTools.GetElementAscensor = function( element, ascensorTagNames )
{
// var e = element.parentNode ;
var e = element ;
var lstTags = "," + ascensorTagNames.toUpperCase() + "," ;
while ( e )
{
if ( lstTags.indexOf( "," + e.nodeName.toUpperCase() + "," ) != -1 )
return e ;
e = e.parentNode ;
}
return null ;
}
// END iCM MODIFICATIONS
FCKTools.CreateEventListener = function( func, params )
{
var f = function()
{
var aAllParams = [] ;
for ( var i = 0 ; i < arguments.length ; i++ )
aAllParams.push( arguments[i] ) ;
func.apply( this, aAllParams.concat( params ) ) ;
}
return f ;
}
FCKTools.IsStrictMode = function( document )
{
// There is no compatMode in Safari, but it seams that it always behave as
// CSS1Compat, so let's assume it as the default.
return ( 'CSS1Compat' == ( document.compatMode || 'CSS1Compat' ) ) ;
}
// Transforms a "arguments" object to an array.
FCKTools.ArgumentsToArray = function( args, startIndex, maxLength )
{
startIndex = startIndex || 0 ;
maxLength = maxLength || args.length ;
var argsArray = new Array() ;
for ( var i = startIndex ; i < startIndex + maxLength && i < args.length ; i++ )
argsArray.push( args[i] ) ;
return argsArray ;
}
FCKTools.CloneObject = function( sourceObject )
{
var fCloneCreator = function() {} ;
fCloneCreator.prototype = sourceObject ;
return new fCloneCreator ;
}
// Appends a bogus <br> at the end of the element, if not yet available.
FCKTools.AppendBogusBr = function( element )
{
if ( !element )
return ;
var eLastChild = this.GetLastItem( element.getElementsByTagName('br') ) ;
if ( !eLastChild || ( eLastChild.getAttribute( 'type', 2 ) != '_moz' && eLastChild.getAttribute( '_moz_dirty' ) == null ) )
{
var doc = this.GetElementDocument( element ) ;
if ( FCKBrowserInfo.IsOpera )
element.appendChild( doc.createTextNode('') ) ;
else
element.appendChild( this.CreateBogusBR( doc ) ) ;
}
}
FCKTools.GetLastItem = function( list )
{
if ( list.length > 0 )
return list[ list.length - 1 ] ;
return null ;
}
FCKTools.GetDocumentPosition = function( w, node )
{
var x = 0 ;
var y = 0 ;
var curNode = node ;
var prevNode = null ;
var curWindow = FCKTools.GetElementWindow( curNode ) ;
while ( curNode && !( curWindow == w && ( curNode == w.document.body || curNode == w.document.documentElement ) ) )
{
x += curNode.offsetLeft - curNode.scrollLeft ;
y += curNode.offsetTop - curNode.scrollTop ;
if ( ! FCKBrowserInfo.IsOpera )
{
var scrollNode = prevNode ;
while ( scrollNode && scrollNode != curNode )
{
x -= scrollNode.scrollLeft ;
y -= scrollNode.scrollTop ;
scrollNode = scrollNode.parentNode ;
}
}
prevNode = curNode ;
if ( curNode.offsetParent )
curNode = curNode.offsetParent ;
else
{
if ( curWindow != w )
{
curNode = curWindow.frameElement ;
prevNode = null ;
if ( curNode )
curWindow = FCKTools.GetElementWindow( curNode ) ;
}
else
curNode = null ;
}
}
// document.body is a special case when it comes to offsetTop and offsetLeft values.
// 1. It matters if document.body itself is a positioned element;
// 2. It matters is when we're in IE and the element has no positioned ancestor.
// Otherwise the values should be ignored.
if ( FCKDomTools.GetCurrentElementStyle( w, w.document.body, 'position') != 'static'
|| ( FCKBrowserInfo.IsIE && FCKDomTools.GetPositionedAncestor( w, node ) == null ) )
{
x += w.document.body.offsetLeft ;
y += w.document.body.offsetTop ;
}
return { "x" : x, "y" : y } ;
}
FCKTools.GetWindowPosition = function( w, node )
{
var pos = this.GetDocumentPosition( w, node ) ;
var scroll = FCKTools.GetScrollPosition( w ) ;
pos.x -= scroll.X ;
pos.y -= scroll.Y ;
return pos ;
}
FCKTools.ProtectFormStyles = function( formNode )
{
if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' )
return [] ;
var hijackRecord = [] ;
var hijackNames = [ 'style', 'className' ] ;
for ( var i = 0 ; i < hijackNames.length ; i++ )
{
var name = hijackNames[i] ;
if ( formNode.elements.namedItem( name ) )
{
var hijackNode = formNode.elements.namedItem( name ) ;
hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] ) ;
formNode.removeChild( hijackNode ) ;
}
}
return hijackRecord ;
}
FCKTools.RestoreFormStyles = function( formNode, hijackRecord )
{
if ( !formNode || formNode.nodeType != 1 || formNode.tagName.toLowerCase() != 'form' )
return ;
if ( hijackRecord.length > 0 )
{
for ( var i = hijackRecord.length - 1 ; i >= 0 ; i-- )
{
var node = hijackRecord[i][0] ;
var sibling = hijackRecord[i][1] ;
if ( sibling )
formNode.insertBefore( node, sibling ) ;
else
formNode.appendChild( node ) ;
}
}
}
// Perform a one-step DFS walk.
FCKTools.GetNextNode = function( node, limitNode )
{
if ( node.firstChild )
return node.firstChild ;
else if ( node.nextSibling )
return node.nextSibling ;
else
{
var ancestor = node.parentNode ;
while ( ancestor )
{
if ( ancestor == limitNode )
return null ;
if ( ancestor.nextSibling )
return ancestor.nextSibling ;
else
ancestor = ancestor.parentNode ;
}
}
return null ;
}
FCKTools.GetNextTextNode = function( textnode, limitNode, checkStop )
{
node = this.GetNextNode( textnode, limitNode ) ;
if ( checkStop && node && checkStop( node ) )
return null ;
while ( node && node.nodeType != 3 )
{
node = this.GetNextNode( node, limitNode ) ;
if ( checkStop && node && checkStop( node ) )
return null ;
}
return node ;
}
/**
* Merge all objects passed by argument into a single object.
*/
FCKTools.Merge = function()
{
var args = arguments ;
var o = args[0] ;
for ( var i = 1 ; i < args.length ; i++ )
{
var arg = args[i] ;
for ( var p in arg )
o[p] = arg[p] ;
}
return o ;
}
/**
* Check if the passed argument is a real Array. It may not working when
* calling it cross windows.
*/
FCKTools.IsArray = function( it )
{
return ( it instanceof Array ) ;
}
/**
* Appends a "length" property to an object, containing the number of
* properties available on it, excluded the append property itself.
*/
FCKTools.AppendLengthProperty = function( targetObject, propertyName )
{
var counter = 0 ;
for ( var n in targetObject )
counter++ ;
return targetObject[ propertyName || 'length' ] = counter ;
}
/**
* Gets the browser parsed version of a css text (style attribute value). On
* some cases, the browser makes changes to the css text, returning a different
* value. For example, hexadecimal colors get transformed to rgb().
*/
FCKTools.NormalizeCssText = function( unparsedCssText )
{
// Injects the style in a temporary span object, so the browser parses it,
// retrieving its final format.
var tempSpan = document.createElement( 'span' ) ;
tempSpan.style.cssText = unparsedCssText ;
return tempSpan.style.cssText ;
}
/**
* Utility function to wrap a call to an object's method,
* so it can be passed for example to an event handler,
* and then it will be executed with 'this' being the object.
*/
FCKTools.Hitch = function( obj, methodName )
{
return function() { obj[methodName].apply(obj, arguments); } ;
}

View file

@ -0,0 +1,270 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Utility functions. (Gecko version).
*/
FCKTools.CancelEvent = function( e )
{
if ( e )
e.preventDefault() ;
}
FCKTools.DisableSelection = function( element )
{
if ( FCKBrowserInfo.IsGecko )
element.style.MozUserSelect = 'none' ; // Gecko only.
else
element.style.userSelect = 'none' ; // CSS3 (not supported yet).
}
// Appends a CSS file to a document.
FCKTools._AppendStyleSheet = function( documentElement, cssFileUrl )
{
var e = documentElement.createElement( 'LINK' ) ;
e.rel = 'stylesheet' ;
e.type = 'text/css' ;
e.href = cssFileUrl ;
documentElement.getElementsByTagName("HEAD")[0].appendChild( e ) ;
return e ;
}
// Appends a CSS style string to a document.
FCKTools._AppendStyleString = function( documentElement, cssStyles )
{
var e = documentElement.createElement( "STYLE" ) ;
e.appendChild( documentElement.createTextNode( cssStyles ) ) ;
documentElement.getElementsByTagName( "HEAD" )[0].appendChild( e ) ;
return e ;
}
// Removes all attributes and values from the element.
FCKTools.ClearElementAttributes = function( element )
{
// Loop throw all attributes in the element
for ( var i = 0 ; i < element.attributes.length ; i++ )
{
// Remove the element by name.
element.removeAttribute( element.attributes[i].name, 0 ) ; // 0 : Case Insensitive
}
}
// Returns an Array of strings with all defined in the elements inside another element.
FCKTools.GetAllChildrenIds = function( parentElement )
{
// Create the array that will hold all Ids.
var aIds = new Array() ;
// Define a recursive function that search for the Ids.
var fGetIds = function( parent )
{
for ( var i = 0 ; i < parent.childNodes.length ; i++ )
{
var sId = parent.childNodes[i].id ;
// Check if the Id is defined for the element.
if ( sId && sId.length > 0 ) aIds[ aIds.length ] = sId ;
// Recursive call.
fGetIds( parent.childNodes[i] ) ;
}
}
// Start the recursive calls.
fGetIds( parentElement ) ;
return aIds ;
}
// Replaces a tag with its contents. For example "<span>My <b>tag</b></span>"
// will be replaced with "My <b>tag</b>".
FCKTools.RemoveOuterTags = function( e )
{
var oFragment = e.ownerDocument.createDocumentFragment() ;
for ( var i = 0 ; i < e.childNodes.length ; i++ )
oFragment.appendChild( e.childNodes[i].cloneNode(true) ) ;
e.parentNode.replaceChild( oFragment, e ) ;
}
FCKTools.CreateXmlObject = function( object )
{
switch ( object )
{
case 'XmlHttp' :
return new XMLHttpRequest() ;
case 'DOMDocument' :
return document.implementation.createDocument( '', '', null ) ;
}
return null ;
}
FCKTools.GetScrollPosition = function( relativeWindow )
{
return { X : relativeWindow.pageXOffset, Y : relativeWindow.pageYOffset } ;
}
FCKTools.AddEventListener = function( sourceObject, eventName, listener )
{
sourceObject.addEventListener( eventName, listener, false ) ;
}
FCKTools.RemoveEventListener = function( sourceObject, eventName, listener )
{
sourceObject.removeEventListener( eventName, listener, false ) ;
}
// Listeners attached with this function cannot be detached.
FCKTools.AddEventListenerEx = function( sourceObject, eventName, listener, paramsArray )
{
sourceObject.addEventListener(
eventName,
function( e )
{
listener.apply( sourceObject, [ e ].concat( paramsArray || [] ) ) ;
},
false
) ;
}
// Returns and object with the "Width" and "Height" properties.
FCKTools.GetViewPaneSize = function( win )
{
return { Width : win.innerWidth, Height : win.innerHeight } ;
}
FCKTools.SaveStyles = function( element )
{
var data = FCKTools.ProtectFormStyles( element ) ;
var oSavedStyles = new Object() ;
if ( element.className.length > 0 )
{
oSavedStyles.Class = element.className ;
element.className = '' ;
}
var sInlineStyle = element.getAttribute( 'style' ) ;
if ( sInlineStyle && sInlineStyle.length > 0 )
{
oSavedStyles.Inline = sInlineStyle ;
element.setAttribute( 'style', '', 0 ) ; // 0 : Case Insensitive
}
FCKTools.RestoreFormStyles( element, data ) ;
return oSavedStyles ;
}
FCKTools.RestoreStyles = function( element, savedStyles )
{
var data = FCKTools.ProtectFormStyles( element ) ;
element.className = savedStyles.Class || '' ;
if ( savedStyles.Inline )
element.setAttribute( 'style', savedStyles.Inline, 0 ) ; // 0 : Case Insensitive
else
element.removeAttribute( 'style', 0 ) ;
FCKTools.RestoreFormStyles( element, data ) ;
}
FCKTools.RegisterDollarFunction = function( targetWindow )
{
targetWindow.$ = function( id )
{
return this.document.getElementById( id ) ;
} ;
}
FCKTools.AppendElement = function( target, elementName )
{
return target.appendChild( target.ownerDocument.createElement( elementName ) ) ;
}
// Get the coordinates of an element.
// @el : The element to get the position.
// @relativeWindow: The window to which we want the coordinates relative to.
FCKTools.GetElementPosition = function( el, relativeWindow )
{
// Initializes the Coordinates object that will be returned by the function.
var c = { X:0, Y:0 } ;
var oWindow = relativeWindow || window ;
var oOwnerWindow = FCKTools.GetElementWindow( el ) ;
var previousElement = null ;
// Loop throw the offset chain.
while ( el )
{
var sPosition = oOwnerWindow.getComputedStyle(el, '').position ;
// Check for non "static" elements.
// 'FCKConfig.FloatingPanelsZIndex' -- Submenus are under a positioned IFRAME.
if ( sPosition && sPosition != 'static' && el.style.zIndex != FCKConfig.FloatingPanelsZIndex )
break ;
/*
FCKDebug.Output( el.tagName + ":" + "offset=" + el.offsetLeft + "," + el.offsetTop + " "
+ "scroll=" + el.scrollLeft + "," + el.scrollTop ) ;
*/
c.X += el.offsetLeft - el.scrollLeft ;
c.Y += el.offsetTop - el.scrollTop ;
// Backtrack due to offsetParent's calculation by the browser ignores scrollLeft and scrollTop.
// Backtracking is not needed for Opera
if ( ! FCKBrowserInfo.IsOpera )
{
var scrollElement = previousElement ;
while ( scrollElement && scrollElement != el )
{
c.X -= scrollElement.scrollLeft ;
c.Y -= scrollElement.scrollTop ;
scrollElement = scrollElement.parentNode ;
}
}
previousElement = el ;
if ( el.offsetParent )
el = el.offsetParent ;
else
{
if ( oOwnerWindow != oWindow )
{
el = oOwnerWindow.frameElement ;
previousElement = null ;
if ( el )
oOwnerWindow = FCKTools.GetElementWindow( el ) ;
}
else
{
c.X += el.scrollLeft ;
c.Y += el.scrollTop ;
break ;
}
}
}
// Return the Coordinates object
return c ;
}

View file

@ -0,0 +1,227 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Utility functions. (IE version).
*/
FCKTools.CancelEvent = function( e )
{
return false ;
}
// Appends one or more CSS files to a document.
FCKTools._AppendStyleSheet = function( documentElement, cssFileUrl )
{
return documentElement.createStyleSheet( cssFileUrl ).owningElement ;
}
// Appends a CSS style string to a document.
FCKTools._AppendStyleString = function( documentElement, cssStyles )
{
var s = documentElement.createStyleSheet( "" ) ;
s.cssText = cssStyles ;
return s ;
}
// Removes all attributes and values from the element.
FCKTools.ClearElementAttributes = function( element )
{
element.clearAttributes() ;
}
FCKTools.GetAllChildrenIds = function( parentElement )
{
var aIds = new Array() ;
for ( var i = 0 ; i < parentElement.all.length ; i++ )
{
var sId = parentElement.all[i].id ;
if ( sId && sId.length > 0 )
aIds[ aIds.length ] = sId ;
}
return aIds ;
}
FCKTools.RemoveOuterTags = function( e )
{
e.insertAdjacentHTML( 'beforeBegin', e.innerHTML ) ;
e.parentNode.removeChild( e ) ;
}
FCKTools.CreateXmlObject = function( object )
{
var aObjs ;
switch ( object )
{
case 'XmlHttp' :
aObjs = [ 'MSXML2.XmlHttp', 'Microsoft.XmlHttp' ] ;
break ;
case 'DOMDocument' :
aObjs = [ 'MSXML2.DOMDocument', 'Microsoft.XmlDom' ] ;
break ;
}
for ( var i = 0 ; i < 2 ; i++ )
{
try { return new ActiveXObject( aObjs[i] ) ; }
catch (e)
{}
}
if ( FCKLang.NoActiveX )
{
alert( FCKLang.NoActiveX ) ;
FCKLang.NoActiveX = null ;
}
return null ;
}
FCKTools.DisableSelection = function( element )
{
element.unselectable = 'on' ;
var e, i = 0 ;
// The extra () is to avoid a warning with strict error checking. This is ok.
while ( (e = element.all[ i++ ]) )
{
switch ( e.tagName )
{
case 'IFRAME' :
case 'TEXTAREA' :
case 'INPUT' :
case 'SELECT' :
/* Ignore the above tags */
break ;
default :
e.unselectable = 'on' ;
}
}
}
FCKTools.GetScrollPosition = function( relativeWindow )
{
var oDoc = relativeWindow.document ;
// Try with the doc element.
var oPos = { X : oDoc.documentElement.scrollLeft, Y : oDoc.documentElement.scrollTop } ;
if ( oPos.X > 0 || oPos.Y > 0 )
return oPos ;
// If no scroll, try with the body.
return { X : oDoc.body.scrollLeft, Y : oDoc.body.scrollTop } ;
}
FCKTools.AddEventListener = function( sourceObject, eventName, listener )
{
sourceObject.attachEvent( 'on' + eventName, listener ) ;
}
FCKTools.RemoveEventListener = function( sourceObject, eventName, listener )
{
sourceObject.detachEvent( 'on' + eventName, listener ) ;
}
// Listeners attached with this function cannot be detached.
FCKTools.AddEventListenerEx = function( sourceObject, eventName, listener, paramsArray )
{
// Ok... this is a closures party, but is the only way to make it clean of memory leaks.
var o = new Object() ;
o.Source = sourceObject ;
o.Params = paramsArray || [] ; // Memory leak if we have DOM objects here.
o.Listener = function( ev )
{
return listener.apply( o.Source, [ ev ].concat( o.Params ) ) ;
}
if ( FCK.IECleanup )
FCK.IECleanup.AddItem( null, function() { o.Source = null ; o.Params = null ; } ) ;
sourceObject.attachEvent( 'on' + eventName, o.Listener ) ;
sourceObject = null ; // Memory leak cleaner (because of the above closure).
paramsArray = null ; // Memory leak cleaner (because of the above closure).
}
// Returns and object with the "Width" and "Height" properties.
FCKTools.GetViewPaneSize = function( win )
{
var oSizeSource ;
var oDoc = win.document.documentElement ;
if ( oDoc && oDoc.clientWidth ) // IE6 Strict Mode
oSizeSource = oDoc ;
else
oSizeSource = win.document.body ; // Other IEs
if ( oSizeSource )
return { Width : oSizeSource.clientWidth, Height : oSizeSource.clientHeight } ;
else
return { Width : 0, Height : 0 } ;
}
FCKTools.SaveStyles = function( element )
{
var data = FCKTools.ProtectFormStyles( element ) ;
var oSavedStyles = new Object() ;
if ( element.className.length > 0 )
{
oSavedStyles.Class = element.className ;
element.className = '' ;
}
var sInlineStyle = element.style.cssText ;
if ( sInlineStyle.length > 0 )
{
oSavedStyles.Inline = sInlineStyle ;
element.style.cssText = '' ;
}
FCKTools.RestoreFormStyles( element, data ) ;
return oSavedStyles ;
}
FCKTools.RestoreStyles = function( element, savedStyles )
{
var data = FCKTools.ProtectFormStyles( element ) ;
element.className = savedStyles.Class || '' ;
element.style.cssText = savedStyles.Inline || '' ;
FCKTools.RestoreFormStyles( element, data ) ;
}
FCKTools.RegisterDollarFunction = function( targetWindow )
{
targetWindow.$ = targetWindow.document.getElementById ;
}
FCKTools.AppendElement = function( target, elementName )
{
return target.appendChild( this.GetElementDocument( target ).createElement( elementName ) ) ;
}
// This function may be used by Regex replacements.
FCKTools.ToLowerCase = function( strValue )
{
return strValue.toLowerCase() ;
}

View file

@ -0,0 +1,221 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*/
var FCKUndo = new Object() ;
FCKUndo.SavedData = new Array() ;
FCKUndo.CurrentIndex = -1 ;
FCKUndo.TypesCount = 0 ;
FCKUndo.Changed = false ; // Is the document changed in respect to its initial image?
FCKUndo.MaxTypes = 25 ;
FCKUndo.Typing = false ;
FCKUndo.SaveLocked = false ;
FCKUndo._GetBookmark = function()
{
var range = new FCKDomRange( FCK.EditorWindow ) ;
try
{
// There are some tricky cases where this might fail (e.g. having a lone empty table in IE)
range.MoveToSelection() ;
}
catch ( e )
{
return null ;
}
if ( FCKBrowserInfo.IsIE )
{
var bookmark = range.CreateBookmark() ;
var dirtyHtml = FCK.EditorDocument.body.innerHTML ;
range.MoveToBookmark( bookmark ) ;
return [ bookmark, dirtyHtml ] ;
}
return range.CreateBookmark2() ;
}
FCKUndo._SelectBookmark = function( bookmark )
{
if ( ! bookmark )
return ;
var range = new FCKDomRange( FCK.EditorWindow ) ;
if ( bookmark instanceof Object )
{
if ( FCKBrowserInfo.IsIE )
range.MoveToBookmark( bookmark[0] ) ;
else
range.MoveToBookmark2( bookmark ) ;
try
{
// this does not always succeed, there are still some tricky cases where it fails
// e.g. add a special character at end of document, undo, redo -> error
range.Select() ;
}
catch ( e )
{
// if select restore fails, put the caret at the end of the document
range.MoveToPosition( FCK.EditorDocument.body, 4 ) ;
range.Select() ;
}
}
}
FCKUndo._CompareCursors = function( cursor1, cursor2 )
{
for ( var i = 0 ; i < Math.min( cursor1.length, cursor2.length ) ; i++ )
{
if ( cursor1[i] < cursor2[i] )
return -1;
else if (cursor1[i] > cursor2[i] )
return 1;
}
if ( cursor1.length < cursor2.length )
return -1;
else if (cursor1.length > cursor2.length )
return 1;
return 0;
}
FCKUndo._CheckIsBookmarksEqual = function( bookmark1, bookmark2 )
{
if ( ! ( bookmark1 && bookmark2 ) )
return false ;
if ( FCKBrowserInfo.IsIE )
{
var startOffset1 = bookmark1[1].search( bookmark1[0].StartId ) ;
var startOffset2 = bookmark2[1].search( bookmark2[0].StartId ) ;
var endOffset1 = bookmark1[1].search( bookmark1[0].EndId ) ;
var endOffset2 = bookmark2[1].search( bookmark2[0].EndId ) ;
return startOffset1 == startOffset2 && endOffset1 == endOffset2 ;
}
else
{
return this._CompareCursors( bookmark1.Start, bookmark2.Start ) == 0
&& this._CompareCursors( bookmark1.End, bookmark2.End ) == 0 ;
}
}
FCKUndo.SaveUndoStep = function()
{
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG || this.SaveLocked )
return ;
// Assume the editor content is changed when SaveUndoStep() is called after the first time.
// This also enables the undo button in toolbar.
if ( this.SavedData.length )
this.Changed = true ;
// Get the HTML content.
var sHtml = FCK.EditorDocument.body.innerHTML ;
var bookmark = this._GetBookmark() ;
// Shrink the array to the current level.
this.SavedData = this.SavedData.slice( 0, this.CurrentIndex + 1 ) ;
// Cancel operation if the new step is identical to the previous one.
if ( this.CurrentIndex > 0
&& sHtml == this.SavedData[ this.CurrentIndex ][0]
&& this._CheckIsBookmarksEqual( bookmark, this.SavedData[ this.CurrentIndex ][1] ) )
return ;
// Save the selection and caret position in the first undo level for the first change.
else if ( this.CurrentIndex == 0 && this.SavedData.length && sHtml == this.SavedData[0][0] )
{
this.SavedData[0][1] = bookmark ;
return ;
}
// If we reach the Maximum number of undo levels, we must remove the first
// entry of the list shifting all elements.
if ( this.CurrentIndex + 1 >= FCKConfig.MaxUndoLevels )
this.SavedData.shift() ;
else
this.CurrentIndex++ ;
// Save the new level in front of the actual position.
this.SavedData[ this.CurrentIndex ] = [ sHtml, bookmark ] ;
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
FCKUndo.CheckUndoState = function()
{
return ( this.Changed || this.CurrentIndex > 0 ) ;
}
FCKUndo.CheckRedoState = function()
{
return ( this.CurrentIndex < ( this.SavedData.length - 1 ) ) ;
}
FCKUndo.Undo = function()
{
if ( this.CheckUndoState() )
{
// If it is the first step.
if ( this.CurrentIndex == ( this.SavedData.length - 1 ) )
{
// Save the actual state for a possible "Redo" call.
this.SaveUndoStep() ;
}
// Go a step back.
this._ApplyUndoLevel( --this.CurrentIndex ) ;
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
}
FCKUndo.Redo = function()
{
if ( this.CheckRedoState() )
{
// Go a step forward.
this._ApplyUndoLevel( ++this.CurrentIndex ) ;
FCK.Events.FireEvent( "OnSelectionChange" ) ;
}
}
FCKUndo._ApplyUndoLevel = function( level )
{
var oData = this.SavedData[ level ] ;
if ( !oData )
return ;
// Update the editor contents with that step data.
if ( FCKBrowserInfo.IsIE )
{
if ( oData[1] && oData[1][1] )
FCK.SetInnerHtml( oData[1][1] ) ;
else
FCK.SetInnerHtml( oData[0] ) ;
}
else
FCK.EditorDocument.body.innerHTML = oData[0] ;
// Restore the selection
this._SelectBookmark( oData[1] ) ;
this.TypesCount = 0 ;
this.Changed = false ;
this.Typing = false ;
}

View file

@ -0,0 +1,39 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKURLParams object that is used to get all parameters
* passed by the URL QueryString (after the "?").
*/
// #### URLParams: holds all URL passed parameters (like ?Param1=Value1&Param2=Value2)
var FCKURLParams = new Object() ;
(function()
{
var aParams = document.location.search.substr(1).split('&') ;
for ( var i = 0 ; i < aParams.length ; i++ )
{
var aParam = aParams[i].split('=') ;
var sParamName = decodeURIComponent( aParam[0] ) ;
var sParamValue = decodeURIComponent( aParam[1] ) ;
FCKURLParams[ sParamName ] = sParamValue ;
}
})();

View file

@ -0,0 +1,486 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKXHtml object, responsible for the XHTML operations.
*/
var FCKXHtml = new Object() ;
FCKXHtml.CurrentJobNum = 0 ;
FCKXHtml.GetXHTML = function( node, includeNode, format )
{
FCKDomTools.CheckAndRemovePaddingNode( node.ownerDocument, FCKConfig.EnterMode ) ;
FCKXHtmlEntities.Initialize() ;
// Set the correct entity to use for empty blocks.
this._NbspEntity = ( FCKConfig.ProcessHTMLEntities? 'nbsp' : '#160' ) ;
// Save the current IsDirty state. The XHTML processor may change the
// original HTML, dirtying it.
var bIsDirty = FCK.IsDirty() ;
// Special blocks are blocks of content that remain untouched during the
// process. It is used for SCRIPTs and STYLEs.
FCKXHtml.SpecialBlocks = new Array() ;
// Create the XML DOMDocument object.
this.XML = FCKTools.CreateXmlObject( 'DOMDocument' ) ;
// Add a root element that holds all child nodes.
this.MainNode = this.XML.appendChild( this.XML.createElement( 'xhtml' ) ) ;
FCKXHtml.CurrentJobNum++ ;
// var dTimer = new Date() ;
if ( includeNode )
this._AppendNode( this.MainNode, node ) ;
else
this._AppendChildNodes( this.MainNode, node, false ) ;
// Get the resulting XHTML as a string.
var sXHTML = this._GetMainXmlString() ;
// alert( 'Time: ' + ( ( ( new Date() ) - dTimer ) ) + ' ms' ) ;
this.XML = null ;
// Safari adds xmlns="http://www.w3.org/1999/xhtml" to the root node (#963)
if ( FCKBrowserInfo.IsSafari )
sXHTML = sXHTML.replace( /^<xhtml.*?>/, '<xhtml>' ) ;
// Strip the "XHTML" root node.
sXHTML = sXHTML.substr( 7, sXHTML.length - 15 ).Trim() ;
// Add a space in the tags with no closing tags, like <br/> -> <br />
sXHTML = sXHTML.replace( FCKRegexLib.SpaceNoClose, ' />');
if ( FCKConfig.ForceSimpleAmpersand )
sXHTML = sXHTML.replace( FCKRegexLib.ForceSimpleAmpersand, '&' ) ;
if ( format )
sXHTML = FCKCodeFormatter.Format( sXHTML ) ;
// Now we put back the SpecialBlocks contents.
for ( var i = 0 ; i < FCKXHtml.SpecialBlocks.length ; i++ )
{
var oRegex = new RegExp( '___FCKsi___' + i ) ;
sXHTML = sXHTML.replace( oRegex, FCKXHtml.SpecialBlocks[i] ) ;
}
// Replace entities marker with the ampersand.
sXHTML = sXHTML.replace( FCKRegexLib.GeckoEntitiesMarker, '&' ) ;
// Restore the IsDirty state if it was not dirty.
if ( !bIsDirty )
FCK.ResetIsDirty() ;
FCKDomTools.EnforcePaddingNode( FCKTools.GetElementDocument( node ), FCKConfig.EnterMode ) ;
return sXHTML ;
}
FCKXHtml._AppendAttribute = function( xmlNode, attributeName, attributeValue )
{
try
{
if ( attributeValue == undefined || attributeValue == null )
attributeValue = '' ;
else if ( attributeValue.replace )
{
if ( FCKConfig.ForceSimpleAmpersand )
attributeValue = attributeValue.replace( /&/g, '___FCKAmp___' ) ;
// Entities must be replaced in the attribute values.
attributeValue = attributeValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ;
}
// Create the attribute.
var oXmlAtt = this.XML.createAttribute( attributeName ) ;
oXmlAtt.value = attributeValue ;
// Set the attribute in the node.
xmlNode.attributes.setNamedItem( oXmlAtt ) ;
}
catch (e)
{}
}
FCKXHtml._AppendChildNodes = function( xmlNode, htmlNode, isBlockElement )
{
var oNode = htmlNode.firstChild ;
while ( oNode )
{
this._AppendNode( xmlNode, oNode ) ;
oNode = oNode.nextSibling ;
}
// Trim block elements. This is also needed to avoid Firefox leaving extra
// BRs at the end of them.
if ( isBlockElement && htmlNode.tagName && htmlNode.tagName.toLowerCase() != 'pre' )
{
FCKDomTools.TrimNode( xmlNode ) ;
if ( FCKConfig.FillEmptyBlocks )
{
var lastChild = xmlNode.lastChild ;
if ( lastChild && lastChild.nodeType == 1 && lastChild.nodeName == 'br' )
this._AppendEntity( xmlNode, this._NbspEntity ) ;
}
}
// If the resulting node is empty.
if ( xmlNode.childNodes.length == 0 )
{
if ( isBlockElement && FCKConfig.FillEmptyBlocks )
{
this._AppendEntity( xmlNode, this._NbspEntity ) ;
return xmlNode ;
}
var sNodeName = xmlNode.nodeName ;
// Some inline elements are required to have something inside (span, strong, etc...).
if ( FCKListsLib.InlineChildReqElements[ sNodeName ] )
return null ;
// We can't use short representation of empty elements that are not marked
// as empty in th XHTML DTD.
if ( !FCKListsLib.EmptyElements[ sNodeName ] )
xmlNode.appendChild( this.XML.createTextNode('') ) ;
}
return xmlNode ;
}
FCKXHtml._AppendNode = function( xmlNode, htmlNode )
{
if ( !htmlNode )
return false ;
switch ( htmlNode.nodeType )
{
// Element Node.
case 1 :
// If we detect a <br> inside a <pre> in Gecko, turn it into a line break instead.
// This is a workaround for the Gecko bug here: https://bugzilla.mozilla.org/show_bug.cgi?id=92921
if ( FCKBrowserInfo.IsGecko
&& htmlNode.tagName.toLowerCase() == 'br'
&& htmlNode.parentNode.tagName.toLowerCase() == 'pre' )
{
var val = '\r' ;
if ( htmlNode == htmlNode.parentNode.firstChild )
val += '\r' ;
return FCKXHtml._AppendNode( xmlNode, this.XML.createTextNode( val ) ) ;
}
// Here we found an element that is not the real element, but a
// fake one (like the Flash placeholder image), so we must get the real one.
if ( htmlNode.getAttribute('_fckfakelement') )
return FCKXHtml._AppendNode( xmlNode, FCK.GetRealElement( htmlNode ) ) ;
// Ignore bogus BR nodes in the DOM.
if ( FCKBrowserInfo.IsGecko &&
htmlNode.nextSibling &&
( htmlNode.hasAttribute('_moz_editor_bogus_node') || htmlNode.getAttribute( 'type' ) == '_moz' ) )
return false ;
// This is for elements that are instrumental to FCKeditor and
// must be removed from the final HTML.
if ( htmlNode.getAttribute('_fcktemp') )
return false ;
// Get the element name.
var sNodeName = htmlNode.tagName.toLowerCase() ;
if ( FCKBrowserInfo.IsIE )
{
// IE doens't include the scope name in the nodeName. So, add the namespace.
if ( htmlNode.scopeName && htmlNode.scopeName != 'HTML' && htmlNode.scopeName != 'FCK' )
sNodeName = htmlNode.scopeName.toLowerCase() + ':' + sNodeName ;
}
else
{
if ( sNodeName.StartsWith( 'fck:' ) )
sNodeName = sNodeName.Remove( 0,4 ) ;
}
// Check if the node name is valid, otherwise ignore this tag.
// If the nodeName starts with a slash, it is a orphan closing tag.
// On some strange cases, the nodeName is empty, even if the node exists.
if ( !FCKRegexLib.ElementName.test( sNodeName ) )
return false ;
// The already processed nodes must be marked to avoid then to be duplicated (bad formatted HTML).
// So here, the "mark" is checked... if the element is Ok, then mark it.
if ( htmlNode._fckxhtmljob && htmlNode._fckxhtmljob == FCKXHtml.CurrentJobNum )
return false ;
var oNode = this.XML.createElement( sNodeName ) ;
// Add all attributes.
FCKXHtml._AppendAttributes( xmlNode, htmlNode, oNode, sNodeName ) ;
htmlNode._fckxhtmljob = FCKXHtml.CurrentJobNum ;
// Tag specific processing.
var oTagProcessor = FCKXHtml.TagProcessors[ sNodeName ] ;
if ( oTagProcessor )
oNode = oTagProcessor( oNode, htmlNode, xmlNode ) ;
else
oNode = this._AppendChildNodes( oNode, htmlNode, Boolean( FCKListsLib.NonEmptyBlockElements[ sNodeName ] ) ) ;
if ( !oNode )
return false ;
xmlNode.appendChild( oNode ) ;
break ;
// Text Node.
case 3 :
if ( htmlNode.parentNode && htmlNode.parentNode.nodeName.IEquals( 'pre' ) )
return this._AppendTextNode( xmlNode, htmlNode.nodeValue ) ;
return this._AppendTextNode( xmlNode, htmlNode.nodeValue.ReplaceNewLineChars(' ') ) ;
// Comment
case 8 :
// IE catches the <!DOTYPE ... > as a comment, but it has no
// innerHTML, so we can catch it, and ignore it.
if ( FCKBrowserInfo.IsIE && !htmlNode.innerHTML )
break ;
try { xmlNode.appendChild( this.XML.createComment( htmlNode.nodeValue ) ) ; }
catch (e) { /* Do nothing... probably this is a wrong format comment. */ }
break ;
// Unknown Node type.
default :
xmlNode.appendChild( this.XML.createComment( "Element not supported - Type: " + htmlNode.nodeType + " Name: " + htmlNode.nodeName ) ) ;
break ;
}
return true ;
}
// Append an item to the SpecialBlocks array and returns the tag to be used.
FCKXHtml._AppendSpecialItem = function( item )
{
return '___FCKsi___' + FCKXHtml.SpecialBlocks.AddItem( item ) ;
}
FCKXHtml._AppendEntity = function( xmlNode, entity )
{
xmlNode.appendChild( this.XML.createTextNode( '#?-:' + entity + ';' ) ) ;
}
FCKXHtml._AppendTextNode = function( targetNode, textValue )
{
var bHadText = textValue.length > 0 ;
if ( bHadText )
targetNode.appendChild( this.XML.createTextNode( textValue.replace( FCKXHtmlEntities.EntitiesRegex, FCKXHtml_GetEntity ) ) ) ;
return bHadText ;
}
// Retrieves a entity (internal format) for a given character.
function FCKXHtml_GetEntity( character )
{
// We cannot simply place the entities in the text, because the XML parser
// will translate & to &amp;. So we use a temporary marker which is replaced
// in the end of the processing.
var sEntity = FCKXHtmlEntities.Entities[ character ] || ( '#' + character.charCodeAt(0) ) ;
return '#?-:' + sEntity + ';' ;
}
// An object that hold tag specific operations.
FCKXHtml.TagProcessors =
{
a : function( node, htmlNode )
{
// Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1556878).
if ( htmlNode.innerHTML.Trim().length == 0 && !htmlNode.name )
return false ;
var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
if ( sSavedUrl != null )
FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
// Anchors with content has been marked with an additional class, now we must remove it.
if ( FCKBrowserInfo.IsIE )
{
// Buggy IE, doesn't copy the name of changed anchors.
if ( htmlNode.name )
FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
}
node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
return node ;
},
area : function( node, htmlNode )
{
var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
if ( sSavedUrl != null )
FCKXHtml._AppendAttribute( node, 'href', sSavedUrl ) ;
// IE ignores the "COORDS" and "SHAPE" attribute so we must add it manually.
if ( FCKBrowserInfo.IsIE )
{
if ( ! node.attributes.getNamedItem( 'coords' ) )
{
var sCoords = htmlNode.getAttribute( 'coords', 2 ) ;
if ( sCoords && sCoords != '0,0,0' )
FCKXHtml._AppendAttribute( node, 'coords', sCoords ) ;
}
if ( ! node.attributes.getNamedItem( 'shape' ) )
{
var sShape = htmlNode.getAttribute( 'shape', 2 ) ;
if ( sShape && sShape.length > 0 )
FCKXHtml._AppendAttribute( node, 'shape', sShape.toLowerCase() ) ;
}
}
return node ;
},
body : function( node, htmlNode )
{
node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
// Remove spellchecker attributes added for Firefox when converting to HTML code (Bug #1351).
node.removeAttribute( 'spellcheck' ) ;
return node ;
},
// IE loses contents of iframes, and Gecko does give it back HtmlEncoded
// Note: Opera does lose the content and doesn't provide it in the innerHTML string
iframe : function( node, htmlNode )
{
var sHtml = htmlNode.innerHTML ;
// Gecko does give back the encoded html
if ( FCKBrowserInfo.IsGecko )
sHtml = FCKTools.HTMLDecode( sHtml );
// Remove the saved urls here as the data won't be processed as nodes
sHtml = sHtml.replace( /\s_fcksavedurl="[^"]*"/g, '' ) ;
node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( sHtml ) ) ) ;
return node ;
},
img : function( node, htmlNode )
{
// The "ALT" attribute is required in XHTML.
if ( ! node.attributes.getNamedItem( 'alt' ) )
FCKXHtml._AppendAttribute( node, 'alt', '' ) ;
var sSavedUrl = htmlNode.getAttribute( '_fcksavedurl' ) ;
if ( sSavedUrl != null )
FCKXHtml._AppendAttribute( node, 'src', sSavedUrl ) ;
return node ;
},
// Fix nested <ul> and <ol>.
ol : function( node, htmlNode, targetNode )
{
if ( htmlNode.innerHTML.Trim().length == 0 )
return false ;
var ePSibling = targetNode.lastChild ;
if ( ePSibling && ePSibling.nodeType == 3 )
ePSibling = ePSibling.previousSibling ;
if ( ePSibling && ePSibling.nodeName.toUpperCase() == 'LI' )
{
htmlNode._fckxhtmljob = null ;
FCKXHtml._AppendNode( ePSibling, htmlNode ) ;
return false ;
}
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
},
pre : function ( node, htmlNode )
{
var firstChild = htmlNode.firstChild ;
if ( firstChild && firstChild.nodeType == 3 )
node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( '\r\n' ) ) ) ;
FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
},
script : function( node, htmlNode )
{
// The "TYPE" attribute is required in XHTML.
if ( ! node.attributes.getNamedItem( 'type' ) )
FCKXHtml._AppendAttribute( node, 'type', 'text/javascript' ) ;
node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( htmlNode.text ) ) ) ;
return node ;
},
span : function( node, htmlNode )
{
// Firefox may create empty tags when deleting the selection in some special cases (SF-BUG 1084404).
if ( htmlNode.innerHTML.length == 0 )
return false ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, false ) ;
return node ;
},
style : function( node, htmlNode )
{
// The "TYPE" attribute is required in XHTML.
if ( ! node.attributes.getNamedItem( 'type' ) )
FCKXHtml._AppendAttribute( node, 'type', 'text/css' ) ;
var cssText = htmlNode.innerHTML ;
if ( FCKBrowserInfo.IsIE ) // Bug #403 : IE always appends a \r\n to the beginning of StyleNode.innerHTML
cssText = cssText.replace( /^(\r\n|\n|\r)/, '' ) ;
node.appendChild( FCKXHtml.XML.createTextNode( FCKXHtml._AppendSpecialItem( cssText ) ) ) ;
return node ;
},
title : function( node, htmlNode )
{
node.appendChild( FCKXHtml.XML.createTextNode( FCK.EditorDocument.title ) ) ;
return node ;
}
} ;
FCKXHtml.TagProcessors.ul = FCKXHtml.TagProcessors.ol ;

View file

@ -0,0 +1,105 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKXHtml object, responsible for the XHTML operations.
* Gecko specific.
*/
FCKXHtml._GetMainXmlString = function()
{
// Create the XMLSerializer.
var oSerializer = new XMLSerializer() ;
// Return the serialized XML as a string.
return oSerializer.serializeToString( this.MainNode ) ;
}
FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node )
{
var aAttributes = htmlNode.attributes ;
for ( var n = 0 ; n < aAttributes.length ; n++ )
{
var oAttribute = aAttributes[n] ;
if ( oAttribute.specified )
{
var sAttName = oAttribute.nodeName.toLowerCase() ;
var sAttValue ;
// Ignore any attribute starting with "_fck".
if ( sAttName.StartsWith( '_fck' ) )
continue ;
// There is a bug in Mozilla that returns '_moz_xxx' attributes as specified.
else if ( sAttName.indexOf( '_moz' ) == 0 )
continue ;
// There are one cases (on Gecko) when the oAttribute.nodeValue must be used:
// - for the "class" attribute
else if ( sAttName == 'class' )
{
sAttValue = oAttribute.nodeValue.replace( FCKRegexLib.FCK_Class, '' ) ;
if ( sAttValue.length == 0 )
continue ;
}
// XHTML doens't support attribute minimization like "CHECKED". It must be transformed to checked="checked".
else if ( oAttribute.nodeValue === true )
sAttValue = sAttName ;
else
sAttValue = htmlNode.getAttribute( sAttName, 2 ) ; // We must use getAttribute to get it exactly as it is defined.
this._AppendAttribute( node, sAttName, sAttValue ) ;
}
}
}
if ( FCKBrowserInfo.IsOpera )
{
// Opera moves the <FCK:meta> element outside head (#1166).
// Save a reference to the XML <head> node, so we can use it for
// orphan <meta>s.
FCKXHtml.TagProcessors['head'] = function( node, htmlNode )
{
FCKXHtml.XML._HeadElement = node ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
// Check whether a <meta> element is outside <head>, and move it to the
// proper place.
FCKXHtml.TagProcessors['meta'] = function( node, htmlNode, xmlNode )
{
if ( htmlNode.parentNode.nodeName.toLowerCase() != 'head' )
{
var headElement = FCKXHtml.XML._HeadElement ;
if ( headElement && xmlNode != headElement )
{
delete htmlNode._fckxhtmljob ;
FCKXHtml._AppendNode( headElement, htmlNode ) ;
return null ;
}
}
return node ;
}
}

View file

@ -0,0 +1,203 @@
/*
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
* Copyright (C) 2003-2007 Frederico Caldeira Knabben
*
* == BEGIN LICENSE ==
*
* Licensed under the terms of any of the following licenses at your
* choice:
*
* - GNU General Public License Version 2 or later (the "GPL")
* http://www.gnu.org/licenses/gpl.html
*
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
* http://www.gnu.org/licenses/lgpl.html
*
* - Mozilla Public License Version 1.1 or later (the "MPL")
* http://www.mozilla.org/MPL/MPL-1.1.html
*
* == END LICENSE ==
*
* Defines the FCKXHtml object, responsible for the XHTML operations.
* IE specific.
*/
FCKXHtml._GetMainXmlString = function()
{
return this.MainNode.xml ;
}
FCKXHtml._AppendAttributes = function( xmlNode, htmlNode, node, nodeName )
{
var aAttributes = htmlNode.attributes ;
for ( var n = 0 ; n < aAttributes.length ; n++ )
{
var oAttribute = aAttributes[n] ;
if ( oAttribute.specified )
{
var sAttName = oAttribute.nodeName.toLowerCase() ;
var sAttValue ;
// Ignore any attribute starting with "_fck".
if ( sAttName.StartsWith( '_fck' ) )
continue ;
// The following must be done because of a bug on IE regarding the style
// attribute. It returns "null" for the nodeValue.
else if ( sAttName == 'style' )
{
var data = FCKTools.ProtectFormStyles( htmlNode ) ;
sAttValue = htmlNode.style.cssText.replace( FCKRegexLib.StyleProperties, FCKTools.ToLowerCase ) ;
FCKTools.RestoreFormStyles( htmlNode, data ) ;
}
// There are two cases when the oAttribute.nodeValue must be used:
// - for the "class" attribute
// - for events attributes (on IE only).
else if ( sAttName == 'class' )
{
sAttValue = oAttribute.nodeValue.replace( FCKRegexLib.FCK_Class, '' ) ;
if ( sAttValue.length == 0 )
continue ;
}
else if ( sAttName.indexOf('on') == 0 )
sAttValue = oAttribute.nodeValue ;
else if ( nodeName == 'body' && sAttName == 'contenteditable' )
continue ;
// XHTML doens't support attribute minimization like "CHECKED". It must be transformed to checked="checked".
else if ( oAttribute.nodeValue === true )
sAttValue = sAttName ;
else
{
// We must use getAttribute to get it exactly as it is defined.
// There are some rare cases that IE throws an error here, so we must try/catch.
try
{
sAttValue = htmlNode.getAttribute( sAttName, 2 ) ;
}
catch (e) {}
}
this._AppendAttribute( node, sAttName, sAttValue || oAttribute.nodeValue ) ;
}
}
}
// On very rare cases, IE is loosing the "align" attribute for DIV. (right align and apply bulleted list)
FCKXHtml.TagProcessors['div'] = function( node, htmlNode )
{
if ( htmlNode.align.length > 0 )
FCKXHtml._AppendAttribute( node, 'align', htmlNode.align ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
// IE automatically changes <FONT> tags to <FONT size=+0>.
FCKXHtml.TagProcessors['font'] = function( node, htmlNode )
{
if ( node.attributes.length == 0 )
node = FCKXHtml.XML.createDocumentFragment() ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}
FCKXHtml.TagProcessors['form'] = function( node, htmlNode )
{
if ( htmlNode.acceptCharset && htmlNode.acceptCharset.length > 0 && htmlNode.acceptCharset != 'UNKNOWN' )
FCKXHtml._AppendAttribute( node, 'accept-charset', htmlNode.acceptCharset ) ;
// IE has a bug and htmlNode.attributes['name'].specified=false if there is
// no element with id="name" inside the form (#360 and SF-BUG-1155726).
var nameAtt = htmlNode.attributes['name'] ;
if ( nameAtt && nameAtt.value.length > 0 )
FCKXHtml._AppendAttribute( node, 'name', nameAtt.value ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
// IE doens't see the value attribute as an attribute for the <INPUT> tag.
FCKXHtml.TagProcessors['input'] = function( node, htmlNode )
{
if ( htmlNode.name )
FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
if ( htmlNode.value && !node.attributes.getNamedItem( 'value' ) )
FCKXHtml._AppendAttribute( node, 'value', htmlNode.value ) ;
if ( !node.attributes.getNamedItem( 'type' ) )
FCKXHtml._AppendAttribute( node, 'type', 'text' ) ;
return node ;
}
FCKXHtml.TagProcessors['label'] = function( node, htmlNode )
{
if ( htmlNode.htmlFor.length > 0 )
FCKXHtml._AppendAttribute( node, 'for', htmlNode.htmlFor ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}
// Fix behavior for IE, it doesn't read back the .name on newly created maps
FCKXHtml.TagProcessors['map'] = function( node, htmlNode )
{
if ( ! node.attributes.getNamedItem( 'name' ) )
{
var name = htmlNode.name ;
if ( name )
FCKXHtml._AppendAttribute( node, 'name', name ) ;
}
node = FCKXHtml._AppendChildNodes( node, htmlNode, true ) ;
return node ;
}
FCKXHtml.TagProcessors['meta'] = function( node, htmlNode )
{
var oHttpEquiv = node.attributes.getNamedItem( 'http-equiv' ) ;
if ( oHttpEquiv == null || oHttpEquiv.value.length == 0 )
{
// Get the http-equiv value from the outerHTML.
var sHttpEquiv = htmlNode.outerHTML.match( FCKRegexLib.MetaHttpEquiv ) ;
if ( sHttpEquiv )
{
sHttpEquiv = sHttpEquiv[1] ;
FCKXHtml._AppendAttribute( node, 'http-equiv', sHttpEquiv ) ;
}
}
return node ;
}
// IE ignores the "SELECTED" attribute so we must add it manually.
FCKXHtml.TagProcessors['option'] = function( node, htmlNode )
{
if ( htmlNode.selected && !node.attributes.getNamedItem( 'selected' ) )
FCKXHtml._AppendAttribute( node, 'selected', 'selected' ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}
// IE doens't hold the name attribute as an attribute for the <TEXTAREA> and <SELECT> tags.
FCKXHtml.TagProcessors['textarea'] = FCKXHtml.TagProcessors['select'] = function( node, htmlNode )
{
if ( htmlNode.name )
FCKXHtml._AppendAttribute( node, 'name', htmlNode.name ) ;
node = FCKXHtml._AppendChildNodes( node, htmlNode ) ;
return node ;
}

View file

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