635 lines
14 KiB
JavaScript
635 lines
14 KiB
JavaScript
/*
|
|
* FCKeditor - The text editor for Internet - http://www.fckeditor.net
|
|
* Copyright (C) 2003-2009 Frederico Caldeira Knabben
|
|
*
|
|
* == BEGIN LICENSE ==
|
|
*
|
|
* Licensed under the terms of any of the following licenses at your
|
|
* choice:
|
|
*
|
|
* - GNU General Public License Version 2 or later (the "GPL")
|
|
* http://www.gnu.org/licenses/gpl.html
|
|
*
|
|
* - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
|
|
* http://www.gnu.org/licenses/lgpl.html
|
|
*
|
|
* - Mozilla Public License Version 1.1 or later (the "MPL")
|
|
* http://www.mozilla.org/MPL/MPL-1.1.html
|
|
*
|
|
* == END LICENSE ==
|
|
*
|
|
* Definition of other commands that are not available internaly in the
|
|
* browser (see FCKNamedCommand).
|
|
*/
|
|
|
|
// ### General Dialog Box Commands.
|
|
var FCKDialogCommand = function( name, title, url, width, height, getStateFunction, getStateParam, customValue )
|
|
{
|
|
this.Name = name ;
|
|
this.Title = title ;
|
|
this.Url = url ;
|
|
this.Width = width ;
|
|
this.Height = height ;
|
|
this.CustomValue = customValue ;
|
|
|
|
this.GetStateFunction = getStateFunction ;
|
|
this.GetStateParam = getStateParam ;
|
|
|
|
this.Resizable = false ;
|
|
}
|
|
|
|
FCKDialogCommand.prototype.Execute = function()
|
|
{
|
|
FCKDialog.OpenDialog( 'FCKDialog_' + this.Name , this.Title, this.Url, this.Width, this.Height, this.CustomValue, null, this.Resizable ) ;
|
|
}
|
|
|
|
FCKDialogCommand.prototype.GetState = function()
|
|
{
|
|
if ( this.GetStateFunction )
|
|
return this.GetStateFunction( this.GetStateParam ) ;
|
|
else
|
|
return FCK.EditMode == FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
|
|
}
|
|
|
|
// Generic Undefined command (usually used when a command is under development).
|
|
var FCKUndefinedCommand = function()
|
|
{
|
|
this.Name = 'Undefined' ;
|
|
}
|
|
|
|
FCKUndefinedCommand.prototype.Execute = function()
|
|
{
|
|
alert( FCKLang.NotImplemented ) ;
|
|
}
|
|
|
|
FCKUndefinedCommand.prototype.GetState = function()
|
|
{
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
|
|
|
|
// ### FormatBlock
|
|
var FCKFormatBlockCommand = function()
|
|
{}
|
|
|
|
FCKFormatBlockCommand.prototype =
|
|
{
|
|
Name : 'FormatBlock',
|
|
|
|
Execute : FCKStyleCommand.prototype.Execute,
|
|
|
|
GetState : function()
|
|
{
|
|
return FCK.EditorDocument ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
|
|
}
|
|
};
|
|
|
|
// ### FontName
|
|
|
|
var FCKFontNameCommand = function()
|
|
{}
|
|
|
|
FCKFontNameCommand.prototype =
|
|
{
|
|
Name : 'FontName',
|
|
Execute : FCKStyleCommand.prototype.Execute,
|
|
GetState : FCKFormatBlockCommand.prototype.GetState
|
|
};
|
|
|
|
// ### FontSize
|
|
var FCKFontSizeCommand = function()
|
|
{}
|
|
|
|
FCKFontSizeCommand.prototype =
|
|
{
|
|
Name : 'FontSize',
|
|
Execute : FCKStyleCommand.prototype.Execute,
|
|
GetState : FCKFormatBlockCommand.prototype.GetState
|
|
};
|
|
|
|
// ### Preview
|
|
var FCKPreviewCommand = function()
|
|
{
|
|
this.Name = 'Preview' ;
|
|
}
|
|
|
|
FCKPreviewCommand.prototype.Execute = function()
|
|
{
|
|
FCK.Preview() ;
|
|
}
|
|
|
|
FCKPreviewCommand.prototype.GetState = function()
|
|
{
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
|
|
// ### Save
|
|
var FCKSaveCommand = function()
|
|
{
|
|
this.Name = 'Save' ;
|
|
}
|
|
|
|
FCKSaveCommand.prototype.Execute = function()
|
|
{
|
|
// Get the linked field form.
|
|
var oForm = FCK.GetParentForm() ;
|
|
|
|
if ( typeof( oForm.onsubmit ) == 'function' )
|
|
{
|
|
var bRet = oForm.onsubmit() ;
|
|
if ( bRet != null && bRet === false )
|
|
return ;
|
|
}
|
|
|
|
// Submit the form.
|
|
// If there's a button named "submit" then the form.submit() function is masked and
|
|
// can't be called in Mozilla, so we call the click() method of that button.
|
|
if ( typeof( oForm.submit ) == 'function' )
|
|
oForm.submit() ;
|
|
else
|
|
oForm.submit.click() ;
|
|
}
|
|
|
|
FCKSaveCommand.prototype.GetState = function()
|
|
{
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
|
|
// ### NewPage
|
|
var FCKNewPageCommand = function()
|
|
{
|
|
this.Name = 'NewPage' ;
|
|
}
|
|
|
|
FCKNewPageCommand.prototype.Execute = function()
|
|
{
|
|
FCKUndo.SaveUndoStep() ;
|
|
FCK.SetData( '' ) ;
|
|
FCKUndo.Typing = true ;
|
|
FCK.Focus() ;
|
|
}
|
|
|
|
FCKNewPageCommand.prototype.GetState = function()
|
|
{
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
|
|
// ### Source button
|
|
var FCKSourceCommand = function()
|
|
{
|
|
this.Name = 'Source' ;
|
|
}
|
|
|
|
FCKSourceCommand.prototype.Execute = function()
|
|
{
|
|
if ( FCKConfig.SourcePopup ) // Until v2.2, it was mandatory for FCKBrowserInfo.IsGecko.
|
|
{
|
|
var iWidth = FCKConfig.ScreenWidth * 0.65 ;
|
|
var iHeight = FCKConfig.ScreenHeight * 0.65 ;
|
|
FCKDialog.OpenDialog( 'FCKDialog_Source', FCKLang.Source, 'dialog/fck_source.html', iWidth, iHeight, null, null, true ) ;
|
|
}
|
|
else
|
|
FCK.SwitchEditMode() ;
|
|
}
|
|
|
|
FCKSourceCommand.prototype.GetState = function()
|
|
{
|
|
return ( FCK.EditMode == FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_OFF : FCK_TRISTATE_ON ) ;
|
|
}
|
|
|
|
// ### Undo
|
|
var FCKUndoCommand = function()
|
|
{
|
|
this.Name = 'Undo' ;
|
|
}
|
|
|
|
FCKUndoCommand.prototype.Execute = function()
|
|
{
|
|
FCKUndo.Undo() ;
|
|
}
|
|
|
|
FCKUndoCommand.prototype.GetState = function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return ( FCKUndo.CheckUndoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
|
|
}
|
|
|
|
// ### Redo
|
|
var FCKRedoCommand = function()
|
|
{
|
|
this.Name = 'Redo' ;
|
|
}
|
|
|
|
FCKRedoCommand.prototype.Execute = function()
|
|
{
|
|
FCKUndo.Redo() ;
|
|
}
|
|
|
|
FCKRedoCommand.prototype.GetState = function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return ( FCKUndo.CheckRedoState() ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ) ;
|
|
}
|
|
|
|
// ### Page Break
|
|
var FCKPageBreakCommand = function()
|
|
{
|
|
this.Name = 'PageBreak' ;
|
|
}
|
|
|
|
FCKPageBreakCommand.prototype.Execute = function()
|
|
{
|
|
// Take an undo snapshot before changing the document
|
|
FCKUndo.SaveUndoStep() ;
|
|
|
|
// var e = FCK.EditorDocument.createElement( 'CENTER' ) ;
|
|
// e.style.pageBreakAfter = 'always' ;
|
|
|
|
// Tidy was removing the empty CENTER tags, so the following solution has
|
|
// been found. It also validates correctly as XHTML 1.0 Strict.
|
|
var e = FCK.EditorDocument.createElement( 'DIV' ) ;
|
|
e.style.pageBreakAfter = 'always' ;
|
|
e.innerHTML = '<span style="DISPLAY:none"> </span>' ;
|
|
|
|
var oFakeImage = FCKDocumentProcessor_CreateFakeImage( 'FCK__PageBreak', e ) ;
|
|
var oRange = new FCKDomRange( FCK.EditorWindow ) ;
|
|
oRange.MoveToSelection() ;
|
|
var oSplitInfo = oRange.SplitBlock() ;
|
|
oRange.InsertNode( oFakeImage ) ;
|
|
|
|
FCK.Events.FireEvent( 'OnSelectionChange' ) ;
|
|
}
|
|
|
|
FCKPageBreakCommand.prototype.GetState = function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return 0 ; // FCK_TRISTATE_OFF
|
|
}
|
|
|
|
// FCKUnlinkCommand - by Johnny Egeland (johnny@coretrek.com)
|
|
var FCKUnlinkCommand = function()
|
|
{
|
|
this.Name = 'Unlink' ;
|
|
}
|
|
|
|
FCKUnlinkCommand.prototype.Execute = function()
|
|
{
|
|
// Take an undo snapshot before changing the document
|
|
FCKUndo.SaveUndoStep() ;
|
|
|
|
if ( FCKBrowserInfo.IsGeckoLike )
|
|
{
|
|
var oLink = FCK.Selection.MoveToAncestorNode( 'A' ) ;
|
|
// The unlink command can generate a span in Firefox, so let's do it our way. See #430
|
|
if ( oLink )
|
|
FCKTools.RemoveOuterTags( oLink ) ;
|
|
|
|
return ;
|
|
}
|
|
|
|
FCK.ExecuteNamedCommand( this.Name ) ;
|
|
}
|
|
|
|
FCKUnlinkCommand.prototype.GetState = function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
var state = FCK.GetNamedCommandState( this.Name ) ;
|
|
|
|
// Check that it isn't an anchor
|
|
if ( state == FCK_TRISTATE_OFF && FCK.EditMode == FCK_EDITMODE_WYSIWYG )
|
|
{
|
|
var oLink = FCKSelection.MoveToAncestorNode( 'A' ) ;
|
|
var bIsAnchor = ( oLink && oLink.name.length > 0 && oLink.href.length == 0 ) ;
|
|
if ( bIsAnchor )
|
|
state = FCK_TRISTATE_DISABLED ;
|
|
}
|
|
|
|
return state ;
|
|
}
|
|
|
|
var FCKVisitLinkCommand = function()
|
|
{
|
|
this.Name = 'VisitLink';
|
|
}
|
|
FCKVisitLinkCommand.prototype =
|
|
{
|
|
GetState : function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
var state = FCK.GetNamedCommandState( 'Unlink' ) ;
|
|
|
|
if ( state == FCK_TRISTATE_OFF )
|
|
{
|
|
var el = FCKSelection.MoveToAncestorNode( 'A' ) ;
|
|
if ( !el.href )
|
|
state = FCK_TRISTATE_DISABLED ;
|
|
}
|
|
|
|
return state ;
|
|
},
|
|
|
|
Execute : function()
|
|
{
|
|
var el = FCKSelection.MoveToAncestorNode( 'A' ) ;
|
|
var url = el.getAttribute( '_fcksavedurl' ) || el.getAttribute( 'href', 2 ) ;
|
|
|
|
// Check if it's a full URL.
|
|
// If not full URL, we'll need to apply the BaseHref setting.
|
|
if ( ! /:\/\//.test( url ) )
|
|
{
|
|
var baseHref = FCKConfig.BaseHref ;
|
|
var parentWindow = FCK.GetInstanceObject( 'parent' ) ;
|
|
if ( !baseHref )
|
|
{
|
|
baseHref = parentWindow.document.location.href ;
|
|
baseHref = baseHref.substring( 0, baseHref.lastIndexOf( '/' ) + 1 ) ;
|
|
}
|
|
|
|
if ( /^\//.test( url ) )
|
|
{
|
|
try
|
|
{
|
|
baseHref = baseHref.match( /^.*:\/\/+[^\/]+/ )[0] ;
|
|
}
|
|
catch ( e )
|
|
{
|
|
baseHref = parentWindow.document.location.protocol + '://' + parentWindow.parent.document.location.host ;
|
|
}
|
|
}
|
|
|
|
url = baseHref + url ;
|
|
}
|
|
|
|
if ( !window.open( url, '_blank' ) )
|
|
alert( FCKLang.VisitLinkBlocked ) ;
|
|
}
|
|
} ;
|
|
|
|
// FCKSelectAllCommand
|
|
var FCKSelectAllCommand = function()
|
|
{
|
|
this.Name = 'SelectAll' ;
|
|
}
|
|
|
|
FCKSelectAllCommand.prototype.Execute = function()
|
|
{
|
|
if ( FCK.EditMode == FCK_EDITMODE_WYSIWYG )
|
|
{
|
|
FCK.ExecuteNamedCommand( 'SelectAll' ) ;
|
|
}
|
|
else
|
|
{
|
|
// Select the contents of the textarea
|
|
var textarea = FCK.EditingArea.Textarea ;
|
|
if ( FCKBrowserInfo.IsIE )
|
|
{
|
|
textarea.createTextRange().execCommand( 'SelectAll' ) ;
|
|
}
|
|
else
|
|
{
|
|
textarea.selectionStart = 0 ;
|
|
textarea.selectionEnd = textarea.value.length ;
|
|
}
|
|
textarea.focus() ;
|
|
}
|
|
}
|
|
|
|
FCKSelectAllCommand.prototype.GetState = function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return FCK_TRISTATE_OFF ;
|
|
}
|
|
|
|
// FCKPasteCommand
|
|
var FCKPasteCommand = function()
|
|
{
|
|
this.Name = 'Paste' ;
|
|
}
|
|
|
|
FCKPasteCommand.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
if ( FCKBrowserInfo.IsIE )
|
|
FCK.Paste() ;
|
|
else
|
|
FCK.ExecuteNamedCommand( 'Paste' ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return FCK.GetNamedCommandState( 'Paste' ) ;
|
|
}
|
|
} ;
|
|
|
|
// FCKRuleCommand
|
|
var FCKRuleCommand = function()
|
|
{
|
|
this.Name = 'Rule' ;
|
|
}
|
|
|
|
FCKRuleCommand.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
FCKUndo.SaveUndoStep() ;
|
|
FCK.InsertElement( 'hr' ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return FCK.GetNamedCommandState( 'InsertHorizontalRule' ) ;
|
|
}
|
|
} ;
|
|
|
|
// FCKCutCopyCommand
|
|
var FCKCutCopyCommand = function( isCut )
|
|
{
|
|
this.Name = isCut ? 'Cut' : 'Copy' ;
|
|
}
|
|
|
|
FCKCutCopyCommand.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
var enabled = false ;
|
|
|
|
if ( FCKBrowserInfo.IsIE )
|
|
{
|
|
// The following seems to be the only reliable way to detect that
|
|
// cut/copy is enabled in IE. It will fire the oncut/oncopy event
|
|
// only if the security settings enabled the command to execute.
|
|
|
|
var onEvent = function()
|
|
{
|
|
enabled = true ;
|
|
} ;
|
|
|
|
var eventName = 'on' + this.Name.toLowerCase() ;
|
|
|
|
FCK.EditorDocument.body.attachEvent( eventName, onEvent ) ;
|
|
FCK.ExecuteNamedCommand( this.Name ) ;
|
|
FCK.EditorDocument.body.detachEvent( eventName, onEvent ) ;
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
// Other browsers throw an error if the command is disabled.
|
|
FCK.ExecuteNamedCommand( this.Name ) ;
|
|
enabled = true ;
|
|
}
|
|
catch(e){}
|
|
}
|
|
|
|
if ( !enabled )
|
|
alert( FCKLang[ 'PasteError' + this.Name ] ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
// Strangely, the Cut command happens to have the correct states for
|
|
// both Copy and Cut in all browsers.
|
|
return FCK.EditMode != FCK_EDITMODE_WYSIWYG ?
|
|
FCK_TRISTATE_DISABLED :
|
|
FCK.GetNamedCommandState( 'Cut' ) ;
|
|
}
|
|
};
|
|
|
|
var FCKAnchorDeleteCommand = function()
|
|
{
|
|
this.Name = 'AnchorDelete' ;
|
|
}
|
|
|
|
FCKAnchorDeleteCommand.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
if (FCK.Selection.GetType() == 'Control')
|
|
{
|
|
FCK.Selection.Delete();
|
|
}
|
|
else
|
|
{
|
|
var oFakeImage = FCK.Selection.GetSelectedElement() ;
|
|
if ( oFakeImage )
|
|
{
|
|
if ( oFakeImage.tagName == 'IMG' && oFakeImage.getAttribute('_fckanchor') )
|
|
oAnchor = FCK.GetRealElement( oFakeImage ) ;
|
|
else
|
|
oFakeImage = null ;
|
|
}
|
|
|
|
//Search for a real anchor
|
|
if ( !oFakeImage )
|
|
{
|
|
oAnchor = FCK.Selection.MoveToAncestorNode( 'A' ) ;
|
|
if ( oAnchor )
|
|
FCK.Selection.SelectNode( oAnchor ) ;
|
|
}
|
|
|
|
// If it's also a link, then just remove the name and exit
|
|
if ( oAnchor.href.length != 0 )
|
|
{
|
|
oAnchor.removeAttribute( 'name' ) ;
|
|
// Remove temporary class for IE
|
|
if ( FCKBrowserInfo.IsIE )
|
|
oAnchor.className = oAnchor.className.replace( FCKRegexLib.FCK_Class, '' ) ;
|
|
return ;
|
|
}
|
|
|
|
// We need to remove the anchor
|
|
// If we got a fake image, then just remove it and we're done
|
|
if ( oFakeImage )
|
|
{
|
|
oFakeImage.parentNode.removeChild( oFakeImage ) ;
|
|
return ;
|
|
}
|
|
// Empty anchor, so just remove it
|
|
if ( oAnchor.innerHTML.length == 0 )
|
|
{
|
|
oAnchor.parentNode.removeChild( oAnchor ) ;
|
|
return ;
|
|
}
|
|
// Anchor with content, leave the content
|
|
FCKTools.RemoveOuterTags( oAnchor ) ;
|
|
}
|
|
if ( FCKBrowserInfo.IsGecko )
|
|
FCK.Selection.Collapse( true ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
return FCK.GetNamedCommandState( 'Unlink') ;
|
|
}
|
|
};
|
|
|
|
var FCKDeleteDivCommand = function()
|
|
{
|
|
}
|
|
FCKDeleteDivCommand.prototype =
|
|
{
|
|
GetState : function()
|
|
{
|
|
if ( FCK.EditMode != FCK_EDITMODE_WYSIWYG )
|
|
return FCK_TRISTATE_DISABLED ;
|
|
|
|
var node = FCKSelection.GetParentElement() ;
|
|
var path = new FCKElementPath( node ) ;
|
|
return path.BlockLimit && path.BlockLimit.nodeName.IEquals( 'div' ) ? FCK_TRISTATE_OFF : FCK_TRISTATE_DISABLED ;
|
|
},
|
|
|
|
Execute : function()
|
|
{
|
|
// Create an undo snapshot before doing anything.
|
|
FCKUndo.SaveUndoStep() ;
|
|
|
|
// Find out the nodes to delete.
|
|
var nodes = FCKDomTools.GetSelectedDivContainers() ;
|
|
|
|
// Remember the current selection position.
|
|
var range = new FCKDomRange( FCK.EditorWindow ) ;
|
|
range.MoveToSelection() ;
|
|
var bookmark = range.CreateBookmark() ;
|
|
|
|
// Delete the container DIV node.
|
|
for ( var i = 0 ; i < nodes.length ; i++)
|
|
FCKDomTools.RemoveNode( nodes[i], true ) ;
|
|
|
|
// Restore selection.
|
|
range.MoveToBookmark( bookmark ) ;
|
|
range.Select() ;
|
|
}
|
|
} ;
|
|
|
|
// FCKRuleCommand
|
|
var FCKNbsp = function()
|
|
{
|
|
this.Name = 'Non Breaking Space' ;
|
|
}
|
|
|
|
FCKNbsp.prototype =
|
|
{
|
|
Execute : function()
|
|
{
|
|
FCK.InsertHtml( ' ' ) ;
|
|
},
|
|
|
|
GetState : function()
|
|
{
|
|
return ( FCK.EditMode != FCK_EDITMODE_WYSIWYG ? FCK_TRISTATE_DISABLED : FCK_TRISTATE_OFF ) ;
|
|
}
|
|
} ;
|