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
@@ -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 ]
|
||||
};
|
||||
} );
|
||||
|
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
|
||||
*/
|
||||
@@ -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 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"> </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( ' ' );
|
||||
|
||||
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(' ');
|
||||
}
|
||||
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&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"> </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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
} );
|
||||
})();
|
||||
|
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: <object><embed></embed></object>
|
||||
* @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 at the end of blocks, which are actually placeholders.
|
||||
var tailNbspRegex = /^[\t\r\n ]* $/;
|
||||
|
||||
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 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() ); "<p class="MyClass">Hello</p>"
|
||||
*/
|
||||
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 " />"
|
||||
* @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 "<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 ">".
|
||||
* writer.openTagClose( 'p', false );
|
||||
* @example
|
||||
* // Writes " />".
|
||||
* 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( /&/, '&' );
|
||||
|
||||
this._.output.push( ' ', attName, '="', attValue, '"' );
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a closer tag.
|
||||
* @param {String} tagName The element name for this tag.
|
||||
* @example
|
||||
* // Writes "</p>".
|
||||
* 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 "<!-- My comment -->".
|
||||
* 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 );
|
||||
}
|
||||
} );
|
||||
})();
|
||||
}
|
||||
} );
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
} );
|
||||
|
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 = '';
|
||||
|
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;"> </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, ' ') ;
|
||||
|
||||
// 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* \s*<\/SPAN>/gi, ' ' ) ;
|
||||
|
||||
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)> <\/\1>/g, ' ' ) ;
|
||||
|
||||
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;
|
||||
|
After Width: | Height: | Size: 288 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 229 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 229 B |
|
After Width: | Height: | Size: 236 B |
|
After Width: | Height: | Size: 216 B |
|
After Width: | Height: | Size: 205 B |
|
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 ]
|
||||
};
|
||||
} );
|
||||
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 443 B |
|
After Width: | Height: | Size: 192 B |
|
After Width: | Height: | Size: 464 B |
|
After Width: | Height: | Size: 468 B |
|
After Width: | Height: | Size: 436 B |
|
After Width: | Height: | Size: 442 B |
|
After Width: | Height: | Size: 426 B |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 241 B |
|
After Width: | Height: | Size: 368 B |
|
After Width: | Height: | Size: 451 B |
|
After Width: | Height: | Size: 450 B |