HTML composition, take 2

Monotone-Parent: dbd490c81ea6cac4c12b2e17661e2fef43219e68
Monotone-Revision: 0801dc9f1e4fdc49ea44fc0450fb025c2639ed26

Monotone-Author: crobert@inverse.ca
Monotone-Date: 2009-06-25T19:18:02
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
C Robert
2009-06-25 19:18:02 +00:00
parent 6ea89d62cd
commit b943372f17
1386 changed files with 231527 additions and 82366 deletions
@@ -0,0 +1,73 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'about', function( editor )
{
var lang = editor.lang.about;
return {
title : lang.title,
minWidth : 390,
minHeight : 230,
contents : [
{
id : 'tab1',
label : '',
title : '',
expand : true,
padding : 0,
elements :
[
{
type : 'html',
html :
'<style type="text/css">' +
'.cke_about_container' +
'{' +
'color:#000 !important;' +
'padding:10px 10px 0;' +
'margin-top:5px' +
'}' +
'.cke_about_container p' +
'{' +
'margin: 0 0 10px;' +
'}' +
'.cke_about_container .cke_about_logo' +
'{' +
'height:81px;' +
'background-color:#fff;' +
'background-image:url(' + CKEDITOR.plugins.get( 'about' ).path + 'dialogs/logo_ckeditor.png);' +
'background-position:center; ' +
'background-repeat:no-repeat;' +
'margin-bottom:10px;' +
'}' +
'.cke_about_container a' +
'{' +
'cursor:pointer !important;' +
'color:blue !important;' +
'text-decoration:underline !important;' +
'}' +
'</style>' +
'<div class="cke_about_container">' +
'<div class="cke_about_logo"></div>' +
'<p>' +
'CKEditor ' + CKEDITOR.version + ' (revision ' + CKEDITOR.revision + ')<br>' +
'<a href="http://ckeditor.com/">http://ckeditor.com</a>' +
'</p>' +
'<p>' +
lang.moreInfo + '<br>' +
'<a href="http://ckeditor.com/license">http://ckeditor.com/license</a>' +
'</p>' +
'<p>' +
lang.copy.replace( '$1', '<a href="http://cksource.com/">CKSource</a> - Frederico Knabben' ) +
'</p>' +
'</div>'
}
]
}
],
buttons : [ CKEDITOR.dialog.cancelButton ]
};
} );
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@@ -0,0 +1,22 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'about',
{
init : function( editor )
{
var command = editor.addCommand( 'about', new CKEDITOR.dialogCommand( 'about' ) );
command.modes = { wysiwyg:1, source:1 };
command.canUndo = false;
editor.ui.addButton( 'About',
{
label : editor.lang.about.title,
command : 'about'
});
CKEDITOR.dialog.add( 'about', this.path + 'dialogs/about.js' );
}
});
@@ -0,0 +1,50 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'basicstyles',
{
requires : [ 'styles', 'button' ],
init : function( editor )
{
// All buttons use the same code to register. So, to avoid
// duplications, let's use this tool function.
var addButtonCommand = function( buttonName, buttonLabel, commandName, styleDefiniton )
{
var style = new CKEDITOR.style( styleDefiniton );
editor.attachStyleStateChange( style, function( state )
{
editor.getCommand( commandName ).setState( state );
});
editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
editor.ui.addButton( buttonName,
{
label : buttonLabel,
command : commandName
});
};
var config = editor.config;
var lang = editor.lang;
addButtonCommand( 'Bold' , lang.bold , 'bold' , config.coreStyles_bold );
addButtonCommand( 'Italic' , lang.italic , 'italic' , config.coreStyles_italic );
addButtonCommand( 'Underline' , lang.underline , 'underline' , config.coreStyles_underline );
addButtonCommand( 'Strike' , lang.strike , 'strike' , config.coreStyles_strike );
addButtonCommand( 'Subscript' , lang.subscript , 'subscript' , config.coreStyles_subscript );
addButtonCommand( 'Superscript' , lang.superscript , 'superscript' , config.coreStyles_superscript );
}
});
// Basic Inline Styles.
CKEDITOR.config.coreStyles_bold = { element : 'strong', overrides : 'b' };
CKEDITOR.config.coreStyles_italic = { element : 'em', overrides : 'i' };
CKEDITOR.config.coreStyles_underline = { element : 'u' };
CKEDITOR.config.coreStyles_strike = { element : 'strike' };
CKEDITOR.config.coreStyles_subscript = { element : 'sub' };
CKEDITOR.config.coreStyles_superscript = { element : 'sup' };
@@ -0,0 +1,301 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Blockquote.
*/
(function()
{
function getState( editor, path )
{
var firstBlock = path.block || path.blockLimit;
if ( !firstBlock || firstBlock.getName() == 'body' )
return CKEDITOR.TRISTATE_OFF;
// See if the first block has a blockquote parent.
if ( firstBlock.getAscendant( 'blockquote', true ) )
return CKEDITOR.TRISTATE_ON;
return CKEDITOR.TRISTATE_OFF;
}
function onSelectionChange( evt )
{
var editor = evt.editor,
command = editor.getCommand( 'blockquote' );
command.state = getState( editor, evt.data.path );
command.fire( 'state' );
}
function noBlockLeft( bqBlock )
{
for ( var i = 0, length = bqBlock.getChildCount(), child ; i < length && ( child = bqBlock.getChild( i ) ) ; i++ )
{
if ( child.type == CKEDITOR.NODE_ELEMENT && child.isBlockBoundary() )
return false;
}
return true;
}
var commandObject =
{
exec : function( editor )
{
var state = editor.getCommand( 'blockquote' ).state,
selection = editor.getSelection(),
range = selection && selection.getRanges()[0];
if ( !range )
return;
var bookmarks = selection.createBookmarks();
// Kludge for #1592: if the bookmark nodes are in the beginning of
// blockquote, then move them to the nearest block element in the
// blockquote.
if ( CKEDITOR.env.ie )
{
var bookmarkStart = bookmarks[0].startNode,
bookmarkEnd = bookmarks[0].endNode,
cursor;
if ( bookmarkStart && bookmarkStart.getParent().getName() == 'blockquote' )
{
cursor = bookmarkStart;
while ( ( cursor = cursor.getNext() ) )
{
if ( cursor.type == CKEDITOR.NODE_ELEMENT &&
cursor.isBlockBoundary() )
{
bookmarkStart.move( cursor, true );
break;
}
}
}
if ( bookmarkEnd
&& bookmarkEnd.getParent().getName() == 'blockquote' )
{
cursor = bookmarkEnd;
while ( ( cursor = cursor.getPrevious() ) )
{
if ( cursor.type == CKEDITOR.NODE_ELEMENT &&
cursor.isBlockBoundary() )
{
bookmarkEnd.move( cursor );
break;
}
}
}
}
var iterator = range.createIterator(),
block;
if ( state == CKEDITOR.TRISTATE_OFF )
{
var paragraphs = [];
while ( ( block = iterator.getNextParagraph() ) )
paragraphs.push( block );
// If no paragraphs, create one from the current selection position.
if ( paragraphs.length < 1 )
{
var para = editor.document.createElement( editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' : 'div' ),
firstBookmark = bookmarks.shift();
range.insertNode( para );
para.append( new CKEDITOR.dom.text( '\ufeff', editor.document ) );
range.moveToBookmark( firstBookmark );
range.selectNodeContents( para );
range.collapse( true );
firstBookmark = range.createBookmark();
paragraphs.push( para );
bookmarks.unshift( firstBookmark );
}
// Make sure all paragraphs have the same parent.
var commonParent = paragraphs[0].getParent(),
tmp = [];
for ( var i = 0 ; i < paragraphs.length ; i++ )
{
block = paragraphs[i];
commonParent = commonParent.getCommonAncestor( block.getParent() );
}
// The common parent must not be the following tags: table, tbody, tr, ol, ul.
var denyTags = { table : 1, tbody : 1, tr : 1, ol : 1, ul : 1 };
while ( denyTags[ commonParent.getName() ] )
commonParent = commonParent.getParent();
// Reconstruct the block list to be processed such that all resulting blocks
// satisfy parentNode.equals( commonParent ).
var lastBlock = null;
while ( paragraphs.length > 0 )
{
block = paragraphs.shift();
while ( !block.getParent().equals( commonParent ) )
block = block.getParent();
if ( !block.equals( lastBlock ) )
tmp.push( block );
lastBlock = block;
}
// If any of the selected blocks is a blockquote, remove it to prevent
// nested blockquotes.
while ( tmp.length > 0 )
{
block = tmp.shift();
if ( block.getName() == 'blockquote' )
{
var docFrag = new CKEDITOR.dom.documentFragment( editor.document );
while ( block.getFirst() )
{
docFrag.append( block.getFirst().remove() );
paragraphs.push( docFrag.getLast() );
}
docFrag.replace( block );
}
else
paragraphs.push( block );
}
// Now we have all the blocks to be included in a new blockquote node.
var bqBlock = editor.document.createElement( 'blockquote' );
bqBlock.insertBefore( paragraphs[0] );
while ( paragraphs.length > 0 )
{
block = paragraphs.shift();
bqBlock.append( block );
}
}
else if ( state == CKEDITOR.TRISTATE_ON )
{
var moveOutNodes = [],
database = {};
while ( ( block = iterator.getNextParagraph() ) )
{
var bqParent = null,
bqChild = null;
while ( block.getParent() )
{
if ( block.getParent().getName() == 'blockquote' )
{
bqParent = block.getParent();
bqChild = block;
break;
}
block = block.getParent();
}
// Remember the blocks that were recorded down in the moveOutNodes array
// to prevent duplicates.
if ( bqParent && bqChild && !bqChild.getCustomData( 'blockquote_moveout' ) )
{
moveOutNodes.push( bqChild );
CKEDITOR.dom.element.setMarker( database, bqChild, 'blockquote_moveout', true );
}
}
CKEDITOR.dom.element.clearAllMarkers( database );
var movedNodes = [],
processedBlockquoteBlocks = [];
database = {};
while ( moveOutNodes.length > 0 )
{
var node = moveOutNodes.shift();
bqBlock = node.getParent();
// If the node is located at the beginning or the end, just take it out
// without splitting. Otherwise, split the blockquote node and move the
// paragraph in between the two blockquote nodes.
if ( !node.getPrevious() )
node.remove().insertBefore( bqBlock );
else if ( !node.getNext() )
node.remove().insertAfter( bqBlock );
else
{
node.breakParent( node.getParent() );
processedBlockquoteBlocks.push( node.getNext() );
}
// Remember the blockquote node so we can clear it later (if it becomes empty).
if ( !bqBlock.getCustomData( 'blockquote_processed' ) )
{
processedBlockquoteBlocks.push( bqBlock );
CKEDITOR.dom.element.setMarker( database, bqBlock, 'blockquote_processed', true );
}
movedNodes.push( node );
}
CKEDITOR.dom.element.clearAllMarkers( database );
// Clear blockquote nodes that have become empty.
for ( i = processedBlockquoteBlocks.length - 1 ; i >= 0 ; i-- )
{
bqBlock = processedBlockquoteBlocks[i];
if ( noBlockLeft( bqBlock ) )
bqBlock.remove();
}
if ( editor.config.enterMode == CKEDITOR.ENTER_BR )
{
var firstTime = true;
while ( movedNodes.length )
{
node = movedNodes.shift();
if ( node.getName() == 'div' )
{
docFrag = new CKEDITOR.dom.documentFragment( editor.document );
var needBeginBr = firstTime && node.getPrevious() &&
!( node.getPrevious().type == CKEDITOR.NODE_ELEMENT && node.getPrevious().isBlockBoundary() );
if ( needBeginBr )
docFrag.append( editor.document.createElement( 'br' ) );
var needEndBr = node.getNext() &&
!( node.getNext().type == CKEDITOR.NODE_ELEMENT && node.getNext().isBlockBoundary() );
while ( node.getFirst() )
node.getFirst().remove().appendTo( docFrag );
if ( needEndBr )
docFrag.append( editor.document.createElement( 'br' ) );
docFrag.replace( node );
firstTime = false;
}
}
}
}
selection.selectBookmarks( bookmarks );
editor.focus();
}
};
CKEDITOR.plugins.add( 'blockquote',
{
init : function( editor )
{
editor.addCommand( 'blockquote', commandObject );
editor.ui.addButton( 'Blockquote',
{
label : editor.lang.blockquote,
command : 'blockquote'
} );
editor.on( 'selectionChange', onSelectionChange );
},
requires : [ 'domiterator' ]
} );
})();
@@ -0,0 +1,258 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'button',
{
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_BUTTON, CKEDITOR.ui.button.handler );
}
});
/**
* Button UI element.
* @constant
* @example
*/
CKEDITOR.UI_BUTTON = 1;
/**
* Represents a button UI element. This class should not be called directly. To
* create new buttons use {@link CKEDITOR.ui.prototype.addButton} instead.
* @constructor
* @param {Object} definition The button definition.
* @example
*/
CKEDITOR.ui.button = function( definition )
{
// Copy all definition properties to this object.
CKEDITOR.tools.extend( this, definition,
// Set defaults.
{
title : definition.label,
className : definition.className || ( definition.command && 'cke_button_' + definition.command ) || '',
click : definition.click || function( editor )
{
editor.execCommand( definition.command );
}
});
this._ = {};
};
/**
* Transforms a button definition in a {@link CKEDITOR.ui.button} instance.
* @type Object
* @example
*/
CKEDITOR.ui.button.handler =
{
create : function( definition )
{
return new CKEDITOR.ui.button( definition );
}
};
CKEDITOR.ui.button.prototype =
{
canGroup : true,
/**
* Renders the button.
* @param {CKEDITOR.editor} editor The editor instance which this button is
* to be used by.
* @param {Array} output The output array to which append the HTML relative
* to this button.
* @example
*/
render : function( editor, output )
{
var env = CKEDITOR.env;
var id = this._.id = 'cke_' + CKEDITOR.tools.getNextNumber();
this._.editor = editor;
var instance =
{
id : id,
button : this,
editor : editor,
focus : function()
{
var element = CKEDITOR.document.getById( id );
element.focus();
},
execute : function()
{
this.button.click( editor );
}
};
var clickFn = CKEDITOR.tools.addFunction( instance.execute, instance );
var index = CKEDITOR.ui.button._.instances.push( instance ) - 1;
var classes = '';
// Get the command name.
var command = this.command;
if ( command )
{
// Get the command instance.
command = editor.getCommand( command );
if ( command )
{
command.on( 'state', function()
{
this.setState( command.state );
}, this);
classes += 'cke_' + (
command.state == CKEDITOR.TRISTATE_ON ? 'on' :
command.state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' :
'off' );
}
}
if ( !command )
classes += 'cke_off';
if ( this.className )
classes += ' ' + this.className;
output.push(
'<span class="cke_button">',
'<a id="', id, '"' +
' class="', classes, '" href="javascript:void(\'', ( this.title || '' ).replace( "'", '' ), '\')"' +
' title="', this.title, '"' +
' tabindex="-1"' +
' role="button"' +
' hidefocus="true"' );
// Some browsers don't cancel key events in the keydown but in the
// keypress.
// TODO: Check if really needed for Gecko+Mac.
if ( env.opera || ( env.gecko && env.mac ) )
{
output.push(
' onkeypress="return false;"' );
}
// With Firefox, we need to force the button to redraw, otherwise it
// will remain in the focus state.
if ( env.gecko )
{
output.push(
' onblur="this.style.cssText = this.style.cssText;"' );
}
output.push(
' onkeydown="return CKEDITOR.ui.button._.keydown(', index, ', event);"' +
' onfocus="return CKEDITOR.ui.button._.focus(', index, ', event);"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +
'<span class="cke_icon"' );
if ( this.icon )
{
var offset = ( this.iconOffset || 0 ) * -16;
output.push( ' style="background-image:url(', CKEDITOR.getUrl( this.icon ), ');background-position:0 ' + offset + 'px;"' );
}
output.push(
'></span>' +
'<span class="cke_label">', this.label, '</span>' );
if ( this.hasArrow )
{
output.push(
'<span class="cke_buttonarrow"></span>' );
}
output.push(
'</a>',
'</span>' );
if ( this.onRender )
this.onRender();
return instance;
},
setState : function( state )
{
if ( this._.state == state )
return;
var element = CKEDITOR.document.getById( this._.id );
if ( element )
{
element.setState( state );
var htmlTitle = this.title,
unavailable = this._.editor.lang.common.unavailable,
labelElement = element.getChild( 1 );
if ( state == CKEDITOR.TRISTATE_DISABLED )
htmlTitle = unavailable.replace( '%1', this.title );
labelElement.setHtml( htmlTitle );
}
this._.state = state;
}
};
/**
* Handles a button click.
* @private
*/
CKEDITOR.ui.button._ =
{
instances : [],
keydown : function( index, ev )
{
var instance = CKEDITOR.ui.button._.instances[ index ];
if ( instance.onkey )
{
ev = new CKEDITOR.dom.event( ev );
return ( instance.onkey( instance, ev.getKeystroke() ) !== false );
}
},
focus : function( index, ev )
{
var instance = CKEDITOR.ui.button._.instances[ index ],
retVal;
if ( instance.onfocus )
retVal = ( instance.onfocus( instance, new CKEDITOR.dom.event( ev ) ) !== false );
// FF2: prevent focus event been bubbled up to editor container, which caused unexpected editor focus.
if ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )
ev.preventBubble();
return retVal;
}
};
/**
* Adds a button definition to the UI elements list.
* @param {String} The button name.
* @param {Object} The button definition.
* @example
* editorInstance.ui.addButton( 'MyBold',
* {
* label : 'My Bold',
* command : 'bold'
* });
*/
CKEDITOR.ui.prototype.addButton = function( name, definition )
{
this.add( name, CKEDITOR.UI_BUTTON, definition );
};
@@ -0,0 +1,154 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'paste', function( editor )
{
var isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
return {
title : editor.lang.clipboard.title,
minWidth : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
minHeight : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 250 : 240,
htmlToLoad : '<!doctype html><script type="text/javascript">'
+ 'window.onload = function()'
+ '{'
+ 'if ( ' + CKEDITOR.env.ie + ' ) '
+ 'document.body.contentEditable = "true";'
+ 'else '
+ 'document.designMode = "on";'
+ 'var iframe = new window.parent.CKEDITOR.dom.element( frameElement );'
+ 'var dialog = iframe.getCustomData( "dialog" );'
+ 'dialog.fire( "iframeAdded", { iframe : iframe } );'
+ '};'
+ '</script><style>body { margin: 3px; height: 95%; } </style><body></body>',
onShow : function()
{
if ( CKEDITOR.env.ie )
this.getParentEditor().document.getBody().$.contentEditable = 'false';
// FIREFOX BUG: Force the browser to render the dialog to make the to-be-
// inserted iframe editable. (#3366)
this.parts.dialog.$.offsetHeight;
var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
iframe = CKEDITOR.dom.element.createFromHtml( '<iframe src="javascript:void(0)" frameborder="0" allowtransparency="1"></iframe>' );
var lang = this.getParentEditor().lang;
iframe.setStyles(
{
width : '346px',
height : '130px',
'background-color' : 'white',
border : '1px solid black'
} );
iframe.setCustomData( 'dialog', this );
var accTitle = lang.editorTitle.replace( '%1', lang.clipboard.title );
if ( CKEDITOR.env.ie )
container.setHtml( '<legend style="position:absolute;top:-1000000px;left:-1000000px;">'
+ CKEDITOR.tools.htmlEncode( accTitle )
+ '</legend>' );
else
{
container.setHtml( '' );
container.setAttributes(
{
role : 'region',
title : accTitle
} );
iframe.setAttributes(
{
role : 'region',
title : ' '
} );
}
container.append( iframe );
if ( CKEDITOR.env.ie )
container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
if ( isCustomDomain )
{
CKEDITOR._cke_htmlToLoad = this.definition.htmlToLoad;
iframe.setAttribute( 'src',
'javascript:void( (function(){' +
'document.open();' +
'document.domain="' + document.domain + '";' +
'document.write( window.parent.CKEDITOR._cke_htmlToLoad );' +
'delete window.parent.CKEDITOR._cke_htmlToLoad;' +
'document.close();' +
'})() )' );
}
else
{
var doc = iframe.$.contentWindow.document;
doc.open();
doc.write( this.definition.htmlToLoad );
doc.close();
}
},
onHide : function()
{
if ( CKEDITOR.env.ie )
this.getParentEditor().document.getBody().$.contentEditable = 'true';
},
onOk : function()
{
var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
iframe = container.getElementsByTag( 'iframe' ).getItem( 0 ),
editor = this.getParentEditor(),
html = iframe.$.contentWindow.document.body.innerHTML;
editor.insertHtml( html );
},
contents : [
{
id : 'general',
label : editor.lang.common.generalTab,
elements : [
{
type : 'html',
id : 'securityMsg',
html : '<div style="white-space:normal;width:340px;">' + editor.lang.clipboard.securityMsg + '</div>'
},
{
type : 'html',
id : 'pasteMsg',
html : '<div style="white-space:normal;width:340px;">'+editor.lang.clipboard.pasteMsg +'</div>'
},
{
type : 'html',
id : 'editing_area',
style : 'width: 100%; height: 100%;',
html : '<fieldset></fieldset>',
focus : function()
{
var div = this.getElement();
var iframe = div.getElementsByTag( 'iframe' );
if ( iframe.count() < 1 )
return;
iframe = iframe.getItem( 0 );
// #3291 : JAWS needs the 500ms delay to detect that the editor iframe
// iframe is no longer editable. So that it will put the focus into the
// Paste from Word dialog's editable area instead.
setTimeout( function()
{
iframe.$.contentWindow.focus();
}, 500 );
}
}
]
}
]
};
});
@@ -0,0 +1,208 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Clipboard support
*/
(function()
{
// Tries to execute any of the paste, cut or copy commands in IE. Returns a
// boolean indicating that the operation succeeded.
var execIECommand = function( editor, command )
{
var doc = editor.document,
body = doc.getBody();
var enabled = false;
var onExec = function()
{
enabled = true;
};
// The following seems to be the only reliable way to detect that
// clipboard commands are enabled in IE. It will fire the
// onpaste/oncut/oncopy events only if the security settings allowed
// the command to execute.
body.on( command, onExec );
doc.$.execCommand( command );
body.removeListener( command, onExec );
return enabled;
};
// Attempts to execute the Cut and Copy operations.
var tryToCutCopy =
CKEDITOR.env.ie ?
function( editor, type )
{
return execIECommand( editor, type );
}
: // !IE.
function( editor, type )
{
try
{
// Other browsers throw an error if the command is disabled.
return editor.document.$.execCommand( type );
}
catch( e )
{
return false;
}
};
// A class that represents one of the cut or copy commands.
var cutCopyCmd = function( type )
{
this.type = type;
this.canUndo = ( this.type == 'cut' ); // We can't undo copy to clipboard.
};
cutCopyCmd.prototype =
{
exec : function( editor, data )
{
var success = tryToCutCopy( editor, this.type );
if ( !success )
alert( editor.lang.clipboard[ this.type + 'Error' ] ); // Show cutError or copyError.
return success;
}
};
// Paste command.
var pasteCmd =
CKEDITOR.env.ie ?
{
exec : function( editor, data )
{
// Prevent IE from pasting at the begining of the document.
editor.focus();
if ( !editor.fire( 'beforePaste' )
&& !execIECommand( editor, 'paste' ) )
{
editor.openDialog( 'paste' );
}
}
}
:
{
exec : function( editor )
{
try
{
if ( !editor.fire( 'beforePaste' )
&& !editor.document.$.execCommand( 'Paste', false, null ) )
{
throw 0;
}
}
catch ( e )
{
// Open the paste dialog.
editor.openDialog( 'paste' );
}
}
};
// Listens for some clipboard related keystrokes, so they get customized.
var onKey = function( event )
{
switch ( event.data.keyCode )
{
// Paste
case CKEDITOR.CTRL + 86 : // CTRL+V
case CKEDITOR.SHIFT + 45 : // SHIFT+INS
var editor = this;
editor.fire( 'saveSnapshot' ); // Save before paste
if ( editor.fire( 'beforePaste' ) )
event.cancel();
setTimeout( function()
{
editor.fire( 'saveSnapshot' ); // Save after paste
}, 0 );
return;
// Cut
case CKEDITOR.CTRL + 88 : // CTRL+X
case CKEDITOR.SHIFT + 46 : // SHIFT+DEL
// Save Undo snapshot.
editor = this;
editor.fire( 'saveSnapshot' ); // Save before paste
setTimeout( function()
{
editor.fire( 'saveSnapshot' ); // Save after paste
}, 0 );
}
};
// Register the plugin.
CKEDITOR.plugins.add( 'clipboard',
{
init : function( editor )
{
function addButtonCommand( buttonName, commandName, command, ctxMenuOrder )
{
var lang = editor.lang[ commandName ];
editor.addCommand( commandName, command );
editor.ui.addButton( buttonName,
{
label : lang,
command : commandName
});
// If the "menu" plugin is loaded, register the menu item.
if ( editor.addMenuItems )
{
editor.addMenuItem( commandName,
{
label : lang,
command : commandName,
group : 'clipboard',
order : ctxMenuOrder
});
}
}
addButtonCommand( 'Cut', 'cut', new cutCopyCmd( 'cut' ), 1 );
addButtonCommand( 'Copy', 'copy', new cutCopyCmd( 'copy' ), 4 );
addButtonCommand( 'Paste', 'paste', pasteCmd, 8 );
CKEDITOR.dialog.add( 'paste', CKEDITOR.getUrl( this.path + 'dialogs/paste.js' ) );
editor.on( 'key', onKey, editor );
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu )
{
function stateFromNamedCommand( command )
{
return editor.document.$.queryCommandEnabled( command ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
}
editor.contextMenu.addListener( function()
{
return {
cut : stateFromNamedCommand( 'Cut' ),
// Browser bug: 'Cut' has the correct states for both Copy and Cut.
copy : stateFromNamedCommand( 'Cut' ),
paste : CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste' )
};
});
}
}
});
})();
@@ -0,0 +1,161 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'colorbutton',
{
requires : [ 'panelbutton', 'floatpanel', 'styles' ],
init : function( editor )
{
var config = editor.config,
lang = editor.lang.colorButton;
var clickFn;
if ( !CKEDITOR.env.hc )
{
addButton( 'TextColor', 'fore', lang.textColorTitle );
addButton( 'BGColor', 'back', lang.bgColorTitle );
}
function addButton( name, type, title )
{
editor.ui.add( name, CKEDITOR.UI_PANELBUTTON,
{
label : title,
title : title,
className : 'cke_button_' + name.toLowerCase(),
panel :
{
css : [ CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ]
},
onBlock : function( panel, blockName )
{
var block = panel.addBlock( blockName );
block.autoSize = true;
block.element.addClass( 'cke_colorblock' );
block.element.setHtml( renderColors( panel, type ) );
var keys = block.keys;
keys[ 39 ] = 'next'; // ARROW-RIGHT
keys[ 9 ] = 'next'; // TAB
keys[ 37 ] = 'prev'; // ARROW-LEFT
keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
keys[ 32 ] = 'click'; // SPACE
}
});
}
function renderColors( panel, type )
{
var output = [],
colors = CKEDITOR.config.colorButton_colors.split( ',' );
var clickFn = CKEDITOR.tools.addFunction( function( color, type )
{
if ( color == '?' )
{
// TODO : Implement the colors dialog.
// editor.openDialog( '' );
return;
}
editor.focus();
panel.hide();
var style = new CKEDITOR.style( config['colorButton_' + type + 'Style'], color && { color : color } );
editor.fire( 'saveSnapshot' );
if ( color )
style.apply( editor.document );
else
style.remove( editor.document );
});
// Render the "Automatic" button.
output.push(
'<a class="cke_colorauto" _cke_focus=1 hidefocus=true' +
' title="', lang.auto, '"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ',null,\'', type, '\');return false;"' +
' href="javascript:void(\'', lang.auto, '\')">' +
'<table cellspacing=0 cellpadding=0 width="100%">' +
'<tr>' +
'<td>' +
'<span class="cke_colorbox" style="background-color:#000"></span>' +
'</td>' +
'<td colspan=7 align=center>',
lang.auto,
'</td>' +
'</tr>' +
'</table>' +
'</a>' +
'<table cellspacing=0 cellpadding=0 width="100%">' );
// Render the color boxes.
for ( var i = 0 ; i < colors.length ; i++ )
{
if ( ( i % 8 ) === 0 )
output.push( '</tr><tr>' );
var colorCode = colors[ i ];
var colorLabel = editor.lang.colors[ colorCode ] || colorCode;
output.push(
'<td>' +
'<a class="cke_colorbox" _cke_focus=1 hidefocus=true' +
' title="', colorLabel, '"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ',\'#', colorCode, '\',\'', type, '\'); return false;"' +
' href="javascript:void(\'', colorLabel, '\')">' +
'<span class="cke_colorbox" style="background-color:#', colorCode, '"></span>' +
'</a>' +
'</td>' );
}
// Render the "More Colors" button.
if ( config.colorButton_enableMore )
{
output.push(
'</tr>' +
'<tr>' +
'<td colspan=8 align=center>' +
'<a class="cke_colormore" _cke_focus=1 hidefocus=true' +
' title="', lang.more, '"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ',\'?\',\'', type, '\');return false;"' +
' href="javascript:void(\'', lang.more, '\')">',
lang.more,
'</a>' +
'</td>' ); // It is later in the code.
}
output.push( '</tr></table>' );
return output.join( '' );
}
}
});
CKEDITOR.config.colorButton_enableMore = false;
CKEDITOR.config.colorButton_colors =
'000,800000,8B4513,2F4F4F,008080,000080,4B0082,696969,' +
'B22222,A52A2A,DAA520,006400,40E0D0,0000CD,800080,808080,' +
'F00,FF8C00,FFD700,008000,0FF,00F,EE82EE,A9A9A9,' +
'FFA07A,FFA500,FFFF00,00FF00,AFEEEE,ADD8E6,DDA0DD,D3D3D3,' +
'FFF0F5,FAEBD7,FFFFE0,F0FFF0,F0FFFF,F0F8FF,E6E6FA,FFF';
CKEDITOR.config.colorButton_foreStyle =
{
element : 'span',
styles : { 'color' : '#(color)' },
overrides : [ { element : 'font', attributes : { 'color' : null } } ]
};
CKEDITOR.config.colorButton_backStyle =
{
element : 'span',
styles : { 'background-color' : '#(color)' }
};
@@ -0,0 +1,178 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'contextmenu',
{
requires : [ 'menu' ],
beforeInit : function( editor )
{
editor.contextMenu = new CKEDITOR.plugins.contextMenu( editor );
editor.addCommand( 'contextMenu',
{
exec : function()
{
editor.contextMenu.show();
}
});
}
});
CKEDITOR.plugins.contextMenu = CKEDITOR.tools.createClass(
{
$ : function( editor )
{
this.id = 'cke_' + CKEDITOR.tools.getNextNumber();
this.editor = editor;
this._.listeners = [];
this._.functionId = CKEDITOR.tools.addFunction( function( commandName )
{
this._.panel.hide();
editor.focus();
editor.execCommand( commandName );
},
this);
},
_ :
{
onMenu : function( offsetParent, corner, offsetX, offsetY )
{
var menu = this._.menu,
editor = this.editor;
if ( menu )
{
menu.hide();
menu.removeAll();
}
else
{
menu = this._.menu = new CKEDITOR.menu( editor );
menu.onClick = CKEDITOR.tools.bind( function( item )
{
var noUnlock = true;
menu.hide();
if ( CKEDITOR.env.ie )
menu.onEscape();
if ( item.onClick )
item.onClick();
else if ( item.command )
editor.execCommand( item.command );
noUnlock = false;
}, this );
menu.onEscape = function()
{
editor.focus();
if ( CKEDITOR.env.ie )
editor.getSelection().unlock( true );
};
}
var listeners = this._.listeners,
includedItems = [];
var selection = this.editor.getSelection(),
element = selection && selection.getStartElement();
// Lock the selection in IE, so it can be restored when closing the
// menu.
if ( CKEDITOR.env.ie )
selection.lock();
menu.onHide = CKEDITOR.tools.bind( function()
{
menu.onHide = null;
if ( CKEDITOR.env.ie )
editor.getSelection().unlock();
this.onHide && this.onHide();
},
this );
// Call all listeners, filling the list of items to be displayed.
for ( var i = 0 ; i < listeners.length ; i++ )
{
var listenerItems = listeners[ i ]( element, selection );
if ( listenerItems )
{
for ( var itemName in listenerItems )
{
var item = this.editor.getMenuItem( itemName );
if ( item )
{
item.state = listenerItems[ itemName ];
menu.add( item );
}
}
}
}
menu.show( offsetParent, corner || ( editor.lang.dir == 'rtl' ? 2 : 1 ), offsetX, offsetY );
}
},
proto :
{
addTarget : function( element )
{
element.on( 'contextmenu', function( event )
{
var domEvent = event.data;
// Cancel the browser context menu.
domEvent.preventDefault();
var offsetParent = domEvent.getTarget().getDocument().getDocumentElement(),
offsetX = domEvent.$.clientX,
offsetY = domEvent.$.clientY;
CKEDITOR.tools.setTimeout( function()
{
this._.onMenu( offsetParent, null, offsetX, offsetY );
},
0, this );
},
this );
},
addListener : function( listenerFn )
{
this._.listeners.push( listenerFn );
},
show : function( offsetParent, corner, offsetX, offsetY )
{
this.editor.focus();
this._.onMenu( offsetParent || CKEDITOR.document.getDocumentElement(), corner, offsetX || 0, offsetY || 0 );
}
}
});
// Fix the "contextmenu" event for DOM elements.
// We may do this if we identify browsers that don't support the context meny
// event on element directly. Leaving here for reference.
//if ( <specific browsers> )
//{
// CKEDITOR.dom.element.prototype.on = CKEDITOR.tools.override( CKEDITOR.dom.element.prototype.on, function( originalOn )
// {
// return function( eventName )
// {
// if ( eventName != 'contextmenu' )
// return originalOn.apply( this, arguments );
//
// // TODO : Implement the fix.
// };
// });
//}
@@ -0,0 +1,315 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview Defines the "virtual" dialog, dialog content and dialog button
* definition classes.
*/
/**
* This class is not really part of the API. It just illustrates the properties
* that developers can use to define and create dialogs.
* @name CKEDITOR.dialog.dialogDefinition
* @constructor
* @example
* // There is no constructor for this class, the user just has to define an
* // object with the appropriate properties.
*
* CKEDITOR.dialog.add( 'testOnly', function( editor )
* {
* return {
* title : 'Test Dialog',
* resizable : CKEDITOR.DIALOG_RESIZE_BOTH,
* minWidth : 500,
* minHeight : 400,
* contents : [
* {
* id : 'tab1',
* label : 'First Tab',
* title : 'First Tab Title',
* accessKey : 'Q',
* elements : [
* {
* type : 'text',
* label : 'Test Text 1',
* id : 'testText1',
* 'default' : 'hello world!'
* }
* ]
* }
* ]
* };
* });
*/
/**
* The dialog title, displayed in the dialog's header. Required.
* @name CKEDITOR.dialog.dialogDefinition.prototype.title
* @field
* @type String
* @example
*/
/**
* How the dialog can be resized, must be one of the four contents defined below.
* <br /><br />
* <strong>CKEDITOR.DIALOG_RESIZE_NONE</strong><br />
* <strong>CKEDITOR.DIALOG_RESIZE_WIDTH</strong><br />
* <strong>CKEDITOR.DIALOG_RESIZE_HEIGHT</strong><br />
* <strong>CKEDITOR.DIALOG_RESIZE_BOTH</strong><br />
* @name CKEDITOR.dialog.dialogDefinition.prototype.resizable
* @field
* @type Number
* @default CKEDITOR.DIALOG_RESIZE_NONE
* @example
*/
/**
* The minimum width of the dialog, in pixels.
* @name CKEDITOR.dialog.dialogDefinition.prototype.minWidth
* @field
* @type Number
* @default 600
* @example
*/
/**
* The minimum height of the dialog, in pixels.
* @name CKEDITOR.dialog.dialogDefinition.prototype.minHeight
* @field
* @type Number
* @default 400
* @example
*/
/**
* The buttons in the dialog, defined as an array of
* {@link CKEDITOR.dialog.buttonDefinition} objects.
* @name CKEDITOR.dialog.dialogDefinition.prototype.buttons
* @field
* @type Array
* @default [ CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton ]
* @example
*/
/**
* The contents in the dialog, defined as an array of
* {@link CKEDITOR.dialog.contentDefinition} objects. Required.
* @name CKEDITOR.dialog.dialogDefinition.prototype.contents
* @field
* @type Array
* @example
*/
/**
* The function to execute when OK is pressed.
* @name CKEDITOR.dialog.dialogDefinition.prototype.onOk
* @field
* @type Function
* @example
*/
/**
* The function to execute when Cancel is pressed.
* @name CKEDITOR.dialog.dialogDefinition.prototype.onCancel
* @field
* @type Function
* @example
*/
/**
* The function to execute when the dialog is displayed for the first time.
* @name CKEDITOR.dialog.dialogDefinition.prototype.onLoad
* @field
* @type Function
* @example
*/
/**
* This class is not really part of the API. It just illustrates the properties
* that developers can use to define and create dialog content pages.
* @name CKEDITOR.dialog.contentDefinition
* @constructor
* @example
* // There is no constructor for this class, the user just has to define an
* // object with the appropriate properties.
*/
/**
* The id of the content page.
* @name CKEDITOR.dialog.contentDefinition.prototype.id
* @field
* @type String
* @example
*/
/**
* The tab label of the content page.
* @name CKEDITOR.dialog.contentDefinition.prototype.label
* @field
* @type String
* @example
*/
/**
* The popup message of the tab label.
* @name CKEDITOR.dialog.contentDefinition.prototype.title
* @field
* @type String
* @example
*/
/**
* The CTRL hotkey for switching to the tab.
* @name CKEDITOR.dialog.contentDefinition.prototype.accessKey
* @field
* @type String
* @example
* contentDefinition.accessKey = 'Q'; // Switch to this page when CTRL-Q is pressed.
*/
/**
* The UI elements contained in this content page, defined as an array of
* {@link CKEDITOR.dialog.uiElementDefinition} objects.
* @name CKEDITOR.dialog.contentDefinition.prototype.elements
* @field
* @type Array
* @example
*/
/**
* This class is not really part of the API. It just illustrates the properties
* that developers can use to define and create dialog buttons.
* @name CKEDITOR.dialog.buttonDefinition
* @constructor
* @example
* // There is no constructor for this class, the user just has to define an
* // object with the appropriate properties.
*/
/**
* The id of the dialog button. Required.
* @name CKEDITOR.dialog.buttonDefinition.prototype.id
* @type String
* @field
* @example
*/
/**
* The label of the dialog button. Required.
* @name CKEDITOR.dialog.buttonDefinition.prototype.label
* @type String
* @field
* @example
*/
/**
* The popup message of the dialog button.
* @name CKEDITOR.dialog.buttonDefinition.prototype.title
* @type String
* @field
* @example
*/
/**
* The CTRL hotkey for the button.
* @name CKEDITOR.dialog.buttonDefinition.prototype.accessKey
* @type String
* @field
* @example
* exitButton.accessKey = 'X'; // Button will be pressed when user presses CTRL-X
*/
/**
* Whether the button is disabled.
* @name CKEDITOR.dialog.buttonDefinition.prototype.disabled
* @type Boolean
* @field
* @default false
* @example
*/
/**
* The function to execute when the button is clicked.
* @name CKEDITOR.dialog.buttonDefinition.prototype.onClick
* @type Function
* @field
* @example
*/
/**
* This class is not really part of the API. It just illustrates the properties
* that developers can use to define and create dialog UI elements.
* @name CKEDITOR.dialog.uiElementDefinition
* @constructor
* @see CKEDITOR.ui.dialog.uiElement
* @example
* // There is no constructor for this class, the user just has to define an
* // object with the appropriate properties.
*/
/**
* The id of the UI element.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.id
* @field
* @type String
* @example
*/
/**
* The type of the UI element. Required.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.type
* @field
* @type String
* @example
*/
/**
* The popup label of the UI element.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.title
* @field
* @type String
* @example
*/
/**
* CSS class names to append to the UI element.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.className
* @field
* @type String
* @example
*/
/**
* Inline CSS classes to append to the UI element.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.style
* @field
* @type String
* @example
*/
/**
* Function to execute the first time the UI element is displayed.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.onLoad
* @field
* @type Function
* @example
*/
/**
* Function to execute whenever the UI element's parent dialog is displayed.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.onShow
* @field
* @type Function
* @example
*/
/**
* Function to execute whenever the UI element's parent dialog is closed.
* @name CKEDITOR.dialog.uiElementDefinition.prototype.onHide
* @field
* @type Function
* @example
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,316 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file DOM iterator, which iterates over list items, lines and paragraphs.
*/
CKEDITOR.plugins.add( 'domiterator' );
(function()
{
var iterator = function( range )
{
if ( arguments.length < 1 )
return;
this.range = range;
this.forceBrBreak = false;
this.enforceRealBlocks = false;
this._ || ( this._ = {} );
},
beginWhitespaceRegex = /^[\r\n\t ]+$/;
iterator.prototype = {
getNextParagraph : function( blockTag )
{
// The block element to be returned.
var block;
// The range object used to identify the paragraph contents.
var range;
// Indicats that the current element in the loop is the last one.
var isLast;
// Instructs to cleanup remaining BRs.
var removePreviousBr, removeLastBr;
// This is the first iteration. Let's initialize it.
if ( !this._.lastNode )
{
range = this.range.clone();
range.enlarge( this.forceBrBreak ? CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS : CKEDITOR.ENLARGE_BLOCK_CONTENTS );
var walker = new CKEDITOR.dom.walker( range ),
ignoreBookmarkTextEvaluator = CKEDITOR.dom.walker.bookmark( true, true );
// Avoid anchor inside bookmark inner text.
walker.evaluator = ignoreBookmarkTextEvaluator;
this._.nextNode = walker.next();
// TODO: It's better to have walker.reset() used here.
walker = new CKEDITOR.dom.walker( range );
walker.evaluator = ignoreBookmarkTextEvaluator;
var lastNode = walker.previous();
this._.lastNode = lastNode.getNextSourceNode( true );
// Probably the document end is reached, we need a marker node.
if ( !this._.lastNode )
{
this._.lastNode = range.document.createText( '' );
this._.lastNode.insertAfter( lastNode );
}
// Let's reuse this variable.
range = null;
}
var currentNode = this._.nextNode;
lastNode = this._.lastNode;
this._.nextNode = null;
while ( currentNode )
{
// closeRange indicates that a paragraph boundary has been found,
// so the range can be closed.
var closeRange = false;
// includeNode indicates that the current node is good to be part
// of the range. By default, any non-element node is ok for it.
var includeNode = ( currentNode.type != CKEDITOR.NODE_ELEMENT ),
continueFromSibling = false;
// If it is an element node, let's check if it can be part of the
// range.
if ( !includeNode )
{
var nodeName = currentNode.getName();
if ( currentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
{
// <br> boundaries must be part of the range. It will
// happen only if ForceBrBreak.
if ( nodeName == 'br' )
includeNode = true;
else if ( !range && !currentNode.getChildCount() && nodeName != 'hr' )
{
// If we have found an empty block, and haven't started
// the range yet, it means we must return this block.
block = currentNode;
isLast = currentNode.equals( lastNode );
break;
}
// The range must finish right before the boundary,
// including possibly skipped empty spaces. (#1603)
if ( range )
{
range.setEndAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
// The found boundary must be set as the next one at this
// point. (#1717)
if ( nodeName != 'br' )
this._.nextNode = currentNode;
}
closeRange = true;
}
else
{
// If we have child nodes, let's check them.
if ( currentNode.getFirst() )
{
// If we don't have a range yet, let's start it.
if ( !range )
{
range = new CKEDITOR.dom.range( this.range.document );
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
}
currentNode = currentNode.getFirst();
continue;
}
includeNode = true;
}
}
else if ( currentNode.type == CKEDITOR.NODE_TEXT )
{
// Ignore normal whitespaces (i.e. not including &nbsp; or
// other unicode whitespaces) before/after a block node.
if ( beginWhitespaceRegex.test( currentNode.getText() ) )
includeNode = false;
}
// The current node is good to be part of the range and we are
// starting a new range, initialize it first.
if ( includeNode && !range )
{
range = new CKEDITOR.dom.range( this.range.document );
range.setStartAt( currentNode, CKEDITOR.POSITION_BEFORE_START );
}
// The last node has been found.
isLast = ( ( !closeRange || includeNode ) && currentNode.equals( lastNode ) );
// If we are in an element boundary, let's check if it is time
// to close the range, otherwise we include the parent within it.
if ( range && !closeRange )
{
while ( !currentNode.getNext() && !isLast )
{
var parentNode = currentNode.getParent();
if ( parentNode.isBlockBoundary( this.forceBrBreak && { br : 1 } ) )
{
closeRange = true;
isLast = isLast || ( parentNode.equals( lastNode) );
break;
}
currentNode = parentNode;
includeNode = true;
isLast = ( currentNode.equals( lastNode ) );
continueFromSibling = true;
}
}
// Now finally include the node.
if ( includeNode )
range.setEndAt( currentNode, CKEDITOR.POSITION_AFTER_END );
// We have found a block boundary. Let's close the range and move out of the
// loop.
if ( ( closeRange || isLast ) && range )
{
var boundaryNodes = range.getBoundaryNodes(),
startPath = new CKEDITOR.dom.elementPath( range.startContainer ),
endPath = new CKEDITOR.dom.elementPath( range.endContainer );
if ( boundaryNodes.startNode.equals( boundaryNodes.endNode )
&& boundaryNodes.startNode.getParent().equals( startPath.blockLimit )
&& boundaryNodes.startNode.type == CKEDITOR.NODE_ELEMENT && boundaryNodes.startNode.getAttribute( '_fck_bookmark' ) )
range = null;
else
break;
}
if ( isLast )
break;
currentNode = currentNode.getNextSourceNode( continueFromSibling, null, lastNode );
}
// Now, based on the processed range, look for (or create) the block to be returned.
if ( !block )
{
// If no range has been found, this is the end.
if ( !range )
{
this._.nextNode = null;
return null;
}
startPath = new CKEDITOR.dom.elementPath( range.startContainer );
var startBlockLimit = startPath.blockLimit,
checkLimits = { div : 1, th : 1, td : 1 };
block = startPath.block;
if ( !block
&& !this.enforceRealBlocks
&& checkLimits[ startBlockLimit.getName() ]
&& range.checkStartOfBlock()
&& range.checkEndOfBlock() )
block = startBlockLimit;
else if ( !block || ( this.enforceRealBlocks && block.getName() == 'li' ) )
{
// Create the fixed block.
block = this.range.document.createElement( blockTag || 'p' );
// Move the contents of the temporary range to the fixed block.
range.extractContents().appendTo( block );
block.trim();
// Insert the fixed block into the DOM.
range.insertNode( block );
removePreviousBr = removeLastBr = true;
}
else if ( block.getName() != 'li' )
{
// If the range doesn't includes the entire contents of the
// block, we must split it, isolating the range in a dedicated
// block.
if ( !range.checkStartOfBlock() || !range.checkEndOfBlock() )
{
// The resulting block will be a clone of the current one.
block = block.clone( false );
// Extract the range contents, moving it to the new block.
range.extractContents().appendTo( block );
block.trim();
// Split the block. At this point, the range will be in the
// right position for our intents.
var splitInfo = range.splitBlock();
removePreviousBr = !splitInfo.wasStartOfBlock;
removeLastBr = !splitInfo.wasEndOfBlock;
// Insert the new block into the DOM.
range.insertNode( block );
}
}
else if ( !isLast )
{
// LIs are returned as is, with all their children (due to the
// nested lists). But, the next node is the node right after
// the current range, which could be an <li> child (nested
// lists) or the next sibling <li>.
this._.nextNode = ( block.equals( lastNode ) ? null :
range.getBoundaryNodes().endNode.getNextSourceNode( true, null, lastNode ) );
}
}
if ( removePreviousBr )
{
var previousSibling = block.getPrevious();
if ( previousSibling && previousSibling.type == CKEDITOR.NODE_ELEMENT )
{
if ( previousSibling.getName() == 'br' )
previousSibling.remove();
else if ( previousSibling.getLast() && previousSibling.getLast().$.nodeName.toLowerCase() == 'br' )
previousSibling.getLast().remove();
}
}
if ( removeLastBr )
{
var lastChild = block.getLast();
if ( lastChild && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.getName() == 'br' )
{
// Take care not to remove the block expanding <br> in non-IE browsers.
if ( CKEDITOR.env.ie || lastChild.getPrevious() || lastChild.getNext() )
lastChild.remove();
}
}
// Get a reference for the next element. This is important because the
// above block can be removed or changed, so we can rely on it for the
// next interation.
if ( !this._.nextNode )
{
this._.nextNode = ( isLast || block.equals( lastNode ) ) ? null :
block.getNextSourceNode( true, null, lastNode );
}
return block;
}
};
CKEDITOR.dom.range.prototype.createIterator = function()
{
return new iterator( this );
};
})();
@@ -0,0 +1,225 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview The default editing block plugin, which holds the editing area
* and source view.
*/
(function()
{
var getMode = function( editor, mode )
{
return editor._.modes && editor._.modes[ mode || editor.mode ];
};
// This is a semaphore used to avoid recursive calls between
// the following data handling functions.
var isHandlingData;
CKEDITOR.plugins.add( 'editingblock',
{
init : function( editor )
{
if ( !editor.config.editingBlock )
return;
editor.on( 'themeSpace', function( event )
{
if ( event.data.space == 'contents' )
event.data.html += '<br>';
});
editor.on( 'themeLoaded', function()
{
editor.fireOnce( 'editingBlockReady' );
});
editor.on( 'uiReady', function()
{
editor.setMode( editor.config.startupMode );
});
editor.on( 'afterSetData', function()
{
if ( !isHandlingData )
{
function setData()
{
isHandlingData = true;
getMode( editor ).loadData( editor.getData() );
isHandlingData = false;
}
if ( editor.mode )
setData();
else
{
editor.on( 'mode', function()
{
setData();
editor.removeListener( 'mode', arguments.callee );
});
}
}
});
editor.on( 'beforeGetData', function()
{
if ( !isHandlingData && editor.mode )
{
isHandlingData = true;
editor.setData( getMode( editor ).getData() );
isHandlingData = false;
}
});
editor.on( 'getSnapshot', function( event )
{
if ( editor.mode )
event.data = getMode( editor ).getSnapshotData();
});
editor.on( 'loadSnapshot', function( event )
{
if ( editor.mode )
getMode( editor ).loadSnapshotData( event.data );
});
// For the first "mode" call, we'll also fire the "instanceReady"
// event.
editor.on( 'mode', function( event )
{
// Do that once only.
event.removeListener();
// Grab editor focus if the editor container is focused. (#3104)
var focusGrabber = editor.container;
// Safari 3 can't handle tabindex in all elements, so we do
// a trick to make it move the focus to the editor on TAB.
if ( CKEDITOR.env.webkit && CKEDITOR.env.version < 528 )
{
var tabIndex = editor.config.tabIndex || editor.element.getAttribute( 'tabindex' ) || 0;
focusGrabber = focusGrabber.append( CKEDITOR.dom.element.createFromHtml(
'<input' +
' tabindex="' + tabIndex + '"' +
' style="position:absolute; left:-10000">' ) );
}
focusGrabber.on( 'focus', function()
{
editor.focus();
});
if ( editor.config.startupFocus )
editor.focus();
// Fire instanceReady for both the editor and CKEDITOR, but
// defer this until the whole execution has completed
// to guarantee the editor is fully responsible.
setTimeout( function(){
editor.fireOnce( 'instanceReady' );
CKEDITOR.fire( 'instanceReady', null, editor );
} );
});
}
});
/**
* The current editing mode. An editing mode is basically a viewport for
* editing or content viewing. By default the possible values for this
* property are "wysiwyg" and "source".
* @type String
* @example
* alert( CKEDITOR.instances.editor1.mode ); // "wysiwyg" (e.g.)
*/
CKEDITOR.editor.prototype.mode = '';
/**
* Registers an editing mode. This function is to be used mainly by plugins.
* @param {String} mode The mode name.
* @param {Object} modeEditor The mode editor definition.
* @example
*/
CKEDITOR.editor.prototype.addMode = function( mode, modeEditor )
{
modeEditor.name = mode;
( this._.modes || ( this._.modes = {} ) )[ mode ] = modeEditor;
};
/**
* Sets the current editing mode in this editor instance.
* @param {String} mode A registered mode name.
* @example
* // Switch to "source" view.
* CKEDITOR.instances.editor1.setMode( 'source' );
*/
CKEDITOR.editor.prototype.setMode = function( mode )
{
var data,
holderElement = this.getThemeSpace( 'contents' ),
isDirty = this.checkDirty();
// Unload the previous mode.
if ( this.mode )
{
if ( mode == this.mode )
return;
var currentMode = getMode( this );
data = currentMode.getData();
currentMode.unload( holderElement );
this.mode = '';
}
holderElement.setHtml( '' );
// Load required mode.
var modeEditor = getMode( this, mode );
if ( !modeEditor )
throw '[CKEDITOR.editor.setMode] Unknown mode "' + mode + '".';
if ( !isDirty )
{
this.on( 'mode', function()
{
this.resetDirty();
this.removeListener( 'mode', arguments.callee );
});
}
modeEditor.load( holderElement, ( typeof data ) != 'string' ? this.getData() : data);
};
/**
* Moves the selection focus to the editing are space in the editor.
*/
CKEDITOR.editor.prototype.focus = function()
{
var mode = getMode( this );
if ( mode )
mode.focus();
};
})();
/**
* The mode to load at the editor startup. It depends on the plugins
* loaded. By default, the "wysiwyg" and "source" modes are available.
* @type String
* @default 'wysiwyg'
* @example
* config.toolbarLocation = 'source';
*/
CKEDITOR.config.startupMode = 'wysiwyg';
/**
* Sets whether the editor should have the focus when the page loads.
* @type Boolean
* @default false
*/
CKEDITOR.config.startupFocus = false;
CKEDITOR.config.editingBlock = true;
@@ -0,0 +1,182 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview The "elementspath" plugin. It shows all elements in the DOM
* parent tree relative to the current selection in the editing area.
*/
(function()
{
var commands =
{
toolbarFocus :
{
exec : function( editor )
{
var idBase = editor._.elementsPath.idBase;
var element = CKEDITOR.document.getById( idBase + '0' );
if ( element )
element.focus();
}
}
};
var emptyHtml = '<span class="cke_empty">&nbsp;</span>';
CKEDITOR.plugins.add( 'elementspath',
{
requires : [ 'selection' ],
init : function( editor )
{
var spaceId = 'cke_path_' + editor.name;
var spaceElement;
var getSpaceElement = function()
{
if ( !spaceElement )
spaceElement = CKEDITOR.document.getById( spaceId );
return spaceElement;
};
var idBase = 'cke_elementspath_' + CKEDITOR.tools.getNextNumber() + '_';
editor._.elementsPath = { idBase : idBase };
editor.on( 'themeSpace', function( event )
{
if ( event.data.space == 'bottom' )
event.data.html += '<div id="' + spaceId + '" class="cke_path">' + emptyHtml + '</div>';
});
editor.on( 'selectionChange', function( ev )
{
var env = CKEDITOR.env;
var selection = ev.data.selection;
var element = selection.getStartElement(),
html = [],
elementsList = this._.elementsPath.list = [];
while ( element )
{
var index = elementsList.push( element ) - 1;
var name;
if ( element.getAttribute( '_cke_real_element_type' ) )
name = element.getAttribute( '_cke_real_element_type' );
else
name = element.getName();
// Use this variable to add conditional stuff to the
// HTML (because we are doing it in reverse order... unshift).
var extra = '';
// Some browsers don't cancel key events in the keydown but in the
// keypress.
// TODO: Check if really needed for Gecko+Mac.
if ( env.opera || ( env.gecko && env.mac ) )
extra += ' onkeypress="return false;"';
// With Firefox, we need to force the button to redraw, otherwise it
// will remain in the focus state.
if ( env.gecko )
extra += ' onblur="this.style.cssText = this.style.cssText;"';
html.unshift(
'<a' +
' id="', idBase, index, '"' +
' href="javascript:void(\'', name, '\')"' +
' tabindex="-1"' +
' title="', editor.lang.elementsPath.eleTitle.replace( /%1/, name ), '"' +
( ( CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 ) ?
' onfocus="event.preventBubble();"' : '' ) +
' hidefocus="true" ' +
' onkeydown="return CKEDITOR._.elementsPath.keydown(\'', this.name, '\',', index, ', event);"' +
extra ,
' onclick="return CKEDITOR._.elementsPath.click(\'', this.name, '\',', index, ');">',
name,
'</a>' );
if ( name == 'body' )
break;
element = element.getParent();
}
getSpaceElement().setHtml( html.join('') + emptyHtml );
});
editor.on( 'contentDomUnload', function()
{
getSpaceElement().setHtml( emptyHtml );
});
editor.addCommand( 'elementsPathFocus', commands.toolbarFocus );
}
});
})();
/**
* Handles the click on an element in the element path.
* @private
*/
CKEDITOR._.elementsPath =
{
click : function( instanceName, elementIndex )
{
var editor = CKEDITOR.instances[ instanceName ];
editor.focus();
var element = editor._.elementsPath.list[ elementIndex ];
editor.getSelection().selectElement( element );
return false;
},
keydown : function( instanceName, elementIndex, ev )
{
var instance = CKEDITOR.ui.button._.instances[ elementIndex ];
var editor = CKEDITOR.instances[ instanceName ];
var idBase = editor._.elementsPath.idBase;
var element;
ev = new CKEDITOR.dom.event( ev );
switch ( ev.getKeystroke() )
{
case 37 : // LEFT-ARROW
case 9 : // TAB
element = CKEDITOR.document.getById( idBase + ( elementIndex + 1 ) );
if ( !element )
element = CKEDITOR.document.getById( idBase + '0' );
element.focus();
return false;
case 39 : // RIGHT-ARROW
case CKEDITOR.SHIFT + 9 : // SHIFT + TAB
element = CKEDITOR.document.getById( idBase + ( elementIndex - 1 ) );
if ( !element )
element = CKEDITOR.document.getById( idBase + ( editor._.elementsPath.list.length - 1 ) );
element.focus();
return false;
case 27 : // ESC
editor.focus();
return false;
case 13 : // ENTER // Opera
case 32 : // SPACE
this.click( instanceName, elementIndex );
return false;
//default :
// alert( ev.getKeystroke() );
}
return true;
}
};
@@ -0,0 +1,323 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
CKEDITOR.plugins.add( 'enterkey',
{
requires : [ 'keystrokes', 'indent' ],
init : function( editor )
{
var specialKeys = editor.specialKeys;
specialKeys[ 13 ] = enter;
specialKeys[ CKEDITOR.SHIFT + 13 ] = shiftEnter;
}
});
var forceMode,
headerTagRegex = /^h[1-6]$/;
function shiftEnter( editor )
{
// On SHIFT+ENTER we want to enforce the mode to be respected, instead
// of cloning the current block. (#77)
forceMode = 1;
return enter( editor, editor.config.shiftEnterMode );
}
function enter( editor, mode )
{
// Only effective within document.
if ( editor.mode != 'wysiwyg' )
return false;
if ( !mode )
mode = editor.config.enterMode;
// Use setTimout so the keys get cancelled immediatelly.
setTimeout( function()
{
editor.fire( 'saveSnapshot' ); // Save undo step.
if ( mode == CKEDITOR.ENTER_BR || editor.getSelection().getStartElement().hasAscendant( 'pre', true ) )
enterBr( editor, mode );
else
enterBlock( editor, mode );
forceMode = 0;
}, 0 );
return true;
}
function enterBlock( editor, mode, range )
{
// Get the range for the current selection.
range = range || getRange( editor );
var doc = range.document;
// Determine the block element to be used.
var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
// Split the range.
var splitInfo = range.splitBlock( blockTag );
if ( !splitInfo )
return;
// Get the current blocks.
var previousBlock = splitInfo.previousBlock,
nextBlock = splitInfo.nextBlock;
var isStartOfBlock = splitInfo.wasStartOfBlock,
isEndOfBlock = splitInfo.wasEndOfBlock;
var node;
// If this is a block under a list item, split it as well. (#1647)
if ( nextBlock )
{
node = nextBlock.getParent();
if ( node.is( 'li' ) )
{
nextBlock.breakParent( node );
nextBlock.move( nextBlock.getNext(), true );
}
}
else if ( previousBlock && ( node = previousBlock.getParent() ) && node.is( 'li' ) )
{
previousBlock.breakParent( node );
range.moveToElementEditStart( previousBlock.getNext() );
previousBlock.move( previousBlock.getPrevious() );
}
// If we have both the previous and next blocks, it means that the
// boundaries were on separated blocks, or none of them where on the
// block limits (start/end).
if ( !isStartOfBlock && !isEndOfBlock )
{
// If the next block is an <li> with another list tree as the first
// child, we'll need to append a placeholder or the list item
// wouldn't be editable. (#1420)
if ( nextBlock.is( 'li' ) && ( node = nextBlock.getFirst() )
&& node.is && node.is( 'ul', 'ol') )
nextBlock.insertBefore( doc.createText( '\xa0' ), node );
// Move the selection to the end block.
if ( nextBlock )
range.moveToElementEditStart( nextBlock );
}
else
{
if ( isStartOfBlock && isEndOfBlock && previousBlock.is( 'li' ) )
{
editor.execCommand( 'outdent' );
return;
}
var newBlock;
if ( previousBlock )
{
// Do not enter this block if it's a header tag, or we are in
// a Shift+Enter (#77). Create a new block element instead
// (later in the code).
if ( !forceMode && !headerTagRegex.test( previousBlock.getName() ) )
{
// Otherwise, duplicate the previous block.
newBlock = previousBlock.clone();
}
}
else if ( nextBlock )
newBlock = nextBlock.clone();
if ( !newBlock )
newBlock = doc.createElement( blockTag );
// Recreate the inline elements tree, which was available
// before hitting enter, so the same styles will be available in
// the new block.
var elementPath = splitInfo.elementPath;
if ( elementPath )
{
for ( var i = 0, len = elementPath.elements.length ; i < len ; i++ )
{
var element = elementPath.elements[ i ];
if ( element.equals( elementPath.block ) || element.equals( elementPath.blockLimit ) )
break;
if ( CKEDITOR.dtd.$removeEmpty[ element.getName() ] )
{
element = element.clone();
newBlock.moveChildren( element );
newBlock.append( element );
}
}
}
if ( !CKEDITOR.env.ie )
newBlock.appendBogus();
range.insertNode( newBlock );
// This is tricky, but to make the new block visible correctly
// we must select it.
// The previousBlock check has been included because it may be
// empty if we have fixed a block-less space (like ENTER into an
// empty table cell).
if ( CKEDITOR.env.ie && isStartOfBlock && ( !isEndOfBlock || !previousBlock.getChildCount() ) )
{
// Move the selection to the new block.
range.moveToElementEditStart( isEndOfBlock ? previousBlock : newBlock );
range.select();
}
// Move the selection to the new block.
range.moveToElementEditStart( isStartOfBlock && !isEndOfBlock ? nextBlock : newBlock );
}
if ( !CKEDITOR.env.ie )
{
if ( nextBlock )
{
// If we have split the block, adds a temporary span at the
// range position and scroll relatively to it.
var tmpNode = doc.createElement( 'span' );
// We need some content for Safari.
tmpNode.setHtml( '&nbsp;' );
range.insertNode( tmpNode );
tmpNode.scrollIntoView();
range.deleteContents();
}
else
{
// We may use the above scroll logic for the new block case
// too, but it gives some weird result with Opera.
newBlock.scrollIntoView();
}
}
range.select();
}
function enterBr( editor, mode )
{
// Get the range for the current selection.
var range = getRange( editor ),
doc = range.document;
// Determine the block element to be used.
var blockTag = ( mode == CKEDITOR.ENTER_DIV ? 'div' : 'p' );
var isEndOfBlock = range.checkEndOfBlock();
var elementPath = new CKEDITOR.dom.elementPath( editor.getSelection().getStartElement() );
var startBlock = elementPath.block,
startBlockTag = startBlock && elementPath.block.getName();
var isPre = false;
if ( !forceMode && startBlockTag == 'li' )
{
enterBlock( editor, mode, range );
return;
}
// If we are at the end of a header block.
if ( !forceMode && isEndOfBlock && headerTagRegex.test( startBlockTag ) )
{
// Insert a <br> after the current paragraph.
doc.createElement( 'br' ).insertAfter( startBlock );
// A text node is required by Gecko only to make the cursor blink.
if ( CKEDITOR.env.gecko )
doc.createText( '' ).insertAfter( startBlock );
// IE has different behaviors regarding position.
range.setStartAt( startBlock.getNext(), CKEDITOR.env.ie ? CKEDITOR.POSITION_BEFORE_START : CKEDITOR.POSITION_AFTER_START );
}
else
{
var lineBreak;
isPre = ( startBlockTag == 'pre' );
if ( isPre )
lineBreak = doc.createText( CKEDITOR.env.ie ? '\r' : '\n' );
else
lineBreak = doc.createElement( 'br' );
range.insertNode( lineBreak );
// A text node is required by Gecko only to make the cursor blink.
// We need some text inside of it, so the bogus <br> is properly
// created.
if ( !CKEDITOR.env.ie )
doc.createText( '\ufeff' ).insertAfter( lineBreak );
// If we are at the end of a block, we must be sure the bogus node is available in that block.
if ( isEndOfBlock && !CKEDITOR.env.ie )
lineBreak.getParent().appendBogus();
// Now we can remove the text node contents, so the caret doesn't
// stop on it.
if ( !CKEDITOR.env.ie )
lineBreak.getNext().$.nodeValue = '';
// IE has different behavior regarding position.
if ( CKEDITOR.env.ie )
range.setStartAt( lineBreak, CKEDITOR.POSITION_AFTER_END );
else
range.setStartAt( lineBreak.getNext(), CKEDITOR.POSITION_AFTER_START );
// Scroll into view, for non IE.
if ( !CKEDITOR.env.ie )
{
var dummy = null;
// BR is not positioned in Opera and Webkit.
if ( !CKEDITOR.env.gecko )
{
dummy = doc.createElement( 'span' );
// We need have some contents for Webkit to position it
// under parent node. ( #3681)
dummy.setHtml('&nbsp;');
}
else
dummy = doc.createElement( 'br' );
dummy.insertBefore( lineBreak.getNext() );
dummy.scrollIntoView();
dummy.remove();
}
}
// This collapse guarantees the cursor will be blinking.
range.collapse( true );
range.select( isPre );
}
function getRange( editor )
{
// Get the selection ranges.
var ranges = editor.getSelection().getRanges();
// Delete the contents of all ranges except the first one.
for ( var i = ranges.length - 1 ; i > 0 ; i-- )
{
ranges[ i ].deleteContents();
}
// Return the first range.
return ranges[ 0 ];
}
})();
@@ -0,0 +1,152 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
var entities =
// Base HTML entities.
'nbsp,gt,lt,quot,' +
// Latin-1 Entities
'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,lceil,' +
'rceil,lfloor,rfloor,lang,rang,loz,spades,clubs,hearts,diams,' +
// Other Special Characters
'circ,tilde,ensp,emsp,thinsp,zwnj,zwj,lrm,rlm,ndash,mdash,lsquo,' +
'rsquo,sbquo,ldquo,rdquo,bdquo,dagger,Dagger,permil,lsaquo,rsaquo,' +
'euro';
// Latin Letters Entities
var latin =
'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';
// Greek Letters Entities.
var greek =
'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,thetasym,' +
'upsih,piv';
function buildTable( entities )
{
var table = {},
regex = [];
// Entities that the browsers DOM don't transform to the final char
// automatically.
var specialTable =
{
nbsp : '\u00A0', // IE | FF
shy : '\u00AD', // IE
gt : '\u003E', // IE | FF | -- | Opera
lt : '\u003C' // IE | FF | Safari | Opera
};
entities = entities.replace( /\b(nbsp|shy|gt|lt|amp)(?:,|$)/g, function( match, entity )
{
table[ specialTable[ entity ] ] = '&' + entity + ';';
regex.push( specialTable[ entity ] );
return '';
});
// Transforms the entities string into an array.
entities = entities.split( ',' );
// Put all entities inside a DOM element, transforming them to their
// final chars.
var div = document.createElement( 'div' ),
chars;
div.innerHTML = '&' + entities.join( ';&' ) + ';';
chars = div.innerHTML;
div = null;
// Add all chars to the table.
for ( var i = 0 ; i < chars.length ; i++ )
{
var charAt = chars.charAt( i );
table[ charAt ] = '&' + entities[ i ] + ';';
regex.push( charAt );
}
table.regex = regex.join( '' );
return table;
}
CKEDITOR.plugins.add( 'entities',
{
afterInit : function( editor )
{
var config = editor.config;
if ( !config.entities )
return;
var dataProcessor = editor.dataProcessor,
htmlFilter = dataProcessor && dataProcessor.htmlFilter;
if ( htmlFilter )
{
var selectedEntities = entities;
if ( config.entities_latin )
selectedEntities += ',' + latin;
if ( config.entities_greek )
selectedEntities += ',' + greek;
if ( config.entities_additional )
selectedEntities += ',' + config.entities_additional;
var entitiesTable = buildTable( selectedEntities );
// Create the Regex used to find entities in the text.
var entitiesRegex = '[' + entitiesTable.regex + ']';
delete entitiesTable.regex;
if ( config.entities_processNumerical )
entitiesRegex = '[^ -~]|' + entitiesRegex ;
entitiesRegex = new RegExp( entitiesRegex, 'g' );
function getChar( character )
{
return entitiesTable[ character ] || ( '&#' + character.charCodeAt(0) + ';' );
}
htmlFilter.addRules(
{
text : function( text )
{
return text.replace( entitiesRegex, getChar );
}
});
}
}
});
})();
CKEDITOR.config.entities = true;
CKEDITOR.config.entities_latin = true;
CKEDITOR.config.entities_greek = true;
CKEDITOR.config.entities_processNumerical = false;
CKEDITOR.config.entities_additional = '#39';
@@ -0,0 +1,383 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview The "filebrowser" plugin, it adds support for file uploads and
* browsing.
*
* When file is selected inside of the file browser or uploaded, its url is
* inserted automatically to a field, which is described in the 'filebrowser'
* attribute. To specify field that should be updated, pass the tab id and
* element id, separated with a colon.
*
* Example 1: (Browse)
*
* <pre>
* {
* type : 'button',
* id : 'browse',
* filebrowser : 'tabId:elementId',
* label : editor.lang.common.browseServer
* }
* </pre>
*
* If you set the 'filebrowser' attribute on any element other than
* 'fileButton', the 'Browse' action will be triggered.
*
* Example 2: (Quick Upload)
*
* <pre>
* {
* type : 'fileButton',
* id : 'uploadButton',
* filebrowser : 'tabId:elementId',
* label : editor.lang.common.uploadSubmit,
* 'for' : [ 'upload', 'upload' ]
* }
* </pre>
*
* If you set the 'filebrowser' attribute on a fileButton element, the
* 'QuickUpload' action will be executed.
*
* Filebrowser plugin also supports more advanced configuration (through
* javascript object).
*
* The following settings are supported:
*
* <pre>
* [action] - Browse or QuickUpload
* [target] - field to update, tabId:elementId
* [params] - additional arguments to be passed to the server connector (optional)
* [onSelect] - function to execute when file is selected/uploaded (optional)
* [url] - the URL to be called (optional)
* </pre>
*
* Example 3: (Quick Upload)
*
* <pre>
* {
* type : 'fileButton',
* label : editor.lang.common.uploadSubmit,
* id : 'buttonId',
* filebrowser :
* {
* action : 'QuickUpload', //required
* target : 'tab1:elementId', //required
* params : //optional
* {
* type : 'Files',
* currentFolder : '/folder/'
* },
* onSelect : function( fileUrl, errorMessage ) //optional
* {
* // Do not call the built-in selectFuntion
* // return false;
* }
* },
* 'for' : [ 'tab1', 'myFile' ]
* }
* </pre>
*
* Suppose we have a file element with id 'myFile', text field with id
* 'elementId' and a fileButton. If filebowser.url is not specified explicitly,
* form action will be set to 'filebrowser[DialogName]UploadUrl' or, if not
* specified, to 'filebrowserUploadUrl'. Additional parameters from 'params'
* object will be added to the query string. It is possible to create your own
* uploadHandler and cancel the built-in updateTargetElement command.
*
* Example 4: (Browse)
*
* <pre>
* {
* type : 'button',
* id : 'buttonId',
* label : editor.lang.common.browseServer,
* filebrowser :
* {
* action : 'Browse',
* url : '/ckfinder/ckfinder.html&amp;type=Images',
* target : 'tab1:elementId'
* }
* }
* </pre>
*
* In this example, after pressing a button, file browser will be opened in a
* popup. If we don't specify filebrowser.url attribute,
* 'filebrowser[DialogName]BrowseUrl' or 'filebrowserBrowseUrl' will be used.
* After selecting a file in a file browser, an element with id 'elementId' will
* be updated. Just like in the third example, a custom 'onSelect' function may be
* defined.
*/
( function()
{
/**
* Adds (additional) arguments to given url.
*
* @param {String}
* url The url.
* @param {Object}
* params Additional parameters.
*/
function addQueryString( url, params )
{
var queryString = [];
if ( !params )
return url;
else
{
for ( var i in params )
queryString.push( i + "=" + encodeURIComponent( params[ i ] ) );
}
return url + ( ( url.indexOf( "?" ) != -1 ) ? "&" : "?" ) + queryString.join( "&" );
}
/**
* Make a string's first character uppercase.
*
* @param {String}
* str String.
*/
function ucFirst( str )
{
str += '';
var f = str.charAt( 0 ).toUpperCase();
return f + str.substr( 1 );
}
/**
* The onlick function assigned to the 'Browse Server' button. Opens the
* file browser and updates target field when file is selected.
*
* @param {CKEDITOR.event}
* evt The event object.
*/
function browseServer( evt )
{
var dialog = this.getDialog();
var editor = dialog.getParentEditor();
editor._.filebrowserSe = this;
var width = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowWidth' ]
|| editor.config.filebrowserWindowWidth || '80%';
var height = editor.config[ 'filebrowser' + ucFirst( dialog.getName() ) + 'WindowHeight' ]
|| editor.config.filebrowserWindowHeight || '70%';
var params = this.filebrowser.params || {};
params.CKEditor = editor.name;
params.CKEditorFuncNum = editor._.filebrowserFn;
if ( !params.langCode )
params.langCode = editor.langCode;
var url = addQueryString( this.filebrowser.url, params );
editor.popup( url, width, height );
}
/**
* The onlick function assigned to the 'Upload' button. Makes the final
* decision whether form is really submitted and updates target field when
* file is uploaded.
*
* @param {CKEDITOR.event}
* evt The event object.
*/
function uploadFile( evt )
{
var dialog = this.getDialog();
var editor = dialog.getParentEditor();
editor._.filebrowserSe = this;
// If user didn't select the file, stop the upload.
if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getInputElement().$.value )
return false;
if ( !dialog.getContentElement( this[ 'for' ][ 0 ], this[ 'for' ][ 1 ] ).getAction() )
return false;
return true;
}
/**
* Setups the file element.
*
* @param {CKEDITOR.ui.dialog.file}
* fileInput The file element used during file upload.
* @param {Object}
* filebrowser Object containing filebrowser settings assigned to
* the fileButton associated with this file element.
*/
function setupFileElement( editor, fileInput, filebrowser )
{
var params = filebrowser.params || {};
params.CKEditor = editor.name;
params.CKEditorFuncNum = editor._.filebrowserFn;
if ( !params.langCode )
params.langCode = editor.langCode;
fileInput.action = addQueryString( filebrowser.url, params );
fileInput.filebrowser = filebrowser;
}
/**
* Traverse through the content definition and attach filebrowser to
* elements with 'filebrowser' attribute.
*
* @param String
* dialogName Dialog name.
* @param {CKEDITOR.dialog.dialogDefinitionObject}
* definition Dialog definition.
* @param {Array}
* elements Array of {@link CKEDITOR.dialog.contentDefinition}
* objects.
*/
function attachFileBrowser( editor, dialogName, definition, elements )
{
var element, fileInput;
for ( var i in elements )
{
element = elements[ i ];
if ( element.type == 'hbox' || element.type == 'vbox' )
attachFileBrowser( editor, dialogName, definition, element.children );
if ( !element.filebrowser )
continue;
if ( typeof element.filebrowser == 'string' )
{
var fb =
{
action : ( element.type == 'fileButton' ) ? 'QuickUpload' : 'Browse',
target : element.filebrowser
};
element.filebrowser = fb;
}
if ( element.filebrowser.action == 'Browse' )
{
var url = element.filebrowser.url || editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'BrowseUrl' ]
|| editor.config.filebrowserBrowseUrl;
if ( url )
{
element.onClick = browseServer;
element.filebrowser.url = url;
element.hidden = false;
}
}
else if ( element.filebrowser.action == 'QuickUpload' && element[ 'for' ] )
{
url = element.filebrowser.url || editor.config[ 'filebrowser' + ucFirst( dialogName ) + 'UploadUrl' ]
|| editor.config.filebrowserUploadUrl;
if ( url )
{
element.onClick = uploadFile;
element.filebrowser.url = url;
element.hidden = false;
setupFileElement( editor, definition.getContents( element[ 'for' ][ 0 ] ).get( element[ 'for' ][ 1 ] ), element.filebrowser );
}
}
}
}
/**
* Updates the target element with the url of uploaded/selected file.
*
* @param {String}
* url The url of a file.
*/
function updateTargetElement( url, sourceElement )
{
var dialog = sourceElement.getDialog();
var targetElement = sourceElement.filebrowser.target || null;
url = url.replace( /#/g, '%23' );
// If there is a reference to targetElement, update it.
if ( targetElement )
{
var target = targetElement.split( ':' );
var element = dialog.getContentElement( target[ 0 ], target[ 1 ] );
if ( element )
{
element.setValue( url );
dialog.selectPage( target[ 0 ] );
}
}
}
/**
* Returns true if filebrowser is configured in one of the elements.
*
* @param {CKEDITOR.dialog.dialogDefinitionObject}
* definition Dialog definition.
* @param String
* tabId The tab id where element(s) can be found.
* @param String
* elementId The element id (or ids, separated with a semicolon) to check.
*/
function isConfigured( definition, tabId, elementId )
{
if ( elementId.indexOf( ";" ) !== -1 )
{
var ids = elementId.split( ";" );
for ( var i = 0 ; i < ids.length ; i++ )
{
if ( isConfigured( definition, tabId, ids[i]) )
return true;
}
return false;
}
return ( definition.getContents( tabId ).get( elementId ).filebrowser && definition.getContents( tabId ).get( elementId ).filebrowser.url );
}
function setUrl( fileUrl, data )
{
var dialog = this._.filebrowserSe.getDialog(),
targetInput = this._.filebrowserSe[ 'for' ],
onSelect = this._.filebrowserSe.filebrowser.onSelect;
if ( targetInput )
dialog.getContentElement( targetInput[ 0 ], targetInput[ 1 ] ).reset();
if ( onSelect && onSelect.call( this._.filebrowserSe, fileUrl, data ) === false )
return;
// The "data" argument may be used to pass the error message to the editor.
if ( typeof data == 'string' && data )
alert( data );
if ( fileUrl )
updateTargetElement( fileUrl, this._.filebrowserSe );
}
CKEDITOR.plugins.add( 'filebrowser',
{
init : function( editor, pluginPath )
{
editor._.filebrowserFn = CKEDITOR.tools.addFunction( setUrl, editor );
CKEDITOR.on( 'dialogDefinition', function( evt )
{
// Associate filebrowser to elements with 'filebrowser' attribute.
for ( var i in evt.data.definition.contents )
{
attachFileBrowser( evt.editor, evt.data.name, evt.data.definition, evt.data.definition.contents[ i ].elements );
if ( evt.data.definition.contents[ i ].hidden && evt.data.definition.contents[ i ].filebrowser )
{
evt.data.definition.contents[ i ].hidden =
!isConfigured( evt.data.definition, evt.data.definition.contents[ i ][ 'id' ], evt.data.definition.contents[ i ].filebrowser );
}
}
} );
}
} );
} )();
@@ -0,0 +1,843 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
function guardDomWalkerNonEmptyTextNode( node )
{
return ( node.type == CKEDITOR.NODE_TEXT && node.getLength() > 0 );
}
/**
* Elements which break characters been considered as sequence.
*/
function checkCharactersBoundary ( node )
{
var dtd = CKEDITOR.dtd;
return node.isBlockBoundary(
CKEDITOR.tools.extend( {}, dtd.$empty, dtd.$nonEditable ) );
}
/**
* Get the cursor object which represent both current character and it's dom
* position thing.
*/
var cursorStep = function()
{
return {
textNode : this.textNode,
offset : this.offset,
character : this.textNode ?
this.textNode.getText().charAt( this.offset ) : null,
hitMatchBoundary : this._.matchBoundary
};
};
var pages = [ 'find', 'replace' ],
fieldsMapping = [
[ 'txtFindFind', 'txtFindReplace' ],
[ 'txtFindCaseChk', 'txtReplaceCaseChk' ],
[ 'txtFindWordChk', 'txtReplaceWordChk' ],
[ 'txtFindCyclic', 'txtReplaceCyclic' ] ];
/**
* Synchronize corresponding filed values between 'replace' and 'find' pages.
* @param {String} currentPageId The page id which receive values.
*/
function syncFieldsBetweenTabs( currentPageId )
{
var sourceIndex, targetIndex,
sourceField, targetField;
sourceIndex = currentPageId === 'find' ? 1 : 0;
targetIndex = 1 - sourceIndex;
var i, l = fieldsMapping.length;
for ( i = 0 ; i < l ; i++ )
{
sourceField = this.getContentElement( pages[ sourceIndex ],
fieldsMapping[ i ][ sourceIndex ] );
targetField = this.getContentElement( pages[ targetIndex ],
fieldsMapping[ i ][ targetIndex ] );
targetField.setValue( sourceField.getValue() );
}
}
var findDialog = function( editor, startupPage )
{
// Style object for highlights.
var highlightStyle = new CKEDITOR.style( editor.config.find_highlight );
/**
* Iterator which walk through the specified range char by char. By
* default the walking will not stop at the character boundaries, until
* the end of the range is encountered.
* @param { CKEDITOR.dom.range } range
* @param {Boolean} matchWord Whether the walking will stop at character boundary.
*/
var characterWalker = function( range , matchWord )
{
var walker =
new CKEDITOR.dom.walker( range );
walker[ matchWord ? 'guard' : 'evaluator' ] =
guardDomWalkerNonEmptyTextNode;
walker.breakOnFalse = true;
this._ = {
matchWord : matchWord,
walker : walker,
matchBoundary : false
};
};
characterWalker.prototype = {
next : function()
{
return this.move();
},
back : function()
{
return this.move( true );
},
move : function( rtl )
{
var currentTextNode = this.textNode;
// Already at the end of document, no more character available.
if( currentTextNode === null )
return cursorStep.call( this );
this._.matchBoundary = false;
// There are more characters in the text node, step forward.
if( currentTextNode
&& rtl
&& this.offset > 0 )
{
this.offset--;
return cursorStep.call( this );
}
else if( currentTextNode
&& this.offset < currentTextNode.getLength() - 1 )
{
this.offset++;
return cursorStep.call( this );
}
else
{
currentTextNode = null;
// At the end of the text node, walking foward for the next.
while ( !currentTextNode )
{
currentTextNode =
this._.walker[ rtl ? 'previous' : 'next' ].call( this._.walker );
// Stop searching if we're need full word match OR
// already reach document end.
if ( this._.matchWord && !currentTextNode
||this._.walker._.end )
break;
// Marking as match character boundaries.
if( !currentTextNode
&& checkCharactersBoundary( this._.walker.current ) )
this._.matchBoundary = true;
}
// Found a fresh text node.
this.textNode = currentTextNode;
if ( currentTextNode )
this.offset = rtl ? currentTextNode.getLength() - 1 : 0;
else
this.offset = 0;
}
return cursorStep.call( this );
}
};
/**
* A range of cursors which represent a trunk of characters which try to
* match, it has the same length as the pattern string.
*/
var characterRange = function( characterWalker, rangeLength )
{
this._ = {
walker : characterWalker,
cursors : [],
rangeLength : rangeLength,
highlightRange : null,
isMatched : false
};
};
characterRange.prototype = {
/**
* Translate this range to {@link CKEDITOR.dom.range}
*/
toDomRange : function()
{
var cursors = this._.cursors;
if ( cursors.length < 1 )
return null;
var first = cursors[0],
last = cursors[ cursors.length - 1 ],
range = new CKEDITOR.dom.range( editor.document );
range.setStart( first.textNode, first.offset );
range.setEnd( last.textNode, last.offset + 1 );
return range;
},
/**
* Reflect the latest changes from dom range.
*/
updateFromDomRange : function( domRange )
{
var cursor,
walker = new characterWalker( domRange );
this._.cursors = [];
do
{
cursor = walker.next();
if ( cursor.character )
this._.cursors.push( cursor );
}
while ( cursor.character );
this._.rangeLength = this._.cursors.length;
},
setMatched : function()
{
this._.isMatched = true;
},
clearMatched : function()
{
this._.isMatched = false;
},
isMatched : function()
{
return this._.isMatched;
},
/**
* Hightlight the current matched chunk of text.
*/
highlight : function()
{
// Do not apply if nothing is found.
if ( this._.cursors.length < 1 )
return;
// Remove the previous highlight if there's one.
if ( this._.highlightRange )
this.removeHighlight();
// Apply the highlight.
var range = this.toDomRange();
highlightStyle.applyToRange( range );
this._.highlightRange = range;
// Scroll the editor to the highlighted area.
var element = range.startContainer;
if ( element.type != CKEDITOR.NODE_ELEMENT )
element = element.getParent();
element.scrollIntoView();
// Update the character cursors.
this.updateFromDomRange( range );
},
/**
* Remove highlighted find result.
*/
removeHighlight : function()
{
if ( !this._.highlightRange )
return;
highlightStyle.removeFromRange( this._.highlightRange );
this.updateFromDomRange( this._.highlightRange );
this._.highlightRange = null;
},
moveBack : function()
{
var retval = this._.walker.back(),
cursors = this._.cursors;
if ( retval.hitMatchBoundary )
this._.cursors = cursors = [];
cursors.unshift( retval );
if ( cursors.length > this._.rangeLength )
cursors.pop();
return retval;
},
moveNext : function()
{
var retval = this._.walker.next(),
cursors = this._.cursors;
// Clear the cursors queue if we've crossed a match boundary.
if ( retval.hitMatchBoundary )
this._.cursors = cursors = [];
cursors.push( retval );
if ( cursors.length > this._.rangeLength )
cursors.shift();
return retval;
},
getEndCharacter : function()
{
var cursors = this._.cursors;
if ( cursors.length < 1 )
return null;
return cursors[ cursors.length - 1 ].character;
},
getNextCharacterRange : function( maxLength )
{
var lastCursor,
cursors = this._.cursors;
if ( !( lastCursor = cursors[ cursors.length - 1 ] ) )
return null;
return new characterRange(
new characterWalker(
getRangeAfterCursor( lastCursor ) ),
maxLength );
},
getCursors : function()
{
return this._.cursors;
}
};
// The remaining document range after the character cursor.
function getRangeAfterCursor( cursor , inclusive )
{
var range = new CKEDITOR.dom.range();
range.setStart( cursor.textNode,
( inclusive ? cursor.offset : cursor.offset + 1 ) );
range.setEndAt( editor.document.getBody(),
CKEDITOR.POSITION_BEFORE_END );
return range;
}
// The document range before the character cursor.
function getRangeBeforeCursor( cursor )
{
var range = new CKEDITOR.dom.range();
range.setStartAt( editor.document.getBody(),
CKEDITOR.POSITION_AFTER_START );
range.setEnd( cursor.textNode, cursor.offset );
return range;
}
var KMP_NOMATCH = 0,
KMP_ADVANCED = 1,
KMP_MATCHED = 2;
/**
* Examination the occurrence of a word which implement KMP algorithm.
*/
var kmpMatcher = function( pattern, ignoreCase )
{
var overlap = [ -1 ];
if ( ignoreCase )
pattern = pattern.toLowerCase();
for ( var i = 0 ; i < pattern.length ; i++ )
{
overlap.push( overlap[i] + 1 );
while ( overlap[ i + 1 ] > 0
&& pattern.charAt( i ) != pattern
.charAt( overlap[ i + 1 ] - 1 ) )
overlap[ i + 1 ] = overlap[ overlap[ i + 1 ] - 1 ] + 1;
}
this._ = {
overlap : overlap,
state : 0,
ignoreCase : !!ignoreCase,
pattern : pattern
};
};
kmpMatcher.prototype =
{
feedCharacter : function( c )
{
if ( this._.ignoreCase )
c = c.toLowerCase();
while ( true )
{
if ( c == this._.pattern.charAt( this._.state ) )
{
this._.state++;
if ( this._.state == this._.pattern.length )
{
this._.state = 0;
return KMP_MATCHED;
}
return KMP_ADVANCED;
}
else if ( !this._.state )
return KMP_NOMATCH;
else
this._.state = this._.overlap[ this._.state ];
}
return null;
},
reset : function()
{
this._.state = 0;
}
};
var wordSeparatorRegex =
/[.,"'?!;: \u0085\u00a0\u1680\u280e\u2028\u2029\u202f\u205f\u3000]/;
var isWordSeparator = function( c )
{
if ( !c )
return true;
var code = c.charCodeAt( 0 );
return ( code >= 9 && code <= 0xd )
|| ( code >= 0x2000 && code <= 0x200a )
|| wordSeparatorRegex.test( c );
};
var finder = {
searchRange : null,
matchRange : null,
find : function( pattern, matchCase, matchWord, matchCyclic, highlightMatched )
{
if( !this.matchRange )
this.matchRange =
new characterRange(
new characterWalker( this.searchRange ),
pattern.length );
else
{
this.matchRange.removeHighlight();
this.matchRange = this.matchRange.getNextCharacterRange( pattern.length );
}
var matcher = new kmpMatcher( pattern, !matchCase ),
matchState = KMP_NOMATCH,
character = '%';
while ( character !== null )
{
this.matchRange.moveNext();
while ( ( character = this.matchRange.getEndCharacter() ) )
{
matchState = matcher.feedCharacter( character );
if ( matchState == KMP_MATCHED )
break;
if ( this.matchRange.moveNext().hitMatchBoundary )
matcher.reset();
}
if ( matchState == KMP_MATCHED )
{
if ( matchWord )
{
var cursors = this.matchRange.getCursors(),
tail = cursors[ cursors.length - 1 ],
head = cursors[ 0 ];
var headWalker = new characterWalker( getRangeBeforeCursor( head ), true ),
tailWalker = new characterWalker( getRangeAfterCursor( tail ), true );
if ( ! ( isWordSeparator( headWalker.back().character )
&& isWordSeparator( tailWalker.next().character ) ) )
continue;
}
this.matchRange.setMatched();
if ( highlightMatched !== false )
this.matchRange.highlight();
return true;
}
}
this.matchRange.clearMatched();
this.matchRange.removeHighlight();
// Clear current session and restart with the default search
// range.
if ( matchCyclic )
{
this.searchRange = getSearchRange( true );
this.matchRange = null;
}
return false;
},
/**
* Record how much replacement occurred toward one replacing.
*/
replaceCounter : 0,
replace : function( dialog, pattern, newString, matchCase, matchWord,
matchCyclic , isReplaceAll )
{
// Successiveness of current replace/find.
var result = false;
// 1. Perform the replace when there's already a match here.
// 2. Otherwise perform the find but don't replace it immediately.
if ( this.matchRange && this.matchRange.isMatched()
&& !this.matchRange._.isReplaced )
{
// Turn off highlight for a while when saving snapshots.
this.matchRange.removeHighlight();
var domRange = this.matchRange.toDomRange();
var text = editor.document.createText( newString );
if ( !isReplaceAll )
{
// Save undo snaps before and after the replacement.
var selection = editor.getSelection();
selection.selectRanges( [ domRange ] );
editor.fire( 'saveSnapshot' );
}
domRange.deleteContents();
domRange.insertNode( text );
if ( !isReplaceAll )
{
selection.selectRanges( [ domRange ] );
editor.fire( 'saveSnapshot' );
}
this.matchRange.updateFromDomRange( domRange );
if ( !isReplaceAll )
this.matchRange.highlight();
this.matchRange._.isReplaced = true;
this.replaceCounter++;
result = true;
}
else
result = this.find( pattern, matchCase, matchWord, matchCyclic, !isReplaceAll );
return result;
}
};
/**
* The range in which find/replace happened, receive from user
* selection prior.
*/
function getSearchRange( isDefault )
{
var searchRange,
sel = editor.getSelection(),
body = editor.document.getBody();
if ( sel && !isDefault )
{
searchRange = sel.getRanges()[ 0 ].clone();
searchRange.collapse( true );
}
else
{
searchRange = new CKEDITOR.dom.range();
searchRange.setStartAt( body, CKEDITOR.POSITION_AFTER_START );
}
searchRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END );
return searchRange;
}
return {
title : editor.lang.findAndReplace.title,
resizable : CKEDITOR.DIALOG_RESIZE_NONE,
minWidth : 350,
minHeight : 165,
buttons : [ CKEDITOR.dialog.cancelButton ], //Cancel button only.
contents : [
{
id : 'find',
label : editor.lang.findAndReplace.find,
title : editor.lang.findAndReplace.find,
accessKey : '',
elements : [
{
type : 'hbox',
widths : [ '230px', '90px' ],
children :
[
{
type : 'text',
id : 'txtFindFind',
label : editor.lang.findAndReplace.findWhat,
isChanged : false,
labelLayout : 'horizontal',
accessKey : 'F'
},
{
type : 'button',
align : 'left',
style : 'width:100%',
label : editor.lang.findAndReplace.find,
onClick : function()
{
var dialog = this.getDialog();
if ( !finder.find( dialog.getValueOf( 'find', 'txtFindFind' ),
dialog.getValueOf( 'find', 'txtFindCaseChk' ),
dialog.getValueOf( 'find', 'txtFindWordChk' ),
dialog.getValueOf( 'find', 'txtFindCyclic' ) ) )
alert( editor.lang.findAndReplace
.notFoundMsg );
}
}
]
},
{
type : 'vbox',
padding : 0,
children :
[
{
type : 'checkbox',
id : 'txtFindCaseChk',
isChanged : false,
style : 'margin-top:28px',
label : editor.lang.findAndReplace.matchCase
},
{
type : 'checkbox',
id : 'txtFindWordChk',
isChanged : false,
label : editor.lang.findAndReplace.matchWord
},
{
type : 'checkbox',
id : 'txtFindCyclic',
isChanged : false,
'default' : true,
label : editor.lang.findAndReplace.matchCyclic
}
]
}
]
},
{
id : 'replace',
label : editor.lang.findAndReplace.replace,
accessKey : 'M',
elements : [
{
type : 'hbox',
widths : [ '230px', '90px' ],
children :
[
{
type : 'text',
id : 'txtFindReplace',
label : editor.lang.findAndReplace.findWhat,
isChanged : false,
labelLayout : 'horizontal',
accessKey : 'F'
},
{
type : 'button',
align : 'left',
style : 'width:100%',
label : editor.lang.findAndReplace.replace,
onClick : function()
{
var dialog = this.getDialog();
if ( !finder.replace( dialog,
dialog.getValueOf( 'replace', 'txtFindReplace' ),
dialog.getValueOf( 'replace', 'txtReplace' ),
dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),
dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),
dialog.getValueOf( 'replace', 'txtReplaceCyclic' ) ) )
alert( editor.lang.findAndReplace
.notFoundMsg );
}
}
]
},
{
type : 'hbox',
widths : [ '230px', '90px' ],
children :
[
{
type : 'text',
id : 'txtReplace',
label : editor.lang.findAndReplace.replaceWith,
isChanged : false,
labelLayout : 'horizontal',
accessKey : 'R'
},
{
type : 'button',
align : 'left',
style : 'width:100%',
label : editor.lang.findAndReplace.replaceAll,
isChanged : false,
onClick : function()
{
var dialog = this.getDialog();
var replaceNums;
finder.replaceCounter = 0;
// Scope to full document.
finder.searchRange = getSearchRange( true );
if ( finder.matchRange )
{
finder.matchRange.removeHighlight();
finder.matchRange = null;
}
editor.fire( 'saveSnapshot' );
while( finder.replace( dialog,
dialog.getValueOf( 'replace', 'txtFindReplace' ),
dialog.getValueOf( 'replace', 'txtReplace' ),
dialog.getValueOf( 'replace', 'txtReplaceCaseChk' ),
dialog.getValueOf( 'replace', 'txtReplaceWordChk' ),
false, true ) )
;
if ( finder.replaceCounter )
{
alert( editor.lang.findAndReplace.replaceSuccessMsg.replace( /%1/, finder.replaceCounter ) );
editor.fire( 'saveSnapshot' );
}
else
alert( editor.lang.findAndReplace.notFoundMsg );
}
}
]
},
{
type : 'vbox',
padding : 0,
children :
[
{
type : 'checkbox',
id : 'txtReplaceCaseChk',
isChanged : false,
label : editor.lang.findAndReplace
.matchCase
},
{
type : 'checkbox',
id : 'txtReplaceWordChk',
isChanged : false,
label : editor.lang.findAndReplace
.matchWord
},
{
type : 'checkbox',
id : 'txtReplaceCyclic',
isChanged : false,
'default' : true,
label : editor.lang.findAndReplace
.matchCyclic
}
]
}
]
}
],
onLoad : function()
{
var dialog = this;
//keep track of the current pattern field in use.
var patternField, wholeWordChkField;
//Ignore initial page select on dialog show
var isUserSelect = false;
this.on('hide', function()
{
isUserSelect = false;
} );
this.on('show', function()
{
isUserSelect = true;
} );
this.selectPage = CKEDITOR.tools.override( this.selectPage, function( originalFunc )
{
return function( pageId )
{
originalFunc.call( dialog, pageId );
var currPage = dialog._.tabs[ pageId ];
var patternFieldInput, patternFieldId, wholeWordChkFieldId;
patternFieldId = pageId === 'find' ? 'txtFindFind' : 'txtFindReplace';
wholeWordChkFieldId = pageId === 'find' ? 'txtFindWordChk' : 'txtReplaceWordChk';
patternField = dialog.getContentElement( pageId,
patternFieldId );
wholeWordChkField = dialog.getContentElement( pageId,
wholeWordChkFieldId );
// prepare for check pattern text filed 'keyup' event
if ( !currPage.initialized )
{
patternFieldInput = CKEDITOR.document
.getById( patternField._.inputId );
currPage.initialized = true;
}
if( isUserSelect )
// synchronize fields on tab switch.
syncFieldsBetweenTabs.call( this, pageId );
};
} );
},
onShow : function()
{
// Establish initial searching start position.
finder.searchRange = getSearchRange();
if ( startupPage == 'replace' )
this.getContentElement( 'replace', 'txtFindReplace' ).focus();
else
this.getContentElement( 'find', 'txtFindFind' ).focus();
},
onHide : function()
{
if ( finder.matchRange && finder.matchRange.isMatched() )
{
finder.matchRange.removeHighlight();
editor.focus();
editor.getSelection().selectRanges(
[ finder.matchRange.toDomRange() ] );
}
// Clear current session before dialog close
delete finder.matchRange;
}
};
};
CKEDITOR.dialog.add( 'find', function( editor )
{
return findDialog( editor, 'find' );
});
CKEDITOR.dialog.add( 'replace', function( editor )
{
return findDialog( editor, 'replace' );
});
})();
@@ -0,0 +1,35 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'find',
{
init : function( editor )
{
var forms = CKEDITOR.plugins.find;
editor.ui.addButton( 'Find',
{
label : editor.lang.findAndReplace.find,
command : 'find'
});
var findCommand = editor.addCommand( 'find', new CKEDITOR.dialogCommand( 'find' ) );
findCommand.canUndo = false;
editor.ui.addButton( 'Replace',
{
label : editor.lang.findAndReplace.replace,
command : 'replace'
});
var replaceCommand = editor.addCommand( 'replace', new CKEDITOR.dialogCommand( 'replace' ) );
replaceCommand.canUndo = false;
CKEDITOR.dialog.add( 'find', this.path + 'dialogs/find.js' );
CKEDITOR.dialog.add( 'replace', this.path + 'dialogs/find.js' );
},
requires : [ 'styles' ]
} );
// Styles for highlighting search results.
CKEDITOR.config.find_highlight = { element : 'span', styles : { 'background-color' : '#004', 'color' : '#fff' } };
@@ -0,0 +1,678 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
/*
* It is possible to set things in three different places.
* 1. As attributes in the object tag.
* 2. As param tags under the object tag.
* 3. As attributes in the embed tag.
* It is possible for a single attribute to be present in more than one place.
* So let's define a mapping between a sementic attribute and its syntactic
* equivalents.
* Then we'll set and retrieve attribute values according to the mapping,
* instead of having to check and set each syntactic attribute every time.
*
* Reference: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_12701
*/
var ATTRTYPE_OBJECT = 1,
ATTRTYPE_PARAM = 2,
ATTRTYPE_EMBED = 4;
var attributesMap =
{
id : [ { type : ATTRTYPE_OBJECT, name : CKEDITOR.env.ie ? '_cke_saved_id' : 'id' } ],
classid : [ { type : ATTRTYPE_OBJECT, name : 'classid' } ],
codebase : [ { type : ATTRTYPE_OBJECT, name : 'codebase'} ],
pluginspage : [ { type : ATTRTYPE_EMBED, name : 'pluginspage' } ],
src : [ { type : ATTRTYPE_PARAM, name : 'movie' }, { type : ATTRTYPE_EMBED, name : 'src' } ],
name : [ { type : ATTRTYPE_EMBED, name : 'name' } ],
align : [ { type : ATTRTYPE_OBJECT, name : 'align' } ],
title : [ { type : ATTRTYPE_OBJECT, name : 'title' }, { type : ATTRTYPE_EMBED, name : 'title' } ],
'class' : [ { type : ATTRTYPE_OBJECT, name : 'class' }, { type : ATTRTYPE_EMBED, name : 'class'} ],
width : [ { type : ATTRTYPE_OBJECT, name : 'width' }, { type : ATTRTYPE_EMBED, name : 'width' } ],
height : [ { type : ATTRTYPE_OBJECT, name : 'height' }, { type : ATTRTYPE_EMBED, name : 'height' } ],
hSpace : [ { type : ATTRTYPE_OBJECT, name : 'hSpace' }, { type : ATTRTYPE_EMBED, name : 'hSpace' } ],
vSpace : [ { type : ATTRTYPE_OBJECT, name : 'vSpace' }, { type : ATTRTYPE_EMBED, name : 'vSpace' } ],
style : [ { type : ATTRTYPE_OBJECT, name : 'style' }, { type : ATTRTYPE_EMBED, name : 'style' } ],
type : [ { type : ATTRTYPE_EMBED, name : 'type' } ]
};
var names = [ 'play', 'loop', 'menu', 'quality', 'scale', 'salign', 'wmode', 'bgcolor', 'base', 'flashvars', 'allowScriptAccess',
'allowFullScreen' ];
for ( var i = 0 ; i < names.length ; i++ )
attributesMap[ names[i] ] = [ { type : ATTRTYPE_EMBED, name : names[i] }, { type : ATTRTYPE_PARAM, name : names[i] } ];
names = [ 'allowFullScreen', 'play', 'loop', 'menu' ];
for ( i = 0 ; i < names.length ; i++ )
attributesMap[ names[i] ][0]['default'] = attributesMap[ names[i] ][1]['default'] = true;
function loadValue( objectNode, embedNode, paramMap )
{
var attributes = attributesMap[ this.id ];
if ( !attributes )
return;
var isCheckbox = ( this instanceof CKEDITOR.ui.dialog.checkbox );
for ( var i = 0 ; i < attributes.length ; i++ )
{
var attrDef = attributes[ i ];
switch ( attrDef.type )
{
case ATTRTYPE_OBJECT:
if ( !objectNode )
continue;
if ( objectNode.getAttribute( attrDef.name ) !== null )
{
var value = objectNode.getAttribute( attrDef.name );
if ( isCheckbox )
this.setValue( value.toLowerCase() == 'true' );
else
this.setValue( value );
return;
}
else if ( isCheckbox )
this.setValue( !!attrDef[ 'default' ] );
break;
case ATTRTYPE_PARAM:
if ( !objectNode )
continue;
if ( attrDef.name in paramMap )
{
value = paramMap[ attrDef.name ];
if ( isCheckbox )
this.setValue( value.toLowerCase() == 'true' );
else
this.setValue( value );
return;
}
else if ( isCheckbox )
this.setValue( !!attrDef[ 'default' ] );
break;
case ATTRTYPE_EMBED:
if ( !embedNode )
continue;
if ( embedNode.getAttribute( attrDef.name ) )
{
value = embedNode.getAttribute( attrDef.name );
if ( isCheckbox )
this.setValue( value.toLowerCase() == 'true' );
else
this.setValue( value );
return;
}
else if ( isCheckbox )
this.setValue( !!attrDef[ 'default' ] );
}
}
}
function commitValue( objectNode, embedNode, paramMap )
{
var attributes = attributesMap[ this.id ];
if ( !attributes )
return;
var isRemove = ( this.getValue() === '' ),
isCheckbox = ( this instanceof CKEDITOR.ui.dialog.checkbox );
for ( var i = 0 ; i < attributes.length ; i++ )
{
var attrDef = attributes[i];
switch ( attrDef.type )
{
case ATTRTYPE_OBJECT:
if ( !objectNode )
continue;
var value = this.getValue();
if ( isRemove || isCheckbox && value === attrDef[ 'default' ] )
objectNode.removeAttribute( attrDef.name );
else
objectNode.setAttribute( attrDef.name, value );
break;
case ATTRTYPE_PARAM:
if ( !objectNode )
continue;
value = this.getValue();
if ( isRemove || isCheckbox && value === attrDef[ 'default' ] )
{
if ( attrDef.name in paramMap )
paramMap[ attrDef.name ].remove();
}
else
{
if ( attrDef.name in paramMap )
paramMap[ attrDef.name ].setAttribute( 'value', value );
else
{
var param = CKEDITOR.dom.element.createFromHtml( '<cke:param></cke:param>', objectNode.getDocument() );
param.setAttributes( { name : attrDef.name, value : value } );
if ( objectNode.getChildCount() < 1 )
param.appendTo( objectNode );
else
param.insertBefore( objectNode.getFirst() );
}
}
break;
case ATTRTYPE_EMBED:
if ( !embedNode )
continue;
value = this.getValue();
if ( isRemove || isCheckbox && value === attrDef[ 'default' ])
embedNode.removeAttribute( attrDef.name );
else
embedNode.setAttribute( attrDef.name, value );
}
}
}
CKEDITOR.dialog.add( 'flash', function( editor )
{
var makeObjectTag = !editor.config.flashEmbedTagOnly,
makeEmbedTag = editor.config.flashAddEmbedTag || editor.config.flashEmbedTagOnly;
var previewAreaHtml = '<div>' + CKEDITOR.tools.htmlEncode( editor.lang.image.preview ) +'<br>' +
'<div id="FlashPreviewLoader" style="display:none"><div class="loading">&nbsp;</div></div>' +
'<div id="FlashPreviewBox"></div></div>';
return {
title : editor.lang.flash.title,
minWidth : 420,
minHeight : 310,
onShow : function()
{
// Clear previously saved elements.
this.fakeImage = this.objectNode = this.embedNode = null;
// Try to detect any embed or object tag that has Flash parameters.
var fakeImage = this.getSelectedElement();
if ( fakeImage && fakeImage.getAttribute( '_cke_real_element_type' ) && fakeImage.getAttribute( '_cke_real_element_type' ) == 'flash' )
{
this.fakeImage = fakeImage;
var realElement = editor.restoreRealElement( fakeImage ),
objectNode = null, embedNode = null, paramMap = {};
if ( realElement.getName() == 'cke:object' )
{
objectNode = realElement;
var embedList = objectNode.getElementsByTag( 'embed', 'cke' );
if ( embedList.count() > 0 )
embedNode = embedList.getItem( 0 );
var paramList = objectNode.getElementsByTag( 'param', 'cke' );
for ( var i = 0, length = paramList.count() ; i < length ; i++ )
{
var item = paramList.getItem( i ),
name = item.getAttribute( 'name' ),
value = item.getAttribute( 'value' );
paramMap[ name ] = value;
}
}
else if ( realElement.getName() == 'cke:embed' )
embedNode = realElement;
this.objectNode = objectNode;
this.embedNode = embedNode;
this.setupContent( objectNode, embedNode, paramMap, fakeImage );
}
},
onOk : function()
{
// If there's no selected object or embed, create one. Otherwise, reuse the
// selected object and embed nodes.
var objectNode = null,
embedNode = null,
paramMap = null;
if ( !this.fakeImage )
{
if ( makeObjectTag )
{
objectNode = CKEDITOR.dom.element.createFromHtml( '<cke:object></cke:object>', editor.document );
var attributes = {
classid : 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
codebase : 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0'
};
objectNode.setAttributes( attributes );
}
if ( makeEmbedTag )
{
embedNode = CKEDITOR.dom.element.createFromHtml( '<cke:embed></cke:embed>', editor.document );
embedNode.setAttributes(
{
type : 'application/x-shockwave-flash',
pluginspage : 'http://www.macromedia.com/go/getflashplayer'
} );
if ( objectNode )
embedNode.appendTo( objectNode );
}
}
else
{
objectNode = this.objectNode;
embedNode = this.embedNode;
}
// Produce the paramMap if there's an object tag.
if ( objectNode )
{
paramMap = {};
var paramList = objectNode.getElementsByTag( 'param', 'cke' );
for ( var i = 0, length = paramList.count() ; i < length ; i++ )
paramMap[ paramList.getItem( i ).getAttribute( 'name' ) ] = paramList.getItem( i );
}
// Apply or remove flash parameters.
var extraStyles = {};
this.commitContent( objectNode, embedNode, paramMap, extraStyles );
// Refresh the fake image.
var newFakeImage = editor.createFakeElement( objectNode || embedNode, 'cke_flash', 'flash', true );
newFakeImage.setStyles( extraStyles );
if ( this.fakeImage )
newFakeImage.replace( this.fakeImage );
else
editor.insertElement( newFakeImage );
},
onHide : function()
{
if ( this.preview )
this.preview.setHtml('');
},
contents : [
{
id : 'info',
label : editor.lang.common.generalTab,
accessKey : 'I',
elements :
[
{
type : 'vbox',
padding : 0,
children :
[
{
type : 'html',
html : '<span>' + CKEDITOR.tools.htmlEncode( editor.lang.image.url ) + '</span>'
},
{
type : 'hbox',
widths : [ '280px', '110px' ],
align : 'right',
children :
[
{
id : 'src',
type : 'text',
label : '',
validate : CKEDITOR.dialog.validate.notEmpty( editor.lang.flash.validateSrc ),
setup : loadValue,
commit : commitValue,
onLoad : function()
{
var dialog = this.getDialog(),
updatePreview = function( src ){
dialog.preview.setHtml( '<embed height="100%" width="100%" src="'
+ CKEDITOR.tools.htmlEncode( src )
+ '" type="application/x-shockwave-flash"></embed>' );
};
// Preview element
dialog.preview = dialog.getContentElement( 'info', 'preview' ).getElement().getChild( 3 );
// Sync on inital value loaded.
this.on( 'change', function( evt ){
if ( evt.data && evt.data.value )
updatePreview( evt.data.value );
} );
// Sync when input value changed.
this.getInputElement().on( 'change', function( evt ){
updatePreview( this.getValue() );
}, this );
}
},
{
type : 'button',
id : 'browse',
filebrowser : 'info:src',
hidden : true,
align : 'center',
label : editor.lang.common.browseServer
}
]
}
]
},
{
type : 'hbox',
widths : [ '25%', '25%', '25%', '25%', '25%' ],
children :
[
{
type : 'text',
id : 'width',
label : editor.lang.flash.width,
validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateWidth ),
setup : function( objectNode, embedNode, paramMap, fakeImage )
{
loadValue.apply( this, arguments );
if ( fakeImage )
{
var fakeImageWidth = parseInt( fakeImage.$.style.width, 10 );
if ( !isNaN( fakeImageWidth ) )
this.setValue( fakeImageWidth );
}
},
commit : function( objectNode, embedNode, paramMap, extraStyles )
{
commitValue.apply( this, arguments );
if ( this.getValue() )
extraStyles.width = this.getValue() + 'px';
}
},
{
type : 'text',
id : 'height',
label : editor.lang.flash.height,
validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateHeight ),
setup : function( objectNode, embedNode, paramMap, fakeImage )
{
loadValue.apply( this, arguments );
if ( fakeImage )
{
var fakeImageHeight = parseInt( fakeImage.$.style.height, 10 );
if ( !isNaN( fakeImageHeight ) )
this.setValue( fakeImageHeight );
}
},
commit : function( objectNode, embedNode, paramMap, extraStyles )
{
commitValue.apply( this, arguments );
if ( this.getValue() )
extraStyles.height = this.getValue() + 'px';
}
},
{
type : 'text',
id : 'hSpace',
label : editor.lang.flash.hSpace,
validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateHSpace ),
setup : loadValue,
commit : commitValue
},
{
type : 'text',
id : 'vSpace',
label : editor.lang.flash.vSpace,
validate : CKEDITOR.dialog.validate.integer( editor.lang.flash.validateVSpace ),
setup : loadValue,
commit : commitValue
}
]
},
{
type : 'vbox',
children :
[
{
type : 'html',
id : 'preview',
style : 'width:95%;',
html : previewAreaHtml
}
]
}
]
},
{
id : 'Upload',
hidden : true,
filebrowser : 'uploadButton',
label : editor.lang.common.upload,
elements :
[
{
type : 'file',
id : 'upload',
label : editor.lang.common.upload,
size : 38
},
{
type : 'fileButton',
id : 'uploadButton',
label : editor.lang.common.uploadSubmit,
filebrowser : 'info:src',
'for' : [ 'Upload', 'upload' ]
}
]
},
{
id : 'properties',
label : editor.lang.flash.propertiesTab,
elements :
[
{
type : 'hbox',
widths : [ '50%', '50%' ],
children :
[
{
id : 'scale',
type : 'select',
label : editor.lang.flash.scale,
'default' : '',
style : 'width : 100%;',
items :
[
[ editor.lang.common.notSet , ''],
[ editor.lang.flash.scaleAll, 'showall' ],
[ editor.lang.flash.scaleNoBorder, 'noborder' ],
[ editor.lang.flash.scaleFit, 'exactfit' ]
],
setup : loadValue,
commit : commitValue
},
{
id : 'allowScriptAccess',
type : 'select',
label : editor.lang.flash.access,
'default' : '',
style : 'width : 100%;',
items :
[
[ editor.lang.common.notSet , ''],
[ editor.lang.flash.accessAlways, 'always' ],
[ editor.lang.flash.accessSameDomain, 'samedomain' ],
[ editor.lang.flash.accessNever, 'never' ]
],
setup : loadValue,
commit : commitValue
}
]
},
{
type : 'hbox',
widths : [ '50%', '50%' ],
children :
[
{
id : 'wmode',
type : 'select',
label : editor.lang.flash.windowMode,
'default' : '',
style : 'width : 100%;',
items :
[
[ editor.lang.common.notSet , '' ],
[ editor.lang.flash.windowModeWindow, 'window' ],
[ editor.lang.flash.windowModeOpaque, 'opaque' ],
[ editor.lang.flash.windowModeTransparent, 'transparent' ]
],
setup : loadValue,
commit : commitValue
},
{
id : 'quality',
type : 'select',
label : editor.lang.flash.quality,
'default' : 'high',
style : 'width : 100%;',
items :
[
[ editor.lang.common.notSet , '' ],
[ editor.lang.flash.qualityBest, 'best' ],
[ editor.lang.flash.qualityHigh, 'high' ],
[ editor.lang.flash.qualityAutoHigh, 'autohigh' ],
[ editor.lang.flash.qualityMedium, 'medium' ],
[ editor.lang.flash.qualityAutoLow, 'autolow' ],
[ editor.lang.flash.qualityLow, 'low' ]
],
setup : loadValue,
commit : commitValue
}
]
},
{
type : 'hbox',
widths : [ '50%', '50%' ],
children :
[
{
id : 'align',
type : 'select',
label : editor.lang.flash.align,
'default' : '',
style : 'width : 100%;',
items :
[
[ editor.lang.common.notSet , ''],
[ editor.lang.image.alignLeft , 'left'],
[ editor.lang.image.alignAbsBottom , 'absBottom'],
[ editor.lang.image.alignAbsMiddle , 'absMiddle'],
[ editor.lang.image.alignBaseline , 'baseline'],
[ editor.lang.image.alignBottom , 'bottom'],
[ editor.lang.image.alignMiddle , 'middle'],
[ editor.lang.image.alignRight , 'right'],
[ editor.lang.image.alignTextTop , 'textTop'],
[ editor.lang.image.alignTop , 'top']
],
setup : loadValue,
commit : commitValue
},
{
type : 'html',
html : '<div></div>'
}
]
},
{
type : 'vbox',
padding : 0,
children :
[
{
type : 'html',
html : CKEDITOR.tools.htmlEncode( editor.lang.flash.flashvars )
},
{
type : 'checkbox',
id : 'menu',
label : editor.lang.flash.chkMenu,
'default' : true,
setup : loadValue,
commit : commitValue
},
{
type : 'checkbox',
id : 'play',
label : editor.lang.flash.chkPlay,
'default' : true,
setup : loadValue,
commit : commitValue
},
{
type : 'checkbox',
id : 'loop',
label : editor.lang.flash.chkLoop,
'default' : true,
setup : loadValue,
commit : commitValue
},
{
type : 'checkbox',
id : 'allowFullScreen',
label : editor.lang.flash.chkFull,
'default' : true,
setup : loadValue,
commit : commitValue
}
]
}
]
},
{
id : 'advanced',
label : editor.lang.common.advancedTab,
elements :
[
{
type : 'hbox',
widths : [ '45%', '55%' ],
children :
[
{
type : 'text',
id : 'id',
label : editor.lang.common.id,
setup : loadValue,
commit : commitValue
},
{
type : 'text',
id : 'title',
label : editor.lang.common.advisoryTitle,
setup : loadValue,
commit : commitValue
}
]
},
{
type : 'hbox',
widths : [ '45%', '55%' ],
children :
[
{
type : 'text',
id : 'bgcolor',
label : editor.lang.flash.bgcolor,
setup : loadValue,
commit : commitValue
},
{
type : 'text',
id : 'class',
label : editor.lang.common.cssClass,
setup : loadValue,
commit : commitValue
}
]
},
{
type : 'text',
id : 'style',
label : editor.lang.common.cssStyle,
setup : loadValue,
commit : commitValue
}
]
}
]
};
} );
})();
Binary file not shown.

After

Width:  |  Height:  |  Size: 256 B

@@ -0,0 +1,165 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
var flashFilenameRegex = /\.swf(?:$|\?)/i,
numberRegex = /^\d+(?:\.\d+)?$/;
function cssifyLength( length )
{
if ( numberRegex.test( length ) )
return length + 'px';
return length;
}
function isFlashEmbed( element )
{
var attributes = element.attributes;
return ( attributes.type != 'application/x-shockwave-flash' || !flashFilenameRegex.test( attributes.src || '' ) );
}
function createFakeElement( editor, realElement )
{
var fakeElement = editor.createFakeParserElement( realElement, 'cke_flash', 'flash', true ),
fakeStyle = fakeElement.attributes.style || '';
var width = realElement.attributes.width,
height = realElement.attributes.height;
if ( typeof width != 'undefined' )
fakeStyle = fakeElement.attributes.style = fakeStyle + 'width:' + cssifyLength( width ) + ';';
if ( typeof height != 'undefined' )
fakeStyle = fakeElement.attributes.style = fakeStyle + 'height:' + cssifyLength( height ) + ';';
return fakeElement;
}
CKEDITOR.plugins.add( 'flash',
{
init : function( editor )
{
editor.addCommand( 'flash', new CKEDITOR.dialogCommand( 'flash' ) );
editor.ui.addButton( 'Flash',
{
label : editor.lang.common.flash,
command : 'flash'
});
CKEDITOR.dialog.add( 'flash', this.path + 'dialogs/flash.js' );
editor.addCss(
'img.cke_flash' +
'{' +
'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/placeholder.png' ) + ');' +
'background-position: center center;' +
'background-repeat: no-repeat;' +
'border: 1px solid #a9a9a9;' +
'width: 80px;' +
'height: 80px;' +
'}'
);
// If the "menu" plugin is loaded, register the menu items.
if ( editor.addMenuItems )
{
editor.addMenuItems(
{
flash :
{
label : editor.lang.flash.properties,
command : 'flash',
group : 'flash'
}
});
}
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu )
{
editor.contextMenu.addListener( function( element, selection )
{
if ( element && element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'flash' )
return { flash : CKEDITOR.TRISTATE_OFF };
});
}
},
afterInit : function( editor )
{
var dataProcessor = editor.dataProcessor,
dataFilter = dataProcessor && dataProcessor.dataFilter;
if ( dataFilter )
{
dataFilter.addRules(
{
elements :
{
'cke:object' : function( element )
{
var attributes = element.attributes,
classId = attributes.classid && String( attributes.classid ).toLowerCase();
if ( !classId )
{
// Look for the inner <embed>
for ( var i = 0 ; i < element.children.length ; i++ )
{
if ( element.children[ i ].name == 'embed' )
{
if ( !isFlashEmbed( element.children[ i ] ) )
return null;
return createFakeElement( editor, element );
}
}
return null;
}
return createFakeElement( editor, element );
},
'cke:embed' : function( element )
{
if ( !isFlashEmbed( element ) )
return null;
return createFakeElement( editor, element );
}
}
},
5);
}
},
requires : [ 'fakeobjects' ]
});
})();
CKEDITOR.tools.extend( CKEDITOR.config,
{
/**
* Save as EMBED tag only. This tag is unrecommended.
* @type Boolean
* @default false
*/
flashEmbedTagOnly : false,
/**
* Add EMBED tag as alternative: &lt;object&gt&lt;embed&gt&lt;/embed&gt&lt;/object&gt
* @type Boolean
* @default false
*/
flashAddEmbedTag : true,
/**
* Use embedTagOnly and addEmbedTag values on edit.
* @type Boolean
* @default false
*/
flashConvertOnEdit : false
} );
@@ -0,0 +1,322 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'floatpanel',
{
requires : [ 'panel' ]
});
(function()
{
var panels = {};
var isShowing = false;
function getPanel( editor, doc, parentElement, definition, level )
{
// Generates the panel key: docId-eleId-skinName-langDir[-uiColor][-CSSs][-level]
var key =
doc.getUniqueId() +
'-' + parentElement.getUniqueId() +
'-' + editor.skinName +
'-' + editor.lang.dir +
( ( editor.uiColor && ( '-' + editor.uiColor ) ) || '' ) +
( ( definition.css && ( '-' + definition.css ) ) || '' ) +
( ( level && ( '-' + level ) ) || '' );
var panel = panels[ key ];
if ( !panel )
{
panel = panels[ key ] = new CKEDITOR.ui.panel( doc, definition );
panel.element = parentElement.append( CKEDITOR.dom.element.createFromHtml( panel.renderHtml( editor ), doc ) );
panel.element.setStyles(
{
display : 'none',
position : 'absolute'
});
}
return panel;
}
CKEDITOR.ui.floatPanel = CKEDITOR.tools.createClass(
{
$ : function( editor, parentElement, definition, level )
{
definition.forceIFrame = true;
var doc = parentElement.getDocument(),
panel = getPanel( editor, doc, parentElement, definition, level || 0 ),
element = panel.element,
iframe = element.getFirst().getFirst();
this.element = element;
this._ =
{
// The panel that will be floating.
panel : panel,
parentElement : parentElement,
definition : definition,
document : doc,
iframe : iframe,
children : [],
dir : editor.lang.dir
};
},
proto :
{
addBlock : function( name, block )
{
return this._.panel.addBlock( name, block );
},
addListBlock : function( name, multiSelect )
{
return this._.panel.addListBlock( name, multiSelect );
},
getBlock : function( name )
{
return this._.panel.getBlock( name );
},
/*
corner (LTR):
1 = top-left
2 = top-right
3 = bottom-right
4 = bottom-left
corner (RTL):
1 = top-right
2 = top-left
3 = bottom-left
4 = bottom-right
*/
showBlock : function( name, offsetParent, corner, offsetX, offsetY )
{
var panel = this._.panel,
block = panel.showBlock( name );
this.allowBlur( false );
isShowing = true;
var element = this.element,
iframe = this._.iframe,
definition = this._.definition,
position = offsetParent.getDocumentPosition( element.getDocument() ),
rtl = this._.dir == 'rtl';
var left = position.x + ( offsetX || 0 ),
top = position.y + ( offsetY || 0 );
if ( ( rtl && ( corner == 1 || corner == 4 ) ) || ( !rtl && ( corner == 2 || corner == 3 ) ) )
left += offsetParent.$.offsetWidth - 1;
if ( corner == 3 || corner == 4 )
top += offsetParent.$.offsetHeight - 1;
element.setStyles(
{
top : top + 'px',
left : '-3000px',
visibility : 'hidden',
opacity : '0', // FF3 is ignoring "visibility"
display : ''
});
// Configure the IFrame blur event. Do that only once.
if ( !this._.blurSet )
{
// Non IE prefer the event into a window object.
var focused = CKEDITOR.env.ie ? iframe : new CKEDITOR.dom.window( iframe.$.contentWindow );
// With addEventListener compatible browsers, we must
// useCapture when registering the focus/blur events to
// guarantee they will be firing in all situations. (#3068, #3222 )
CKEDITOR.event.useCapture = true;
focused.on( 'blur', function( ev )
{
if ( CKEDITOR.env.ie && !this.allowBlur() )
return;
// As we are using capture to register the listener,
// the blur event may get fired even when focusing
// inside the window itself, so we must ensure the
// target is out of it.
var target = ev.data.getTarget(),
targetWindow = target.getWindow && target.getWindow();
if ( targetWindow && targetWindow.equals( focused ) )
return;
if ( this.visible && !this._.activeChild && !isShowing )
this.hide();
},
this );
focused.on( 'focus', function()
{
this._.focused = true;
this.hideChild();
this.allowBlur( true );
},
this );
CKEDITOR.event.useCapture = false;
this._.blurSet = 1;
}
panel.onEscape = CKEDITOR.tools.bind( function()
{
this.onEscape && this.onEscape();
},
this );
setTimeout( function()
{
if ( rtl )
left -= element.$.offsetWidth;
element.setStyles(
{
left : left + 'px',
visibility : '',
opacity : '1' // FF3 is ignoring "visibility"
});
if ( block.autoSize )
{
function setHeight()
{
var target = element.getFirst();
var height = block.element.$.scrollHeight;
// Account for extra height needed due to IE quirks box model bug:
// http://en.wikipedia.org/wiki/Internet_Explorer_box_model_bug
// (#3426)
if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && height > 0 )
height += ( target.$.offsetHeight || 0 ) - ( target.$.clientHeight || 0 );
target.setStyle( 'height', height + 'px' );
// Fix IE < 8 visibility.
panel._.currentBlock.element.setStyle( 'display', 'none' ).removeStyle( 'display' );
}
if ( !CKEDITOR.env.gecko || panel.isLoaded )
{
// IE7 needs some time (setting the delay to 0ms won't work) to refresh
// the scrollHeight. (#3174)
if ( CKEDITOR.env.ie && CKEDITOR.env.version >= 7 )
setTimeout( setHeight, 50 );
else
setHeight();
}
else
panel.onLoad = setHeight;
}
else
element.getFirst().removeStyle( 'height' );
// Set the IFrame focus, so the blur event gets fired.
setTimeout( function()
{
if ( definition.voiceLabel )
{
if ( CKEDITOR.env.gecko )
{
var container = iframe.getParent();
container.setAttribute( 'role', 'region' );
container.setAttribute( 'title', definition.voiceLabel );
iframe.setAttribute( 'role', 'region' );
iframe.setAttribute( 'title', ' ' );
}
}
if ( CKEDITOR.env.ie && CKEDITOR.env.quirks )
iframe.focus();
else
iframe.$.contentWindow.focus();
}, 0);
}, 0);
this.visible = 1;
if ( this.onShow )
this.onShow.call( this );
isShowing = false;
},
hide : function()
{
if ( this.visible && ( !this.onHide || this.onHide.call( this ) !== true ) )
{
this.hideChild();
this.element.setStyle( 'display', 'none' );
this.visible = 0;
}
},
allowBlur : function( allow ) // Prevent editor from hiding the panel. #3222.
{
var panel = this._.panel;
if ( allow != undefined )
panel.allowBlur = allow;
return panel.allowBlur;
},
showAsChild : function( panel, blockName, offsetParent, corner, offsetX, offsetY )
{
this.hideChild();
panel.onHide = CKEDITOR.tools.bind( function()
{
// Use a timeout, so we give time for this menu to get
// potentially focused.
CKEDITOR.tools.setTimeout( function()
{
if ( !this._.focused )
this.hide();
},
0, this );
},
this );
this._.activeChild = panel;
this._.focused = false;
panel.showBlock( blockName, offsetParent, corner, offsetX, offsetY );
/* #3767 IE: Second level menu may not have borders */
if ( CKEDITOR.env.ie7Compat || ( CKEDITOR.env.ie8 && CKEDITOR.env.ie6Compat ) )
{
setTimeout(function()
{
panel.element.getChild( 0 ).$.style.cssText += '';
}, 100);
}
},
hideChild : function()
{
var activeChild = this._.activeChild;
if ( activeChild )
{
delete activeChild.onHide;
delete this._.activeChild;
activeChild.hide();
}
}
}
});
})();
@@ -0,0 +1,152 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
function addCombo( editor, comboName, styleType, lang, entries, defaultLabel, styleDefinition )
{
var config = editor.config;
// Gets the list of fonts from the settings.
var names = entries.split( ';' ),
values = [];
// Create style objects for all fonts.
var styles = {};
for ( var i = 0 ; i < names.length ; i++ )
{
var vars = {};
var parts = names[ i ].split( '/' );
var name = names[ i ] = parts[ 0 ];
vars[ styleType ] = values[ i ] = parts[ 1 ] || name;
styles[ name ] = new CKEDITOR.style( styleDefinition, vars );
}
editor.ui.addRichCombo( comboName,
{
label : lang.label,
title : lang.panelTitle,
voiceLabel : lang.voiceLabel,
className : 'cke_' + ( styleType == 'size' ? 'fontSize' : 'font' ),
multiSelect : false,
panel :
{
css : [ config.contentsCss, CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ],
voiceLabel : lang.panelVoiceLabel
},
init : function()
{
this.startGroup( lang.panelTitle );
for ( var i = 0 ; i < names.length ; i++ )
{
var name = names[ i ];
// Add the tag entry to the panel list.
this.add( name, '<span style="font-' + styleType + ':' + values[ i ] + '">' + name + '</span>', name );
}
},
onClick : function( value )
{
editor.focus();
editor.fire( 'saveSnapshot' );
var style = styles[ value ];
if ( this.getValue() == value )
style.remove( editor.document );
else
style.apply( editor.document );
editor.fire( 'saveSnapshot' );
},
onRender : function()
{
editor.on( 'selectionChange', function( ev )
{
var currentValue = this.getValue();
var elementPath = ev.data.path,
elements = elementPath.elements;
// For each element into the elements path.
for ( var i = 0, element ; i < elements.length ; i++ )
{
element = elements[i];
// Check if the element is removable by any of
// the styles.
for ( var value in styles )
{
if ( styles[ value ].checkElementRemovable( element, true ) )
{
if ( value != currentValue )
this.setValue( value );
return;
}
}
}
// If no styles match, just empty it.
this.setValue( '', defaultLabel );
},
this);
}
});
}
CKEDITOR.plugins.add( 'font',
{
requires : [ 'richcombo', 'styles' ],
init : function( editor )
{
var config = editor.config;
addCombo( editor, 'Font', 'family', editor.lang.font, config.font_names, config.font_defaultLabel, config.font_style );
addCombo( editor, 'FontSize', 'size', editor.lang.fontSize, config.fontSize_sizes, config.fontSize_defaultLabel, config.fontSize_style );
}
});
})();
// Font settings.
CKEDITOR.config.font_names =
'Arial/Arial, Helvetica, sans-serif;' +
'Comic Sans MS/Comic Sans MS, cursive;' +
'Courier New/Courier New, Courier, monospace;' +
'Georgia/Georgia, serif;' +
'Lucida Sans Unicode/Lucida Sans Unicode, Lucida Grande, sans-serif;' +
'Tahoma/Tahoma, Geneva, sans-serif;' +
'Times New Roman/Times New Roman, Times, serif;' +
'Trebuchet MS/Trebuchet MS, Helvetica, sans-serif;' +
'Verdana/Verdana, Geneva, sans-serif';
CKEDITOR.config.font_defaultLabel = '';
CKEDITOR.config.font_style =
{
element : 'span',
styles : { 'font-family' : '#(family)' },
overrides : [ { element : 'font', attributes : { 'face' : null } } ]
};
// Font Size setting.
CKEDITOR.config.fontSize_sizes =
'8/8px;9/9px;10/10px;11/11px;12/12px;14/14px;16/16px;18/18px;20/20px;22/22px;24/24px;26/26px;28/28px;36/36px;48/48px;72/72px';
CKEDITOR.config.fontSize_defaultLabel = '';
CKEDITOR.config.fontSize_style =
{
element : 'span',
styles : { 'font-size' : '#(size)' },
overrides : [ { element : 'font', attributes : { 'face' : null } } ]
};
@@ -0,0 +1,101 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'format',
{
requires : [ 'richcombo', 'styles' ],
init : function( editor )
{
var config = editor.config,
lang = editor.lang.format;
// Gets the list of tags from the settings.
var tags = config.format_tags.split( ';' );
// Create style objects for all defined styles.
var styles = {};
for ( var i = 0 ; i < tags.length ; i++ )
{
var tag = tags[ i ];
styles[ tag ] = new CKEDITOR.style( config[ 'format_' + tag ] );
}
editor.ui.addRichCombo( 'Format',
{
label : lang.label,
title : lang.panelTitle,
voiceLabel : lang.voiceLabel,
className : 'cke_format',
multiSelect : false,
panel :
{
css : [ config.contentsCss, CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ],
voiceLabel : lang.panelVoiceLabel
},
init : function()
{
this.startGroup( lang.panelTitle );
for ( var tag in styles )
{
var label = lang[ 'tag_' + tag ];
// Add the tag entry to the panel list.
this.add( tag, '<' + tag + '>' + label + '</' + tag + '>', label );
}
},
onClick : function( value )
{
editor.focus();
editor.fire( 'saveSnapshot' );
styles[ value ].apply( editor.document );
editor.fire( 'saveSnapshot' );
},
onRender : function()
{
editor.on( 'selectionChange', function( ev )
{
var currentTag = this.getValue();
var elementPath = ev.data.path;
for ( var tag in styles )
{
if ( styles[ tag ].checkActive( elementPath ) )
{
if ( tag != currentTag )
this.setValue( tag, editor.lang.format[ 'tag_' + tag ] );
return;
}
}
// If no styles match, just empty it.
this.setValue( '' );
},
this);
}
});
}
});
CKEDITOR.config.format_tags = 'p;h1;h2;h3;h4;h5;h6;pre;address;div';
CKEDITOR.config.format_p = { element : 'p' };
CKEDITOR.config.format_div = { element : 'div' };
CKEDITOR.config.format_pre = { element : 'pre' };
CKEDITOR.config.format_address = { element : 'address' };
CKEDITOR.config.format_h1 = { element : 'h1' };
CKEDITOR.config.format_h2 = { element : 'h2' };
CKEDITOR.config.format_h3 = { element : 'h3' };
CKEDITOR.config.format_h4 = { element : 'h4' };
CKEDITOR.config.format_h5 = { element : 'h5' };
CKEDITOR.config.format_h6 = { element : 'h6' };
@@ -0,0 +1,135 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'button', function( editor )
{
return {
title : editor.lang.button.title,
minWidth : 350,
minHeight : 150,
onShow : function()
{
delete this.button;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "input" )
{
var type = element.getAttribute( 'type' );
if ( type == "button" || type == "reset" || type == "submit" )
{
this.button = element;
this.setupContent( element );
}
}
},
onOk : function()
{
var editor,
element = this.button,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'input' );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( { element : element } );
},
contents : [
{
id : 'info',
label : editor.lang.button.title,
title : editor.lang.button.title,
elements : [
{
id : '_cke_saved_name',
type : 'text',
label : editor.lang.common.name,
'default' : '',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'value',
type : 'text',
label : editor.lang.button.text,
accessKey : 'V',
'default' : '',
setup : function( element )
{
this.setValue( element.getAttribute( 'value' ) || '' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( 'value', this.getValue() );
else
element.removeAttribute( 'value' );
}
},
{
id : 'type',
type : 'select',
label : editor.lang.button.type,
'default' : 'button',
accessKey : 'T',
items :
[
[ editor.lang.button.typeBtn, 'button' ],
[ editor.lang.button.typeSbm, 'submit' ],
[ editor.lang.button.typeRst, 'reset' ]
],
setup : function( element )
{
this.setValue( element.getAttribute( 'type' ) || '' );
},
commit : function( data )
{
var element = data.element;
if ( CKEDITOR.env.ie )
{
var elementType = element.getAttribute( 'type' );
var currentType = this.getValue();
if ( currentType != elementType )
{
var replace = CKEDITOR.dom.element.createFromHtml( '<input type="' + currentType +
'"></input>', editor.document );
element.copyAttributes( replace, { type : 1 } );
replace.replace( element );
editor.getSelection().selectElement( replace );
data.element = replace;
}
}
else
element.setAttribute( 'type', this.getValue() );
}
}
]
}
]
};
});
@@ -0,0 +1,138 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'checkbox', function( editor )
{
return {
title : editor.lang.checkboxAndRadio.checkboxTitle,
minWidth : 350,
minHeight : 140,
onShow : function()
{
delete this.checkbox;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getAttribute( 'type' ) == "checkbox" )
{
this.checkbox = element;
this.setupContent( element );
}
},
onOk : function()
{
var editor,
element = this.checkbox,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'input' );
element.setAttribute( 'type', 'checkbox' );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( { element : element } );
},
contents : [
{
id : 'info',
label : editor.lang.checkboxAndRadio.checkboxTitle,
title : editor.lang.checkboxAndRadio.checkboxTitle,
startupFocus : 'txtName',
elements : [
{
id : 'txtName',
type : 'text',
label : editor.lang.common.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( data )
{
var element = data.element;
// IE failed to update 'name' property on input elements, protect it now.
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'txtValue',
type : 'text',
label : editor.lang.checkboxAndRadio.value,
'default' : '',
accessKey : 'V',
setup : function( element )
{
this.setValue( element.getAttribute( 'value' ) || '' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( 'value', this.getValue() );
else
element.removeAttribute( 'value' );
}
},
{
id : 'cmbSelected',
type : 'checkbox',
label : editor.lang.checkboxAndRadio.selected,
'default' : '',
accessKey : 'S',
value : "checked",
setup : function( element )
{
this.setValue( element.getAttribute( 'checked' ) );
},
commit : function( data )
{
var element = data.element;
if ( CKEDITOR.env.ie )
{
var isElementChecked = !!element.getAttribute( 'checked' );
var isChecked = !!this.getValue();
if ( isElementChecked != isChecked )
{
var replace = CKEDITOR.dom.element.createFromHtml( '<input type="checkbox"'
+ ( isChecked ? ' checked="checked"' : '' )
+ '></input>', editor.document );
element.copyAttributes( replace, { type : 1, checked : 1 } );
replace.replace( element );
editor.getSelection().selectElement( replace );
data.element = replace;
}
}
else
{
if ( this.getValue() )
element.setAttribute( 'checked', this.getValue() );
else
element.removeAttribute( 'checked' );
}
}
}
]
}
]
};
});
@@ -0,0 +1,177 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'form', function( editor )
{
var autoAttributes =
{
action : 1,
id : 1,
method : 1,
encoding : 1,
target : 1
};
return {
title : editor.lang.form.title,
minWidth : 350,
minHeight : 200,
onShow : function()
{
delete this.form;
var element = this.getParentEditor().getSelection().getStartElement();
var form = element && element.getAscendant( 'form', true );
if ( form )
{
this.form = form;
this.setupContent( form );
}
},
onOk : function()
{
var editor,
element = this.form,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'form' );
element.append( editor.document.createElement( 'br' ) );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( element );
},
onLoad : function()
{
function autoSetup( element )
{
this.setValue( element.getAttribute( this.id ) || '' );
}
function autoCommit( element )
{
if ( this.getValue() )
element.setAttribute( this.id, this.getValue() );
else
element.removeAttribute( this.id );
}
this.foreach( function( contentObj )
{
if ( autoAttributes[ contentObj.id ] )
{
contentObj.setup = autoSetup;
contentObj.commit = autoCommit;
}
} );
},
contents : [
{
id : 'info',
label : editor.lang.form.title,
title : editor.lang.form.title,
elements : [
{
id : 'txtName',
type : 'text',
label : editor.lang.common.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue( element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'action',
type : 'text',
label : editor.lang.form.action,
'default' : '',
accessKey : 'A'
},
{
type : 'hbox',
widths : [ '45%', '55%' ],
children :
[
{
id : 'id',
type : 'text',
label : editor.lang.common.id,
'default' : '',
accessKey : 'I'
},
{
id : 'encoding',
type : 'select',
label : editor.lang.form.encoding,
style : 'width:100%',
accessKey : 'E',
'default' : '',
items :
[
[ '' ],
[ 'text/plain' ],
[ 'multipart/form-data' ],
[ 'application/x-www-form-urlencoded' ]
]
}
]
},
{
type : 'hbox',
widths : [ '45%', '55%' ],
children :
[
{
id : 'target',
type : 'select',
label : editor.lang.form.target,
style : 'width:100%',
accessKey : 'M',
'default' : '',
items :
[
[ editor.lang.form.targetNotSet, '' ],
[ editor.lang.form.targetNew, '_blank' ],
[ editor.lang.form.targetTop, '_top' ],
[ editor.lang.form.targetSelf, '_self' ],
[ editor.lang.form.targetParent, '_parent' ]
]
},
{
id : 'method',
type : 'select',
label : editor.lang.form.method,
accessKey : 'M',
'default' : 'GET',
items :
[
[ 'GET', 'get' ],
[ 'POST', 'post' ]
]
}
]
}
]
}
]
};
});
@@ -0,0 +1,91 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'hiddenfield', function( editor )
{
return {
title : editor.lang.hidden.title,
minWidth : 350,
minHeight : 110,
onShow : function()
{
delete this.hiddenField;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "input" && element.getAttribute( 'type' ) == "checkbox" )
{
this.hiddenField = element;
this.setupContent( element );
}
},
onOk : function()
{
var editor,
element = this.hiddenField,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'input' );
element.setAttribute( 'type', 'hidden' );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( element );
},
contents : [
{
id : 'info',
label : editor.lang.hidden.title,
title : editor.lang.hidden.title,
elements : [
{
id : '_cke_saved_name',
type : 'text',
label : editor.lang.hidden.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'value',
type : 'text',
label : editor.lang.hidden.value,
'default' : '',
accessKey : 'V',
setup : function( element )
{
this.setValue( element.getAttribute( 'value' ) || '' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( 'value', this.getValue() );
else
element.removeAttribute( 'value' );
}
}
]
}
]
};
});
@@ -0,0 +1,135 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'radio', function( editor )
{
return {
title : editor.lang.checkboxAndRadio.radioTitle,
minWidth : 350,
minHeight : 140,
onShow : function()
{
delete this.radioButton;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "input" && element.getAttribute( 'type' ) == "radio" )
{
this.radioButton = element;
this.setupContent( element );
}
},
onOk : function()
{
var editor,
element = this.radioButton,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'input' );
element.setAttribute( 'type', 'radio' );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( { element : element } );
},
contents : [
{
id : 'info',
label : editor.lang.checkboxAndRadio.radioTitle,
title : editor.lang.checkboxAndRadio.radioTitle,
elements : [
{
id : 'name',
type : 'text',
label : editor.lang.common.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'value',
type : 'text',
label : editor.lang.checkboxAndRadio.value,
'default' : '',
accessKey : 'V',
setup : function( element )
{
this.setValue( element.getAttribute( 'value' ) || '' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( 'value', this.getValue() );
else
element.removeAttribute( 'value' );
}
},
{
id : 'checked',
type : 'checkbox',
label : editor.lang.checkboxAndRadio.selected,
'default' : '',
accessKey : 'S',
value : "checked",
setup : function( element )
{
this.setValue( element.getAttribute( 'checked' ) );
},
commit : function( data )
{
var element = data.element;
if ( !CKEDITOR.env.ie )
{
if ( this.getValue() )
element.setAttribute( 'checked', 'checked' );
else
element.removeAttribute( 'checked' );
}
else
{
var isElementChecked = element.getAttribute( 'checked' );
var isChecked = !!this.getValue();
if ( isElementChecked != isChecked )
{
var replace = CKEDITOR.dom.element.createFromHtml( '<input type="radio"'
+ ( isChecked ? ' checked="checked"' : '' )
+ '></input>', editor.document );
element.copyAttributes( replace, { type : 1, checked : 1 } );
replace.replace( element );
editor.getSelection().selectElement( replace );
data.element = replace;
}
}
}
}
]
}
]
};
});
@@ -0,0 +1,541 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'select', function( editor )
{
// Add a new option to a SELECT object (combo or list).
function addOption( combo, optionText, optionValue, documentObject, index )
{
combo = getSelect( combo );
var oOption;
if ( documentObject )
oOption = documentObject.createElement( "OPTION" );
else
oOption = document.createElement( "OPTION" );
if ( combo && oOption && oOption.getName() == 'option' )
{
if ( CKEDITOR.env.ie ) {
if ( !isNaN( parseInt( index, 10) ) )
combo.$.options.add( oOption.$, index );
else
combo.$.options.add( oOption.$ );
oOption.$.innerHTML = optionText.length > 0 ? optionText : '';
oOption.$.value = optionValue;
}
else
{
if ( index !== null && index < combo.getChildCount() )
combo.getChild( index < 0 ? 0 : index ).insertBeforeMe( oOption );
else
combo.append( oOption );
oOption.setText( optionText.length > 0 ? optionText : '' );
oOption.setValue( optionValue );
}
}
else
return false;
return oOption;
}
// Remove all selected options from a SELECT object.
function removeSelectedOptions( combo )
{
combo = getSelect( combo );
// Save the selected index
var iSelectedIndex = getSelectedIndex( combo );
// Remove all selected options.
for ( var i = combo.getChildren().count() - 1 ; i >= 0 ; i-- )
{
if ( combo.getChild( i ).$.selected )
combo.getChild( i ).remove();
}
// Reset the selection based on the original selected index.
setSelectedIndex( combo, iSelectedIndex );
}
//Modify option from a SELECT object.
function modifyOption( combo, index, title, value )
{
combo = getSelect( combo );
if ( index < 0 )
return false;
var child = combo.getChild( index );
child.setText( title );
child.setValue( value );
return child;
}
function removeAllOptions( combo )
{
combo = getSelect( combo );
while( combo.getChild( 0 ) && combo.getChild( 0 ).remove() )
{ /*jsl:pass*/ }
}
// Moves the selected option by a number of steps (also negative).
function changeOptionPosition( combo, steps, documentObject )
{
combo = getSelect( combo );
var iActualIndex = getSelectedIndex( combo );
if ( iActualIndex < 0 )
return false;
var iFinalIndex = iActualIndex + steps;
iFinalIndex = ( iFinalIndex < 0 ) ? 0 : iFinalIndex;
iFinalIndex = ( iFinalIndex >= combo.getChildCount() ) ? combo.getChildCount() - 1 : iFinalIndex;
if ( iActualIndex == iFinalIndex )
return false;
var oOption = combo.getChild( iActualIndex ),
sText = oOption.getText(),
sValue = oOption.getValue();
oOption.remove();
oOption = addOption( combo, sText, sValue, ( !documentObject ) ? null : documentObject, iFinalIndex );
setSelectedIndex( combo, iFinalIndex );
return oOption;
}
function getSelectedIndex( combo )
{
combo = getSelect( combo );
return combo ? combo.$.selectedIndex : -1;
}
function setSelectedIndex( combo, index )
{
combo = getSelect( combo );
if ( index < 0 )
return null;
var count = combo.getChildren().count();
combo.$.selectedIndex = ( index >= count ) ? ( count - 1 ) : index;
return combo;
}
function getOptions( combo )
{
combo = getSelect( combo );
return combo ? combo.getChildren() : false;
}
function getSelect( obj )
{
if ( obj && obj.domId && obj.getInputElement().$ ) // Dialog element.
return obj.getInputElement();
else if ( obj && obj.$ )
return obj;
return false;
}
return {
title : editor.lang.select.title,
minWidth : CKEDITOR.env.ie ? 460 : 395,
minHeight : CKEDITOR.env.ie ? 320 : 300,
onShow : function()
{
delete this.selectBox;
this.setupContent( 'clear' );
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "select" )
{
this.selectBox = element;
this.setupContent( element.getName(), element );
// Load Options into dialog.
var objOptions = getOptions( element );
for ( var i = 0 ; i < objOptions.count() ; i++ )
this.setupContent( 'option', objOptions.getItem( i ) );
}
},
onOk : function()
{
var editor = this.getParentEditor(),
element = this.selectBox,
isInsertMode = !element;
if ( isInsertMode )
element = editor.document.createElement( 'select' );
this.commitContent( element );
if ( isInsertMode )
editor.insertElement( element );
},
contents : [
{
id : 'info',
label : editor.lang.select.selectInfo,
title : editor.lang.select.selectInfo,
accessKey : '',
elements : [
{
id : 'txtName',
type : 'text',
widths : [ '25%','75%' ],
labelLayout : 'horizontal',
label : editor.lang.common.name,
'default' : '',
accessKey : 'N',
align : 'center',
style : 'width:350px',
setup : function( name, element )
{
if ( name == 'clear' )
this.setValue( '' );
else if ( name == 'select' )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
}
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' ) ;
element.removeAttribute( 'name' );
}
}
},
{
id : 'txtValue',
type : 'text',
widths : [ '25%','75%' ],
labelLayout : 'horizontal',
label : editor.lang.select.value,
style : 'width:350px',
'default' : '',
className : 'cke_disabled',
onLoad : function()
{
this.getInputElement().setAttribute( 'readOnly', true );
},
setup : function( name, element )
{
if ( name == 'clear' )
this.setValue( '' );
else if ( name == 'option' && element.getAttribute( 'selected' ) )
this.setValue( element.$.value );
}
},
{
type : 'hbox',
widths : [ '175px', '170px' ],
align : 'center',
children :
[
{
id : 'txtSize',
type : 'text',
align : 'center',
labelLayout : 'horizontal',
label : editor.lang.select.size,
'default' : '',
accessKey : 'S',
style : 'width:175px',
validate: function()
{
var func = CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed );
return ( ( this.getValue() === '' ) || func.apply( this ) );
},
setup : function( name, element )
{
if ( name == 'select' )
this.setValue( element.getAttribute( 'size' ) || '' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( 'size', this.getValue() );
else
element.removeAttribute( 'size' );
}
},
{
type : 'html',
html : '<span>' + CKEDITOR.tools.htmlEncode( editor.lang.select.lines ) + '</span>'
}
]
},
{
type : 'html',
html : '<span>' + CKEDITOR.tools.htmlEncode( editor.lang.select.opAvail ) + '</span>'
},
{
type : 'hbox',
widths : [ '115px', '115px' ,'100px' ],
align : 'top',
children :
[
{
type : 'vbox',
children :
[
{
id : 'txtOptName',
type : 'text',
label : editor.lang.select.opText,
style : 'width:115px',
setup : function( name, element )
{
if ( name == 'clear' )
this.setValue( "" );
}
},
{
type : 'select',
id : 'cmbName',
label : '',
title : '',
size : 5,
style : 'width:115px;height:75px',
items : [],
onChange : function()
{
var dialog = this.getDialog(),
values = dialog.getContentElement( 'info', 'cmbValue' ),
optName = dialog.getContentElement( 'info', 'txtOptName' ),
optValue = dialog.getContentElement( 'info', 'txtOptValue' ),
iIndex = getSelectedIndex( this );
setSelectedIndex( values, iIndex );
optName.setValue( this.getValue() );
optValue.setValue( values.getValue() );
},
setup : function( name, element )
{
if ( name == 'clear' )
removeAllOptions( this );
else if ( name == 'option' )
addOption( this, element.getText(), element.getText(),
this.getDialog().getParentEditor().document );
},
commit : function( element )
{
var dialog = this.getDialog(),
optionsNames = getOptions( this ),
optionsValues = getOptions( dialog.getContentElement( 'info', 'cmbValue' ) ),
selectValue = dialog.getContentElement( 'info', 'txtValue' ).getValue();
removeAllOptions( element );
for ( var i = 0 ; i < optionsNames.count() ; i++ )
{
var oOption = addOption( element, optionsNames.getItem( i ).getValue(),
optionsValues.getItem( i ).getValue(), dialog.getParentEditor().document );
if ( optionsValues.getItem( i ).getValue() == selectValue )
{
oOption.setAttribute( 'selected', 'selected' );
oOption.selected = true;
}
}
}
}
]
},
{
type : 'vbox',
children :
[
{
id : 'txtOptValue',
type : 'text',
label : editor.lang.select.opValue,
style : 'width:115px',
setup : function( name, element )
{
if ( name == 'clear' )
this.setValue( "" );
}
},
{
type : 'select',
id : 'cmbValue',
label : '',
size : 5,
style : 'width:115px;height:75px',
items : [],
onChange : function()
{
var dialog = this.getDialog(),
names = dialog.getContentElement( 'info', 'cmbName' ),
optName = dialog.getContentElement( 'info', 'txtOptName' ),
optValue = dialog.getContentElement( 'info', 'txtOptValue' ),
iIndex = getSelectedIndex( this );
setSelectedIndex( names, iIndex );
optName.setValue( names.getValue() );
optValue.setValue( this.getValue() );
},
setup : function( name, element )
{
if ( name == 'clear' )
removeAllOptions( this );
else if ( name == 'option' )
{
var oValue = element.getValue();
addOption( this, oValue, oValue,
this.getDialog().getParentEditor().document );
if ( element.getAttribute( 'selected' ) == 'selected' )
this.getDialog().getContentElement( 'info', 'txtValue' ).setValue( oValue );
}
}
}
]
},
{
type : 'vbox',
padding : 5,
children :
[
{
type : 'button',
style : '',
label : editor.lang.select.btnAdd,
title : editor.lang.select.btnAdd,
style : 'width:100%;',
onClick : function()
{
//Add new option.
var dialog = this.getDialog(),
parentEditor = dialog.getParentEditor(),
optName = dialog.getContentElement( 'info', 'txtOptName' ),
optValue = dialog.getContentElement( 'info', 'txtOptValue' ),
names = dialog.getContentElement( 'info', 'cmbName' ),
values = dialog.getContentElement( 'info', 'cmbValue' );
addOption(names, optName.getValue(), optName.getValue(), dialog.getParentEditor().document );
addOption(values, optValue.getValue(), optValue.getValue(), dialog.getParentEditor().document );
optName.setValue( "" );
optValue.setValue( "" );
}
},
{
type : 'button',
label : editor.lang.select.btnModify,
title : editor.lang.select.btnModify,
style : 'width:100%;',
onClick : function()
{
//Modify selected option.
var dialog = this.getDialog(),
optName = dialog.getContentElement( 'info', 'txtOptName' ),
optValue = dialog.getContentElement( 'info', 'txtOptValue' ),
names = dialog.getContentElement( 'info', 'cmbName' ),
values = dialog.getContentElement( 'info', 'cmbValue' ),
iIndex = getSelectedIndex( names );
if ( iIndex >= 0 )
{
modifyOption( names, iIndex, optName.getValue(), optName.getValue() );
modifyOption( values, iIndex, optValue.getValue(), optValue.getValue() );
}
}
},
{
type : 'button',
style : 'width:100%;',
label : editor.lang.select.btnUp,
title : editor.lang.select.btnUp,
onClick : function()
{
//Move up.
var dialog = this.getDialog(),
names = dialog.getContentElement( 'info', 'cmbName' ),
values = dialog.getContentElement( 'info', 'cmbValue' );
changeOptionPosition( names, -1, dialog.getParentEditor().document );
changeOptionPosition( values, -1, dialog.getParentEditor().document );
}
},
{
type : 'button',
style : 'width:100%;',
label : editor.lang.select.btnDown,
title : editor.lang.select.btnDown,
onClick : function()
{
//Move down.
var dialog = this.getDialog(),
names = dialog.getContentElement( 'info', 'cmbName' ),
values = dialog.getContentElement( 'info', 'cmbValue' );
changeOptionPosition( names, 1, dialog.getParentEditor().document );
changeOptionPosition( values, 1, dialog.getParentEditor().document );
}
}
]
}
]
},
{
type : 'hbox',
widths : [ '40%', '20%', '40%' ],
children :
[
{
type : 'button',
label : editor.lang.select.btnSetValue,
title : editor.lang.select.btnSetValue,
onClick : function()
{
//Set as default value.
var dialog = this.getDialog(),
values = dialog.getContentElement( 'info', 'cmbValue' ),
txtValue = dialog.getContentElement( 'info', 'txtValue' );
txtValue.setValue( values.getValue() );
}
},
{
type : 'button',
label : editor.lang.select.btnDelete,
title : editor.lang.select.btnDelete,
onClick : function()
{
// Delete option.
var dialog = this.getDialog(),
names = dialog.getContentElement( 'info', 'cmbName' ),
values = dialog.getContentElement( 'info', 'cmbValue' ),
optName = dialog.getContentElement( 'info', 'txtOptName' ),
optValue = dialog.getContentElement( 'info', 'txtOptValue' );
removeSelectedOptions( names );
removeSelectedOptions( values );
optName.setValue( "" );
optValue.setValue( "" );
}
},
{
id : 'chkMulti',
type : 'checkbox',
label : editor.lang.select.chkMulti,
'default' : '',
accessKey : 'M',
value : "checked",
setup : function( name, element )
{
if ( name == 'select' )
this.setValue( element.getAttribute( 'multiple' ) );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( 'multiple', this.getValue() );
else
element.removeAttribute( 'multiple' );
}
}
]
}
]
}
]
};
});
@@ -0,0 +1,114 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'textarea', function( editor )
{
return {
title : editor.lang.textarea.title,
minWidth : 350,
minHeight : 150,
onShow : function()
{
delete this.textarea;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "textarea" )
{
this.textarea = element;
this.setupContent( element );
}
},
onOk : function()
{
var editor,
element = this.textarea,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'textarea' );
}
this.commitContent( element );
if ( isInsertMode )
editor.insertElement( element );
},
contents : [
{
id : 'info',
label : editor.lang.textarea.title,
title : editor.lang.textarea.title,
elements : [
{
id : '_cke_saved_name',
type : 'text',
label : editor.lang.common.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'cols',
type : 'text',
label : editor.lang.textarea.cols,
'default' : '',
accessKey : 'C',
style : 'width:50px',
validate : CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed ),
setup : function( element )
{
var value = element.hasAttribute( 'cols' ) && element.getAttribute( 'cols' );
this.setValue( value || '' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( 'cols', this.getValue() );
else
element.removeAttribute( 'cols' );
}
},
{
id : 'rows',
type : 'text',
label : editor.lang.textarea.rows,
'default' : '',
accessKey : 'R',
style : 'width:50px',
validate : CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed ),
setup : function( element )
{
var value = element.hasAttribute( 'rows' ) && element.getAttribute( 'rows' );
this.setValue( value || '' );
},
commit : function( element )
{
if ( this.getValue() )
element.setAttribute( 'rows', this.getValue() );
else
element.removeAttribute( 'rows' );
}
}
]
}
]
};
});
@@ -0,0 +1,193 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'textfield', function( editor )
{
var autoAttributes =
{
value : 1,
size : 1,
maxLength : 1
};
var acceptedTypes =
{
text : 1,
password : 1
};
return {
title : editor.lang.textfield.title,
minWidth : 350,
minHeight : 150,
onShow : function()
{
delete this.textField;
var element = this.getParentEditor().getSelection().getSelectedElement();
if ( element && element.getName() == "input" &&
( acceptedTypes[ element.getAttribute( 'type' ) ] || !element.getAttribute( 'type' ) ) )
{
this.textField = element;
this.setupContent( element );
}
},
onOk : function()
{
var editor,
element = this.textField,
isInsertMode = !element;
if ( isInsertMode )
{
editor = this.getParentEditor();
element = editor.document.createElement( 'input' );
element.setAttribute( 'type', 'text' );
}
if ( isInsertMode )
editor.insertElement( element );
this.commitContent( { element : element } );
},
onLoad : function()
{
var autoSetup = function( element )
{
var value = element.hasAttribute( this.id ) && element.getAttribute( this.id );
this.setValue( value || '' );
};
var autoCommit = function( data )
{
var element = data.element;
var value = this.getValue();
if ( value )
element.setAttribute( this.id, value );
else
element.removeAttribute( this.id );
};
this.foreach( function( contentObj )
{
if ( autoAttributes[ contentObj.id ] )
{
contentObj.setup = autoSetup;
contentObj.commit = autoCommit;
}
} );
},
contents : [
{
id : 'info',
label : editor.lang.textfield.title,
title : editor.lang.textfield.title,
elements : [
{
type : 'hbox',
widths : [ '50%', '50%' ],
children :
[
{
id : '_cke_saved_name',
type : 'text',
label : editor.lang.textfield.name,
'default' : '',
accessKey : 'N',
setup : function( element )
{
this.setValue(
element.getAttribute( '_cke_saved_name' ) ||
element.getAttribute( 'name' ) ||
'' );
},
commit : function( data )
{
var element = data.element;
if ( this.getValue() )
element.setAttribute( '_cke_saved_name', this.getValue() );
else
{
element.removeAttribute( '_cke_saved_name' );
element.removeAttribute( 'name' );
}
}
},
{
id : 'value',
type : 'text',
label : editor.lang.textfield.value,
'default' : '',
accessKey : 'V'
}
]
},
{
type : 'hbox',
widths : [ '50%', '50%' ],
children :
[
{
id : 'size',
type : 'text',
label : editor.lang.textfield.charWidth,
'default' : '',
accessKey : 'C',
style : 'width:50px',
validate : CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed )
},
{
id : 'maxLength',
type : 'text',
label : editor.lang.textfield.maxChars,
'default' : '',
accessKey : 'M',
style : 'width:50px',
validate : CKEDITOR.dialog.validate.integer( editor.lang.common.validateNumberFailed )
}
]
},
{
id : 'type',
type : 'select',
label : editor.lang.textfield.type,
'default' : 'text',
accessKey : 'M',
items :
[
[ editor.lang.textfield.typeText, 'text' ],
[ editor.lang.textfield.typePass, 'password' ]
],
setup : function( element )
{
this.setValue( element.getAttribute( 'type' ) );
},
commit : function( data )
{
var element = data.element;
if ( CKEDITOR.env.ie )
{
var elementType = element.getAttribute( 'type' );
var myType = this.getValue();
if ( elementType != myType )
{
var replace = CKEDITOR.dom.element.createFromHtml( '<input type="' + myType + '"></input>', editor.document );
element.copyAttributes( replace, { type : 1 } );
replace.replace( element );
editor.getSelection().selectElement( replace );
data.element = element;
}
}
else
element.setAttribute( 'type', this.getValue() );
}
}
]
}
]
};
});
@@ -0,0 +1,193 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Forms Plugin
*/
CKEDITOR.plugins.add( 'forms',
{
init : function( editor )
{
var lang = editor.lang;
editor.addCss(
'form' +
'{' +
'border: 1px dotted #FF0000;' +
'padding: 2px;' +
'}' );
// All buttons use the same code to register. So, to avoid
// duplications, let's use this tool function.
var addButtonCommand = function( buttonName, commandName, dialogFile )
{
editor.addCommand( commandName, new CKEDITOR.dialogCommand( commandName ) );
editor.ui.addButton( buttonName,
{
label : lang.common[ buttonName.charAt(0).toLowerCase() + buttonName.slice(1) ],
command : commandName
});
CKEDITOR.dialog.add( commandName, dialogFile );
};
var dialogPath = this.path + 'dialogs/';
addButtonCommand( 'Form', 'form', dialogPath + 'form.js' );
addButtonCommand( 'Checkbox', 'checkbox', dialogPath + 'checkbox.js' );
addButtonCommand( 'Radio', 'radio', dialogPath + 'radio.js' );
addButtonCommand( 'TextField', 'textfield', dialogPath + 'textfield.js' );
addButtonCommand( 'Textarea', 'textarea', dialogPath + 'textarea.js' );
addButtonCommand( 'Select', 'select', dialogPath + 'select.js' );
addButtonCommand( 'Button', 'button', dialogPath + 'button.js' );
addButtonCommand( 'ImageButton', 'imagebutton', CKEDITOR.plugins.getPath('image') + 'dialogs/image.js' );
addButtonCommand( 'HiddenField', 'hiddenfield', dialogPath + 'hiddenfield.js' );
// If the "menu" plugin is loaded, register the menu items.
if ( editor.addMenuItems )
{
editor.addMenuItems(
{
form :
{
label : lang.form.menu,
command : 'form',
group : 'form'
},
checkbox :
{
label : lang.checkboxAndRadio.checkboxTitle,
command : 'checkbox',
group : 'checkbox'
},
radio :
{
label : lang.checkboxAndRadio.radioTitle,
command : 'radio',
group : 'radio'
},
textfield :
{
label : lang.textfield.title,
command : 'textfield',
group : 'textfield'
},
hiddenfield :
{
label : lang.hidden.title,
command : 'hiddenfield',
group : 'hiddenfield'
},
imagebutton :
{
label : lang.image.titleButton,
command : 'imagebutton',
group : 'imagebutton'
},
button :
{
label : lang.button.title,
command : 'button',
group : 'button'
},
select :
{
label : lang.select.title,
command : 'select',
group : 'select'
},
textarea :
{
label : lang.textarea.title,
command : 'textarea',
group : 'textarea'
}
});
}
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu )
{
editor.contextMenu.addListener( function( element )
{
if ( element && element.hasAscendant( 'form' ) )
return { form : CKEDITOR.TRISTATE_OFF };
});
editor.contextMenu.addListener( function( element )
{
if ( element )
{
var name = element.getName();
if ( name == 'select' )
return { select : CKEDITOR.TRISTATE_OFF };
if ( name == 'textarea' )
return { textarea : CKEDITOR.TRISTATE_OFF };
if ( name == 'input' )
{
var type = element.getAttribute( 'type' );
if ( type == 'text' || type == 'password' )
return { textfield : CKEDITOR.TRISTATE_OFF };
if ( type == 'button' || type == 'submit' || type == 'reset' )
return { button : CKEDITOR.TRISTATE_OFF };
if ( type == 'checkbox' )
return { checkbox : CKEDITOR.TRISTATE_OFF };
if ( type == 'radio' )
return { radio : CKEDITOR.TRISTATE_OFF };
if ( type == 'image' )
return { imagebutton : CKEDITOR.TRISTATE_OFF };
}
if ( name == 'img' && element.getAttribute( '_cke_real_element_type' ) == 'hiddenfield' )
return { hiddenfield : CKEDITOR.TRISTATE_OFF };
}
});
}
},
requires : [ 'image' ]
} );
if ( CKEDITOR.env.ie )
{
CKEDITOR.dom.element.prototype.hasAttribute = function( name )
{
var $attr = this.$.attributes.getNamedItem( name );
if ( this.getName() == 'input' )
{
switch ( name )
{
case 'class' :
return this.$.className.length > 0;
case 'checked' :
return !!this.$.checked;
case 'value' :
var type = this.getAttribute( 'type' );
if ( type == 'checkbox' || type == 'radio' )
return this.$.value != 'on';
break;
default:
}
}
return !!( $attr && $attr.specified );
};
}
@@ -0,0 +1,35 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Horizontal Rule plugin.
*/
(function()
{
var horizontalruleCmd =
{
exec : function( editor )
{
editor.insertElement( editor.document.createElement( 'hr' ) );
}
};
var pluginName = 'horizontalrule';
// Register a plugin named "horizontalrule".
CKEDITOR.plugins.add( pluginName,
{
init : function( editor )
{
editor.addCommand( pluginName, horizontalruleCmd );
editor.ui.addButton( 'HorizontalRule',
{
label : editor.lang.horizontalrule,
command : pluginName
});
}
});
})();
@@ -0,0 +1,334 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
// Regex to scan for &nbsp; at the end of blocks, which are actually placeholders.
var tailNbspRegex = /^[\t\r\n ]*&nbsp;$/;
var protectedSourceMarker = '{cke_protected}';
function trimFillers( block, fromSource )
{
// If the current node is a block, and if we're converting from source or
// we're not in IE then search for and remove any tailing BR node.
//
// Also, any &nbsp; at the end of blocks are fillers, remove them as well.
// (#2886)
var children = block.children;
var lastChild = children[ children.length - 1 ];
if ( lastChild )
{
if ( ( fromSource || !CKEDITOR.env.ie ) && lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br' )
children.pop();
if ( lastChild.type == CKEDITOR.NODE_TEXT && tailNbspRegex.test( lastChild.value ) )
children.pop();
}
}
function blockNeedsExtension( block )
{
if ( block.children.length < 1 )
return true;
var lastChild = block.children[ block.children.length - 1 ];
return lastChild.type == CKEDITOR.NODE_ELEMENT && lastChild.name == 'br';
}
function extendBlockForDisplay( block )
{
trimFillers( block, true );
if ( blockNeedsExtension( block ) )
{
if ( CKEDITOR.env.ie )
block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
else
block.add( new CKEDITOR.htmlParser.element( 'br', {} ) );
}
}
function extendBlockForOutput( block )
{
trimFillers( block );
if ( blockNeedsExtension( block ) )
block.add( new CKEDITOR.htmlParser.text( '\xa0' ) );
}
var dtd = CKEDITOR.dtd;
// Find out the list of block-like tags that can contain <br>.
var blockLikeTags = CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent );
for ( var i in blockLikeTags )
{
if ( ! ( 'br' in dtd[i] ) )
delete blockLikeTags[i];
}
// We just avoid filler in <pre> right now.
// TODO: Support filler for <pre>, line break is also occupy line height.
delete blockLikeTags.pre;
var defaultDataFilterRules =
{
elementNames :
[
// Elements that cause problems in wysiwyg mode.
[ ( /^(object|embed|param)$/ ), 'cke:$1' ]
],
attributeNames :
[
// Event attributes (onXYZ) must not be directly set. They can become
// active in the editing area (IE|WebKit).
[ ( /^on/ ), '_cke_pa_on' ]
]
};
var defaultDataBlockFilterRules = { elements : {} };
for ( i in blockLikeTags )
defaultDataBlockFilterRules.elements[ i ] = extendBlockForDisplay;
/**
* IE sucks with dynamic 'name' attribute after element is created, '_cke_saved_name' is used instead for this attribute.
*/
var removeName = function( element )
{
var attribs = element.attributes;
if ( attribs._cke_saved_name )
delete attribs.name;
};
var defaultHtmlFilterRules =
{
elementNames :
[
// Remove the "cke:" namespace prefix.
[ ( /^cke:/ ), '' ],
// Ignore <?xml:namespace> tags.
[ ( /^\?xml:namespace$/ ), '' ]
],
attributeNames :
[
// Attributes saved for changes and protected attributes.
[ ( /^_cke_(saved|pa)_/ ), '' ],
// All "_cke" attributes are to be ignored.
[ ( /^_cke.*/ ), '' ]
],
elements :
{
embed : function( element )
{
var parent = element.parent;
// If the <embed> is child of a <object>, copy the width
// and height attributes from it.
if ( parent && parent.name == 'object' )
{
element.attributes.width = parent.attributes.width;
element.attributes.height = parent.attributes.height;
}
},
img : function( element )
{
var attribs = element.attributes;
if ( attribs._cke_saved_name )
delete attribs.name;
if ( attribs._cke_saved_src )
delete attribs.src;
},
a : function( element )
{
var attribs = element.attributes;
if ( attribs._cke_saved_name )
delete attribs.name;
if ( attribs._cke_saved_href )
delete attribs.href;
},
input : removeName,
textarea : removeName,
select : removeName,
form : removeName
},
attributes :
{
'class' : function( value, element )
{
// Remove all class names starting with "cke_".
return CKEDITOR.tools.ltrim( value.replace( /(?:^|\s+)cke_[^\s]*/g, '' ) ) || false;
}
},
comment : function( contents )
{
if ( contents.substr( 0, protectedSourceMarker.length ) == protectedSourceMarker )
return new CKEDITOR.htmlParser.cdata( decodeURIComponent( contents.substr( protectedSourceMarker.length ) ) );
return contents;
}
};
var defaultHtmlBlockFilterRules = { elements : {} };
for ( i in blockLikeTags )
defaultHtmlBlockFilterRules.elements[ i ] = extendBlockForOutput;
if ( CKEDITOR.env.ie )
{
// IE outputs style attribute in capital letters. We should convert
// them back to lower case.
defaultHtmlFilterRules.attributes.style = function( value, element )
{
return value.toLowerCase();
};
}
var protectAttributeRegex = /<(?:a|area|img|input).*?\s((?:href|src|name)\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|(?:[^ "'>]+)))/gi;
function protectAttributes( html )
{
return html.replace( protectAttributeRegex, '$& _cke_saved_$1' );
}
var protectStyleTagsRegex = /<(style)(?=[ >])[^>]*>[^<]*<\/\1>/gi;
var encodedTagsRegex = /<cke:encoded>([^<]*)<\/cke:encoded>/gi;
function protectStyleTagsMatch( match )
{
return '<cke:encoded>' + encodeURIComponent( match ) + '</cke:encoded>';
}
function protectStyleTags( html )
{
return html.replace( protectStyleTagsRegex, protectStyleTagsMatch );
}
function unprotectEncodedTagsMatch( match, encoded )
{
return decodeURIComponent( encoded );
}
function unprotectEncodedTags( html )
{
return html.replace( encodedTagsRegex, unprotectEncodedTagsMatch );
}
function protectSource( data, protectRegexes )
{
var regexes =
[
// 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
]
.concat( protectRegexes );
for ( var i = 0 ; i < regexes.length ; i++ )
{
data = data.replace( regexes[i], function( match )
{
return '<!--' + protectedSourceMarker + encodeURIComponent( match ).replace( /--/g, '%2D%2D' ) + '-->';
});
}
return data;
}
CKEDITOR.plugins.add( 'htmldataprocessor',
{
requires : [ 'htmlwriter' ],
init : function( editor )
{
var dataProcessor = editor.dataProcessor = new CKEDITOR.htmlDataProcessor( editor );
dataProcessor.writer.forceSimpleAmpersand = editor.config.forceSimpleAmpersand;
dataProcessor.dataFilter.addRules( defaultDataFilterRules );
dataProcessor.dataFilter.addRules( defaultDataBlockFilterRules );
dataProcessor.htmlFilter.addRules( defaultHtmlFilterRules );
dataProcessor.htmlFilter.addRules( defaultHtmlBlockFilterRules );
}
});
CKEDITOR.htmlDataProcessor = function( editor )
{
this.editor = editor;
this.writer = new CKEDITOR.htmlWriter();
this.dataFilter = new CKEDITOR.htmlParser.filter();
this.htmlFilter = new CKEDITOR.htmlParser.filter();
};
CKEDITOR.htmlDataProcessor.prototype =
{
toHtml : function( data, fixForBody )
{
// The source data is already HTML, but we need to clean
// it up and apply the filter.
data = protectSource( data, this.editor.config.protectedSource );
// Before anything, we must protect the URL attributes as the
// browser may changing them when setting the innerHTML later in
// the code.
data = protectAttributes( data );
// IE remvoes style tags from innerHTML. (#3710).
if ( CKEDITOR.env.ie )
data = protectStyleTags( data );
// Call the browser to help us fixing a possibly invalid HTML
// structure.
var div = document.createElement( 'div' );
div.innerHTML = data;
data = div.innerHTML;
if ( CKEDITOR.env.ie )
data = unprotectEncodedTags( data );
// Now use our parser to make further fixes to the structure, as
// well as apply the filter.
var fragment = CKEDITOR.htmlParser.fragment.fromHtml( data, fixForBody ),
writer = new CKEDITOR.htmlParser.basicWriter();
fragment.writeHtml( writer, this.dataFilter );
return writer.getHtml( true );
},
toDataFormat : function( html, fixForBody )
{
var writer = this.writer,
fragment = CKEDITOR.htmlParser.fragment.fromHtml( html, fixForBody );
writer.reset();
fragment.writeHtml( writer, this.htmlFilter );
return writer.getHtml( true );
}
};
})();
CKEDITOR.config.forceSimpleAmpersand = false;
@@ -0,0 +1,289 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'htmlwriter' );
/**
* Class used to write HTML data.
* @constructor
* @example
* var writer = new CKEDITOR.htmlWriter();
* writer.openTag( 'p' );
* writer.attribute( 'class', 'MyClass' );
* writer.openTagClose( 'p' );
* writer.text( 'Hello' );
* writer.closeTag( 'p' );
* alert( writer.getHtml() ); "&lt;p class="MyClass"&gt;Hello&lt;/p&gt;"
*/
CKEDITOR.htmlWriter = CKEDITOR.tools.createClass(
{
base : CKEDITOR.htmlParser.basicWriter,
$ : function()
{
// Call the base contructor.
this.base();
/**
* The characters to be used for each identation step.
* @type String
* @default "\t" (tab)
* @example
* // Use two spaces for indentation.
* editorInstance.dataProcessor.writer.indentationChars = ' ';
*/
this.indentationChars = '\t';
/**
* The characters to be used to close "self-closing" elements, like "br" or
* "img".
* @type String
* @default " /&gt;"
* @example
* // Use HTML4 notation for self-closing elements.
* editorInstance.dataProcessor.writer.selfClosingEnd = '>';
*/
this.selfClosingEnd = ' />';
/**
* The characters to be used for line breaks.
* @type String
* @default "\n" (LF)
* @example
* // Use CRLF for line breaks.
* editorInstance.dataProcessor.writer.lineBreakChars = '\r\n';
*/
this.lineBreakChars = '\n';
this.forceSimpleAmpersand = false;
this.sortAttributes = true;
this._.indent = false;
this._.indentation = '';
this._.rules = {};
var dtd = CKEDITOR.dtd;
for ( var e in CKEDITOR.tools.extend( {}, dtd.$block, dtd.$listItem, dtd.$tableContent ) )
{
this.setRules( e,
{
indent : true,
breakBeforeOpen : true,
breakAfterOpen : true,
breakBeforeClose : !dtd[ e ][ '#' ],
breakAfterClose : true
});
}
this.setRules( 'br',
{
breakAfterOpen : true
});
// Disable indentation on <pre>.
this.setRules( 'pre',
{
indent: false
} );
},
proto :
{
/**
* Writes the tag opening part for a opener tag.
* @param {String} tagName The element name for this tag.
* @param {Object} attributes The attributes defined for this tag. The
* attributes could be used to inspect the tag.
* @example
* // Writes "&lt;p".
* writer.openTag( 'p', { class : 'MyClass', id : 'MyId' } );
*/
openTag : function( tagName, attributes )
{
var rules = this._.rules[ tagName ];
if ( this._.indent )
this.indentation();
// Do not break if indenting.
else if ( rules && rules.breakBeforeOpen )
{
this.lineBreak();
this.indentation();
}
this._.output.push( '<', tagName );
},
/**
* Writes the tag closing part for a opener tag.
* @param {String} tagName The element name for this tag.
* @param {Boolean} isSelfClose Indicates that this is a self-closing tag,
* like "br" or "img".
* @example
* // Writes "&gt;".
* writer.openTagClose( 'p', false );
* @example
* // Writes " /&gt;".
* writer.openTagClose( 'br', true );
*/
openTagClose : function( tagName, isSelfClose )
{
var rules = this._.rules[ tagName ];
if ( isSelfClose )
this._.output.push( this.selfClosingEnd );
else
{
this._.output.push( '>' );
if ( rules && rules.indent )
this._.indentation += this.indentationChars;
}
if ( rules && rules.breakAfterOpen )
this.lineBreak();
},
/**
* Writes an attribute. This function should be called after opening the
* tag with {@link #openTagClose}.
* @param {String} attName The attribute name.
* @param {String} attValue The attribute value.
* @example
* // Writes ' class="MyClass"'.
* writer.attribute( 'class', 'MyClass' );
*/
attribute : function( attName, attValue )
{
if ( this.forceSimpleAmpersand )
attValue = attValue.replace( /&amp;/, '&' );
this._.output.push( ' ', attName, '="', attValue, '"' );
},
/**
* Writes a closer tag.
* @param {String} tagName The element name for this tag.
* @example
* // Writes "&lt;/p&gt;".
* writer.closeTag( 'p' );
*/
closeTag : function( tagName )
{
var rules = this._.rules[ tagName ];
if ( rules && rules.indent )
this._.indentation = this._.indentation.substr( this.indentationChars.length );
if ( this._.indent )
this.indentation();
// Do not break if indenting.
else if ( rules && rules.breakBeforeClose )
{
this.lineBreak();
this.indentation();
}
this._.output.push( '</', tagName, '>' );
if ( rules && rules.breakAfterClose )
this.lineBreak();
},
/**
* Writes text.
* @param {String} text The text value
* @example
* // Writes "Hello Word".
* writer.text( 'Hello Word' );
*/
text : function( text )
{
if ( this._.indent )
{
this.indentation();
text = CKEDITOR.tools.ltrim( text );
}
this._.output.push( text );
},
/**
* Writes a comment.
* @param {String} comment The comment text.
* @example
* // Writes "&lt;!-- My comment --&gt;".
* writer.comment( ' My comment ' );
*/
comment : function( comment )
{
if ( this._.indent )
this.indentation();
this._.output.push( '<!--', comment, '-->' );
},
/**
* Writes a line break. It uses the {@link #lineBreakChars} property for it.
* @example
* // Writes "\n" (e.g.).
* writer.lineBreak();
*/
lineBreak : function()
{
if ( this._.output.length > 0 )
this._.output.push( this.lineBreakChars );
this._.indent = true;
},
/**
* Writes the current indentation chars. It uses the
* {@link #indentationChars} property, repeating it for the current
* indentation steps.
* @example
* // Writes "\t" (e.g.).
* writer.indentation();
*/
indentation : function()
{
this._.output.push( this._.indentation );
this._.indent = false;
},
/**
* Sets formatting rules for a give element. The possible rules are:
* <ul>
* <li><b>indent</b>: indent the element contents.</li>
* <li><b>breakBeforeOpen</b>: break line before the opener tag for this element.</li>
* <li><b>breakAfterOpen</b>: break line after the opener tag for this element.</li>
* <li><b>breakBeforeClose</b>: break line before the closer tag for this element.</li>
* <li><b>breakAfterClose</b>: break line after the closer tag for this element.</li>
* </ul>
*
* All rules default to "false".
*
* By default, all elements available in the {@link CKEDITOR.dtd.$block),
* {@link CKEDITOR.dtd.$listItem} and {@link CKEDITOR.dtd.$tableContent}
* lists have all the above rules set to "true". Additionaly, the "br"
* element has the "breakAfterOpen" set to "true".
* @param {String} tagName The element name to which set the rules.
* @param {Object} rules An object containing the element rules.
* @example
* // Break line before and after "img" tags.
* writer.setRules( 'img',
* {
* breakBeforeOpen : true
* breakAfterOpen : true
* });
* @example
* // Reset the rules for the "h1" tag.
* writer.setRules( 'h1', {} );
*/
setRules : function( tagName, rules )
{
this._.rules[ tagName ] = rules;
}
}
});
@@ -0,0 +1,136 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview Plugin for making iframe based dialogs.
*/
CKEDITOR.plugins.add( 'iframedialog',
{
requires : [ 'dialog' ],
onLoad : function()
{
CKEDITOR.dialog.addIframe = function( name, title, src, width, height, onContentLoad )
{
var element =
{
type : 'iframe',
src : src,
width : '100%',
height : '100%'
};
if ( typeof( onContentLoad ) == 'function' )
element.onContentLoad = onContentLoad;
var definition =
{
title : title,
minWidth : width,
minHeight : height,
contents :
[
{
id : 'iframe',
label : title,
expand : true,
elements : [ element ]
}
]
};
return this.add( name, function(){ return definition; } );
};
(function()
{
/**
* An iframe element.
* @extends CKEDITOR.ui.dialog.uiElement
* @example
* @constructor
* @param {CKEDITOR.dialog} dialog
* Parent dialog object.
* @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition
* The element definition. Accepted fields:
* <ul>
* <li><strong>src</strong> (Required) The src field of the iframe. </li>
* <li><strong>width</strong> (Required) The iframe's width.</li>
* <li><strong>height</strong> (Required) The iframe's height.</li>
* <li><strong>onContentLoad</strong> (Optional) A function to be executed
* after the iframe's contents has finished loading.</li>
* </ul>
* @param {Array} htmlList
* List of HTML code to output to.
*/
var iframeElement = function( dialog, elementDefinition, htmlList )
{
if ( arguments.length < 3 )
return;
var _ = ( this._ || ( this._ = {} ) ),
contentLoad = elementDefinition.onContentLoad && CKEDITOR.tools.bind( elementDefinition.onContentLoad, this ),
cssWidth = CKEDITOR.tools.cssLength( elementDefinition.width ),
cssHeight = CKEDITOR.tools.cssLength( elementDefinition.height );
_.frameId = CKEDITOR.tools.getNextNumber() + '_iframe';
// IE BUG: Parent container does not resize to contain the iframe automatically.
dialog.on( 'load', function()
{
var iframe = CKEDITOR.document.getById( _.frameId ),
parentContainer = iframe.getParent();
parentContainer.setStyles(
{
width : cssWidth,
height : cssHeight
} );
} );
var attributes =
{
src : '%2',
id : _.frameId,
frameborder : 0,
allowtransparency : true
};
var myHtml = [];
if ( typeof( elementDefinition.onContentLoad ) == 'function' )
attributes.onload = 'CKEDITOR.tools.callFunction(%1);';
CKEDITOR.ui.dialog.uiElement.call( this, dialog, elementDefinition, myHtml, 'iframe',
{
width : cssWidth,
height : cssHeight
}, attributes, '' );
// Put a placeholder for the first time.
htmlList.push( '<div style="width:' + cssWidth + ';height:' + cssHeight + ';" id="' + this.domId + '"></div>' );
// Iframe elements should be refreshed whenever it is shown.
myHtml = myHtml.join( '' );
dialog.on( 'show', function()
{
var iframe = CKEDITOR.document.getById( _.frameId ),
parentContainer = iframe.getParent(),
callIndex = CKEDITOR.tools.addFunction( contentLoad ),
html = myHtml.replace( '%1', callIndex ).replace( '%2', CKEDITOR.tools.htmlEncode( elementDefinition.src ) );
parentContainer.setHtml( html );
} );
};
iframeElement.prototype = new CKEDITOR.ui.dialog.uiElement;
CKEDITOR.dialog.addUIElement( 'iframe',
{
build : function( dialog, elementDefinition, output )
{
return new iframeElement( dialog, elementDefinition, output );
}
} );
})();
}
} );
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,57 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Image plugin
*/
CKEDITOR.plugins.add( 'image',
{
init : function( editor )
{
var pluginName = 'image';
// Register the dialog.
CKEDITOR.dialog.add( pluginName, this.path + 'dialogs/image.js' );
// Register the command.
editor.addCommand( pluginName, new CKEDITOR.dialogCommand( pluginName ) );
// Register the toolbar button.
editor.ui.addButton( 'Image',
{
label : editor.lang.common.image,
command : pluginName
});
// If the "menu" plugin is loaded, register the menu items.
if ( editor.addMenuItems )
{
editor.addMenuItems(
{
image :
{
label : editor.lang.image.menu,
command : 'image',
group : 'image'
}
});
}
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu )
{
editor.contextMenu.addListener( function( element, selection )
{
if ( !element || !element.is( 'img' ) || element.getAttribute( '_cke_realelement' ) )
return null;
return { image : CKEDITOR.TRISTATE_OFF };
});
}
}
} );
CKEDITOR.config.image_removeLinkByEmptyURL = true;
@@ -0,0 +1,281 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Increse and decrease indent commands.
*/
(function()
{
var listNodeNames = { ol : 1, ul : 1 };
function setState( editor, state )
{
editor.getCommand( this.name ).setState( state );
}
function onSelectionChange( evt )
{
var elements = evt.data.path.elements,
listNode, listItem,
editor = evt.editor;
for ( var i = 0 ; i < elements.length ; i++ )
{
if ( elements[i].getName() == 'li' )
{
listItem = elements[i];
continue;
}
if ( listNodeNames[ elements[i].getName() ] )
{
listNode = elements[i];
break;
}
}
if ( listNode )
{
if ( this.name == 'outdent' )
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
else
{
while ( listItem && ( listItem = listItem.getPrevious() ) )
{
if ( listItem.getName && listItem.getName() == 'li' )
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
}
return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
}
}
if ( !this.useIndentClasses && this.name == 'indent' )
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
var path = evt.data.path,
firstBlock = path.block || path.blockLimit;
if ( !firstBlock )
return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
if ( this.useIndentClasses )
{
var indentClass = firstBlock.$.className.match( this.classNameRegex ),
indentStep = 0;
if ( indentClass )
{
indentClass = indentClass[1];
indentStep = this.indentClassMap[ indentClass ];
}
if ( ( this.name == 'outdent' && !indentStep ) ||
( this.name == 'indent' && indentStep == editor.config.indentClass.length ) )
return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
}
else
{
var indent = parseInt( firstBlock.getStyle( this.indentCssProperty ), 10 );
if ( isNaN( indent ) )
indent = 0;
if ( indent <= 0 )
return setState.call( this, editor, CKEDITOR.TRISTATE_DISABLED );
return setState.call( this, editor, CKEDITOR.TRISTATE_OFF );
}
}
function indentList( editor, range, listNode )
{
// Our starting and ending points of the range might be inside some blocks under a list item...
// So before playing with the iterator, we need to expand the block to include the list items.
var startContainer = range.startContainer,
endContainer = range.endContainer;
while ( startContainer && !startContainer.getParent().equals( listNode ) )
startContainer = startContainer.getParent();
while ( endContainer && !endContainer.getParent().equals( listNode ) )
endContainer = endContainer.getParent();
if ( !startContainer || !endContainer )
return;
// Now we can iterate over the individual items on the same tree depth.
var block = startContainer,
itemsToMove = [],
stopFlag = false;
while ( !stopFlag )
{
if ( block.equals( endContainer ) )
stopFlag = true;
itemsToMove.push( block );
block = block.getNext();
}
if ( itemsToMove.length < 1 )
return;
// Do indent or outdent operations on the array model of the list, not the
// list's DOM tree itself. The array model demands that it knows as much as
// possible about the surrounding lists, we need to feed it the further
// ancestor node that is still a list.
var listParents = listNode.getParents();
for ( var i = 0 ; i < listParents.length ; i++ )
{
if ( listParents[i].getName && listNodeNames[ listParents[i].getName() ] )
{
listNode = listParents[i];
break;
}
}
var indentOffset = this.name == 'indent' ? 1 : -1,
startItem = itemsToMove[0],
lastItem = itemsToMove[ itemsToMove.length - 1 ],
database = {};
// Convert the list DOM tree into a one dimensional array.
var listArray = CKEDITOR.plugins.list.listToArray( listNode, database );
// Apply indenting or outdenting on the array.
var baseIndent = listArray[ lastItem.getCustomData( 'listarray_index' ) ].indent;
for ( i = startItem.getCustomData( 'listarray_index' ) ; i <= lastItem.getCustomData( 'listarray_index' ) ; i++ )
listArray[i].indent += indentOffset;
for ( i = lastItem.getCustomData( 'listarray_index' ) + 1 ;
i < listArray.length && listArray[i].indent > baseIndent ; i++ )
listArray[i].indent += indentOffset;
// Convert the array back to a DOM forest (yes we might have a few subtrees now).
// And replace the old list with the new forest.
var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode, 0 );
if ( newList )
newList.listNode.replace( listNode );
// Clean up the markers.
CKEDITOR.dom.element.clearAllMarkers( database );
}
function indentBlock( editor, range )
{
var iterator = range.createIterator();
iterator.enforceRealBlocks = true;
var block;
while ( ( block = iterator.getNextParagraph() ) )
{
if ( this.useIndentClasses )
{
// Transform current class name to indent step index.
var indentClass = block.$.className.match( this.classNameRegex ),
indentStep = 0;
if ( indentClass )
{
indentClass = indentClass[1];
indentStep = this.indentClassMap[ indentClass ];
}
// Operate on indent step index, transform indent step index back to class
// name.
if ( this.name == 'outdent' )
indentStep--;
else
indentStep++;
indentStep = Math.min( indentStep, editor.config.indentClasses.length );
indentStep = Math.max( indentStep, 0 );
var className = CKEDITOR.tools.ltrim( block.$.className.replace( this.classNameRegex, '' ) );
if ( indentStep < 1 )
block.$.className = className;
else
block.addClass( editor.config.indentClasses[ indentStep - 1 ] );
}
else
{
var currentOffset = parseInt( block.getStyle( this.indentCssProperty ), 10 );
if ( isNaN( currentOffset ) )
currentOffset = 0;
currentOffset += ( this.name == 'indent' ? 1 : -1 ) * editor.config.indentOffset;
currentOffset = Math.max( currentOffset, 0 );
currentOffset = Math.ceil( currentOffset / editor.config.indentOffset ) * editor.config.indentOffset;
block.setStyle( this.indentCssProperty, currentOffset ? currentOffset + editor.config.indentUnit : '' );
if ( block.getAttribute( 'style' ) === '' )
block.removeAttribute( 'style' );
}
}
}
function indentCommand( editor, name )
{
this.name = name;
this.useIndentClasses = editor.config.indentClasses && editor.config.indentClasses.length > 0;
if ( this.useIndentClasses )
{
this.classNameRegex = new RegExp( '(?:^|\\s+)(' + editor.config.indentClasses.join( '|' ) + ')(?=$|\\s)' );
this.indentClassMap = {};
for ( var i = 0 ; i < editor.config.indentClasses.length ; i++ )
this.indentClassMap[ editor.config.indentClasses[i] ] = i + 1;
}
else
this.indentCssProperty = editor.config.contentsLangDirection == 'ltr' ? 'margin-left' : 'margin-right';
}
indentCommand.prototype = {
exec : function( editor )
{
var selection = editor.getSelection(),
range = selection && selection.getRanges()[0];
if ( !selection || !range )
return;
var bookmarks = selection.createBookmarks( true ),
nearestListBlock = range.getCommonAncestor();
while ( nearestListBlock && !( nearestListBlock.type == CKEDITOR.NODE_ELEMENT &&
listNodeNames[ nearestListBlock.getName() ] ) )
nearestListBlock = nearestListBlock.getParent();
if ( nearestListBlock )
indentList.call( this, editor, range, nearestListBlock );
else
indentBlock.call( this, editor, range );
editor.focus();
editor.forceNextSelectionCheck();
selection.selectBookmarks( bookmarks );
}
};
CKEDITOR.plugins.add( 'indent',
{
init : function( editor )
{
// Register commands.
var indent = new indentCommand( editor, 'indent' ),
outdent = new indentCommand( editor, 'outdent' );
editor.addCommand( 'indent', indent );
editor.addCommand( 'outdent', outdent );
// Register the toolbar buttons.
editor.ui.addButton( 'Indent',
{
label : editor.lang.indent,
command : 'indent'
});
editor.ui.addButton( 'Outdent',
{
label : editor.lang.outdent,
command : 'outdent'
});
// Register the state changing handlers.
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, indent ) );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, outdent ) );
},
requires : [ 'domiterator', 'list' ]
} );
})();
CKEDITOR.tools.extend( CKEDITOR.config,
{
indentOffset : 40,
indentUnit : 'px',
indentClasses : null
});
@@ -0,0 +1,164 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Justify commands.
*/
(function()
{
var alignRemoveRegex = /(-moz-|-webkit-|start|auto)/i;
function getState( editor, path )
{
var firstBlock = path.block || path.blockLimit;
if ( !firstBlock || firstBlock.getName() == 'body' )
return CKEDITOR.TRISTATE_OFF;
var currentAlign = firstBlock.getComputedStyle( 'text-align' ).replace( alignRemoveRegex, '' );
if ( ( !currentAlign && this.isDefaultAlign ) || currentAlign == this.value )
return CKEDITOR.TRISTATE_ON;
return CKEDITOR.TRISTATE_OFF;
}
function onSelectionChange( evt )
{
var command = evt.editor.getCommand( this.name );
command.state = getState.call( this, evt.editor, evt.data.path );
command.fire( 'state' );
}
function justifyCommand( editor, name, value )
{
this.name = name;
this.value = value;
var contentDir = editor.config.contentsLangDirection;
this.isDefaultAlign = ( value == 'left' && contentDir == 'ltr' ) ||
( value == 'right' && contentDir == 'rtl' );
var classes = editor.config.justifyClasses;
if ( classes )
{
switch ( value )
{
case 'left' :
this.cssClassName = classes[0];
break;
case 'center' :
this.cssClassName = classes[1];
break;
case 'right' :
this.cssClassName = classes[2];
break;
case 'justify' :
this.cssClassName = classes[3];
break;
}
this.cssClassRegex = new RegExp( '(?:^|\\s+)(?:' + classes.join( '|' ) + ')(?=$|\\s)' );
}
}
justifyCommand.prototype = {
exec : function( editor )
{
var selection = editor.getSelection();
if ( !selection )
return;
var bookmarks = selection.createBookmarks(),
ranges = selection.getRanges();
var cssClassName = this.cssClassName,
iterator,
block;
for ( var i = ranges.length - 1 ; i >= 0 ; i-- )
{
iterator = ranges[ i ].createIterator();
while ( ( block = iterator.getNextParagraph() ) )
{
block.removeAttribute( 'align' );
if ( cssClassName )
{
// Remove any of the alignment classes from the className.
var className = block.$.className =
CKEDITOR.tools.ltrim( block.$.className.replace( this.cssClassRegex, '' ) );
// Append the desired class name.
if ( this.state == CKEDITOR.TRISTATE_OFF && !this.isDefaultAlign )
block.addClass( cssClassName );
else if ( !className )
block.removeAttribute( 'class' );
}
else
{
if ( this.state == CKEDITOR.TRISTATE_OFF && !this.isDefaultAlign )
block.setStyle( 'text-align', this.value );
else
block.removeStyle( 'text-align' );
}
}
}
editor.focus();
editor.forceNextSelectionCheck();
selection.selectBookmarks( bookmarks );
}
};
CKEDITOR.plugins.add( 'justify',
{
init : function( editor )
{
var left = new justifyCommand( editor, 'justifyleft', 'left' ),
center = new justifyCommand( editor, 'justifycenter', 'center' ),
right = new justifyCommand( editor, 'justifyright', 'right' ),
justify = new justifyCommand( editor, 'justifyblock', 'justify' );
editor.addCommand( 'justifyleft', left );
editor.addCommand( 'justifycenter', center );
editor.addCommand( 'justifyright', right );
editor.addCommand( 'justifyblock', justify );
editor.ui.addButton( 'JustifyLeft',
{
label : editor.lang.justify.left,
command : 'justifyleft'
} );
editor.ui.addButton( 'JustifyCenter',
{
label : editor.lang.justify.center,
command : 'justifycenter'
} );
editor.ui.addButton( 'JustifyRight',
{
label : editor.lang.justify.right,
command : 'justifyright'
} );
editor.ui.addButton( 'JustifyBlock',
{
label : editor.lang.justify.block,
command : 'justifyblock'
} );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, left ) );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, right ) );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, center ) );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, justify ) );
},
requires : [ 'domiterator' ]
});
})();
CKEDITOR.tools.extend( CKEDITOR.config,
{
justifyClasses : null
} );
@@ -0,0 +1,188 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
// Register a plugin named "sample".
CKEDITOR.plugins.add( 'keystrokes',
{
beforeInit : function( editor )
{
/**
* Controls keystrokes typing in this editor instance.
* @name CKEDITOR.editor.prototype.keystrokeHandler
* @type CKEDITOR.keystrokeHandler
* @example
*/
editor.keystrokeHandler = new CKEDITOR.keystrokeHandler( editor );
editor.specialKeys = {};
},
init : function( editor )
{
var keystrokesConfig = editor.config.keystrokes,
blockedConfig = editor.config.blockedKeystrokes;
var keystrokes = editor.keystrokeHandler.keystrokes,
blockedKeystrokes = editor.keystrokeHandler.blockedKeystrokes;
for ( var i = 0 ; i < keystrokesConfig.length ; i++ )
{
keystrokes[ keystrokesConfig[i][0] ] = keystrokesConfig[i][1];
}
for ( i = 0 ; i < blockedConfig.length ; i++ )
{
blockedKeystrokes[ blockedConfig[i] ] = 1;
}
}
});
/**
* Controls keystrokes typing in an editor instance.
* @constructor
* @param {CKEDITOR.editor} editor The editor instance.
* @example
*/
CKEDITOR.keystrokeHandler = function( editor )
{
if ( editor.keystrokeHandler )
return editor.keystrokeHandler;
/**
* List of keystrokes associated to commands. Each entry points to the
* command to be executed.
* @type Object
* @example
*/
this.keystrokes = {};
/**
* List of keystrokes that should be blocked if not defined at
* {@link keystrokes}. In this way it is possible to block the default
* browser behavior for those keystrokes.
* @type Object
* @example
*/
this.blockedKeystrokes = {};
this._ =
{
editor : editor
};
return this;
};
(function()
{
var cancel;
var onKeyDown = function( event )
{
// The DOM event object is passed by the "data" property.
event = event.data;
var keyCombination = event.getKeystroke();
var command = this.keystrokes[ keyCombination ];
var editor = this._.editor;
cancel = ( editor.fire( 'key', { keyCode : keyCombination } ) === true );
if ( !cancel )
{
if ( command )
{
var data = { from : 'keystrokeHandler' };
cancel = ( editor.execCommand( command, data ) !== false );
}
if ( !cancel )
{
var handler = editor.specialKeys[ keyCombination ];
cancel = ( handler && handler( editor ) === true );
if ( !cancel )
cancel = !!this.blockedKeystrokes[ keyCombination ];
}
}
if ( cancel )
event.preventDefault( true );
return !cancel;
};
var onKeyPress = function( event )
{
if ( cancel )
{
cancel = false;
event.data.preventDefault( true );
}
};
CKEDITOR.keystrokeHandler.prototype =
{
/**
* Attaches this keystroke handle to a DOM object. Keystrokes typed
** over this object will get handled by this keystrokeHandler.
* @param {CKEDITOR.dom.domObject} domObject The DOM object to attach
* to.
* @example
*/
attach : function( domObject )
{
// For most browsers, it is enough to listen to the keydown event
// only.
domObject.on( 'keydown', onKeyDown, this );
// Some browsers instead, don't cancel key events in the keydown, but in the
// keypress. So we must do a longer trip in those cases.
if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
domObject.on( 'keypress', onKeyPress, this );
}
};
})();
/**
* A list of keystrokes to be blocked if not defined in the {@link #keystrokes}
* setting. In this way it is possible to block the default browser behavior
* for those keystrokes.
* @type Array
* @example
*/
CKEDITOR.config.blockedKeystrokes =
[
CKEDITOR.CTRL + 66 /*B*/,
CKEDITOR.CTRL + 73 /*I*/,
CKEDITOR.CTRL + 85 /*U*/
];
/**
* A list associating keystrokes to editor commands. Each element in the list
* is an array where the first item is the keystroke, and the second is the
* command to be executed.
* @type Array
* @example
*/
CKEDITOR.config.keystrokes =
[
[ CKEDITOR.ALT + 121 /*F10*/, 'toolbarFocus' ],
[ CKEDITOR.ALT + 122 /*F11*/, 'elementsPathFocus' ],
[ CKEDITOR.SHIFT + 121 /*F10*/, 'contextMenu' ],
[ CKEDITOR.CTRL + 90 /*Z*/, 'undo' ],
[ CKEDITOR.CTRL + 89 /*Y*/, 'redo' ],
[ CKEDITOR.CTRL + CKEDITOR.SHIFT + 90 /*Z*/, 'redo' ],
[ CKEDITOR.CTRL + 76 /*L*/, 'link' ],
[ CKEDITOR.CTRL + 66 /*B*/, 'bold' ],
[ CKEDITOR.CTRL + 73 /*I*/, 'italic' ],
[ CKEDITOR.CTRL + 85 /*U*/, 'underline' ],
[ CKEDITOR.ALT + 109 /*-*/, 'toolbarCollapse' ]
];
@@ -0,0 +1,98 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'anchor', function( editor )
{
// Function called in onShow to load selected element.
var loadElements = function( editor, selection, element )
{
this.editMode = true;
this.editObj = element;
var attributeValue = this.editObj.getAttribute( 'name' );
if ( attributeValue )
this.setValueOf( 'info','txtName', attributeValue );
else
this.setValueOf( 'info','txtName', "" );
};
return {
title : editor.lang.anchor.title,
minWidth : 300,
minHeight : 60,
onOk : function()
{
// Always create a new anchor, because of IE BUG.
var name = this.getValueOf( 'info', 'txtName' ),
element = CKEDITOR.env.ie ?
editor.document.createElement( '<a name="' + CKEDITOR.tools.htmlEncode( name ) + '">' ) :
editor.document.createElement( 'a' );
// Move contents and attributes of old anchor to new anchor.
if ( this.editMode )
{
this.editObj.copyAttributes( element, { name : 1 } );
this.editObj.moveChildren( element );
}
// Set name.
element.removeAttribute( '_cke_saved_name' );
element.setAttribute( 'name', name );
// Insert a new anchor.
var fakeElement = editor.createFakeElement( element, 'cke_anchor', 'anchor' );
if ( !this.editMode )
editor.insertElement( fakeElement );
else
{
fakeElement.replace( this.fakeObj );
editor.getSelection().selectElement( fakeElement );
}
return true;
},
onShow : function()
{
this.editObj = false;
this.fakeObj = false;
this.editMode = false;
var selection = editor.getSelection();
var element = selection.getSelectedElement();
if ( element && element.getAttribute( '_cke_real_element_type' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' )
{
this.fakeObj = element;
element = editor.restoreRealElement( this.fakeObj );
loadElements.apply( this, [ editor, selection, element ] );
selection.selectElement( this.fakeObj );
}
this.getContentElement( 'info', 'txtName' ).focus();
},
contents : [
{
id : 'info',
label : editor.lang.anchor.title,
accessKey : 'I',
elements :
[
{
type : 'text',
id : 'txtName',
label : editor.lang.anchor.name,
validate : function()
{
if ( !this.getValue() )
{
alert( editor.lang.anchor.errorName );
return false;
}
return true;
}
}
]
}
]
};
} );
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

@@ -0,0 +1,188 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'link',
{
init : function( editor )
{
// Add the link and unlink buttons.
editor.addCommand( 'link', new CKEDITOR.dialogCommand( 'link' ) );
editor.addCommand( 'anchor', new CKEDITOR.dialogCommand( 'anchor' ) );
editor.addCommand( 'unlink', new CKEDITOR.unlinkCommand() );
editor.ui.addButton( 'Link',
{
label : editor.lang.link.toolbar,
command : 'link'
} );
editor.ui.addButton( 'Unlink',
{
label : editor.lang.unlink,
command : 'unlink'
} );
editor.ui.addButton( 'Anchor',
{
label : editor.lang.anchor.toolbar,
command : 'anchor'
} );
CKEDITOR.dialog.add( 'link', this.path + 'dialogs/link.js' );
CKEDITOR.dialog.add( 'anchor', this.path + 'dialogs/anchor.js' );
// Add the CSS styles for anchor placeholders.
editor.addCss(
'img.cke_anchor' +
'{' +
'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +
'background-position: center center;' +
'background-repeat: no-repeat;' +
'border: 1px solid #a9a9a9;' +
'width: 18px;' +
'height: 18px;' +
'}\n' +
'a.cke_anchor' +
'{' +
'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/anchor.gif' ) + ');' +
'background-position: 0 center;' +
'background-repeat: no-repeat;' +
'border: 1px solid #a9a9a9;' +
'padding-left: 18px;' +
'}'
);
// Register selection change handler for the unlink button.
editor.on( 'selectionChange', function( evt )
{
/*
* Despite our initial hope, document.queryCommandEnabled() does not work
* for this in Firefox. So we must detect the state by element paths.
*/
var command = editor.getCommand( 'unlink' ),
element = evt.data.path.lastElement.getAscendant( 'a', true );
if ( element && element.getName() == 'a' && element.getAttribute( 'href' ) )
command.setState( CKEDITOR.TRISTATE_OFF );
else
command.setState( CKEDITOR.TRISTATE_DISABLED );
} );
// If the "menu" plugin is loaded, register the menu items.
if ( editor.addMenuItems )
{
editor.addMenuItems(
{
anchor :
{
label : editor.lang.anchor.menu,
command : 'anchor',
group : 'anchor'
},
link :
{
label : editor.lang.link.menu,
command : 'link',
group : 'link',
order : 1
},
unlink :
{
label : editor.lang.unlink,
command : 'unlink',
group : 'link',
order : 5
}
});
}
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu )
{
editor.contextMenu.addListener( function( element, selection )
{
if ( !element )
return null;
var isAnchor = ( element.is( 'img' ) && element.getAttribute( '_cke_real_element_type' ) == 'anchor' );
if ( !isAnchor )
{
if ( !( element = element.getAscendant( 'a', true ) ) )
return null;
isAnchor = ( element.getAttribute( 'name' ) && !element.getAttribute( 'href' ) );
}
return isAnchor ?
{ anchor : CKEDITOR.TRISTATE_OFF } :
{ link : CKEDITOR.TRISTATE_OFF, unlink : CKEDITOR.TRISTATE_OFF };
});
}
},
afterInit : function( editor )
{
// Register a filter to displaying placeholders after mode change.
var dataProcessor = editor.dataProcessor,
dataFilter = dataProcessor && dataProcessor.dataFilter;
if ( dataFilter )
{
dataFilter.addRules(
{
elements :
{
a : function( element )
{
var attributes = element.attributes;
if ( attributes.name && !attributes.href )
return editor.createFakeParserElement( element, 'cke_anchor', 'anchor' );
}
}
});
}
},
requires : [ 'fakeobjects' ]
} );
CKEDITOR.unlinkCommand = function(){};
CKEDITOR.unlinkCommand.prototype =
{
/** @ignore */
exec : function( editor )
{
/*
* execCommand( 'unlink', ... ) in Firefox leaves behind <span> tags at where
* the <a> was, so again we have to remove the link ourselves. (See #430)
*
* TODO: Use the style system when it's complete. Let's use execCommand()
* as a stopgap solution for now.
*/
var selection = editor.getSelection(),
bookmarks = selection.createBookmarks(),
ranges = selection.getRanges(),
rangeRoot,
element;
for ( var i = 0 ; i < ranges.length ; i++ )
{
rangeRoot = ranges[i].getCommonAncestor( true );
element = rangeRoot.getAscendant( 'a', true );
if ( !element )
continue;
ranges[i].selectNodeContents( element );
}
selection.selectRanges( ranges );
editor.document.$.execCommand( 'unlink', false, null );
selection.selectBookmarks( bookmarks );
}
};
CKEDITOR.tools.extend( CKEDITOR.config,
{
linkShowAdvancedTab : true,
linkShowTargetTab : true
} );
@@ -0,0 +1,536 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Insert and remove numbered and bulleted lists.
*/
(function()
{
var listNodeNames = { ol : 1, ul : 1 },
emptyTextRegex = /^[\n\r\t ]*$/;
CKEDITOR.plugins.list = {
/*
* 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 database is specified.
*/
listToArray : function( listNode, database, baseArray, baseIndentLevel, grandparentNode )
{
if ( !listNodeNames[ listNode.getName() ] )
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, count = listNode.getChildCount() ; i < count ; i++ )
{
var listItem = listNode.getChild( i );
// It may be a text node or some funny stuff.
if ( listItem.$.nodeName.toLowerCase() != 'li' )
continue;
var itemObj = { 'parent' : listNode, indent : baseIndentLevel, contents : [] };
if ( !grandparentNode )
{
itemObj.grandparent = listNode.getParent();
if ( itemObj.grandparent && itemObj.grandparent.$.nodeName.toLowerCase() == 'li' )
itemObj.grandparent = itemObj.grandparent.getParent();
}
else
itemObj.grandparent = grandparentNode;
if ( database )
CKEDITOR.dom.element.setMarker( database, listItem, 'listarray_index', baseArray.length );
baseArray.push( itemObj );
for ( var j = 0, itemChildCount = listItem.getChildCount() ; j < itemChildCount ; j++ )
{
var child = listItem.getChild( j );
if ( child.type == CKEDITOR.NODE_ELEMENT && listNodeNames[ child.getName() ] )
// Note the recursion here, it pushes inner list items with
// +1 indentation in the correct order.
CKEDITOR.plugins.list.listToArray( child, database, 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, database, baseIndex, paragraphMode )
{
if ( !baseIndex )
baseIndex = 0;
if ( !listArray || listArray.length < baseIndex + 1 )
return null;
var doc = listArray[ baseIndex ].parent.getDocument(),
retval = new CKEDITOR.dom.documentFragment( doc ),
rootNode = null,
currentIndex = baseIndex,
indentLevel = Math.max( listArray[ baseIndex ].indent, 0 ),
currentListItem = null,
paragraphName = ( paragraphMode == CKEDITOR.ENTER_P ? 'p' : 'div' );
while ( true )
{
var item = listArray[ currentIndex ];
if ( item.indent == indentLevel )
{
if ( !rootNode || listArray[ currentIndex ].parent.getName() != rootNode.getName() )
{
rootNode = listArray[ currentIndex ].parent.clone( false, true );
retval.append( rootNode );
}
currentListItem = rootNode.append( doc.createElement( 'li' ) );
for ( var i = 0 ; i < item.contents.length ; i++ )
currentListItem.append( item.contents[i].clone( true, true ) );
currentIndex++;
}
else if ( item.indent == Math.max( indentLevel, 0 ) + 1 )
{
var listData = CKEDITOR.plugins.list.arrayToList( listArray, null, currentIndex, paragraphMode );
currentListItem.append( listData.listNode );
currentIndex = listData.nextIndex;
}
else if ( item.indent == -1 && !baseIndex && item.grandparent )
{
currentListItem;
if ( listNodeNames[ item.grandparent.getName() ] )
currentListItem = doc.createElement( 'li' );
else
{
if ( paragraphMode != CKEDITOR.ENTER_BR && item.grandparent.getName() != 'td' )
currentListItem = doc.createElement( paragraphName );
else
currentListItem = new CKEDITOR.dom.documentFragment( doc );
}
for ( i = 0 ; i < item.contents.length ; i++ )
currentListItem.append( item.contents[i].clone( true, true ) );
if ( currentListItem.type == CKEDITOR.NODE_DOCUMENT_FRAGMENT )
{
if ( currentListItem.getLast()
&& currentListItem.getLast().type == CKEDITOR.NODE_ELEMENT
&& currentListItem.getLast().getAttribute( 'type' ) == '_moz' )
currentListItem.getLast().remove();
currentListItem.appendBogus();
}
if ( currentListItem.type == CKEDITOR.NODE_ELEMENT &&
currentListItem.getName() == paragraphName &&
currentListItem.$.firstChild )
{
currentListItem.trim();
var firstChild = currentListItem.getFirst();
if ( firstChild.type == CKEDITOR.NODE_ELEMENT && firstChild.isBlockBoundary() )
{
var tmp = new CKEDITOR.dom.documentFragment( doc );
currentListItem.moveChildren( tmp );
currentListItem = tmp;
}
}
var currentListItemName = currentListItem.$.nodeName.toLowerCase();
if ( !CKEDITOR.env.ie && ( currentListItemName == 'div' || currentListItemName == 'p' ) )
currentListItem.appendBogus();
retval.append( 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 ( database )
{
var currentNode = retval.getFirst();
while ( currentNode )
{
if ( currentNode.type == CKEDITOR.NODE_ELEMENT )
CKEDITOR.dom.element.clearMarkers( database, currentNode );
currentNode = currentNode.getNextSourceNode();
}
}
return { listNode : retval, nextIndex : currentIndex };
}
};
function setState( editor, state )
{
editor.getCommand( this.name ).setState( state );
}
function onSelectionChange( evt )
{
var elements = evt.data.path.elements;
for ( var i = 0 ; i < elements.length ; i++ )
{
if ( listNodeNames[ elements[i].getName() ] )
{
return setState.call( this, evt.editor,
this.type == elements[i].getName() ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
}
}
return setState.call( this, evt.editor, CKEDITOR.TRISTATE_OFF );
}
function changeListType( editor, groupObj, database, listsCreated )
{
// This case is easy...
// 1. Convert the whole list into a one-dimensional array.
// 2. Change the list type by modifying the array.
// 3. Recreate the whole list by converting the array to a list.
// 4. Replace the original list with the recreated list.
var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
selectedListItems = [];
for ( var i = 0 ; i < groupObj.contents.length ; i++ )
{
var itemNode = groupObj.contents[i];
itemNode = itemNode.getAscendant( 'li', true );
if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
continue;
selectedListItems.push( itemNode );
CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
}
var fakeParent = groupObj.root.getDocument().createElement( this.type );
for ( i = 0 ; i < selectedListItems.length ; i++ )
{
var listIndex = selectedListItems[i].getCustomData( 'listarray_index' );
listArray[listIndex].parent = fakeParent;
}
var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
var child, length = newList.listNode.getChildCount();
for ( i = 0 ; i < length && ( child = newList.listNode.getChild( i ) ) ; i++ )
{
if ( child.getName() == this.type )
listsCreated.push( child );
}
newList.listNode.replace( groupObj.root );
}
function createList( editor, groupObj, listsCreated )
{
var contents = groupObj.contents,
doc = groupObj.root.getDocument(),
listContents = [];
// It is possible to have the contents returned by DomRangeIterator to be the same as the root.
// e.g. when we're running into table cells.
// In such a case, enclose the childNodes of contents[0] into a <div>.
if ( contents.length == 1 && contents[0].equals( groupObj.root ) )
{
var divBlock = doc.createElement( 'div' );
contents[0].moveChildren && contents[0].moveChildren( divBlock );
contents[0].append( divBlock );
contents[0] = divBlock;
}
// Calculate the common parent node of all content blocks.
var commonParent = groupObj.contents[0].getParent();
for ( var i = 0 ; i < contents.length ; i++ )
commonParent = commonParent.getCommonAncestor( contents[i].getParent() );
// We want to insert things that are in the same tree level only, so calculate the contents again
// by expanding the selected blocks to the same tree level.
for ( i = 0 ; i < contents.length ; i++ )
{
var contentNode = contents[i],
parentNode;
while ( ( parentNode = contentNode.getParent() ) )
{
if ( parentNode.equals( commonParent ) )
{
listContents.push( contentNode );
break;
}
contentNode = parentNode;
}
}
if ( listContents.length < 1 )
return;
// Insert the list to the DOM tree.
var insertAnchor = listContents[ listContents.length - 1 ].getNext(),
listNode = doc.createElement( this.type );
listsCreated.push( listNode );
while ( listContents.length )
{
var contentBlock = listContents.shift(),
listItem = doc.createElement( 'li' );
contentBlock.moveChildren( listItem );
contentBlock.remove();
listItem.appendTo( listNode );
// Append a bogus BR to force the LI to render at full height
if ( !CKEDITOR.env.ie )
listItem.appendBogus();
}
if ( insertAnchor )
listNode.insertBefore( insertAnchor );
else
listNode.appendTo( commonParent );
}
function removeList( editor, groupObj, database )
{
// This is very much like the change list type operation.
// Except that we're changing the selected items' indent to -1 in the list array.
var listArray = CKEDITOR.plugins.list.listToArray( groupObj.root, database ),
selectedListItems = [];
for ( var i = 0 ; i < groupObj.contents.length ; i++ )
{
var itemNode = groupObj.contents[i];
itemNode = itemNode.getAscendant( 'li', true );
if ( !itemNode || itemNode.getCustomData( 'list_item_processed' ) )
continue;
selectedListItems.push( itemNode );
CKEDITOR.dom.element.setMarker( database, itemNode, 'list_item_processed', true );
}
var lastListIndex = null;
for ( i = 0 ; i < selectedListItems.length ; i++ )
{
var listIndex = selectedListItems[i].getCustomData( 'listarray_index' );
listArray[listIndex].indent = -1;
lastListIndex = listIndex;
}
// After cutting parts of the list out with indent=-1, we still have to maintain the array list
// model's nextItem.indent <= currentItem.indent + 1 invariant. Otherwise the array model of the
// list cannot be converted back to a real DOM list.
for ( i = lastListIndex + 1 ; i < listArray.length ; i++ )
{
if ( listArray[i].indent > listArray[i-1].indent + 1 )
{
var indentOffset = listArray[i-1].indent + 1 - listArray[i].indent;
var oldIndent = listArray[i].indent;
while ( listArray[i] && listArray[i].indent >= oldIndent )
{
listArray[i].indent += indentOffset;
i++;
}
i--;
}
}
var newList = CKEDITOR.plugins.list.arrayToList( listArray, database, null, editor.config.enterMode );
// If groupObj.root is the last element in its parent, or its nextSibling is a <br>, then we should
// not add a <br> after the final item. So, check for the cases and trim the <br>.
if ( !groupObj.root.getNext() || groupObj.root.getNext().$.nodeName.toLowerCase() == 'br' )
{
if ( newList.listNode.getLast().$.nodeName.toLowerCase() == 'br' )
newList.listNode.getLast().remove();
}
newList.listNode.replace( groupObj.root );
}
function listCommand( name, type )
{
this.name = name;
this.type = type;
}
listCommand.prototype = {
exec : function( editor )
{
editor.focus();
var doc = editor.document,
selection = editor.getSelection(),
ranges = selection && selection.getRanges();
// There should be at least one selected range.
if ( !ranges || ranges.length < 1 )
return;
// Midas lists rule #1 says we can create a list even in an empty document.
// But DOM iterator wouldn't run if the document is really empty.
// So create a paragraph if the document is empty and we're going to create a list.
if ( this.state == CKEDITOR.TRISTATE_OFF )
{
var body = doc.getBody();
body.trim();
if ( !body.getFirst() )
{
var paragraph = doc.createElement( editor.config.enterMode == CKEDITOR.ENTER_P ? 'p' :
( editor.config.enterMode == CKEDITOR.ENTER_DIV ? 'div' : 'br' ) );
paragraph.appendTo( body );
ranges = [ new CKEDITOR.dom.range( doc ) ];
// IE exception on inserting anything when anchor inside <br>.
if ( paragraph.is( 'br' ) )
{
ranges[ 0 ].setStartBefore( paragraph );
ranges[ 0 ].setEndAfter( paragraph );
}
else
ranges[ 0 ].selectNodeContents( paragraph );
selection.selectRanges( ranges );
}
}
var bookmarks = selection.createBookmarks( true );
// Group the blocks up because there are many cases where multiple lists have to be created,
// or multiple lists have to be cancelled.
var listGroups = [],
database = {};
while ( ranges.length > 0 )
{
var range = ranges.shift(),
boundaryNodes = range.getBoundaryNodes(),
startNode = boundaryNodes.startNode,
endNode = boundaryNodes.endNode;
if ( startNode.type == CKEDITOR.NODE_ELEMENT && startNode.getName() == 'td' )
range.setStartAt( boundaryNodes.startNode, CKEDITOR.POSITION_AFTER_START );
if ( endNode.type == CKEDITOR.NODE_ELEMENT && endNode.getName() == 'td' )
range.setEndAt( boundaryNodes.endNode, CKEDITOR.POSITION_BEFORE_END );
var iterator = range.createIterator(),
block;
iterator.forceBrBreak = ( this.state == CKEDITOR.TRISTATE_OFF );
while ( ( block = iterator.getNextParagraph() ) )
{
var path = new CKEDITOR.dom.elementPath( block ),
listNode = null,
processedFlag = false,
blockLimit = path.blockLimit;
// First, try to group by a list ancestor.
for ( var i = 0 ; i < path.elements.length ; i++ )
{
var element = path.elements[i];
if ( listNodeNames[ element.getName() ] )
{
// If we've encountered a list inside a block limit
// The last group object of the block limit element should
// no longer be valid. Since paragraphs after the list
// should belong to a different group of paragraphs before
// the list. (Bug #1309)
blockLimit.removeCustomData( 'list_group_object' );
var groupObj = element.getCustomData( 'list_group_object' );
if ( groupObj )
groupObj.contents.push( block );
else
{
groupObj = { root : element, contents : [ block ] };
listGroups.push( groupObj );
CKEDITOR.dom.element.setMarker( database, element, 'list_group_object', groupObj );
}
processedFlag = true;
break;
}
}
if ( processedFlag )
continue;
// No list ancestor? Group by block limit.
var root = blockLimit;
if ( root.getCustomData( 'list_group_object' ) )
root.getCustomData( 'list_group_object' ).contents.push( block );
else
{
groupObj = { root : root, contents : [ block ] };
CKEDITOR.dom.element.setMarker( database, root, 'list_group_object', groupObj );
listGroups.push( groupObj );
}
}
}
// Now we have two kinds of list groups, groups rooted at a list, and groups rooted at a block limit element.
// We either have to build lists or remove lists, for removing a list does not makes sense when we are looking
// at the group that's not rooted at lists. So we have three cases to handle.
var listsCreated = [];
while ( listGroups.length > 0 )
{
groupObj = listGroups.shift();
if ( this.state == CKEDITOR.TRISTATE_OFF )
{
if ( listNodeNames[ groupObj.root.getName() ] )
changeListType.call( this, editor, groupObj, database, listsCreated );
else
createList.call( this, editor, groupObj, listsCreated );
}
else if ( this.state == CKEDITOR.TRISTATE_ON && listNodeNames[ groupObj.root.getName() ] )
removeList.call( this, editor, groupObj, database );
}
// For all new lists created, merge adjacent, same type lists.
for ( i = 0 ; i < listsCreated.length ; i++ )
{
listNode = listsCreated[i];
var mergeSibling, listCommand = this;
( mergeSibling = function( rtl ){
var sibling = listNode[ rtl ? 'getPrevious' : 'getNext' ].call( listNode, true );
if ( sibling && sibling.getName &&
sibling.getName() == listCommand.type )
{
sibling.remove();
sibling.moveChildren( listNode );
}
} )();
mergeSibling( true );
}
// Clean up, restore selection and update toolbar button states.
CKEDITOR.dom.element.clearAllMarkers( database );
selection.selectBookmarks( bookmarks );
editor.focus();
}
};
CKEDITOR.plugins.add( 'list',
{
init : function( editor )
{
// Register commands.
var numberedListCommand = new listCommand( 'numberedlist', 'ol' ),
bulletedListCommand = new listCommand( 'bulletedlist', 'ul' );
editor.addCommand( 'numberedlist', numberedListCommand );
editor.addCommand( 'bulletedlist', bulletedListCommand );
// Register the toolbar button.
editor.ui.addButton( 'NumberedList',
{
label : editor.lang.numberedlist,
command : 'numberedlist'
} );
editor.ui.addButton( 'BulletedList',
{
label : editor.lang.bulletedlist,
command : 'bulletedlist'
} );
// Register the state changing handlers.
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, numberedListCommand ) );
editor.on( 'selectionChange', CKEDITOR.tools.bind( onSelectionChange, bulletedListCommand ) );
},
requires : [ 'domiterator' ]
} );
})();
@@ -0,0 +1,231 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'listblock',
{
requires : [ 'panel' ],
onLoad : function()
{
CKEDITOR.ui.panel.prototype.addListBlock = function( name, multiSelect )
{
return this.addBlock( name, new CKEDITOR.ui.listBlock( this.getHolderElement(), multiSelect ) );
};
CKEDITOR.ui.listBlock = CKEDITOR.tools.createClass(
{
base : CKEDITOR.ui.panel.block,
$ : function( blockHolder, multiSelect )
{
// Call the base contructor.
this.base( blockHolder );
this.multiSelect = !!multiSelect;
var keys = this.keys;
keys[ 40 ] = 'next'; // ARROW-DOWN
keys[ 9 ] = 'next'; // TAB
keys[ 38 ] = 'prev'; // ARROW-UP
keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
keys[ 32 ] = 'click'; // SPACE
this._.pendingHtml = [];
this._.items = {};
this._.groups = {};
},
_ :
{
close : function()
{
if ( this._.started )
{
this._.pendingHtml.push( '</ul>' );
delete this._.started;
}
},
getClick : function()
{
if ( !this._.click )
{
this._.click = CKEDITOR.tools.addFunction( function( value )
{
var marked = true;
if ( this.multiSelect )
marked = this.toggle( value );
else
this.mark( value );
if ( this.onClick )
this.onClick( value, marked );
},
this );
}
return this._.click;
}
},
proto :
{
add : function( value, html, title )
{
var pendingHtml = this._.pendingHtml,
id = 'cke_' + CKEDITOR.tools.getNextNumber();
if ( !this._.started )
{
pendingHtml.push( '<ul class=cke_panel_list>' );
this._.started = 1;
}
this._.items[ value ] = id;
pendingHtml.push(
'<li id=', id, ' class=cke_panel_listItem>' +
'<a _cke_focus=1 hidefocus=true' +
' title="', title || value, '"' +
' href="javascript:void(\'', value, '\')"' +
' onclick="CKEDITOR.tools.callFunction(', this._.getClick(), ',\'', value, '\'); return false;">',
html || value,
'</a>' +
'</li>' );
},
startGroup : function( title )
{
this._.close();
var id = 'cke_' + CKEDITOR.tools.getNextNumber();
this._.groups[ title ] = id;
this._.pendingHtml.push( '<h1 id=', id, ' class=cke_panel_grouptitle>', title, '</h1>' );
},
commit : function()
{
this._.close();
this.element.appendHtml( this._.pendingHtml.join( '' ) );
this._.pendingHtml = [];
},
toggle : function( value )
{
var isMarked = this.isMarked( value );
if ( isMarked )
this.unmark( value );
else
this.mark( value );
return !isMarked;
},
hideGroup : function( groupTitle )
{
var group = this.element.getDocument().getById( this._.groups[ groupTitle ] ),
list = group && group.getNext();
if ( group )
{
group.setStyle( 'display', 'none' );
if ( list && list.getName() == 'ul' )
list.setStyle( 'display', 'none' );
}
},
hideItem : function( value )
{
this.element.getDocument().getById( this._.items[ value ] ).setStyle( 'display', 'none' );
},
showAll : function()
{
var items = this._.items,
groups = this._.groups,
doc = this.element.getDocument();
for ( var value in items )
{
doc.getById( items[ value ] ).setStyle( 'display', '' );
}
for ( var title in groups )
{
var group = doc.getById( groups[ title ] ),
list = group.getNext();
group.setStyle( 'display', '' );
if ( list && list.getName() == 'ul' )
list.setStyle( 'display', '' );
}
},
mark : function( value )
{
if ( !this.multiSelect )
this.unmarkAll();
this.element.getDocument().getById( this._.items[ value ] ).addClass( 'cke_selected' );
},
unmark : function( value )
{
this.element.getDocument().getById( this._.items[ value ] ).removeClass( 'cke_selected' );
},
unmarkAll : function()
{
var items = this._.items,
doc = this.element.getDocument();
for ( var value in items )
{
doc.getById( items[ value ] ).removeClass( 'cke_selected' );
}
},
isMarked : function( value )
{
return this.element.getDocument().getById( this._.items[ value ] ).hasClass( 'cke_selected' );
},
focus : function( value )
{
this._.focusIndex = -1;
if ( value )
{
var selected = this.element.getDocument().getById( this._.items[ value ] ).getFirst();
var links = this.element.getElementsByTag( 'a' ),
link,
i = -1;
while( ( link = links.getItem( ++i ) ) )
{
if ( link.equals( selected ) )
{
this._.focusIndex = i;
break;
}
}
setTimeout( function()
{
selected.focus();
},
0 );
}
}
}
});
}
});
@@ -0,0 +1,267 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
function protectFormStyles( formElement )
{
if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != 'form' )
return [];
var hijackRecord = [];
var hijackNames = [ 'style', 'className' ];
for ( var i = 0 ; i < hijackNames.length ; i++ )
{
var name = hijackNames[i];
var $node = formElement.$.elements.namedItem( name );
if ( $node )
{
var hijackNode = new CKEDITOR.dom.element( $node );
hijackRecord.push( [ hijackNode, hijackNode.nextSibling ] );
hijackNode.remove();
}
}
return hijackRecord;
}
function restoreFormStyles( formElement, hijackRecord )
{
if ( !formElement || formElement.type != CKEDITOR.NODE_ELEMENT || formElement.getName() != '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 )
node.insertBefore( sibling );
else
node.appendTo( formElement );
}
}
}
function saveStyles( element, isInsideEditor )
{
var data = protectFormStyles( element );
var retval = {};
var $element = element.$;
if ( !isInsideEditor )
{
retval[ 'class' ] = $element.className || '';
$element.className = '';
}
retval.inline = $element.style.cssText || '';
if ( !isInsideEditor ) // Reset any external styles that might interfere. (#2474)
$element.style.cssText = 'position: static; overflow: visible';
restoreFormStyles( data );
return retval;
}
function restoreStyles( element, savedStyles )
{
var data = protectFormStyles( element );
var $element = element.$;
if ( 'class' in savedStyles )
$element.className = savedStyles[ 'class' ];
if ( 'inline' in savedStyles )
$element.style.cssText = savedStyles.inline;
restoreFormStyles( data );
}
function getResizeHandler( mainWindow, editor )
{
return function()
{
var viewPaneSize = mainWindow.getViewPaneSize();
editor.resize( viewPaneSize.width, viewPaneSize.height, null, true );
};
}
CKEDITOR.plugins.add( 'maximize',
{
init : function( editor )
{
var lang = editor.lang;
var mainDocument = CKEDITOR.document;
var mainWindow = mainDocument.getWindow();
// Saved selection and scroll position for the editing area.
var savedSelection;
var savedScroll;
// Saved scroll position for the outer window.
var outerScroll;
// Saved resize handler function.
var resizeHandler = getResizeHandler( mainWindow, editor );
// Retain state after mode switches.
var savedState = CKEDITOR.TRISTATE_OFF;
editor.addCommand( 'maximize',
{
modes : { wysiwyg : 1, source : 1 },
exec : function()
{
var container = editor.container.getChild( [ 0, 0 ] );
var contents = editor.getThemeSpace( 'contents' );
// Save current selection and scroll position in editing area.
if ( editor.mode == 'wysiwyg' )
{
savedSelection = editor.getSelection().getRanges();
savedScroll = mainWindow.getScrollPosition();
}
else
{
var $textarea = editor.textarea.$;
savedSelection = !CKEDITOR.env.ie && [ $textarea.selectionStart, $textarea.selectionEnd ];
savedScroll = [ $textarea.scrollLeft, $textarea.scrollTop ];
}
if ( this.state == CKEDITOR.TRISTATE_OFF ) // Go fullscreen if the state is off.
{
// Add event handler for resizing.
mainWindow.on( 'resize', resizeHandler );
// Save the scroll bar position.
outerScroll = mainWindow.getScrollPosition();
// Save and reset the styles for the entire node tree.
var currentNode = editor.container;
while ( ( currentNode = currentNode.getParent() ) )
{
currentNode.setCustomData( 'maximize_saved_styles', saveStyles( currentNode ) );
currentNode.setStyle( 'z-index', editor.config.baseFloatZIndex - 1 );
}
contents.setCustomData( 'maximize_saved_styles', saveStyles( contents, true ) );
container.setCustomData( 'maximize_saved_styles', saveStyles( container, true ) );
// Hide scroll bars.
if ( CKEDITOR.env.ie )
{
mainDocument.$.documentElement.style.overflow =
mainDocument.getBody().$.style.overflow = 'hidden';
}
else
{
mainDocument.getBody().setStyles(
{
overflow : 'hidden',
width : '0px',
height : '0px'
} );
}
// Scroll to the top left.
mainWindow.$.scrollTo( 0, 0 );
// Resize and move to top left.
var viewPaneSize = mainWindow.getViewPaneSize();
container.setStyle( 'position', 'absolute' );
container.$.offsetLeft; // SAFARI BUG: See #2066.
container.setStyles(
{
'z-index' : editor.config.baseFloatZIndex - 1,
left : '0px',
top : '0px'
} );
editor.resize( viewPaneSize.width, viewPaneSize.height, null, true );
// Still not top left? Fix it. (Bug #174)
var offset = container.getDocumentPosition();
container.setStyles(
{
left : ( -1 * offset.x ) + 'px',
top : ( -1 * offset.y ) + 'px'
} );
// Add cke_maximized class.
container.addClass( 'cke_maximized' );
}
else if ( this.state == CKEDITOR.TRISTATE_ON ) // Restore from fullscreen if the state is on.
{
// Remove event handler for resizing.
mainWindow.removeListener( 'resize', resizeHandler );
// Restore CSS styles for the entire node tree.
var editorElements = [ contents, container ];
for ( var i = 0 ; i < editorElements.length ; i++ )
{
restoreStyles( editorElements[i], editorElements[i].getCustomData( 'maximize_saved_styles' ) );
editorElements[i].removeCustomData( 'maximize_saved_styles' );
}
currentNode = editor.container;
while ( ( currentNode = currentNode.getParent() ) )
{
restoreStyles( currentNode, currentNode.getCustomData( 'maximize_saved_styles' ) );
currentNode.removeCustomData( 'maximize_saved_styles' );
}
// Restore the window scroll position.
mainWindow.$.scrollTo( outerScroll.x, outerScroll.y );
// Remove cke_maximized class.
container.removeClass( 'cke_maximized' );
// Emit a resize event, because this time the size is modified in
// restoreStyles.
editor.fire( 'resize' );
}
this.toggleState();
// Restore selection and scroll position in editing area.
if ( editor.mode == 'wysiwyg' )
{
editor.getSelection().selectRanges( savedSelection );
var element = editor.getSelection().getStartElement();
if ( element )
element.scrollIntoView( true );
else
mainWindow.$.scrollTo( savedScroll.x, savedScroll.y );
}
else
{
if ( savedSelection )
{
$textarea.selectionStart = savedSelection[0];
$textarea.selectionEnd = savedSelection[1];
}
$textarea.scrollLeft = savedScroll[0];
$textarea.scrollTop = savedScroll[1];
}
savedSelection = savedScroll = null;
savedState = this.state;
},
canUndo : false
} );
editor.ui.addButton( 'Maximize',
{
label : lang.maximize,
command : 'maximize'
} );
// Restore the command state after mode change.
editor.on( 'mode', function()
{
editor.getCommand( 'maximize' ).setState( savedState );
}, null, null, 100 );
}
} );
})();
@@ -0,0 +1,351 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'menu',
{
beforeInit : function( editor )
{
var groups = editor.config.menu_groups.split( ',' ),
groupsOrder = {};
for ( var i = 0 ; i < groups.length ; i++ )
groupsOrder[ groups[ i ] ] = i + 1;
editor._.menuGroups = groupsOrder;
editor._.menuItems = {};
},
requires : [ 'floatpanel' ]
});
CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
{
addMenuGroup : function( name, order )
{
this._.menuGroups[ name ] = order || 100;
},
addMenuItem : function( name, definition )
{
if ( this._.menuGroups[ definition.group ] )
this._.menuItems[ name ] = new CKEDITOR.menuItem( this, name, definition );
},
addMenuItems : function( definitions )
{
for ( var itemName in definitions )
{
this.addMenuItem( itemName, definitions[ itemName ] );
}
},
getMenuItem : function( name )
{
return this._.menuItems[ name ];
}
});
(function()
{
CKEDITOR.menu = CKEDITOR.tools.createClass(
{
$ : function( editor, level )
{
this.id = 'cke_' + CKEDITOR.tools.getNextNumber();
this.editor = editor;
this.items = [];
this._.level = level || 1;
},
_ :
{
showSubMenu : function( index )
{
var menu = this._.subMenu,
item = this.items[ index ],
subItems = item.getItems && item.getItems();
// If this item has no subitems, we just hide the submenu, if
// available, and return back.
if ( !subItems )
{
this._.panel.hideChild();
return;
}
// Create the submenu, if not available, or clean the existing
// one.
if ( menu )
menu.removeAll();
else
{
menu = this._.subMenu = new CKEDITOR.menu( this.editor, this._.level + 1 );
menu.parent = this;
menu.onClick = CKEDITOR.tools.bind( this.onClick, this );
}
// Add all submenu items to the menu.
for ( var itemName in subItems )
{
menu.add( this.editor.getMenuItem( itemName ) );
}
// Get the element representing the current item.
var element = this._.panel.getBlock( this.id ).element.getDocument().getById( this.id + String( index ) );
// Show the submenu.
menu.show( element, 2 );
}
},
proto :
{
add : function( item )
{
this.items.push( item );
},
removeAll : function()
{
this.items = [];
},
show : function( offsetParent, corner, offsetX, offsetY )
{
var items = this.items,
editor = this.editor,
panel = this._.panel,
element = this._.element;
// Create the floating panel for this menu.
if ( !panel )
{
panel = this._.panel = new CKEDITOR.ui.floatPanel( this.editor, CKEDITOR.document.getBody(),
{
css : [ CKEDITOR.getUrl( editor.skinPath + 'editor.css' ) ],
level : this._.level - 1,
className : editor.skinClass + ' cke_contextmenu'
},
this._.level);
panel.onEscape = CKEDITOR.tools.bind( function()
{
this.onEscape && this.onEscape();
this.hide();
},
this );
panel.onHide = CKEDITOR.tools.bind( function()
{
this.onHide && this.onHide();
},
this );
// Create an autosize block inside the panel.
var block = panel.addBlock( this.id );
block.autoSize = true;
var keys = block.keys;
keys[ 40 ] = 'next'; // ARROW-DOWN
keys[ 9 ] = 'next'; // TAB
keys[ 38 ] = 'prev'; // ARROW-UP
keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
keys[ 32 ] = 'click'; // SPACE
keys[ 39 ] = 'click'; // ARROW-RIGHT
element = this._.element = block.element;
element.addClass( editor.skinClass );
var elementDoc = element.getDocument();
elementDoc.getBody().setStyle( 'overflow', 'hidden' );
elementDoc.getElementsByTag( 'html' ).getItem( 0 ).setStyle( 'overflow', 'hidden' );
this._.itemOverFn = CKEDITOR.tools.addFunction( function( index )
{
clearTimeout( this._.showSubTimeout );
this._.showSubTimeout = CKEDITOR.tools.setTimeout( this._.showSubMenu, editor.config.menu_subMenuDelay, this, [ index ] );
},
this);
this._.itemOutFn = CKEDITOR.tools.addFunction( function( index )
{
clearTimeout( this._.showSubTimeout );
},
this);
this._.itemClickFn = CKEDITOR.tools.addFunction( function( index )
{
var item = this.items[ index ];
if ( item.state == CKEDITOR.TRISTATE_DISABLED )
{
this.hide();
return;
}
if ( item.getItems )
this._.showSubMenu( index );
else
this.onClick && this.onClick( item );
},
this);
}
// Put the items in the right order.
sortItems( items );
// Build the HTML that composes the menu and its items.
var output = [ '<div class="cke_menu">' ];
var length = items.length,
lastGroup = length && items[ 0 ].group;
for ( var i = 0 ; i < length ; i++ )
{
var item = items[ i ];
if ( lastGroup != item.group )
{
output.push( '<div class="cke_menuseparator"></div>' );
lastGroup = item.group;
}
item.render( this, i, output );
}
output.push( '</div>' );
// Inject the HTML inside the panel.
element.setHtml( output.join( '' ) );
// Show the panel.
if ( this.parent )
this.parent._.panel.showAsChild( panel, this.id, offsetParent, corner, offsetX, offsetY );
else
panel.showBlock( this.id, offsetParent, corner, offsetX, offsetY );
},
hide : function()
{
this._.panel && this._.panel.hide();
}
}
});
function sortItems( items )
{
items.sort( function( itemA, itemB )
{
if ( itemA.group < itemB.group )
return -1;
else if ( itemA.group > itemB.group )
return 1;
return itemA.order < itemB.order ? -1 :
itemA.order > itemB.order ? 1 :
0;
});
}
})();
CKEDITOR.menuItem = CKEDITOR.tools.createClass(
{
$ : function( editor, name, definition )
{
CKEDITOR.tools.extend( this, definition,
// Defaults
{
order : 0,
className : 'cke_button_' + name
});
// Transform the group name into its order number.
this.group = editor._.menuGroups[ this.group ];
this.editor = editor;
this.name = name;
},
proto :
{
render : function( menu, index, output )
{
var id = menu.id + String( index ),
state = ( typeof this.state == 'undefined' ) ? CKEDITOR.TRISTATE_OFF : this.state;
var classes = ' cke_' + (
state == CKEDITOR.TRISTATE_ON ? 'on' :
state == CKEDITOR.TRISTATE_DISABLED ? 'disabled' :
'off' );
var htmlLabel = this.label;
if ( state == CKEDITOR.TRISTATE_DISABLED )
htmlLabel = this.editor.lang.common.unavailable.replace( '%1', htmlLabel );
if ( this.className )
classes += ' ' + this.className;
output.push(
'<span class="cke_menuitem">' +
'<a id="', id, '"' +
' class="', classes, '" href="javascript:void(\'', ( this.label || '' ).replace( "'", '' ), '\')"' +
' title="', this.label, '"' +
' tabindex="-1"' +
'_cke_focus=1' +
' hidefocus="true"' );
// Some browsers don't cancel key events in the keydown but in the
// keypress.
// TODO: Check if really needed for Gecko+Mac.
if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
{
output.push(
' onkeypress="return false;"' );
}
// With Firefox, we need to force the button to redraw, otherwise it
// will remain in the focus state.
if ( CKEDITOR.env.gecko )
{
output.push(
' onblur="this.style.cssText = this.style.cssText;"' );
}
var offset = ( this.iconOffset || 0 ) * -16;
output.push(
// ' onkeydown="return CKEDITOR.ui.button._.keydown(', index, ', event);"' +
' onmouseover="CKEDITOR.tools.callFunction(', menu._.itemOverFn, ',', index, ');"' +
' onmouseout="CKEDITOR.tools.callFunction(', menu._.itemOutFn, ',', index, ');"' +
' onclick="CKEDITOR.tools.callFunction(', menu._.itemClickFn, ',', index, '); return false;"' +
'>' +
'<span class="cke_icon_wrapper"><span class="cke_icon"' +
( this.icon ? ' style="background-image:url(' + CKEDITOR.getUrl( this.icon ) + ');background-position:0 ' + offset + 'px;"></span>'
: '' ) +
'></span></span>' +
'<span class="cke_label">' );
if ( this.getItems )
{
output.push(
'<span class="cke_menuarrow"></span>' );
}
output.push(
htmlLabel,
'</span>' +
'</a>' +
'</span>' );
}
}
});
CKEDITOR.config.menu_subMenuDelay = 400;
CKEDITOR.config.menu_groups =
'clipboard,' +
'form,' +
'tablecell,tablecellproperties,tablerow,tablecolumn,table,'+
'anchor,link,image,flash,' +
'checkbox,radio,textfield,hiddenfield,imagebutton,button,select,textarea';
@@ -0,0 +1,93 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'menubutton',
{
requires : [ 'button' ],
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_MENUBUTTON, CKEDITOR.ui.menuButton.handler );
}
});
/**
* Button UI element.
* @constant
* @example
*/
CKEDITOR.UI_MENUBUTTON = 5;
(function()
{
var clickFn = function( editor )
{
var _ = this._;
// Do nothing if this button is disabled.
if ( _.state === CKEDITOR.TRISTATE_DISABLED )
return;
_.previousState = _.state;
// Check if we already have a menu for it, otherwise just create it.
var menu = _.menu;
if ( !menu )
{
menu = _.menu = new CKEDITOR.plugins.contextMenu( editor );
menu.onHide = CKEDITOR.tools.bind( function()
{
this.setState( _.previousState );
},
this );
// Initialize the menu items at this point.
if ( this.onMenu )
{
menu.addListener( this.onMenu );
}
}
if ( _.on )
{
menu.hide();
return;
}
this.setState( CKEDITOR.TRISTATE_ON );
menu.show( CKEDITOR.document.getById( this._.id ), 4 );
};
CKEDITOR.ui.menuButton = CKEDITOR.tools.createClass(
{
base : CKEDITOR.ui.button,
$ : function( definition )
{
// We don't want the panel definition in this object.
var panelDefinition = definition.panel;
delete definition.panel;
this.base( definition );
this.hasArrow = true;
this.click = clickFn;
},
statics :
{
handler :
{
create : function( definition )
{
return new CKEDITOR.ui.menuButton( definition );
}
}
}
});
})();
@@ -0,0 +1,59 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Horizontal Page Break
*/
// Register a plugin named "newpage".
CKEDITOR.plugins.add( 'newpage',
{
init : function( editor )
{
editor.addCommand( 'newpage',
{
modes : { wysiwyg:1, source:1 },
exec : function( editor )
{
var command = this;
function afterCommand()
{
// Defer to happen after 'selectionChange'.
setTimeout( function()
{
editor.fire( 'afterCommandExec',
{
name: command.name,
command: command
} );
}, 500 );
}
if ( editor.mode == 'wysiwyg')
editor.on( 'contentDom', function( evt ){
evt.removeListener();
afterCommand();
} );
editor.setData( editor.config.newpage_html );
editor.focus();
if( editor.mode == 'source' )
afterCommand();
},
async : true
});
editor.ui.addButton( 'NewPage',
{
label : editor.lang.newPage,
command : 'newpage'
});
}
});
CKEDITOR.config.newpage_html = '';
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 B

@@ -0,0 +1,96 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Horizontal Page Break
*/
// Register a plugin named "pagebreak".
CKEDITOR.plugins.add( 'pagebreak',
{
init : function( editor )
{
// Register the command.
editor.addCommand( 'pagebreak', CKEDITOR.plugins.pagebreakCmd );
// Register the toolbar button.
editor.ui.addButton( 'PageBreak',
{
label : editor.lang.pagebreak,
command : 'pagebreak'
});
// Add the style that renders our placeholder.
editor.addCss(
'img.cke_pagebreak' +
'{' +
'background-image: url(' + CKEDITOR.getUrl( this.path + 'images/pagebreak.gif' ) + ');' +
'background-position: center center;' +
'background-repeat: no-repeat;' +
'clear: both;' +
'display: block;' +
'float: none;' +
'width: 100%;' +
'border-top: #999999 1px dotted;' +
'border-bottom: #999999 1px dotted;' +
'height: 5px;' +
'}' );
},
afterInit : function( editor )
{
// Register a filter to displaying placeholders after mode change.
var dataProcessor = editor.dataProcessor,
dataFilter = dataProcessor && dataProcessor.dataFilter;
if ( dataFilter )
{
dataFilter.addRules(
{
elements :
{
div : function( element )
{
var style = element.attributes.style,
child = style && element.children.length == 1 && element.children[ 0 ],
childStyle = child && ( child.name == 'span' ) && child.attributes.style;
if ( childStyle && ( /page-break-after\s*:\s*always/i ).test( style ) && ( /display\s*:\s*none/i ).test( childStyle ) )
return editor.createFakeParserElement( element, 'cke_pagebreak', 'div' );
}
}
});
}
},
requires : [ 'fakeobjects' ]
});
CKEDITOR.plugins.pagebreakCmd =
{
exec : function( editor )
{
// Create the element that represents a print break.
var breakObject = CKEDITOR.dom.element.createFromHtml( '<div style="page-break-after: always;"><span style="display: none;">&nbsp;</span></div>' );
// Creates the fake image used for this element.
breakObject = editor.createFakeElement( breakObject, 'cke_pagebreak', 'div' );
var ranges = editor.getSelection().getRanges();
for ( var range, i = 0 ; i < ranges.length ; i++ )
{
range = ranges[ i ];
if ( i > 0 )
breakObject = breakObject.clone( true );
range.splitBlock( 'p' );
range.insertNode( breakObject );
}
}
};
@@ -0,0 +1,330 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'panel',
{
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_PANEL, CKEDITOR.ui.panel.handler );
}
});
/**
* Panel UI element.
* @constant
* @example
*/
CKEDITOR.UI_PANEL = 2;
CKEDITOR.ui.panel = function( document, definition )
{
// Copy all definition properties to this object.
if ( definition )
CKEDITOR.tools.extend( this, definition );
// Set defaults.
CKEDITOR.tools.extend( this,
{
className : '',
css : []
});
this.id = CKEDITOR.tools.getNextNumber();
this.document = document;
this._ =
{
blocks : {}
};
};
/**
* Transforms a rich combo definition in a {@link CKEDITOR.ui.richCombo}
* instance.
* @type Object
* @example
*/
CKEDITOR.ui.panel.handler =
{
create : function( definition )
{
return new CKEDITOR.ui.panel( definition );
}
};
CKEDITOR.ui.panel.prototype =
{
renderHtml : function( editor )
{
var output = [];
this.render( editor, output );
return output.join( '' );
},
/**
* Renders the combo.
* @param {CKEDITOR.editor} editor The editor instance which this button is
* to be used by.
* @param {Array} output The output array to which append the HTML relative
* to this button.
* @example
*/
render : function( editor, output )
{
var id = 'cke_' + this.id;
output.push(
'<div class="', editor.skinClass ,'"' +
' lang="', editor.langCode, '"' +
' style="z-index:' + ( editor.config.baseFloatZIndex + 1 ) + '">' +
'<div' +
' id=', id,
' dir=', editor.lang.dir,
' class="cke_panel cke_', editor.lang.dir );
if ( this.className )
output.push( ' ', this.className );
output.push(
'">' );
if ( this.forceIFrame || this.css.length )
{
output.push(
'<iframe id="', id, '_frame"' +
' frameborder="0"' +
' src="javascript:void(' );
output.push(
// Support for custom document.domain in IE.
CKEDITOR.env.isCustomDomain() ?
'(function(){' +
'document.open();' +
'document.domain=\'' + document.domain + '\';' +
'document.close();' +
'})()'
:
'0' );
output.push(
')"></iframe>' );
}
output.push(
'</div>' +
'</div>' );
return id;
},
getHolderElement : function()
{
var holder = this._.holder;
if ( !holder )
{
if ( this.forceIFrame || this.css.length )
{
var iframe = this.document.getById( 'cke_' + this.id + '_frame' ),
parentDiv = iframe.getParent(),
dir = parentDiv.getAttribute( 'dir' ),
className = parentDiv.getParent().getAttribute( 'class' ),
langCode = parentDiv.getParent().getAttribute( 'lang' ),
doc = iframe.getFrameDocument();
// Initialize the IFRAME document body.
doc.$.open();
// Support for custom document.domain in IE.
if ( CKEDITOR.env.isCustomDomain() )
doc.$.domain = document.domain;
doc.$.write(
'<!DOCTYPE html>' +
'<html dir="' + dir + '" class="' + className + '_container" lang="' + langCode + '">' +
'<head>' +
'<style>.' + className + '_container{visibility:hidden}</style>' +
'</head>' +
'<body class="cke_' + dir + ' cke_panel_frame ' + CKEDITOR.env.cssClass + '" style="margin:0;padding:0">' +
'</body>' +
// It looks strange, but for FF2, the styles must go
// after <body>, so it (body) becames immediatelly
// available. (#3031)
'<link type="text/css" rel=stylesheet href="' + this.css.join( '"><link type="text/css" rel="stylesheet" href="' ) + '">' +
'<\/html>' );
doc.$.close();
var win = doc.getWindow();
// Register the CKEDITOR global.
win.$.CKEDITOR = CKEDITOR;
win.on( 'load', function( ev )
{
this.isLoaded = true;
if ( this.onLoad )
this.onLoad();
},
this);
doc.on( 'keydown', function( evt )
{
var keystroke = evt.data.getKeystroke();
// Delegate key processing to block.
if ( this._.onKeyDown && this._.onKeyDown( keystroke ) === false )
{
evt.data.preventDefault();
return;
}
if ( keystroke == 27 ) // ESC
this.onEscape && this.onEscape();
},
this );
holder = doc.getBody();
}
else
holder = this.document.getById( 'cke_' + this.id );
this._.holder = holder;
}
return holder;
},
addBlock : function( name, block )
{
block = this._.blocks[ name ] = block || new CKEDITOR.ui.panel.block( this.getHolderElement() );
if ( !this._.currentBlock )
this.showBlock( name );
return block;
},
getBlock : function( name )
{
return this._.blocks[ name ];
},
showBlock : function( name )
{
var blocks = this._.blocks,
block = blocks[ name ],
current = this._.currentBlock;
if ( current )
current.hide();
this._.currentBlock = block;
// Reset the focus index, so it will always go into the first one.
block._.focusIndex = -1;
this._.onKeyDown = block.onKeyDown && CKEDITOR.tools.bind( block.onKeyDown, block );
block.show();
return block;
}
};
CKEDITOR.ui.panel.block = CKEDITOR.tools.createClass(
{
$ : function( blockHolder )
{
this.element = blockHolder.append(
blockHolder.getDocument().createElement( 'div',
{
attributes :
{
'class' : 'cke_panel_block'
},
styles :
{
display : 'none'
}
}) );
this.keys = {};
this._.focusIndex = -1;
},
_ : {},
proto :
{
show : function()
{
this.element.setStyle( 'display', '' );
},
hide : function()
{
if ( !this.onHide || this.onHide.call( this ) !== true )
this.element.setStyle( 'display', 'none' );
},
onKeyDown : function( keystroke )
{
var keyAction = this.keys[ keystroke ];
switch ( keyAction )
{
// Move forward.
case 'next' :
var index = this._.focusIndex,
links = this.element.getElementsByTag( 'a' ),
link;
while ( ( link = links.getItem( ++index ) ) )
{
// Move the focus only if the element is marked with
// the _cke_focus and it it's visible (check if it has
// width).
if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
{
this._.focusIndex = index;
link.focus();
break;
}
}
return false;
// Move backward.
case 'prev' :
index = this._.focusIndex;
links = this.element.getElementsByTag( 'a' );
while ( index > 0 && ( link = links.getItem( --index ) ) )
{
// Move the focus only if the element is marked with
// the _cke_focus and it it's visible (check if it has
// width).
if ( link.getAttribute( '_cke_focus' ) && link.$.offsetWidth )
{
this._.focusIndex = index;
link.focus();
break;
}
}
return false;
case 'click' :
index = this._.focusIndex;
link = index >= 0 && this.element.getElementsByTag( 'a' ).getItem( index );
if ( link )
link.$.click ? link.$.click() : link.$.onclick();
return false;
}
return true;
}
}
});
@@ -0,0 +1,140 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'panelbutton',
{
requires : [ 'button' ],
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_PANELBUTTON, CKEDITOR.ui.panelButton.handler );
}
});
/**
* Button UI element.
* @constant
* @example
*/
CKEDITOR.UI_PANELBUTTON = 4;
(function()
{
var clickFn = function( editor )
{
var _ = this._;
if ( _.state == CKEDITOR.TRISTATE_DISABLED )
return;
this.createPanel( editor );
if ( _.on )
{
_.panel.hide();
return;
}
_.panel.showBlock( this._.id, this.document.getById( this._.id ), 4 );
};
CKEDITOR.ui.panelButton = CKEDITOR.tools.createClass(
{
base : CKEDITOR.ui.button,
$ : function( definition )
{
// We don't want the panel definition in this object.
var panelDefinition = definition.panel;
delete definition.panel;
this.base( definition );
this.document = ( panelDefinition
&& panelDefinition.parent
&& panelDefinition.parent.getDocument() )
|| CKEDITOR.document;
this.hasArrow = true;
this.click = clickFn;
this._ =
{
panelDefinition : panelDefinition
};
},
statics :
{
handler :
{
create : function( definition )
{
return new CKEDITOR.ui.panelButton( definition );
}
}
},
proto :
{
createPanel : function( editor )
{
var _ = this._;
if ( _.panel )
return;
var panelDefinition = this._.panelDefinition || {},
panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
panel = this._.panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
me = this;
panel.onShow = function()
{
if ( me.className )
this.element.getFirst().addClass( me.className + '_panel' );
_.oldState = me._.state;
me.setState( CKEDITOR.TRISTATE_ON );
_.on = 1;
if ( me.onOpen )
me.onOpen();
};
panel.onHide = function()
{
if ( me.className )
this.element.getFirst().removeClass( me.className + '_panel' );
me.setState( _.oldState );
_.on = 0;
if ( me.onClose )
me.onClose();
};
panel.onEscape = function()
{
panel.hide();
me.document.getById( _.id ).focus();
};
if ( this.onBlock )
this.onBlock( panel, _.id );
panel.getBlock( _.id ).onHide = function()
{
_.on = 0;
me.setState( CKEDITOR.TRISTATE_OFF );
};
}
}
});
})();
@@ -0,0 +1,295 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'pastefromword', function( editor )
{
return {
title : editor.lang.pastefromword.title,
minWidth : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 370 : 350,
minHeight : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 270 : 260,
htmlToLoad : '<!doctype html><script type="text/javascript">'
+ 'window.onload = function()'
+ '{'
+ 'if ( ' + CKEDITOR.env.ie + ' ) '
+ 'document.body.contentEditable = "true";'
+ 'else '
+ 'document.designMode = "on";'
+ 'var iframe = new window.parent.CKEDITOR.dom.element( frameElement );'
+ 'var dialog = iframe.getCustomData( "dialog" );'
+ 'dialog.fire( "iframeAdded", { iframe : iframe } );'
+ '};'
+ '</script><style>body { margin: 3px; height: 95%; } </style><body></body>',
cleanWord : function( editor, html, ignoreFont, removeStyles )
{
html = html.replace(/<o:p>\s*<\/o:p>/g, '') ;
html = html.replace(/<o:p>[\s\S]*?<\/o:p>/g, '&nbsp;') ;
// Remove mso-xxx styles.
html = html.replace( /\s*mso-[^:]+:[^;"]+;?/gi, '' ) ;
// Remove margin styles.
html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*;/gi, '' ) ;
html = html.replace( /\s*MARGIN: 0cm 0cm 0pt\s*"/gi, "\"" ) ;
html = html.replace( /\s*TEXT-INDENT: 0cm\s*;/gi, '' ) ;
html = html.replace( /\s*TEXT-INDENT: 0cm\s*"/gi, "\"" ) ;
html = html.replace( /\s*TEXT-ALIGN: [^\s;]+;?"/gi, "\"" ) ;
html = html.replace( /\s*PAGE-BREAK-BEFORE: [^\s;]+;?"/gi, "\"" ) ;
html = html.replace( /\s*FONT-VARIANT: [^\s;]+;?"/gi, "\"" ) ;
html = html.replace( /\s*tab-stops:[^;"]*;?/gi, '' ) ;
html = html.replace( /\s*tab-stops:[^"]*/gi, '' ) ;
// Remove FONT face attributes.
if ( ignoreFont )
{
html = html.replace( /\s*face="[^"]*"/gi, '' ) ;
html = html.replace( /\s*face=[^ >]*/gi, '' ) ;
html = html.replace( /\s*FONT-FAMILY:[^;"]*;?/gi, '' ) ;
}
// Remove Class attributes
html = html.replace(/<(\w[^>]*) class=([^ |>]*)([^>]*)/gi, "<$1$3") ;
// Remove styles.
if ( removeStyles )
html = html.replace( /<(\w[^>]*) style="([^\"]*)"([^>]*)/gi, "<$1$3" ) ;
// Remove style, meta and link tags
html = html.replace( /<STYLE[^>]*>[\s\S]*?<\/STYLE[^>]*>/gi, '' ) ;
html = html.replace( /<(?:META|LINK)[^>]*>\s*/gi, '' ) ;
// Remove empty styles.
html = html.replace( /\s*style="\s*"/gi, '' ) ;
html = html.replace( /<SPAN\s*[^>]*>\s*&nbsp;\s*<\/SPAN>/gi, '&nbsp;' ) ;
html = html.replace( /<SPAN\s*[^>]*><\/SPAN>/gi, '' ) ;
// Remove Lang attributes
html = html.replace(/<(\w[^>]*) lang=([^ |>]*)([^>]*)/gi, "<$1$3") ;
html = html.replace( /<SPAN\s*>([\s\S]*?)<\/SPAN>/gi, '$1' ) ;
html = html.replace( /<FONT\s*>([\s\S]*?)<\/FONT>/gi, '$1' ) ;
// Remove XML elements and declarations
html = html.replace(/<\\?\?xml[^>]*>/gi, '' ) ;
// Remove w: tags with contents.
html = html.replace( /<w:[^>]*>[\s\S]*?<\/w:[^>]*>/gi, '' ) ;
// Remove Tags with XML namespace declarations: <o:p><\/o:p>
html = html.replace(/<\/?\w+:[^>]*>/gi, '' ) ;
// Remove comments [SF BUG-1481861].
html = html.replace(/<\!--[\s\S]*?-->/g, '' ) ;
html = html.replace( /<(U|I|STRIKE)>&nbsp;<\/\1>/g, '&nbsp;' ) ;
html = html.replace( /<H\d>\s*<\/H\d>/gi, '' ) ;
// Remove "display:none" tags.
html = html.replace( /<(\w+)[^>]*\sstyle="[^"]*DISPLAY\s?:\s?none[\s\S]*?<\/\1>/ig, '' ) ;
// Remove language tags
html = html.replace( /<(\w[^>]*) language=([^ |>]*)([^>]*)/gi, "<$1$3") ;
// Remove onmouseover and onmouseout events (from MS Word comments effect)
html = html.replace( /<(\w[^>]*) onmouseover="([^\"]*)"([^>]*)/gi, "<$1$3") ;
html = html.replace( /<(\w[^>]*) onmouseout="([^\"]*)"([^>]*)/gi, "<$1$3") ;
if ( editor.config.pasteFromWordKeepsStructure )
{
// The original <Hn> tag send from Word is something like this: <Hn style="margin-top:0px;margin-bottom:0px">
html = html.replace( /<H(\d)([^>]*)>/gi, '<h$1>' ) ;
// Word likes to insert extra <font> tags, when using MSIE. (Wierd).
html = html.replace( /<(H\d)><FONT[^>]*>([\s\S]*?)<\/FONT><\/\1>/gi, '<$1>$2<\/$1>' );
html = html.replace( /<(H\d)><EM>([\s\S]*?)<\/EM><\/\1>/gi, '<$1>$2<\/$1>' );
}
else
{
html = html.replace( /<H1([^>]*)>/gi, '<div$1><b><font size="6">' ) ;
html = html.replace( /<H2([^>]*)>/gi, '<div$1><b><font size="5">' ) ;
html = html.replace( /<H3([^>]*)>/gi, '<div$1><b><font size="4">' ) ;
html = html.replace( /<H4([^>]*)>/gi, '<div$1><b><font size="3">' ) ;
html = html.replace( /<H5([^>]*)>/gi, '<div$1><b><font size="2">' ) ;
html = html.replace( /<H6([^>]*)>/gi, '<div$1><b><font size="1">' ) ;
html = html.replace( /<\/H\d>/gi, '<\/font><\/b><\/div>' ) ;
// Transform <P> to <DIV>
var re = new RegExp( '(<P)([^>]*>[\\s\\S]*?)(<\/P>)', 'gi' ) ; // Different because of a IE 5.0 error
html = html.replace( re, '<div$2<\/div>' ) ;
// Remove empty tags (three times, just to be sure).
// This also removes any empty anchor
html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
html = html.replace( /<([^\s>]+)(\s[^>]*)?>\s*<\/\1>/g, '' ) ;
}
return html ;
},
onShow : function()
{
// To avoid JAWS putting virtual cursor back to the editor document,
// disable main document 'contentEditable' during dialog opening.
if ( CKEDITOR.env.ie )
this.getParentEditor().document.getBody().$.contentEditable = 'false';
// FIREFOX BUG: Force the browser to render the dialog to make the to-be-
// inserted iframe editable. (#3366)
this.parts.dialog.$.offsetHeight;
var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
iframe = CKEDITOR.dom.element.createFromHtml( '<iframe src="javascript:void(0)" frameborder="0" allowtransparency="1"></iframe>' );
var lang = this.getParentEditor().lang;
iframe.setStyles(
{
width : '346px',
height : '152px',
'background-color' : 'white',
border : '1px solid black'
} );
iframe.setCustomData( 'dialog', this );
var accTitle = lang.editorTitle.replace( '%1', lang.pastefromword.title );
if ( CKEDITOR.env.ie )
container.setHtml( '<legend style="position:absolute;top:-1000000px;left:-1000000px;">'
+ CKEDITOR.tools.htmlEncode( accTitle )
+ '</legend>' );
else
{
container.setHtml( '' );
container.setAttributes(
{
role : 'region',
title : accTitle
} );
iframe.setAttributes(
{
role : 'region',
title : ' '
} );
}
container.append( iframe );
if ( CKEDITOR.env.ie )
container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
var isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
if ( isCustomDomain )
{
CKEDITOR._cke_htmlToLoad = this.definition.htmlToLoad;
iframe.setAttribute( 'src',
'javascript:void( (function(){' +
'document.open();' +
'document.domain="' + document.domain + '";' +
'document.write( window.parent.CKEDITOR._cke_htmlToLoad );' +
'delete window.parent.CKEDITOR._cke_htmlToLoad;' +
'document.close();' +
'})() )' );
}
else
{
var doc = iframe.$.contentWindow.document;
doc.open();
doc.write( this.definition.htmlToLoad );
doc.close();
}
},
onOk : function()
{
var container = this.getContentElement( 'general', 'editing_area' ).getElement(),
iframe = container.getElementsByTag( 'iframe' ).getItem( 0 ),
editor = this.getParentEditor(),
html = this.definition.cleanWord( editor, iframe.$.contentWindow.document.body.innerHTML,
this.getValueOf( 'general', 'ignoreFontFace' ),
this.getValueOf( 'general', 'removeStyle' ) );
// Insertion should happen after main document design mode turned on.
setTimeout( function(){
editor.insertHtml( html );
}, 0 );
},
onHide : function()
{
if ( CKEDITOR.env.ie )
this.getParentEditor().document.getBody().$.contentEditable = 'true';
},
contents :
[
{
id : 'general',
label : editor.lang.pastefromword.title,
elements :
[
{
type : 'html',
style : 'white-space: normal;',
onShow : function()
{
/*
* SAFARI BUG: The advice label would overflow if the table layout
* isn't fixed.
*/
if ( CKEDITOR.env.webkit )
this.getElement().getAscendant( 'table' ).setStyle( 'table-layout', 'fixed' );
},
html : editor.lang.pastefromword.advice
},
{
type : 'html',
id : 'editing_area',
style : 'width: 100%; height: 100%;',
html : '<fieldset></fieldset>',
focus : function()
{
var div = this.getElement();
var iframe = div.getElementsByTag( 'iframe' );
if ( iframe.count() < 1 )
return;
iframe = iframe.getItem( 0 );
// #3291 : JAWS needs the 500ms delay to detect that the editor iframe
// iframe is no longer editable. So that it will put the focus into the
// Paste from Word dialog's editable area instead.
setTimeout( function()
{
iframe.$.contentWindow.focus();
}, 500 );
}
},
{
type : 'vbox',
padding : 0,
children :
[
{
type : 'checkbox',
id : 'ignoreFontFace',
label : editor.lang.pastefromword.ignoreFontFace,
'default' : true
},
{
type : 'checkbox',
id : 'removeStyle',
label : editor.lang.pastefromword.removeStyle
}
]
}
]
}
]
};
} );
@@ -0,0 +1,27 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'pastefromword',
{
init : function( editor )
{
// Register the command.
editor.addCommand( 'pastefromword', new CKEDITOR.dialogCommand( 'pastefromword' ) );
// Register the toolbar button.
editor.ui.addButton( 'PasteFromWord',
{
label : editor.lang.pastefromword.toolbar,
command : 'pastefromword'
} );
// Register the dialog.
CKEDITOR.dialog.add( 'pastefromword', this.path + 'dialogs/pastefromword.js' );
}
} );
CKEDITOR.config.pasteFromWordIgnoreFontFace = true;
CKEDITOR.config.pasteFromWordRemoveStyle = false;
CKEDITOR.config.pasteFromWordKeepsStructure = false;
@@ -0,0 +1,65 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
(function()
{
CKEDITOR.dialog.add( 'pastetext', function( editor )
{
return {
title : editor.lang.pasteText.title,
minWidth : CKEDITOR.env.ie && CKEDITOR.env.quirks ? 368 : 350,
minHeight : 240,
onShow : function()
{
// Reset the textarea value.
this.getContentElement( 'general', 'content' ).getInputElement().setValue( '' );
},
onOk : function()
{
// Get the textarea value.
var text = this.getContentElement( 'general', 'content' ).getInputElement().getValue();
// Inserts the text.
this.getParentEditor().insertText( text );
},
contents :
[
{
label : editor.lang.common.generalTab,
id : 'general',
elements :
[
{
type : 'html',
id : 'pasteMsg',
html : '<div style="white-space:normal;width:340px;">' + editor.lang.clipboard.pasteMsg + '</div>'
},
{
type : 'html',
id : 'content',
style : 'width:340px;height:170px',
html :
'<textarea style="' +
'width:346px;' +
'height:170px;' +
'resize: none;' +
'border:1px solid black;' +
'background-color:white">' +
'</textarea>',
focus : function()
{
this.getElement().focus();
}
}
]
}
]
};
});
})();
@@ -0,0 +1,130 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Paste as plain text plugin
*/
(function()
{
// The pastetext command definition.
var pasteTextCmd =
{
exec : function( editor )
{
// We use getClipboardData just to test if the clipboard access has
// been granted by the user.
if ( CKEDITOR.getClipboardData() === false || !window.clipboardData )
{
editor.openDialog( 'pastetext' );
return;
}
editor.insertText( window.clipboardData.getData( 'Text' ) );
}
};
// Register the plugin.
CKEDITOR.plugins.add( 'pastetext',
{
init : function( editor )
{
var commandName = 'pastetext',
command = editor.addCommand( commandName, pasteTextCmd );
editor.ui.addButton( 'PasteText',
{
label : editor.lang.pasteText.button,
command : commandName
});
CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/pastetext.js' ) );
if ( editor.config.forcePasteAsPlainText )
{
editor.on( 'beforePaste', function( event )
{
setTimeout( function() { command.exec(); }, 0 );
event.cancel();
},
null, null, 20 );
}
},
requires : [ 'clipboard' ]
});
var clipboardDiv;
CKEDITOR.getClipboardData = function()
{
if ( !CKEDITOR.env.ie )
return false;
var doc = CKEDITOR.document,
body = doc.getBody();
if ( !clipboardDiv )
{
clipboardDiv = doc.createElement( 'div',
{
attributes :
{
id: 'cke_hiddenDiv'
},
styles :
{
position : 'absolute',
visibility : 'hidden',
overflow : 'hidden',
width : '1px',
height : '1px'
}
});
clipboardDiv.setHtml( '' );
clipboardDiv.appendTo( body );
}
// The "enabled" flag is used to check whether the paste operation has
// been completed (the onpaste event has been fired).
var enabled = false;
var setEnabled = function()
{
enabled = true;
};
body.on( 'paste', setEnabled );
// Create a text range and move it inside the div.
var textRange = body.$.createTextRange();
textRange.moveToElementText( clipboardDiv.$ );
// The execCommand in will fire the "onpaste", only if the
// security settings are enabled.
textRange.execCommand( 'Paste' );
// Get the DIV html and reset it.
var html = clipboardDiv.getHtml();
clipboardDiv.setHtml( '' );
body.removeListener( 'paste', setEnabled );
// Return the HTML or false if not enabled.
return enabled && html;
};
})();
CKEDITOR.editor.prototype.insertText = function( text )
{
text = CKEDITOR.tools.htmlEncode( text );
// TODO: Replace the following with fill line break processing (see V2).
text = text.replace( /(?:\r\n)|\n|\r/g, '<br>' );
this.insertHtml( text );
};
CKEDITOR.config.forcePasteAsPlainText = false;
@@ -0,0 +1,62 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'popup');
CKEDITOR.tools.extend( CKEDITOR.editor.prototype,
{
/**
* Opens Browser in a popup. The "width" and "height" parameters accept
* numbers (pixels) or percent (of screen size) values.
* @param {String} url The url of the external file browser.
* @param {String} width Popup window width.
* @param {String} height Popup window height.
*/
popup : function( url, width, height )
{
width = width || '80%';
height = height || '70%';
if ( typeof width == 'string' && width.length > 1 && width.substr( width.length - 1, 1 ) == '%' )
width = parseInt( window.screen.width * parseInt( width, 10 ) / 100, 10 );
if ( typeof height == 'string' && height.length > 1 && height.substr( height.length - 1, 1 ) == '%' )
height = parseInt( window.screen.height * parseInt( height, 10 ) / 100, 10 );
if ( width < 640 )
width = 640;
if ( height < 420 )
height = 420;
var top = parseInt( ( window.screen.height - height ) / 2, 10 ),
left = parseInt( ( window.screen.width - width ) / 2, 10 ),
options = 'location=no,menubar=no,toolbar=no,dependent=yes,minimizable=no,modal=yes,alwaysRaised=yes,resizable=yes' +
',width=' + width +
',height=' + height +
',top=' + top +
',left=' + left;
var popupWindow = window.open( '', null, options, true );
// Blocked by a popup blocker.
if ( !popupWindow )
return false;
try
{
popupWindow.moveTo( left, top );
popupWindow.resizeTo( width, height );
popupWindow.focus();
popupWindow.location.href = url;
}
catch (e)
{
popupWindow = window.open( url, null, options, true );
}
return true ;
}
});
@@ -0,0 +1,97 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Preview plugin.
*/
(function()
{
var previewCmd =
{
modes : { wysiwyg:1, source:1 },
canUndo : false,
exec : function( editor )
{
var sHTML,
isCustomDomain = CKEDITOR.env.ie && document.domain != window.location.hostname;
if ( editor.config.fullPage )
sHTML = editor.getData();
else
{
var bodyHtml = '<body ',
body = CKEDITOR.document.getBody(),
baseTag = ( editor.config.baseHref.length > 0 ) ? '<base href="' + editor.config.baseHref + '" _cktemp="true"></base>' : '';
if ( body.getAttribute( 'id' ) )
bodyHtml += 'id="' + body.getAttribute( 'id' ) + '" ';
if ( body.getAttribute( 'class' ) )
bodyHtml += 'class="' + body.getAttribute( 'class' ) + '" ';
bodyHtml += '>';
sHTML =
editor.config.docType +
'<html dir="' + editor.config.contentsLangDirection + '">' +
'<head>' +
baseTag +
'<title>' + editor.lang.preview + '</title>' +
'<link href="' + editor.config.contentsCss + '" type="text/css" rel="stylesheet" _cktemp="true"/>' +
'</head>' + bodyHtml +
editor.getData() +
'</body></html>';
}
var iWidth = 640, // 800 * 0.8,
iHeight = 420, // 600 * 0.7,
iLeft = 80; // (800 - 0.8 * 800) /2 = 800 * 0.1.
try
{
var screen = window.screen;
iWidth = Math.round( screen.width * 0.8 );
iHeight = Math.round( screen.height * 0.7 );
iLeft = Math.round( screen.width * 0.1 );
}
catch ( e ){}
var sOpenUrl = '';
if ( isCustomDomain )
{
window._cke_htmlToLoad = sHTML;
sOpenUrl = 'javascript:void( (function(){' +
'document.open();' +
'document.domain="' + document.domain + '";' +
'document.write( window.opener._cke_htmlToLoad );' +
'document.close();' +
'window.opener._cke_htmlToLoad = null;' +
'})() )';
}
var oWindow = window.open( sOpenUrl, null, 'toolbar=yes,location=no,status=yes,menubar=yes,scrollbars=yes,resizable=yes,width=' +
iWidth + ',height=' + iHeight + ',left=' + iLeft );
if ( !isCustomDomain )
{
oWindow.document.write( sHTML );
oWindow.document.close();
}
}
};
var pluginName = 'preview';
// Register a plugin named "preview".
CKEDITOR.plugins.add( pluginName,
{
init : function( editor )
{
editor.addCommand( pluginName, previewCmd );
editor.ui.addButton( 'Preview',
{
label : editor.lang.preview,
command : pluginName
});
}
});
})();
@@ -0,0 +1,41 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @file Print Plugin
*/
CKEDITOR.plugins.add( 'print',
{
init : function( editor )
{
var pluginName = 'print';
// Register the command.
var command = editor.addCommand( pluginName, CKEDITOR.plugins.print );
// Register the toolbar button.
editor.ui.addButton( 'Print',
{
label : editor.lang.print,
command : pluginName
});
}
} );
CKEDITOR.plugins.print =
{
exec : function( editor )
{
if ( CKEDITOR.env.opera )
return;
else if ( CKEDITOR.env.gecko )
editor.window.$.print();
else
editor.document.$.execCommand( "Print" );
},
canUndo : false,
modes : { wysiwyg : !( CKEDITOR.env.opera ) } // It is imposible to print the inner document in Opera.
};
@@ -0,0 +1,119 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'removeformat',
{
requires : [ 'selection' ],
init : function( editor )
{
editor.addCommand( 'removeFormat', CKEDITOR.plugins.removeformat.commands.removeformat );
editor.ui.addButton( 'RemoveFormat',
{
label : editor.lang.removeFormat,
command : 'removeFormat'
});
}
});
CKEDITOR.plugins.removeformat =
{
commands :
{
removeformat :
{
exec : function( editor )
{
var tagsRegex = editor._.removeFormatRegex ||
( editor._.removeFormatRegex = new RegExp( '^(?:' + editor.config.removeFormatTags.replace( /,/g,'|' ) + ')$', 'i' ) );
var removeAttributes = editor._.removeAttributes ||
( editor._.removeAttributes = editor.config.removeFormatAttributes.split( ',' ) );
var ranges = editor.getSelection().getRanges();
for ( var i = 0, range ; range = ranges[ i ] ; i++ )
{
if ( range.collapsed )
continue;
range.enlarge( CKEDITOR.ENLARGE_ELEMENT );
// Bookmark the range so we can re-select it after processing.
var bookmark = range.createBookmark();
// The style will be applied within the bookmark boundaries.
var startNode = bookmark.startNode;
var endNode = bookmark.endNode;
// 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>
var breakParent = function( node )
{
// Let's start checking the start boundary.
var path = new CKEDITOR.dom.elementPath( node );
var pathElements = path.elements;
for ( var i = 1, pathElement ; pathElement = pathElements[ i ] ; i++ )
{
if ( pathElement.equals( path.block ) || pathElement.equals( path.blockLimit ) )
break;
// If this element can be removed (even partially).
if ( tagsRegex.test( pathElement.getName() ) )
node.breakParent( pathElement );
}
};
breakParent( startNode );
breakParent( endNode );
// Navigate through all nodes between the bookmarks.
var currentNode = startNode.getNextSourceNode( true, CKEDITOR.NODE_ELEMENT );
while ( currentNode )
{
// If we have reached the end of the selection, stop looping.
if ( currentNode.equals( endNode ) )
break;
// Cache the next node to be processed. Do it now, because
// currentNode may be removed.
var nextNode = currentNode.getNextSourceNode( false, CKEDITOR.NODE_ELEMENT );
// This node must not be a fake element.
if ( currentNode.getName() != 'img' || !currentNode.getAttribute( '_cke_protected_html' ) )
{
// Remove elements nodes that match with this style rules.
if ( tagsRegex.test( currentNode.getName() ) )
currentNode.remove( true );
else
currentNode.removeAttributes( removeAttributes );
}
currentNode = nextNode;
}
range.moveToBookmark( bookmark );
}
editor.getSelection().selectRanges( ranges );
}
}
}
};
// Only inline elements are valid.
CKEDITOR.config.removeFormatTags = 'b,big,code,del,dfn,em,font,i,ins,kbd,q,samp,small,span,strike,strong,sub,sup,tt,u,var';
CKEDITOR.config.removeFormatAttributes = 'class,style,lang,width,height,align,hspace,valign';
@@ -0,0 +1,76 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'resize',
{
init : function( editor )
{
var config = editor.config;
if ( config.resize_enabled )
{
var container = null;
var origin, startSize;
function dragHandler( evt )
{
var dx = evt.data.$.screenX - origin.x;
var dy = evt.data.$.screenY - origin.y;
var internalWidth = startSize.width + dx * ( editor.lang.dir == 'rtl' ? -1 : 1 );
var internalHeight = startSize.height + dy;
editor.resize( Math.max( config.resize_minWidth, Math.min( internalWidth, config.resize_maxWidth ) ),
Math.max( config.resize_minHeight, Math.min( internalHeight, config.resize_maxHeight ) ) );
}
function dragEndHandler ( evt )
{
CKEDITOR.document.removeListener( 'mousemove', dragHandler );
CKEDITOR.document.removeListener( 'mouseup', dragEndHandler );
if ( editor.document )
{
editor.document.removeListener( 'mousemove', dragHandler );
editor.document.removeListener( 'mouseup', dragEndHandler );
}
}
var mouseDownFn = CKEDITOR.tools.addFunction( function( $event )
{
if ( !container )
container = editor.getResizable();
startSize = { width : container.$.offsetWidth || 0, height : container.$.offsetHeight || 0 };
origin = { x : $event.screenX, y : $event.screenY };
CKEDITOR.document.on( 'mousemove', dragHandler );
CKEDITOR.document.on( 'mouseup', dragEndHandler );
if ( editor.document )
{
editor.document.on( 'mousemove', dragHandler );
editor.document.on( 'mouseup', dragEndHandler );
}
} );
editor.on( 'themeSpace', function( event )
{
if ( event.data.space == 'bottom' )
{
event.data.html += '<div class="cke_resizer"' +
' title="' + CKEDITOR.tools.htmlEncode( editor.lang.resize ) + '"' +
' onmousedown="CKEDITOR.tools.callFunction(' + mouseDownFn + ', event)"' +
'></div>';
}
}, editor, null, 100 );
}
}
} );
CKEDITOR.config.resize_minWidth = 750;
CKEDITOR.config.resize_minHeight = 250;
CKEDITOR.config.resize_maxWidth = 3000;
CKEDITOR.config.resize_maxHeight = 3000;
CKEDITOR.config.resize_enabled = true;
@@ -0,0 +1,357 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.plugins.add( 'richcombo',
{
requires : [ 'floatpanel', 'listblock', 'button' ],
beforeInit : function( editor )
{
editor.ui.addHandler( CKEDITOR.UI_RICHCOMBO, CKEDITOR.ui.richCombo.handler );
}
});
/**
* Button UI element.
* @constant
* @example
*/
CKEDITOR.UI_RICHCOMBO = 3;
CKEDITOR.ui.richCombo = CKEDITOR.tools.createClass(
{
$ : function( definition )
{
// Copy all definition properties to this object.
CKEDITOR.tools.extend( this, definition,
// Set defaults.
{
title : definition.label,
modes : { wysiwyg : 1 }
});
// We don't want the panel definition in this object.
var panelDefinition = this.panel || {};
delete this.panel;
this.id = CKEDITOR.tools.getNextNumber();
this.document = ( panelDefinition
&& panelDefinition.parent
&& panelDefinition.parent.getDocument() )
|| CKEDITOR.document;
panelDefinition.className = ( panelDefinition.className || '' ) + ' cke_rcombopanel';
this._ =
{
panelDefinition : panelDefinition,
items : {},
state : CKEDITOR.TRISTATE_OFF
};
},
statics :
{
handler :
{
create : function( definition )
{
return new CKEDITOR.ui.richCombo( definition );
}
}
},
proto :
{
renderHtml : function( editor )
{
var output = [];
this.render( editor, output );
return output.join( '' );
},
/**
* Renders the combo.
* @param {CKEDITOR.editor} editor The editor instance which this button is
* to be used by.
* @param {Array} output The output array to which append the HTML relative
* to this button.
* @example
*/
render : function( editor, output )
{
var id = 'cke_' + this.id;
var clickFn = CKEDITOR.tools.addFunction( function( $element )
{
var _ = this._;
if ( _.state == CKEDITOR.TRISTATE_DISABLED )
return;
this.createPanel( editor );
if ( _.on )
{
_.panel.hide();
return;
}
if ( !_.committed )
{
_.list.commit();
_.committed = 1;
}
var value = this.getValue();
if ( value )
_.list.mark( value );
else
_.list.unmarkAll();
_.panel.showBlock( this.id, new CKEDITOR.dom.element( $element ), 4 );
},
this );
var instance = {
id : id,
combo : this,
focus : function()
{
var element = CKEDITOR.document.getById( id ).getChild( 1 );
element.focus();
},
execute : clickFn
};
editor.on( 'mode', function()
{
this.setState( this.modes[ editor.mode ] ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
},
this );
var keyDownFn = CKEDITOR.tools.addFunction( function( ev, element )
{
ev = new CKEDITOR.dom.event( ev );
var keystroke = ev.getKeystroke();
switch ( keystroke )
{
case 13 : // ENTER
case 32 : // SPACE
case 40 : // ARROW-DOWN
// Show panel
CKEDITOR.tools.callFunction( clickFn, element );
break;
default :
// Delegate the default behavior to toolbar button key handling.
instance.onkey( instance, keystroke );
}
// Avoid subsequent focus grab on editor document.
ev.preventDefault();
});
output.push(
'<span class="cke_rcombo">',
'<span id=', id );
if ( this.className )
output.push( ' class="', this.className, ' cke_off"');
output.push(
'>' +
'<span class=cke_label>', this.label, '</span>' +
'<a hidefocus=true title="', this.title, '" tabindex="-1" href="javascript:void(\'', this.label, '\')"' );
// Some browsers don't cancel key events in the keydown but in the
// keypress.
// TODO: Check if really needed for Gecko+Mac.
if ( CKEDITOR.env.opera || ( CKEDITOR.env.gecko && CKEDITOR.env.mac ) )
{
output.push(
' onkeypress="return false;"' );
}
// With Firefox, we need to force it to redraw, otherwise it
// will remain in the focus state.
if ( CKEDITOR.env.gecko )
{
output.push(
' onblur="this.style.cssText = this.style.cssText;"' );
}
output.push(
' onkeydown="CKEDITOR.tools.callFunction( ', keyDownFn, ', event, this );"' +
' onclick="CKEDITOR.tools.callFunction(', clickFn, ', this); return false;">' +
'<span>' +
'<span class="cke_accessibility">' + ( this.voiceLabel ? this.voiceLabel + ' ' : '' ) + '</span>' +
'<span id="' + id + '_text" class="cke_text cke_inline_label">' + this.label + '</span>' +
'</span>' +
'<span class=cke_openbutton></span>' +
'</a>' +
'</span>' +
'</span>' );
if ( this.onRender )
this.onRender();
return instance;
},
createPanel : function( editor )
{
if ( this._.panel )
return;
var panelDefinition = this._.panelDefinition,
panelParentElement = panelDefinition.parent || CKEDITOR.document.getBody(),
panel = new CKEDITOR.ui.floatPanel( editor, panelParentElement, panelDefinition ),
list = panel.addListBlock( this.id, this.multiSelect ),
me = this;
panel.onShow = function()
{
if ( me.className )
this.element.getFirst().addClass( me.className + '_panel' );
me.setState( CKEDITOR.TRISTATE_ON );
list.focus( !me.multiSelect && me.getValue() );
me._.on = 1;
if ( me.onOpen )
me.onOpen();
};
panel.onHide = function()
{
if ( me.className )
this.element.getFirst().removeClass( me.className + '_panel' );
me.setState( CKEDITOR.TRISTATE_OFF );
me._.on = 0;
if ( me.onClose )
me.onClose();
};
panel.onEscape = function()
{
panel.hide();
me.document.getById( 'cke_' + me.id ).getFirst().getNext().focus();
};
list.onClick = function( value, marked )
{
// Move the focus to the main windows, otherwise it will stay
// into the floating panel, even if invisible, and Safari and
// Opera will go a bit crazy.
me.document.getWindow().focus();
if ( me.onClick )
me.onClick.call( me, value, marked );
if ( marked )
me.setValue( value, me._.items[ value ] );
else
me.setValue( '' );
panel.hide();
};
this._.panel = panel;
this._.list = list;
panel.getBlock( this.id ).onHide = function()
{
me._.on = 0;
me.setState( CKEDITOR.TRISTATE_OFF );
};
if ( this.init )
this.init();
},
setValue : function( value, text )
{
this._.value = value;
var textElement = this.document.getById( 'cke_' + this.id + '_text' );
if ( !value )
{
text = this.label;
textElement.addClass( 'cke_inline_label' );
}
else
textElement.removeClass( 'cke_inline_label' );
textElement.setHtml( typeof text != 'undefined' ? text : value );
},
getValue : function()
{
return this._.value || '';
},
unmarkAll : function()
{
this._.list.unmarkAll();
},
mark : function( value )
{
this._.list.mark( value );
},
hideItem : function( value )
{
this._.list.hideItem( value );
},
hideGroup : function( groupTitle )
{
this._.list.hideGroup( groupTitle );
},
showAll : function()
{
this._.list.showAll();
},
add : function( value, html, text )
{
this._.items[ value ] = text || value;
this._.list.add( value, html, text );
},
startGroup : function( title )
{
this._.list.startGroup( title );
},
commit : function()
{
this._.list.commit();
},
setState : function( state )
{
if ( this._.state == state )
return;
this.document.getById( 'cke_' + this.id ).setState( state );
this._.state = state;
}
}
});
CKEDITOR.ui.prototype.addRichCombo = function( name, definition )
{
this.add( name, CKEDITOR.UI_RICHCOMBO, definition );
};
@@ -0,0 +1,55 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileSave plugin.
*/
(function()
{
var saveCmd =
{
modes : { wysiwyg:1, source:1 },
exec : function( editor )
{
var $form = editor.element.$.form;
if ( $form )
{
try
{
$form.submit();
}
catch( e )
{
// If there's a button named "submit" then the form.submit
// function is masked and can't be called in IE/FF, so we
// call the click() method of that button.
if ( $form.submit.click )
$form.submit.click();
}
}
}
};
var pluginName = 'save';
// Register a plugin named "save".
CKEDITOR.plugins.add( pluginName,
{
init : function( editor )
{
var command = editor.addCommand( pluginName, saveCmd );
command.modes = { wysiwyg : !!( editor.element.$.form ) };
editor.ui.addButton( 'Save',
{
label : editor.lang.save,
command : pluginName
});
}
});
})();
@@ -0,0 +1,468 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'scaytcheck', function( editor )
{
var firstLoad = true,
captions,
doc = CKEDITOR.document,
fckLang = 'en';
var dic_buttons = [
// [0] contains buttons for creating
"dic_create,dic_restore",
// [1] contains buton for manipulation
"dic_rename,dic_delete"
];
var init_with_captions = function()
{
var dialog = this,
lang_list = dialog.data.scayt.getLangList(),
buttons = [ 'dic_create','dic_delete','dic_rename','dic_restore' ],
labels = [ 'mixedCase','mixedWithDigits','allCaps','ignoreDomainNames' ],
i;
// Add buttons titles
for ( i in buttons )
{
var button = buttons[ i ];
doc.getById( button ).setHtml( '<span class="cke_dialog_ui_button">' + captions[ 'button_' + button] +'</span>' );
}
doc.getById( 'dic_info' ).setHtml( captions[ 'dic_info' ] );
// Fill options and dictionary labels.
for ( i in labels )
{
var label = 'label_' + labels[ i ],
labelElement = doc.getById( label );
if ( 'undefined' != typeof labelElement
&& 'undefined' != typeof captions[ label ]
&& 'undefined' != typeof dialog.options[labels[ i ]] )
{
labelElement.setHtml( captions[ label ] );
var labelParent = labelElement.getParent();
labelParent.$.style.display = "block";
}
}
var about = '<p>' + captions[ 'about_throwt_image' ] + '</p>'+
'<p>' + captions[ 'version' ] + dialog.data.scayt.version.toString() + '</p>' +
'<p>' + captions[ 'about_throwt_copy' ] + '</p>';
doc.getById( 'scayt_about' ).setHtml( about );
// Create languages tab.
var createOption = function( option, list )
{
var label = doc.createElement( 'label' );
label.setAttribute( 'for', 'cke_option' + option );
label.setHtml( list[ option ] );
if ( dialog.sLang == option ) // Current.
dialog.chosed_lang = option;
var div = doc.createElement( 'div' );
var radio = CKEDITOR.dom.element.createFromHtml( '<input id="cke_option' +
option + '" type="radio" ' +
( dialog.sLang == option ? 'checked="checked"' : '' ) +
' value="' + option + '" name="scayt_lang" />' );
radio.on( 'click', function()
{
this.$.checked = true;
dialog.chosed_lang = option;
});
div.append( radio );
div.append( label );
return {
lang : list[ option ],
code : option,
radio : div
};
};
var langList = [];
for ( i in lang_list.rtl )
langList[ langList.length ] = createOption( i, lang_list.ltr );
for ( i in lang_list.ltr )
langList[ langList.length ] = createOption( i, lang_list.ltr );
langList.sort( function( lang1, lang2 )
{
return ( lang2.lang > lang1.lang ) ? -1 : 1 ;
});
var fieldL = doc.getById( 'scayt_lcol' ),
fieldR = doc.getById( 'scayt_rcol' );
for ( i=0; i < langList.length; i++ )
{
var field = ( i < langList.length / 2 ) ? fieldL : fieldR;
field.append( langList[ i ].radio );
}
// user dictionary handlers
var dic = {};
dic.dic_create = function( el, dic_name , dic_buttons )
{
// comma separated button's ids include repeats if exists
var all_buttons = dic_buttons[0] + ',' + dic_buttons[1];
var err_massage = captions["err_dic_create"];
var suc_massage = captions["succ_dic_create"];
//console.info("--plugin ");
scayt.createUserDictionary(dic_name,
function(arg)
{
//console.info( "dic_create callback called with args" , arg );
hide_dic_buttons ( all_buttons );
display_dic_buttons ( dic_buttons[1] );
suc_massage = suc_massage.replace("%s" , arg.dname );
dic_success_message (suc_massage);
},
function(arg)
{
//console.info( "dic_create errorback called with args" , arg )
err_massage = err_massage.replace("%s" ,arg.dname );
dic_error_message ( err_massage + "( "+ (arg.message || "") +")");
});
};
dic.dic_rename = function( el, dic_name , dic_buttons )
{
//
// try to rename dictionary
// @TODO: rename dict
//console.info ( captions["err_dic_rename"] )
var err_massage = captions["err_dic_rename"] || "";
var suc_massage = captions["succ_dic_rename"] || "";
scayt.renameUserDictionary(dic_name,
function(arg)
{
//console.info( "dic_rename callback called with args" , arg );
suc_massage = suc_massage.replace("%s" , arg.dname );
set_dic_name( dic_name );
dic_success_message ( suc_massage );
},
function(arg)
{
//console.info( "dic_rename errorback called with args" , arg )
err_massage = err_massage.replace("%s" , arg.dname );
set_dic_name( dic_name );
dic_error_message( err_massage + "( " + ( arg.message || "" ) + " )" );
});
};
dic.dic_delete = function ( el, dic_name , dic_buttons )
{
var all_buttons = dic_buttons[0] + ',' + dic_buttons[1];
var err_massage = captions["err_dic_delete"];
var suc_massage = captions["succ_dic_delete"];
// try to delete dictionary
// @TODO: delete dict
scayt.deleteUserDictionary(
function(arg)
{
//console.info( "dic_delete callback " , dic_name ,arg );
suc_massage = suc_massage.replace("%s" , arg.dname );
hide_dic_buttons ( all_buttons );
display_dic_buttons ( dic_buttons[0] );
set_dic_name( "" ); // empty input field
dic_success_message( suc_massage );
},
function(arg)
{
//console.info( " dic_delete errorback called with args" , arg )
err_massage = err_massage.replace("%s" , arg.dname );
dic_error_message(err_massage);
});
};
dic.dic_restore = dialog.dic_restore || function ( el, dic_name , dic_buttons )
{
// try to restore existing dictionary
var all_buttons = dic_buttons[0] + ',' + dic_buttons[1];
var err_massage = captions["err_dic_restore"];
var suc_massage = captions["succ_dic_restore"];
scayt.restoreUserDictionary(dic_name,
function(arg)
{
//console.info( "dic_restore callback called with args" , arg );
suc_massage = suc_massage.replace("%s" , arg.dname );
hide_dic_buttons ( all_buttons );
display_dic_buttons(dic_buttons[1]);
dic_success_message( suc_massage );
},
function(arg)
{
//console.info( " dic_restore errorback called with args" , arg )
err_massage = err_massage.replace("%s" , arg.dname );
dic_error_message( err_massage );
});
};
// ** bind event listeners
var arr_buttons = ( dic_buttons[0] + ',' + dic_buttons[1] ).split( ',' ),
l;
for ( i = 0, l = arr_buttons.length ; i < l ; i += 1 )
{
var dic_button = doc.getById(arr_buttons[i]);
dic_button.on( 'click', function ()
{
var dic_name = doc.getById('dic_name').getValue();
if ( !dic_name )
{
dic_error_message(" Dictionary name should not be empty. ");
return false;
}
//apply handler
dic[ this.getId() ].apply( null, [ this, dic_name, dic_buttons ] );
return true;
});
}
};
var reload = function()
{
var dialog = this;
// Animate options.
for ( var i in dialog.options )
{
var checkbox = doc.getById( i );
if ( checkbox )
{
checkbox.removeAttribute( 'checked' );
if ( dialog.options[ i ] == 1 )
checkbox.setAttribute( 'checked', 'checked' );
// Bind events. Do it only once.
if ( firstLoad )
{
checkbox.on( 'click', function()
{
dialog.options[ this.getId() ] = this.$.checked ? 1 : 0 ;
} );
}
}
}
// * user dictionary
scayt.getNameUserDictionary(
function( o )
{
var dic_name = o.dname;
if ( dic_name )
{
doc.getById( 'dic_name' ).setValue(dic_name);
display_dic_buttons( dic_buttons[1] );
}
else
display_dic_buttons( dic_buttons[0] );
},
function ()
{
doc.getById( 'dic_name' ).setValue("");
});
dic_success_message("");
};
function dic_error_message ( m )
{
doc.getById('dic_message').setHtml('<span style="color:red;">' + m + '</span>' );
}
function dic_success_message ( m )
{
doc.getById('dic_message').setHtml('<span style="color:blue;">' + m + '</span>') ;
}
function display_dic_buttons ( sIds )
{
sIds = new String( sIds );
var aIds = sIds.split(',');
for ( var i=0, l = aIds.length; i < l ; i+=1)
{
doc.getById( aIds[i] ).$.style.display = "inline";
}
}
function hide_dic_buttons ( sIds )
{
sIds = new String( sIds );
var aIds = sIds.split(',');
for ( var i = 0, l = aIds.length; i < l ; i += 1 )
{
doc.getById( aIds[i] ).$.style.display = "none";
}
}
function set_dic_name ( dic_name )
{
doc.getById('dic_name').$.value= dic_name;
}
return {
title : editor.lang.scayt.title,
minWidth : 340,
minHeight : 200,
onShow : function()
{
var dialog = this;
dialog.data = editor.fire( 'scaytDialog', {} );
dialog.options = dialog.data.scayt_control.option();
dialog.sLang = dialog.data.scayt_control.sLang;
if ( !dialog.data || !dialog.data.scayt || !dialog.data.scayt_control )
{
alert( 'Error loading application service' );
dialog.hide();
return;
}
var stop = 0;
if ( firstLoad )
{
dialog.data.scayt.getCaption( 'en', function( caps )
{
if ( stop++ > 0 ) // Once only
return;
captions = caps;
init_with_captions.apply( dialog );
reload.apply( dialog );
firstLoad = false;
});
}
else
reload.apply( dialog );
dialog.selectPage( dialog.data.tab );
},
onOk : function()
{
var scayt_control = this.data.scayt_control,
o = scayt_control.option(),
c = 0;
// Set up options if any was set.
for ( var oN in this.options )
{
if (o[oN] != this.options[ oN ] && c === 0 )
{
scayt_control.option( this.options );
c++;
}
}
// Setup languge if it was changed.
var csLang = this.chosed_lang;
if ( csLang && this.data.sLang != csLang )
{
scayt_control.setLang( csLang );
c++;
}
if ( c > 0 )
scayt_control.refresh();
},
contents : [
{
id : 'options',
label : editor.lang.scayt.optionsTab,
elements : [
{
type : 'html',
id : 'options',
html : '<div class="inner_options">' +
' <div class="messagebox"></div>' +
' <div style="display:none;">' +
' <input type="checkbox" value="0" id="allCaps" />' +
' <label for="allCaps" id="label_allCaps"></label>' +
' </div>' +
' <div style="display:none;">' +
' <input type="checkbox" value="0" id="ignoreDomainNames" />' +
' <label for="ignoreDomainNames" id="label_ignoreDomainNames"></label>' +
' </div>' +
' <div style="display:none;">' +
' <input type="checkbox" value="0" id="mixedCase" />' +
' <label for="mixedCase" id="label_mixedCase"></label>' +
' </div>' +
' <div style="display:none;">' +
' <input type="checkbox" value="0" id="mixedWithDigits" />' +
' <label for="mixedWithDigits" id="label_mixedWithDigits"></label>' +
' </div>' +
'</div>'
}
]
},
{
id : 'langs',
label : editor.lang.scayt.languagesTab,
elements : [
{
type : 'html',
id : 'langs',
html : '<div class="inner_langs">' +
' <div class="messagebox"></div> ' +
' <div style="float:left;width:47%;margin-left:5px;" id="scayt_lcol" ></div>' +
' <div style="float:left;width:47%;margin-left:15px;" id="scayt_rcol"></div>' +
'</div>'
}
]
},
{
id : 'dictionaries',
label : editor.lang.scayt.dictionariesTab,
elements : [
{
type : 'html',
style: '',
id : 'dic',
html : '<div class="inner_dictionary" style="text-align:left; white-space:normal;">' +
' <div style="margin:5px auto; width:80%;white-space:normal; overflow:hidden;" id="dic_message"> </div>' +
' <div style="margin:5px auto; width:80%;white-space:normal;"> ' +
' <span class="cke_dialog_ui_labeled_label" >Dictionary name</span><br>'+
' <span class="cke_dialog_ui_labeled_content" >'+
' <div class="cke_dialog_ui_input_text">'+
' <input id="dic_name" type="text" class="cke_dialog_ui_input_text"/>'+
' </div></span></div>'+
' <div style="margin:5px auto; width:80%;white-space:normal;">'+
' <a style="display:none;" class="cke_dialog_ui_button" href="javascript:void(0)" id="dic_create">'+
' </a>' +
' <a style="display:none;" class="cke_dialog_ui_button" href="javascript:void(0)" id="dic_delete">'+
' </a>' +
' <a style="display:none;" class="cke_dialog_ui_button" href="javascript:void(0)" id="dic_rename">'+
' </a>' +
' <a style="display:none;" class="cke_dialog_ui_button" href="javascript:void(0)" id="dic_restore">'+
' </a>' +
' </div>' +
' <div style="margin:5px auto; width:95%;white-space:normal;" id="dic_info"></div>' +
'</div>'
}
]
},
{
id : 'about',
label : editor.lang.scayt.aboutTab,
elements : [
{
type : 'html',
id : 'about',
style : 'margin: 10px 40px;',
html : '<div id="scayt_about"></div>'
}
]
}
]
};
});
@@ -0,0 +1,71 @@
a
{
text-decoration:none;
padding: 2px 4px 4px 6px;
display : block;
border-width: 1px;
border-style: solid;
margin : 0px;
}
a.cke_scayt_toogle:hover,
a.cke_scayt_toogle:focus,
a.cke_scayt_toogle:active
{
border-color: #316ac5;
background-color: #dff1ff;
color : #000;
cursor: pointer;
margin : 0px;
}
a.cke_scayt_toogle {
color : #316ac5;
border-color: #fff;
}
.scayt_enabled a.cke_scayt_item {
color : #316ac5;
border-color: #fff;
margin : 0px;
}
.scayt_disabled a.cke_scayt_item {
color : gray;
border-color : #fff;
}
.scayt_enabled a.cke_scayt_item:hover,
.scayt_enabled a.cke_scayt_item:focus,
.scayt_enabled a.cke_scayt_item:active
{
border-color: #316ac5;
background-color: #dff1ff;
color : #000;
cursor: pointer;
}
.scayt_disabled a.cke_scayt_item:hover,
.scayt_disabled a.cke_scayt_item:focus,
.scayt_disabled a.cke_scayt_item:active
{
border-color: gray;
background-color: #dff1ff;
color : gray;
cursor: no-drop;
}
.cke_scayt_set_on, .cke_scayt_set_off
{
display: none;
}
.scayt_enabled .cke_scayt_set_on
{
display: none;
}
.scayt_disabled .cke_scayt_set_on
{
display: inline;
}
.scayt_disabled .cke_scayt_set_off
{
display: none;
}
.scayt_enabled .cke_scayt_set_off
{
display: inline;
}
@@ -0,0 +1,485 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview Spell Check As You Type (SCAYT).
* Button name : Scayt.
*/
(function()
{
var commandName = 'scaytcheck',
sc_on_cssclass = 'scayt_enabled',
sc_off_cssclass = 'scayt_disabled',
openPage = '';
var onEngineLoad = function()
{
var editor = this;
dojo.requireLocalization( 'scayt', 'caption', '', 'ROOT' );
var createInstance = function() // Create new instance every time Document is created.
{
// Initialise Scayt instance.
var oParams = CKEDITOR.config.scaytParams || {};
oParams.srcNodeRef = editor.document.getWindow().$.frameElement; // Get the iframe.
// syntax : AppName.AppVersion@AppRevision
oParams.assocApp = "CKEDITOR." + CKEDITOR.version + "@" + CKEDITOR.revision;
var scayt_control = new scayt( oParams );
// Copy config.
var lastInstance = plugin.instances[ editor.name ];
if ( lastInstance )
{
scayt_control.sLang = lastInstance.sLang;
scayt_control.option( lastInstance.option() );
scayt_control.paused = lastInstance.paused;
}
plugin.instances[ editor.name ] = scayt_control;
try {
scayt_control.setDisabled( scayt_control.paused === false ); // I really don't know why it causes JS error in IE
} catch (e) {}
editor.fire( 'showScaytState' );
};
editor.on( 'contentDom', createInstance );
editor.on( 'contentDomUnload', function()
{
// Remove scripts.
var scripts = CKEDITOR.document.getElementsByTag( 'script' ),
scaytIdRegex = /^dojoIoScript(\d+)$/i,
scaytSrcRegex = /^https?:\/\/svc\.spellchecker\.net\/spellcheck\/script\/ssrv\.cgi/i;
for ( var i=0; i < scripts.count(); i++ )
{
var script = scripts.getItem( i ),
id = script.getId(),
src = script.getAttribute( 'src' );
if ( id && src && id.match( scaytIdRegex ) && src.match( scaytSrcRegex ))
script.remove();
}
});
editor.on( 'beforeCommandExec', function( ev ) // Disable SCAYT before Source command execution.
{
if ( ev.data.name == 'source' && editor.mode == 'wysiwyg' )
{
var scayt = plugin.getScayt( editor );
if ( scayt )
{
scayt.paused = !scayt.disabled;
scayt.setDisabled( true );
}
}
});
// Listen to data manipulation to reflect scayt markup.
editor.on( 'afterSetData', function()
{
if ( plugin.isScaytEnabled( editor ) )
plugin.getScayt( editor ).refresh();
});
editor.on( 'scaytDialog', function( ev ) // Communication with dialog.
{
ev.data.djConfig = djConfig;
ev.data.scayt_control = plugin.getScayt( editor );
ev.data.tab = openPage;
ev.data.scayt = scayt;
});
var dataProcessor = editor.dataProcessor,
htmlFilter = dataProcessor && dataProcessor.htmlFilter;
if ( htmlFilter )
{
htmlFilter.addRules(
{
elements :
{
span : function( element )
{
if ( element.attributes.scayt_word && element.attributes.scaytid )
{
delete element.name; // Write children, but don't write this node.
return element;
}
}
}
}
);
}
if ( editor.document )
createInstance();
};
CKEDITOR.plugins.scayt =
{
engineLoaded : false,
instances : {},
getScayt : function( editor )
{
var instance = this.instances[ editor.name ];
return instance;
},
isScaytReady : function( editor )
{
return this.engineLoaded === true &&
'undefined' !== typeof scayt && this.getScayt( editor );
},
isScaytEnabled : function( editor )
{
var scayt = this.getScayt( editor );
return ( scayt ) ? scayt.disabled === false : false;
},
loadEngine : function( editor )
{
if ( this.engineLoaded === true )
return onEngineLoad.apply( editor ); // Add new instance.
else if ( this.engineLoaded == -1 ) // We are waiting.
return CKEDITOR.on( 'scaytReady', function(){ onEngineLoad.apply( editor );} ); // Use function(){} to avoid rejection as duplicate.
CKEDITOR.on( 'scaytReady', onEngineLoad, editor );
CKEDITOR.on( 'scaytReady', function()
{
this.engineLoaded = true;
},
this,
null,
0 ); // First to run.
this.engineLoaded = -1; // Loading in progress.
// assign diojo configurable vars
var parseUrl = function(data)
{
var m = data.match(/(.*)[\/\\]([^\/\\]+\.\w+)$/);
return { path: m[1], file: m[2] };
};
// compose scayt url
var protocol = document.location.protocol;
var baseUrl = "svc.spellchecker.net/spellcheck/lf/scayt/scayt.js";
var scaytUrl = editor.config.scaytParams.srcScayt ||
(protocol + "//" + baseUrl);
var scaytConfigBaseUrl = parseUrl(scaytUrl).path + "/";
djScaytConfig =
{
baseUrl: scaytConfigBaseUrl,
addOnLoad:
[
function()
{
CKEDITOR.fireOnce( "scaytReady" );
}
],
isDebug: false
};
// Append javascript code.
CKEDITOR.document.getHead().append(
CKEDITOR.document.createElement( 'script',
{
attributes :
{
type : 'text/javascript',
src : scaytUrl
}
})
);
return null;
}
};
var plugin = CKEDITOR.plugins.scayt;
// Context menu constructing.
var addButtonCommand = function( editor, buttonName, buttonLabel, commandName, command, menugroup, menuOrder )
{
editor.addCommand( commandName, command );
// If the "menu" plugin is loaded, register the menu item.
editor.addMenuItem( commandName,
{
label : buttonLabel,
command : commandName,
group : menugroup,
order : menuOrder
});
};
var commandDefinition =
{
preserveState : true,
exec: function( editor )
{
if ( plugin.isScaytReady( editor ) )
{
var isEnabled = plugin.isScaytEnabled( editor );
this.setState( isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_ON );
var scayt_control = plugin.getScayt( editor );
scayt_control.setDisabled( isEnabled );
}
else if ( !editor.config.scayt_autoStartup && plugin.engineLoaded >= 0 ) // Load first time
{
this.setState( CKEDITOR.TRISTATE_DISABLED );
editor.on( 'showScaytState', function()
{
this.removeListener();
this.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
},
this);
plugin.loadEngine( editor );
}
}
};
// Add scayt plugin.
CKEDITOR.plugins.add( 'scayt',
{
requires : [ 'menubutton' ],
beforeInit : function( editor )
{
// Register own rbc menu group.
editor.config.menu_groups = 'scayt_suggest,scayt_moresuggest,scayt_control,' + editor.config.menu_groups;
},
init : function( editor )
{
var moreSuggestions = {};
var mainSuggestions = {};
// Scayt command.
var command = editor.addCommand( commandName, commandDefinition );
// Add Options dialog.
CKEDITOR.dialog.add( commandName, CKEDITOR.getUrl( this.path + 'dialogs/options.js' ) );
var menuGroup = 'scaytButton';
editor.addMenuGroup( menuGroup );
editor.addMenuItems(
{
scaytToggle :
{
label : editor.lang.scayt.enable,
command : commandName,
group : menuGroup
},
scaytOptions :
{
label : editor.lang.scayt.options,
group : menuGroup,
onClick : function()
{
openPage = 'options';
editor.openDialog( commandName );
}
},
scaytLangs :
{
label : editor.lang.scayt.langs,
group : menuGroup,
onClick : function()
{
openPage = 'langs';
editor.openDialog( commandName );
}
},
scaytAbout :
{
label : editor.lang.scayt.about,
group : menuGroup,
onClick : function()
{
openPage = 'about';
editor.openDialog( commandName );
}
}
});
// Disabling it on IE for now, as it's blocking the browser (#3802).
if ( !CKEDITOR.env.ie )
{
editor.ui.add( 'Scayt', CKEDITOR.UI_MENUBUTTON,
{
label : editor.lang.scayt.title,
title : editor.lang.scayt.title,
className : 'cke_button_scayt',
onRender: function()
{
command.on( 'state', function()
{
this.setState( command.state );
},
this);
},
onMenu : function()
{
var isEnabled = plugin.isScaytEnabled( editor );
editor.getMenuItem( 'scaytToggle' ).label = editor.lang.scayt[ isEnabled ? 'disable' : 'enable' ];
return {
scaytToggle : CKEDITOR.TRISTATE_OFF,
scaytOptions : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
scaytLangs : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED,
scaytAbout : isEnabled ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED
};
}
});
}
// If the "contextmenu" plugin is loaded, register the listeners.
if ( editor.contextMenu && editor.addMenuItems )
{
editor.contextMenu.addListener( function( element, selection )
{
var scayt_control = plugin.getScayt( editor );
if ( !plugin.isScaytEnabled( editor ) || !element || !element.$ )
return null;
var word = scayt_control.getWord( element.$ );
if ( !word )
return null;
var sLang = scayt_control.getLang(),
_r = {},
items_suggestion = scayt.getSuggestion( word, sLang );
if (!items_suggestion || !items_suggestion.length )
return null;
// Remove unused commands and menuitems
for ( i in moreSuggestions )
{
delete editor._.menuItems[ i ];
delete editor._.commands[ i ];
}
for ( i in mainSuggestions )
{
delete editor._.menuItems[ i ];
delete editor._.commands[ i ];
}
moreSuggestions = {}; // Reset items.
mainSuggestions = {};
var moreSuggestionsUnable = false;
for ( var i = 0, l = items_suggestion.length; i < l; i += 1 )
{
var commandName = 'scayt_suggestion_' + items_suggestion[i].replace( ' ', '_' );
var exec = ( function( el, s )
{
return {
exec: function( editor )
{
scayt_control.replace(el, s);
}
};
})( element.$, items_suggestion[i] );
if ( i < editor.config.scayt_maxSuggestions )
{
addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],
commandName, exec, 'scayt_suggest', i + 1 );
_r[ commandName ] = CKEDITOR.TRISTATE_OFF;
mainSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;
}
else
{
addButtonCommand( editor, 'button_' + commandName, items_suggestion[i],
commandName, exec, 'scayt_moresuggest', i + 1 );
moreSuggestions[ commandName ] = CKEDITOR.TRISTATE_OFF;
moreSuggestionsUnable = true;
}
}
if ( moreSuggestionsUnable )
// Rgister the More suggestions group;
editor.addMenuItem( 'scayt_moresuggest',
{
label : editor.lang.scayt.moreSuggestions,
group : 'scayt_moresuggest',
order : 10,
getItems : function()
{
return moreSuggestions;
}
});
var ignore_command =
{
exec: function()
{
scayt_control.ignore( element.$ );
}
};
var ignore_all_command =
{
exec: function()
{
scayt_control.ignoreAll( element.$ );
}
};
var addword_command =
{
exec: function()
{
scayt.addWordToUserDictionary( element.$ );
}
};
addButtonCommand( editor, 'ignore', editor.lang.scayt.ignore,
'scayt_ignore', ignore_command, 'scayt_control', 1);
addButtonCommand( editor, 'ignore_all', editor.lang.scayt.ignoreAll,
'scayt_ignore_all', ignore_all_command, 'scayt_control', 2);
addButtonCommand( editor, 'add_word', editor.lang.scayt.addWord,
'scayt_add_word', addword_command, 'scayt_control', 3);
mainSuggestions[ 'scayt_moresuggest' ] = CKEDITOR.TRISTATE_OFF;
mainSuggestions[ 'scayt_ignore' ] = CKEDITOR.TRISTATE_OFF;
mainSuggestions[ 'scayt_ignore_all' ] = CKEDITOR.TRISTATE_OFF;
mainSuggestions[ 'scayt_add_word' ] = CKEDITOR.TRISTATE_OFF;
// ** ahow ads entry point
// ** hide ads listener register
// try{
//scayt_control.showBanner( editor )
// }catch(err){}
return mainSuggestions;
});
}
// Start plugin
if ( editor.config.scayt_autoStartup )
{
var showInitialState = function()
{
editor.removeListener( 'showScaytState', showInitialState );
command.setState( plugin.isScaytEnabled( editor ) ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
};
editor.on( 'showScaytState', showInitialState );
plugin.loadEngine( editor );
}
}
});
})();
CKEDITOR.config.scaytParams = CKEDITOR.config.scaytParams || {};
CKEDITOR.config.scayt_maxSuggestions = 5;
CKEDITOR.config.scayt_autoStartup = false;
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

@@ -0,0 +1,145 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
/**
* @fileOverview The "showblocks" plugin. Enable it will make all block level
* elements being decorated with a border and the element name
* displayed on the left-right corner.
*/
(function()
{
var cssTemplate = '.%2 p,'+
'.%2 div,'+
'.%2 pre,'+
'.%2 address,'+
'.%2 blockquote,'+
'.%2 h1,'+
'.%2 h2,'+
'.%2 h3,'+
'.%2 h4,'+
'.%2 h5,'+
'.%2 h6'+
'{'+
'background-repeat: no-repeat;'+
'border: 1px dotted gray;'+
'padding-top: 8px;'+
'padding-left: 8px;'+
'}'+
'.%2 p'+
'{'+
'%1p.png);'+
'}'+
'.%2 div'+
'{'+
'%1div.png);'+
'}'+
'.%2 pre'+
'{'+
'%1pre.png);'+
'}'+
'.%2 address'+
'{'+
'%1address.png);'+
'}'+
'.%2 blockquote'+
'{'+
'%1blockquote.png);'+
'}'+
'.%2 h1'+
'{'+
'%1h1.png);'+
'}'+
'.%2 h2'+
'{'+
'%1h2.png);'+
'}'+
'.%2 h3'+
'{'+
'%1h3.png);'+
'}'+
'.%2 h4'+
'{'+
'%1h4.png);'+
'}'+
'.%2 h5'+
'{'+
'%1h5.png);'+
'}'+
'.%2 h6'+
'{'+
'%1h6.png);'+
'}';
var cssTemplateRegex = /%1/g, cssClassRegex = /%2/g;
var commandDefinition =
{
preserveState : true,
exec : function ( editor )
{
this.toggleState();
this.refresh( editor );
},
refresh : function( editor )
{
var funcName = ( this.state == CKEDITOR.TRISTATE_ON ) ? 'addClass' : 'removeClass';
editor.document.getBody()[ funcName ]( 'cke_show_blocks' );
}
};
CKEDITOR.plugins.add( 'showblocks',
{
requires : [ 'wysiwygarea' ],
init : function( editor )
{
var command = editor.addCommand( 'showblocks', commandDefinition );
command.canUndo = false;
if ( editor.config.startupOutlineBlocks )
command.setState( CKEDITOR.TRISTATE_ON );
editor.addCss( cssTemplate
.replace( cssTemplateRegex, 'background-image: url(' + CKEDITOR.getUrl( this.path ) + 'images/block_' )
.replace( cssClassRegex, 'cke_show_blocks ' ) );
editor.ui.addButton( 'ShowBlocks',
{
label : editor.lang.showBlocks,
command : 'showblocks'
});
// Refresh the command on setData.
editor.on( 'mode', function()
{
if ( command.state != CKEDITOR.TRISTATE_DISABLED )
command.refresh( editor );
});
// Refresh the command on setData.
editor.on( 'contentDom', function()
{
if ( command.state != CKEDITOR.TRISTATE_DISABLED )
command.refresh( editor );
});
}
});
} )();
CKEDITOR.config.startupOutlineBlocks = false;
@@ -0,0 +1,219 @@
/*
Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
For licensing, see LICENSE.html or http://ckeditor.com/license
*/
CKEDITOR.dialog.add( 'smiley', function( editor )
{
var config = editor.config,
images = config.smiley_images,
columns = config.smiley_columns,
i;
/**
* Simulate "this" of a dialog for non-dialog events.
* @type {CKEDITOR.dialog}
*/
var dialog;
var onClick = function( evt )
{
var target = evt.data.getTarget(),
targetName = target.getName();
if ( targetName == 'td' )
target = target.getChild( [ 0, 0 ] );
else if ( targetName == 'a' )
target = target.getChild( 0 );
else if ( targetName != 'img' )
return;
var src = target.getAttribute( 'cke_src' ),
title = target.getAttribute( 'title' );
var img = editor.document.createElement( 'img',
{
attributes :
{
src : src,
_cke_saved_src : src,
title : title,
alt : title
}
});
editor.insertElement( img );
dialog.hide();
};
var onKeydown = CKEDITOR.tools.addFunction( function( ev, element )
{
ev = new CKEDITOR.dom.event( ev );
element = new CKEDITOR.dom.element( element );
var relative, nodeToMove;
var keystroke = ev.getKeystroke();
switch ( keystroke )
{
// RIGHT-ARROW
case 39 :
// relative is TD
if ( ( relative = element.getParent().getNext() ) )
{
nodeToMove = relative.getChild( 0 );
nodeToMove.focus();
}
ev.preventDefault();
break;
// LEFT-ARROW
case 37 :
// relative is TD
if ( ( relative = element.getParent().getPrevious() ) )
{
nodeToMove = relative.getChild( 0 );
nodeToMove.focus();
}
ev.preventDefault();
break;
// UP-ARROW
case 38 :
// relative is TR
if ( ( relative = element.getParent().getParent().getPrevious() ) )
{
nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );
nodeToMove.focus();
}
ev.preventDefault();
break;
// DOWN-ARROW
case 40 :
// relative is TR
if ( ( relative = element.getParent().getParent().getNext() ) )
{
nodeToMove = relative.getChild( [element.getParent().getIndex(), 0] );
if ( nodeToMove )
nodeToMove.focus();
}
ev.preventDefault();
break;
// ENTER
// SPACE
case 32 :
onClick( { data: ev } );
ev.preventDefault();
break;
// TAB
case 9 :
// relative is TD
if ( ( relative = element.getParent().getNext() ) )
{
nodeToMove = relative.getChild( 0 );
nodeToMove.focus();
ev.preventDefault(true);
}
// relative is TR
else if ( ( relative = element.getParent().getParent().getNext() ) )
{
nodeToMove = relative.getChild( [0, 0] );
if ( nodeToMove )
nodeToMove.focus();
ev.preventDefault(true);
}
break;
// SHIFT + TAB
case CKEDITOR.SHIFT + 9 :
// relative is TD
if ( ( relative = element.getParent().getPrevious() ) )
{
nodeToMove = relative.getChild( 0 );
nodeToMove.focus();
ev.preventDefault(true);
}
// relative is TR
else if ( ( relative = element.getParent().getParent().getPrevious() ) )
{
nodeToMove = relative.getLast().getChild( 0 );
nodeToMove.focus();
ev.preventDefault(true);
}
break;
default :
// Do not stop not handled events.
return;
}
});
// Build the HTML for the smiley images table.
var html =
[
'<table cellspacing="2" cellpadding="2"',
CKEDITOR.env.ie && CKEDITOR.env.quirks ? ' style="position:absolute;"' : '',
'><tbody>'
];
for ( i = 0 ; i < images.length ; i++ )
{
if ( i % columns === 0 )
html.push( '<tr>' );
html.push(
'<td class="cke_dark_background cke_hand cke_centered" style="vertical-align: middle;">' +
'<a href="javascript:void(0)" class="cke_smile" tabindex="-1" onkeydown="CKEDITOR.tools.callFunction( ', onKeydown, ', event, this );">',
'<img class="hand" title="', config.smiley_descriptions[i], '"' +
' cke_src="', CKEDITOR.tools.htmlEncode( config.smiley_path + images[ i ] ), '" alt="', config.smiley_descriptions[i], '"',
' src="', CKEDITOR.tools.htmlEncode( config.smiley_path + images[ i ] ), '"',
// IE BUG: Below is a workaround to an IE image loading bug to ensure the image sizes are correct.
( CKEDITOR.env.ie ? ' onload="this.setAttribute(\'width\', 2); this.removeAttribute(\'width\');" ' : '' ),
'>' +
'</a>',
'</td>' );
if ( i % columns == columns - 1 )
html.push( '</tr>' );
}
if ( i < columns - 1 )
{
for ( ; i < columns - 1 ; i++ )
html.push( '<td></td>' );
html.push( '</tr>' );
}
html.push( '</tbody></table>' );
var smileySelector =
{
type : 'html',
html : html.join( '' ),
onLoad : function( event )
{
dialog = event.sender;
},
focus : function()
{
var firstSmile = this.getElement().getChild( [0, 0, 0, 0] );
firstSmile.focus();
},
onClick : onClick,
style : 'width: 100%; height: 100%; border-collapse: separate;'
};
return {
title : editor.lang.smiley.title,
minWidth : 270,
minHeight : 120,
contents : [
{
id : 'tab1',
label : '',
title : '',
expand : true,
padding : 0,
elements : [
smileySelector
]
}
],
buttons : [ CKEDITOR.dialog.cancelButton ]
};
} );
Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

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