From 5ea463a3088dbfd0aa98e938f0e89254f2c10e51 Mon Sep 17 00:00:00 2001
From: Christian Steinle
+ New features:
+ Fixed issues:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ Fixed issues:
+ New features:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ New features:
+ Fixed issues:
+ Changelog starts at this release.
+ CKEditor is a text editor to be used inside web pages. It's not a replacement
+ for desktop text editors like Word or OpenOffice, but a component to be used as
+ part of web applications and web sites.
+ Installing CKEditor is an easy task. Just follow these simple steps:
+ Note: CKEditor is by default installed in the "ckeditor"
+ folder. You can place the files in whichever you want though.
+ The editor comes with a few sample pages that can be used to verify that installation
+ proceeded properly. Take a look at the _samples directory.
+ To test your installation, just call the following page at your web site:
+ The full editor documentation is available online at the following address:
+ CKEditor™ - The text editor for Internet™ -
+ http://ckeditor.com
+ Licensed under the terms of any of the following licenses at your choice:
+
+ You are not required to, but if you want to explicitly declare the license you have
+ chosen to be bound to when using, reproducing, modifying and distributing this software,
+ just include a text file titled "LEGAL" in your version of this software, indicating
+ your license choice. In any case, your choice will not restrict any recipient of
+ your version of this software to use, reproduce, modify and distribute this software
+ under any of the above licenses.
+
+ Where not otherwise indicated, all CKEditor content is authored by CKSource engineers
+ and consists of CKSource-owned intellectual property. In some specific instances,
+ CKEditor will incorporate work done by developers outside of CKSource with their
+ express permission.
+
+ YUI Test: At _source/tests/yuitest.js
+ can be found part of the source code of YUI, which is licensed under the terms of
+ the BSD License. YUI is
+ Copyright © 2008, Yahoo! Inc.
+
+ CKEditor is a trademark of CKSource - Frederico Knabben. All other brand and product
+ names are trademarks, registered trademarks or service marks of their respective
+ holders.
+
+
+
+
+ This sample shows how to use the dialog API to customize dialogs whithout changing
+ the original editor code. The following customizations are being done:: The ckeditor.asp file provides a wrapper to ease the work of creating CKEditor instances from classic Asp. To use it, you must first include it into your page:
+ After that script is included, you can use it in different ways, based on the following pattern: Before step 3 you can use a number of methods and properties to adjust the behavior of this class and the CKEditor instances
+that will be created:
+ CKEditor Changelog
+
+
+ CKEditor 3.4.1
+
+
+
+
+
+ CKEditor 3.4
+
+
+
+ CKEditor 3.4 Beta
+
+
+
+
+
+ CKEditor 3.3.2
+
+
+
+
+
+ CKEditor 3.3.1
+
+
+
+ CKEditor 3.3
+
+
+
+ CKEditor 3.2.2
+
+
+
+
+
+
+ CKEditor 3.2.1
+
+
+
+
+
+ CKEditor 3.2
+
+
+
+
+
+
+ CKEditor 3.1.1
+
+
+
+
+
+ CKEditor 3.1
+
+
+
+
+
+ CKEditor 3.0.2
+
+
+
+
+
+ CKEditor 3.0.1
+
+
+
+
+
+ CKEditor 3.0
+
+
+
+
+
+
+ CKEditor 3.0 RC
+
+ CKEditor Installation Guide
+
+ What's CKEditor?
+
+ Installation
+
+
+
+ Checking Your Installation
+
+
+http://<your site>/<CKEditor installation path>/_samples/index.html
+
+For example:
+http://www.example.com/ckeditor/_samples/index.html
+
+ Documentation
+
+ http://docs.cksource.com/ckeditor
+ Software License Agreement
+
+
+ Copyright © 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+
+
+
+ Sources of Intellectual Property Included in CKEditor
+
+
+ Trademarks
+
+
+ CKEditor Sample
+
+
+
+ CKEditor Sample
+
+
+
+ CKEditor Sample
+
+
+
+
+
+
+
+
+
diff --git a/ckeditor/_samples/api_dialog/my_dialog.js b/ckeditor/_samples/api_dialog/my_dialog.js
new file mode 100644
index 0000000..02f412f
--- /dev/null
+++ b/ckeditor/_samples/api_dialog/my_dialog.js
@@ -0,0 +1,28 @@
+/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.dialog.add( 'myDialog', function( editor )
+{
+ return {
+ title : 'My Dialog',
+ minWidth : 400,
+ minHeight : 200,
+ contents : [
+ {
+ id : 'tab1',
+ label : 'First Tab',
+ title : 'First Tab',
+ elements :
+ [
+ {
+ id : 'input1',
+ type : 'text',
+ label : 'Input 1'
+ }
+ ]
+ }
+ ]
+ };
+} );
diff --git a/ckeditor/_samples/asp/advanced.asp b/ckeditor/_samples/asp/advanced.asp
new file mode 100644
index 0000000..dfb94d5
--- /dev/null
+++ b/ckeditor/_samples/asp/advanced.asp
@@ -0,0 +1,105 @@
+<%@ codepage="65001" language="VBScript" %>
+<% Option Explicit %>
+
+<%
+
+ ' You must set "Enable Parent Paths" on your web site
+ ' in order for the above relative include to work.
+ ' Or you can use #INCLUDE VIRTUAL="/full path/ckeditor.asp"
+
+%>
+
+
+
+
+
+ CKEditor Sample
+
+
+
+ CKEditor Sample
+
+
+
+ CKEditor Samples List for ASP
+
+
+ Overview
+
+
+ <!-- #INCLUDE file="../../ckeditor.asp" -->
+
+ Of course, you should adjust the path to make it point to the correct location, and maybe use a full path (with virtual="" instead of file="")
+
+
+dim editor
+set editor = New CKEditor
+ editor.basePath = "../../"
+
+
+ editor.replaceInstance "editor1"
+ editor.replaceAll empty
+ editor.editor "editor1", initialValue
+
+
+
+
+ Basic Samples
+
+
+
+ Advanced Samples
+
+
+
+
+
diff --git a/ckeditor/_samples/asp/replace.asp b/ckeditor/_samples/asp/replace.asp
new file mode 100644
index 0000000..d89e0bf
--- /dev/null
+++ b/ckeditor/_samples/asp/replace.asp
@@ -0,0 +1,72 @@
+<%@ codepage="65001" language="VBScript" %>
+<% Option Explicit %>
+
+<%
+
+ ' You must set "Enable Parent Paths" on your web site
+ ' in order for the above relative include to work.
+ ' Or you can use #INCLUDE VIRTUAL="/full path/ckeditor.asp"
+
+%>
+
+
+
+
+
+ CKEditor Sample
+
+
+
+ CKEditor Sample
+
+
+
+ CKEditor - Posted Data
+
+
+
+
+
+
diff --git a/ckeditor/_samples/asp/standalone.asp b/ckeditor/_samples/asp/standalone.asp
new file mode 100644
index 0000000..02cda38
--- /dev/null
+++ b/ckeditor/_samples/asp/standalone.asp
@@ -0,0 +1,72 @@
+<%@ codepage="65001" language="VBScript" %>
+<% Option Explicit %>
+
+<%
+
+ ' You must set "Enable Parent Paths" on your web site
+ ' in order for the above relative include to work.
+ ' Or you can use #INCLUDE VIRTUAL="/full path/ckeditor.asp"
+
+%>
+
+
+
+
+
+
+
+ <%
+ Dim sForm
+ For Each sForm in Request.Form
+ %>
+ Field Name
+ Value
+
+
+ <% Next %>
+ <%=Server.HTMLEncode( sForm )%>
+
+ <%=Server.HTMLEncode( Request.Form(sForm) )%>
+ CKEditor Sample
+
+
+
+ Double-click on any of the following DIVs to transform them into editor instances.
++ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi + semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna + rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla + nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce + eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus. +
++ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi + semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna + rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla + nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce + eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus. +
++ Donec velit. Mauris massa. Vestibulum non nulla. Nam suscipit arcu nec elit. Phasellus + sollicitudin iaculis ante. Ut non mauris et sapien tincidunt adipiscing. Vestibulum + vitae leo. Suspendisse nec mi tristique nulla laoreet vulputate. +
++ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Cras et ipsum quis mi + semper accumsan. Integer pretium dui id massa. Suspendisse in nisl sit amet urna + rutrum imperdiet. Nulla eu tellus. Donec ante nisi, ullamcorper quis, fringilla + nec, sagittis eleifend, pede. Nulla commodo interdum massa. Donec id metus. Fusce + eu ipsum. Suspendisse auctor. Phasellus fermentum porttitor risus. +
+Your browser is not compatible with CKEditor.'; + + var browsers = + { + gecko : 'Firefox 2.0', + ie : 'Internet Explorer 6.0', + opera : 'Opera 9.5', + webkit : 'Safari 3.0' + }; + + var alsoBrowsers = ''; + + for ( var key in env ) + { + if ( browsers[ key ] ) + { + if ( env[key] ) + html += ' CKEditor is compatible with ' + browsers[ key ] + ' or higher.'; + else + alsoBrowsers += browsers[ key ] + '+, '; + } + } + + alsoBrowsers = alsoBrowsers.replace( /\+,([^,]+), $/, '+ and $1' ); + + html += ' It is also compatible with ' + alsoBrowsers + '.'; + + html += '
With non compatible browsers, you should still be able to see and edit the contents (HTML) in a plain text field.
'; + + var alertsEl = document.getElementById( 'alerts' ); + alertsEl && ( alertsEl.innerHTML = html ); + }; + + var onload = function() + { + // Show a friendly compatibility message as soon as the page is loaded, + // for those browsers that are not compatible with CKEditor. + if ( !CKEDITOR.env.isCompatible ) + showCompatibilityMsg(); + }; + + // Register the onload listener. + if ( window.addEventListener ) + window.addEventListener( 'load', onload, false ); + else if ( window.attachEvent ) + window.attachEvent( 'onload', onload ); + })(); +} diff --git a/ckeditor/_samples/sample_posteddata.php b/ckeditor/_samples/sample_posteddata.php new file mode 100644 index 0000000..af20e89 --- /dev/null +++ b/ckeditor/_samples/sample_posteddata.php @@ -0,0 +1,59 @@ + + + + +| Field Name | +Value | +
|---|---|
| + | + |
+ Click the UI Color Picker button to test your color preferences at runtime.
+ + + + diff --git a/ckeditor/_samples/ui_languages.html b/ckeditor/_samples/ui_languages.html new file mode 100644 index 0000000..e7c2e15 --- /dev/null +++ b/ckeditor/_samples/ui_languages.html @@ -0,0 +1,103 @@ + + + + +...
[text) + // or at the start of block ([text...), by comparing the document position + // with 'enlargeable' node. + this.setStartAt( + blockBoundary, + !blockBoundary.is( 'br' ) && + ( !enlargeable && this.checkStartOfBlock() + || enlargeable && blockBoundary.contains( enlargeable ) ) ? + CKEDITOR.POSITION_AFTER_START : + CKEDITOR.POSITION_AFTER_END ); + + // Enlarging the end boundary. + walkerRange = this.clone(); + walkerRange.collapse(); + walkerRange.setEndAt( body, CKEDITOR.POSITION_BEFORE_END ); + walker = new CKEDITOR.dom.walker( walkerRange ); + + // tailBrGuard only used for on range end. + walker.guard = ( unit == CKEDITOR.ENLARGE_LIST_ITEM_CONTENTS ) ? + tailBrGuard : boundaryGuard; + blockBoundary = null; + // End the range right before the block boundary node. + + enlargeable = walker.lastForward(); + + // It's the body which stop the enlarging if no block boundary found. + blockBoundary = blockBoundary || body; + + // Close the range either before the found block start (text]
...
) or at the block end (...text]) + // by comparing the document position with 'enlargeable' node. + this.setEndAt( + blockBoundary, + ( !enlargeable && this.checkEndOfBlock() + || enlargeable && blockBoundary.contains( enlargeable ) ) ? + CKEDITOR.POSITION_BEFORE_END : + CKEDITOR.POSITION_BEFORE_START ); + // We must include the element, spaces should be touched differently.
+ inPre = false,
+ returnPoint;
+
+ function checkPending( newTagName )
+ {
+ var pendingBRsSent;
+
+ if ( pendingInline.length > 0 )
+ {
+ for ( var i = 0 ; i < pendingInline.length ; i++ )
+ {
+ var pendingElement = pendingInline[ i ],
+ pendingName = pendingElement.name,
+ pendingDtd = CKEDITOR.dtd[ pendingName ],
+ currentDtd = currentNode.name && CKEDITOR.dtd[ currentNode.name ];
+
+ if ( ( !currentDtd || currentDtd[ pendingName ] ) && ( !newTagName || !pendingDtd || pendingDtd[ newTagName ] || !CKEDITOR.dtd[ newTagName ] ) )
+ {
+ if ( !pendingBRsSent )
+ {
+ sendPendingBRs();
+ pendingBRsSent = 1;
+ }
+
+ // Get a clone for the pending element.
+ pendingElement = pendingElement.clone();
+
+ // Add it to the current node and make it the current,
+ // so the new element will be added inside of it.
+ pendingElement.parent = currentNode;
+ currentNode = pendingElement;
+
+ // Remove the pending element (back the index by one
+ // to properly process the next entry).
+ pendingInline.splice( i, 1 );
+ i--;
+ }
+ }
+ }
+ }
+
+ function sendPendingBRs( brsToIgnore )
+ {
+ while ( pendingBRs.length - ( brsToIgnore || 0 ) > 0 )
+ currentNode.add( pendingBRs.shift() );
+ }
+
+ function addElement( element, target, enforceCurrent )
+ {
+ target = target || currentNode || fragment;
+
+ // If the target is the fragment and this element can't go inside
+ // body (if fixForBody).
+ if ( fixForBody && !target.type )
+ {
+ var elementName, realElementName;
+ if ( element.attributes
+ && ( realElementName =
+ element.attributes[ '_cke_real_element_type' ] ) )
+ elementName = realElementName;
+ else
+ elementName = element.name;
+ if ( elementName
+ && !( elementName in CKEDITOR.dtd.$body )
+ && !( elementName in CKEDITOR.dtd.$nonBodyContent ) )
+ {
+ var savedCurrent = currentNode;
+
+ // Create a in the fragment.
+ currentNode = target;
+ parser.onTagOpen( fixForBody, {} );
+
+ // The new target now is the
.
+ target = currentNode;
+
+ if ( enforceCurrent )
+ currentNode = savedCurrent;
+ }
+ }
+
+ // Rtrim empty spaces on block end boundary. (#3585)
+ if ( element._.isBlockLike
+ && element.name != 'pre' )
+ {
+
+ var length = element.children.length,
+ lastChild = element.children[ length - 1 ],
+ text;
+ if ( lastChild && lastChild.type == CKEDITOR.NODE_TEXT )
+ {
+ if ( !( text = CKEDITOR.tools.rtrim( lastChild.value ) ) )
+ element.children.length = length -1;
+ else
+ lastChild.value = text;
+ }
+ }
+
+ target.add( element );
+
+ if ( element.returnPoint )
+ {
+ currentNode = element.returnPoint;
+ delete element.returnPoint;
+ }
+ }
+
+ parser.onTagOpen = function( tagName, attributes, selfClosing )
+ {
+ var element = new CKEDITOR.htmlParser.element( tagName, attributes );
+
+ // "isEmpty" will be always "false" for unknown elements, so we
+ // must force it if the parser has identified it as a selfClosing tag.
+ if ( element.isUnknown && selfClosing )
+ element.isEmpty = true;
+
+ // This is a tag to be removed if empty, so do not add it immediately.
+ if ( CKEDITOR.dtd.$removeEmpty[ tagName ] )
+ {
+ pendingInline.push( element );
+ return;
+ }
+ else if ( tagName == 'pre' )
+ inPre = true;
+ else if ( tagName == 'br' && inPre )
+ {
+ currentNode.add( new CKEDITOR.htmlParser.text( '\n' ) );
+ return;
+ }
+
+ if ( tagName == 'br' )
+ {
+ pendingBRs.push( element );
+ return;
+ }
+
+ var currentName = currentNode.name;
+
+ var currentDtd = currentName
+ && ( CKEDITOR.dtd[ currentName ]
+ || ( currentNode._.isBlockLike ? CKEDITOR.dtd.div : CKEDITOR.dtd.span ) );
+
+ // If the element cannot be child of the current element.
+ if ( currentDtd // Fragment could receive any elements.
+ && !element.isUnknown && !currentNode.isUnknown && !currentDtd[ tagName ] )
+ {
+
+ var reApply = false,
+ addPoint; // New position to start adding nodes.
+
+ // Fixing malformed nested lists by moving it into a previous list item. (#3828)
+ if ( tagName in listBlocks
+ && currentName in listBlocks )
+ {
+ var children = currentNode.children,
+ lastChild = children[ children.length - 1 ];
+
+ // Establish the list item if it's not existed.
+ if ( !( lastChild && lastChild.name in listItems ) )
+ addElement( ( lastChild = new CKEDITOR.htmlParser.element( 'li' ) ), currentNode );
+
+ returnPoint = currentNode, addPoint = lastChild;
+ }
+ // If the element name is the same as the current element name,
+ // then just close the current one and append the new one to the
+ // parent. This situation usually happens with
,
.
+ if ( !currentNode._.hasInlineStarted && !inPre )
+ {
+ text = CKEDITOR.tools.ltrim( text );
+
+ if ( text.length === 0 )
+ return;
+ }
+
+ sendPendingBRs();
+ checkPending();
+
+ if ( fixForBody
+ && ( !currentNode.type || currentNode.name == 'body' )
+ && CKEDITOR.tools.trim( text ) )
+ {
+ this.onTagOpen( fixForBody, {} );
+ }
+
+ // Shrinking consequential spaces into one single for all elements
+ // text contents.
+ if ( !inPre )
+ text = text.replace( /[\t\r\n ]{2,}|[\t\r\n]/g, ' ' );
+
+ currentNode.add( new CKEDITOR.htmlParser.text( text ) );
+ };
+
+ parser.onCDATA = function( cdata )
+ {
+ currentNode.add( new CKEDITOR.htmlParser.cdata( cdata ) );
+ };
+
+ parser.onComment = function( comment )
+ {
+ currentNode.add( new CKEDITOR.htmlParser.comment( comment ) );
+ };
+
+ // Parse it.
+ parser.parse( fragmentHtml );
+
+ // Send all pending BRs except one, which we consider a unwanted bogus. (#5293)
+ sendPendingBRs( !CKEDITOR.env.ie && 1 );
+
+ // Close all pending nodes.
+ while ( currentNode.type )
+ {
+ var parent = currentNode.parent,
+ node = currentNode;
+
+ if ( fixForBody
+ && ( !parent.type || parent.name == 'body' )
+ && !CKEDITOR.dtd.$body[ node.name ] )
+ {
+ currentNode = parent;
+ parser.onTagOpen( fixForBody, {} );
+ parent = currentNode;
+ }
+
+ parent.add( node );
+ currentNode = parent;
+ }
+
+ return fragment;
+ };
+
+ CKEDITOR.htmlParser.fragment.prototype =
+ {
+ /**
+ * Adds a node to this fragment.
+ * @param {Object} node The node to be added. It can be any of of the
+ * following types: {@link CKEDITOR.htmlParser.element},
+ * {@link CKEDITOR.htmlParser.text} and
+ * {@link CKEDITOR.htmlParser.comment}.
+ * @example
+ */
+ add : function( node )
+ {
+ var len = this.children.length,
+ previous = len > 0 && this.children[ len - 1 ] || null;
+
+ if ( previous )
+ {
+ // If the block to be appended is following text, trim spaces at
+ // the right of it.
+ if ( node._.isBlockLike && previous.type == CKEDITOR.NODE_TEXT )
+ {
+ previous.value = CKEDITOR.tools.rtrim( previous.value );
+
+ // If we have completely cleared the previous node.
+ if ( previous.value.length === 0 )
+ {
+ // Remove it from the list and add the node again.
+ this.children.pop();
+ this.add( node );
+ return;
+ }
+ }
+
+ previous.next = node;
+ }
+
+ node.previous = previous;
+ node.parent = this;
+
+ this.children.push( node );
+
+ this._.hasInlineStarted = node.type == CKEDITOR.NODE_TEXT || ( node.type == CKEDITOR.NODE_ELEMENT && !node._.isBlockLike );
+ },
+
+ /**
+ * Writes the fragment HTML to a CKEDITOR.htmlWriter.
+ * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
+ * @example
+ * var writer = new CKEDITOR.htmlWriter();
+ * var fragment = CKEDITOR.htmlParser.fragment.fromHtml( '<P><B>Example' );
+ * fragment.writeHtml( writer )
+ * alert( writer.getHtml() ); "<p><b>Example</b></p>"
+ */
+ writeHtml : function( writer, filter )
+ {
+ var isChildrenFiltered;
+ this.filterChildren = function()
+ {
+ var writer = new CKEDITOR.htmlParser.basicWriter();
+ this.writeChildrenHtml.call( this, writer, filter, true );
+ var html = writer.getHtml();
+ this.children = new CKEDITOR.htmlParser.fragment.fromHtml( html ).children;
+ isChildrenFiltered = 1;
+ };
+
+ // Filtering the root fragment before anything else.
+ !this.name && filter && filter.onFragment( this );
+
+ this.writeChildrenHtml( writer, isChildrenFiltered ? null : filter );
+ },
+
+ writeChildrenHtml : function( writer, filter )
+ {
+ for ( var i = 0 ; i < this.children.length ; i++ )
+ this.children[i].writeHtml( writer, filter );
+ }
+ };
+})();
diff --git a/ckeditor/_source/core/htmlparser/text.js b/ckeditor/_source/core/htmlparser/text.js
new file mode 100644
index 0000000..0d63ac9
--- /dev/null
+++ b/ckeditor/_source/core/htmlparser/text.js
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+ var spacesRegex = /[\t\r\n ]{2,}|[\t\r\n]/g;
+
+ /**
+ * A lightweight representation of HTML text.
+ * @constructor
+ * @example
+ */
+ CKEDITOR.htmlParser.text = function( value )
+ {
+ /**
+ * The text value.
+ * @type String
+ * @example
+ */
+ this.value = value;
+
+ /** @private */
+ this._ =
+ {
+ isBlockLike : false
+ };
+ };
+
+ CKEDITOR.htmlParser.text.prototype =
+ {
+ /**
+ * The node type. This is a constant value set to {@link CKEDITOR.NODE_TEXT}.
+ * @type Number
+ * @example
+ */
+ type : CKEDITOR.NODE_TEXT,
+
+ /**
+ * Writes the HTML representation of this text to a CKEDITOR.htmlWriter.
+ * @param {CKEDITOR.htmlWriter} writer The writer to which write the HTML.
+ * @example
+ */
+ writeHtml : function( writer, filter )
+ {
+ var text = this.value;
+
+ if ( filter && !( text = filter.onText( text, this ) ) )
+ return;
+
+ writer.text( text );
+ }
+ };
+})();
diff --git a/ckeditor/_source/core/imagecacher.js b/ckeditor/_source/core/imagecacher.js
new file mode 100644
index 0000000..0704556
--- /dev/null
+++ b/ckeditor/_source/core/imagecacher.js
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+ var loaded = {};
+
+ var loadImage = function( image, callback )
+ {
+ var doCallback = function()
+ {
+ img.removeAllListeners();
+ loaded[ image ] = 1;
+ callback();
+ };
+
+ var img = new CKEDITOR.dom.element( 'img' );
+ img.on( 'load', doCallback );
+ img.on( 'error', doCallback );
+ img.setAttribute( 'src', image );
+ };
+
+ /**
+ * Load images into the browser cache.
+ * @namespace
+ * @example
+ */
+ CKEDITOR.imageCacher =
+ {
+ /**
+ * Loads one or more images.
+ * @param {Array} images The URLs for the images to be loaded.
+ * @param {Function} callback The function to be called once all images
+ * are loaded.
+ */
+ load : function( images, callback )
+ {
+ var pendingCount = images.length;
+
+ var checkPending = function()
+ {
+ if ( --pendingCount === 0 )
+ callback();
+ };
+
+ for ( var i = 0 ; i < images.length ; i++ )
+ {
+ var image = images[ i ];
+
+ if ( loaded[ image ] )
+ checkPending();
+ else
+ loadImage( image, checkPending );
+ }
+ }
+ };
+})();
diff --git a/ckeditor/_source/core/lang.js b/ckeditor/_source/core/lang.js
new file mode 100644
index 0000000..add9982
--- /dev/null
+++ b/ckeditor/_source/core/lang.js
@@ -0,0 +1,152 @@
+/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+ var loadedLangs = {};
+
+ CKEDITOR.lang =
+ {
+ /**
+ * The list of languages available in the editor core.
+ * @type Object
+ * @example
+ * alert( CKEDITOR.lang.en ); // "true"
+ */
+ languages :
+ {
+ 'af' : 1,
+ 'ar' : 1,
+ 'bg' : 1,
+ 'bn' : 1,
+ 'bs' : 1,
+ 'ca' : 1,
+ 'cs' : 1,
+ 'cy' : 1,
+ 'da' : 1,
+ 'de' : 1,
+ 'el' : 1,
+ 'en-au' : 1,
+ 'en-ca' : 1,
+ 'en-gb' : 1,
+ 'en' : 1,
+ 'eo' : 1,
+ 'es' : 1,
+ 'et' : 1,
+ 'eu' : 1,
+ 'fa' : 1,
+ 'fi' : 1,
+ 'fo' : 1,
+ 'fr-ca' : 1,
+ 'fr' : 1,
+ 'gl' : 1,
+ 'gu' : 1,
+ 'he' : 1,
+ 'hi' : 1,
+ 'hr' : 1,
+ 'hu' : 1,
+ 'is' : 1,
+ 'it' : 1,
+ 'ja' : 1,
+ 'km' : 1,
+ 'ko' : 1,
+ 'lt' : 1,
+ 'lv' : 1,
+ 'mn' : 1,
+ 'ms' : 1,
+ 'nb' : 1,
+ 'nl' : 1,
+ 'no' : 1,
+ 'pl' : 1,
+ 'pt-br' : 1,
+ 'pt' : 1,
+ 'ro' : 1,
+ 'ru' : 1,
+ 'sk' : 1,
+ 'sl' : 1,
+ 'sr-latn' : 1,
+ 'sr' : 1,
+ 'sv' : 1,
+ 'th' : 1,
+ 'tr' : 1,
+ 'uk' : 1,
+ 'vi' : 1,
+ 'zh-cn' : 1,
+ 'zh' : 1
+ },
+
+ /**
+ * Loads a specific language file, or auto detect it. A callback is
+ * then called when the file gets loaded.
+ * @param {String} languageCode The code of the language file to be
+ * loaded. If "autoDetect" is set to true, this language will be
+ * used as the default one, if the detect language is not
+ * available in the core.
+ * @param {Boolean} autoDetect Indicates that the function must try to
+ * detect the user language and load it instead.
+ * @param {Function} callback The function to be called once the
+ * language file is loaded. Two parameters are passed to this
+ * function: the language code and the loaded language entries.
+ * @example
+ */
+ load : function( languageCode, defaultLanguage, callback )
+ {
+ // If no languageCode - fallback to browser or default.
+ // If languageCode - fallback to no-localized version or default.
+ if ( !languageCode || !CKEDITOR.lang.languages[ languageCode ] )
+ languageCode = this.detect( defaultLanguage, languageCode );
+
+ if ( !this[ languageCode ] )
+ {
+ CKEDITOR.scriptLoader.load( CKEDITOR.getUrl(
+ '_source/' + // @Packager.RemoveLine
+ 'lang/' + languageCode + '.js' ),
+ function()
+ {
+ callback( languageCode, this[ languageCode ] );
+ }
+ , this );
+ }
+ else
+ callback( languageCode, this[ languageCode ] );
+ },
+
+ /**
+ * Returns the language that best fit the user language. For example,
+ * suppose that the user language is "pt-br". If this language is
+ * supported by the editor, it is returned. Otherwise, if only "pt" is
+ * supported, it is returned instead. If none of the previous are
+ * supported, a default language is then returned.
+ * @param {String} defaultLanguage The default language to be returned
+ * if the user language is not supported.
+ * @returns {String} The detected language code.
+ * @example
+ * alert( CKEDITOR.lang.detect( 'en' ) ); // e.g., in a German browser: "de"
+ */
+ detect : function( defaultLanguage, probeLanguage )
+ {
+ var languages = this.languages;
+ probeLanguage = probeLanguage || navigator.userLanguage || navigator.language;
+
+ var parts = probeLanguage
+ .toLowerCase()
+ .match( /([a-z]+)(?:-([a-z]+))?/ ),
+ lang = parts[1],
+ locale = parts[2];
+
+ if ( languages[ lang + '-' + locale ] )
+ lang = lang + '-' + locale;
+ else if ( !languages[ lang ] )
+ lang = null;
+
+ CKEDITOR.lang.detect = lang ?
+ function() { return lang; } :
+ function( defaultLanguage ) { return defaultLanguage; };
+
+ return lang || defaultLanguage;
+ }
+ };
+
+})();
diff --git a/ckeditor/_source/core/loader.js b/ckeditor/_source/core/loader.js
new file mode 100644
index 0000000..abeda48
--- /dev/null
+++ b/ckeditor/_source/core/loader.js
@@ -0,0 +1,243 @@
+/*
+Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+/**
+ * @fileOverview Defines the {@link CKEDITOR.loader} objects, which is used to
+ * load core scripts and their dependencies from _source.
+ */
+
+if ( typeof CKEDITOR == 'undefined' )
+ CKEDITOR = {};
+
+if ( !CKEDITOR.loader )
+{
+ /**
+ * Load core scripts and their dependencies from _source.
+ * @namespace
+ * @example
+ */
+ CKEDITOR.loader = (function()
+ {
+ // Table of script names and their dependencies.
+ var scripts =
+ {
+ 'core/_bootstrap' : [ 'core/config', 'core/ckeditor', 'core/plugins', 'core/scriptloader', 'core/tools', /* The following are entries that we want to force loading at the end to avoid dependence recursion */ 'core/dom/comment', 'core/dom/elementpath', 'core/dom/text', 'core/dom/rangelist' ],
+ 'core/ajax' : [ 'core/xml' ],
+ 'core/ckeditor' : [ 'core/ckeditor_basic', 'core/dom', 'core/dtd', 'core/dom/document', 'core/dom/element', 'core/editor', 'core/event', 'core/htmlparser', 'core/htmlparser/element', 'core/htmlparser/fragment', 'core/htmlparser/filter', 'core/htmlparser/basicwriter', 'core/tools' ],
+ 'core/ckeditor_base' : [],
+ 'core/ckeditor_basic' : [ 'core/editor_basic', 'core/env', 'core/event' ],
+ 'core/command' : [],
+ 'core/config' : [ 'core/ckeditor_base' ],
+ 'core/dom' : [],
+ 'core/dom/comment' : [ 'core/dom/node' ],
+ 'core/dom/document' : [ 'core/dom', 'core/dom/domobject', 'core/dom/window' ],
+ 'core/dom/documentfragment' : [ 'core/dom/element' ],
+ 'core/dom/element' : [ 'core/dom', 'core/dom/document', 'core/dom/domobject', 'core/dom/node', 'core/dom/nodelist', 'core/tools' ],
+ 'core/dom/elementpath' : [ 'core/dom/element' ],
+ 'core/dom/event' : [],
+ 'core/dom/node' : [ 'core/dom/domobject', 'core/tools' ],
+ 'core/dom/nodelist' : [ 'core/dom/node' ],
+ 'core/dom/domobject' : [ 'core/dom/event' ],
+ 'core/dom/range' : [ 'core/dom/document', 'core/dom/documentfragment', 'core/dom/element', 'core/dom/walker' ],
+ 'core/dom/rangelist' : [ 'core/dom/range' ],
+ 'core/dom/text' : [ 'core/dom/node', 'core/dom/domobject' ],
+ 'core/dom/walker' : [ 'core/dom/node' ],
+ 'core/dom/window' : [ 'core/dom/domobject' ],
+ 'core/dtd' : [ 'core/tools' ],
+ 'core/editor' : [ 'core/command', 'core/config', 'core/editor_basic', 'core/focusmanager', 'core/lang', 'core/plugins', 'core/skins', 'core/themes', 'core/tools', 'core/ui' ],
+ 'core/editor_basic' : [ 'core/event' ],
+ 'core/env' : [],
+ 'core/event' : [],
+ 'core/focusmanager' : [],
+ 'core/htmlparser' : [],
+ 'core/htmlparser/comment' : [ 'core/htmlparser' ],
+ 'core/htmlparser/element' : [ 'core/htmlparser', 'core/htmlparser/fragment' ],
+ 'core/htmlparser/fragment' : [ 'core/htmlparser', 'core/htmlparser/comment', 'core/htmlparser/text', 'core/htmlparser/cdata' ],
+ 'core/htmlparser/text' : [ 'core/htmlparser' ],
+ 'core/htmlparser/cdata' : [ 'core/htmlparser' ],
+ 'core/htmlparser/filter' : [ 'core/htmlparser' ],
+ 'core/htmlparser/basicwriter': [ 'core/htmlparser' ],
+ 'core/imagecacher' : [ 'core/dom/element' ],
+ 'core/lang' : [],
+ 'core/plugins' : [ 'core/resourcemanager' ],
+ 'core/resourcemanager' : [ 'core/scriptloader', 'core/tools' ],
+ 'core/scriptloader' : [ 'core/dom/element', 'core/env' ],
+ 'core/skins' : [ 'core/imagecacher', 'core/scriptloader' ],
+ 'core/themes' : [ 'core/resourcemanager' ],
+ 'core/tools' : [ 'core/env' ],
+ 'core/ui' : [],
+ 'core/xml' : [ 'core/env' ]
+ };
+
+ var basePath = (function()
+ {
+ // This is a copy of CKEDITOR.basePath, but requires the script having
+ // "_source/core/loader.js".
+ if ( CKEDITOR && CKEDITOR.basePath )
+ return CKEDITOR.basePath;
+
+ // Find out the editor directory path, based on its ' +
+ '';
+
+ var iframe = CKEDITOR.dom.element.createFromHtml(
+ '' );
+
+ iframe.on( 'load', function( e )
+ {
+ e.removeListener();
+ var doc = iframe.getFrameDocument().$;
+ // Custom domain handling is needed after each document.open().
+ doc.open();
+ if ( isCustomDomain )
+ doc.domain = document.domain;
+ doc.write( htmlToLoad );
+ doc.close();
+ }, this );
+
+ iframe.setCustomData( 'dialog', this );
+
+ var field = this.getContentElement( 'general', 'editing_area' ),
+ container = field.getElement();
+ container.setHtml( '' );
+ container.append( iframe );
+
+ // IE need a redirect on focus to make
+ // the cursor blinking inside iframe. (#5461)
+ if ( CKEDITOR.env.ie )
+ {
+ var focusGrabber = CKEDITOR.dom.element.createFromHtml( '' );
+ focusGrabber.on( 'focus', function()
+ {
+ iframe.$.contentWindow.focus();
+ });
+ container.append( focusGrabber );
+
+ // Override focus handler on field.
+ field.focus = function()
+ {
+ focusGrabber.focus();
+ this.fire( 'focus' );
+ };
+ }
+
+ field.getInputElement = function(){ return iframe; };
+
+ // Force container to scale in IE.
+ if ( CKEDITOR.env.ie )
+ {
+ container.setStyle( 'display', 'block' );
+ container.setStyle( 'height', ( iframe.$.offsetHeight + 2 ) + 'px' );
+ }
+ },
+
+ onHide : function()
+ {
+ if ( CKEDITOR.env.ie )
+ this.getParentEditor().document.getBody().$.contentEditable = 'true';
+ },
+
+ onLoad : function()
+ {
+ if ( ( CKEDITOR.env.ie7Compat || CKEDITOR.env.ie6Compat ) && editor.lang.dir == 'rtl' )
+ this.parts.contents.setStyle( 'overflow', 'hidden' );
+ },
+
+ 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;
+
+ setTimeout( function(){
+ editor.fire( 'paste', { 'html' : html } );
+ }, 0 );
+
+ },
+
+ contents : [
+ {
+ id : 'general',
+ label : editor.lang.common.generalTab,
+ elements : [
+ {
+ type : 'html',
+ id : 'securityMsg',
+ html : '' + lang.securityMsg + ''
+ },
+ {
+ type : 'html',
+ id : 'pasteMsg',
+ html : ''+lang.pasteMsg +''
+ },
+ {
+ type : 'html',
+ id : 'editing_area',
+ style : 'width: 100%; height: 100%;',
+ html : '',
+ focus : function()
+ {
+ var win = this.getInputElement().$.contentWindow;
+
+ // #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()
+ {
+ win.focus();
+ }, 500 );
+ }
+ }
+ ]
+ }
+ ]
+ };
+});
diff --git a/ckeditor/_source/plugins/clipboard/plugin.js b/ckeditor/_source/plugins/clipboard/plugin.js
new file mode 100644
index 0000000..9dc230e
--- /dev/null
+++ b/ckeditor/_source/plugins/clipboard/plugin.js
@@ -0,0 +1,412 @@
+/*
+Copyright (c) 2003-2010, 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 );
+
+ // IE6/7: document.execCommand has problem to paste into positioned element.
+ ( CKEDITOR.env.version > 7 ? doc.$ : doc.$.selection.createRange() ) [ '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 )
+ {
+ this.type == 'cut' && fixCut( editor );
+
+ 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 =
+ {
+ canUndo : false,
+
+ exec :
+ CKEDITOR.env.ie ?
+ function( editor )
+ {
+ // Prevent IE from pasting at the begining of the document.
+ editor.focus();
+
+ if ( !editor.document.getBody().fire( 'beforepaste' )
+ && !execIECommand( editor, 'paste' ) )
+ {
+ editor.fire( 'pasteDialog' );
+ return false;
+ }
+ }
+ :
+ function( editor )
+ {
+ try
+ {
+ if ( !editor.document.getBody().fire( 'beforepaste' )
+ && !editor.document.$.execCommand( 'Paste', false, null ) )
+ {
+ throw 0;
+ }
+ }
+ catch ( e )
+ {
+ setTimeout( function()
+ {
+ editor.fire( 'pasteDialog' );
+ }, 0 );
+ return false;
+ }
+ }
+ };
+
+ // Listens for some clipboard related keystrokes, so they get customized.
+ var onKey = function( event )
+ {
+ if ( this.mode != 'wysiwyg' )
+ return;
+
+ switch ( event.data.keyCode )
+ {
+ // Paste
+ case CKEDITOR.CTRL + 86 : // CTRL+V
+ case CKEDITOR.SHIFT + 45 : // SHIFT+INS
+
+ var body = this.document.getBody();
+
+ // Simulate 'beforepaste' event for all none-IEs.
+ if ( !CKEDITOR.env.ie && body.fire( 'beforepaste' ) )
+ event.cancel();
+ // Simulate 'paste' event for Opera/Firefox2.
+ else if ( CKEDITOR.env.opera
+ || CKEDITOR.env.gecko && CKEDITOR.env.version < 10900 )
+ body.fire( 'paste' );
+ return;
+
+ // Cut
+ case CKEDITOR.CTRL + 88 : // CTRL+X
+ case CKEDITOR.SHIFT + 46 : // SHIFT+DEL
+
+ // Save Undo snapshot.
+ var editor = this;
+ this.fire( 'saveSnapshot' ); // Save before paste
+ setTimeout( function()
+ {
+ editor.fire( 'saveSnapshot' ); // Save after paste
+ }, 0 );
+ }
+ };
+
+ // Allow to peek clipboard content by redirecting the
+ // pasting content into a temporary bin and grab the content of it.
+ function getClipboardData( evt, mode, callback )
+ {
+ var doc = this.document;
+
+ // Avoid recursions on 'paste' event for IE.
+ if ( CKEDITOR.env.ie && doc.getById( 'cke_pastebin' ) )
+ return;
+
+ // If the browser supports it, get the data directly
+ if (mode == 'text' && evt.data && evt.data.$.clipboardData)
+ {
+ // evt.data.$.clipboardData.types contains all the flavours in Mac's Safari, but not on windows.
+ var plain = evt.data.$.clipboardData.getData( 'text/plain' );
+ if (plain)
+ {
+ evt.data.preventDefault();
+ callback( plain );
+ return;
+ }
+ }
+
+ var sel = this.getSelection(),
+ range = new CKEDITOR.dom.range( doc );
+
+ // Create container to paste into
+ var pastebin = new CKEDITOR.dom.element( mode == 'text' ? 'textarea' : CKEDITOR.env.webkit ? 'body' : 'div', doc );
+ pastebin.setAttribute( 'id', 'cke_pastebin' );
+ // Safari requires a filler node inside the div to have the content pasted into it. (#4882)
+ CKEDITOR.env.webkit && pastebin.append( doc.createText( '\xa0' ) );
+ doc.getBody().append( pastebin );
+
+ pastebin.setStyles(
+ {
+ position : 'absolute',
+ // Position the bin exactly at the position of the selected element
+ // to avoid any subsequent document scroll.
+ top : sel.getStartElement().getDocumentPosition().y + 'px',
+ width : '1px',
+ height : '1px',
+ overflow : 'hidden'
+ });
+
+ // It's definitely a better user experience if we make the paste-bin pretty unnoticed
+ // by pulling it off the screen.
+ pastebin.setStyle( this.config.contentsLangDirection == 'ltr' ? 'left' : 'right', '-1000px' );
+
+ var bms = sel.createBookmarks();
+
+ // Turn off design mode temporarily before give focus to the paste bin.
+ if ( mode == 'text' )
+ {
+ if ( CKEDITOR.env.ie )
+ {
+ var ieRange = doc.getBody().$.createTextRange();
+ ieRange.moveToElementText( pastebin.$ );
+ ieRange.execCommand( 'Paste' );
+ evt.data.preventDefault();
+ }
+ else
+ {
+ doc.$.designMode = 'off';
+ pastebin.$.focus();
+ }
+ }
+ else
+ {
+ range.setStartAt( pastebin, CKEDITOR.POSITION_AFTER_START );
+ range.setEndAt( pastebin, CKEDITOR.POSITION_BEFORE_END );
+ range.select( true );
+ }
+
+ // Wait a while and grab the pasted contents
+ window.setTimeout( function()
+ {
+ mode == 'text' && !CKEDITOR.env.ie && ( doc.$.designMode = 'on' );
+ pastebin.remove();
+
+ // Grab the HTML contents.
+ // We need to look for a apple style wrapper on webkit it also adds
+ // a div wrapper if you copy/paste the body of the editor.
+ // Remove hidden div and restore selection.
+ var bogusSpan;
+ pastebin = ( CKEDITOR.env.webkit
+ && ( bogusSpan = pastebin.getFirst() )
+ && ( bogusSpan.is && bogusSpan.hasClass( 'Apple-style-span' ) ) ?
+ bogusSpan : pastebin );
+
+ sel.selectBookmarks( bms );
+ callback( pastebin[ 'get' + ( mode == 'text' ? 'Value' : 'Html' ) ]() );
+ }, 0 );
+ }
+
+ // Cutting off control type element in IE standards breaks the selection entirely. (#4881)
+ function fixCut( editor )
+ {
+ if ( !CKEDITOR.env.ie || editor.document.$.compatMode == 'BackCompat' )
+ return;
+
+ var sel = editor.getSelection();
+ var control;
+ if( ( sel.getType() == CKEDITOR.SELECTION_ELEMENT ) && ( control = sel.getSelectedElement() ) )
+ {
+ var range = sel.getRanges()[ 0 ];
+ var dummy = editor.document.createText( '' );
+ dummy.insertBefore( control );
+ range.setStartBefore( dummy );
+ range.setEndAfter( control );
+ sel.selectRanges( [ range ] );
+
+ // Clear up the fix if the paste wasn't succeeded.
+ setTimeout( function()
+ {
+ // Element still online?
+ if ( control.getParent() )
+ {
+ dummy.remove();
+ sel.selectElement( control );
+ }
+ }, 0 );
+ }
+ }
+
+ // Register the plugin.
+ CKEDITOR.plugins.add( 'clipboard',
+ {
+ requires : [ 'dialog', 'htmldataprocessor' ],
+ init : function( editor )
+ {
+ // Inserts processed data into the editor at the end of the
+ // events chain.
+ editor.on( 'paste', function( evt )
+ {
+ var data = evt.data;
+ if ( data[ 'html' ] )
+ editor.insertHtml( data[ 'html' ] );
+ else if ( data[ 'text' ] )
+ editor.insertText( data[ 'text' ] );
+
+ }, null, null, 1000 );
+
+ editor.on( 'pasteDialog', function( evt )
+ {
+ setTimeout( function()
+ {
+ // Open default paste dialog.
+ editor.openDialog( 'paste' );
+ }, 0 );
+ });
+
+ 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 );
+
+ var mode = editor.config.forcePasteAsPlainText ? 'text' : 'html';
+
+ // We'll be catching all pasted content in one line, regardless of whether the
+ // it's introduced by a document command execution (e.g. toolbar buttons) or
+ // user paste behaviors. (e.g. Ctrl-V)
+ editor.on( 'contentDom', function()
+ {
+ var body = editor.document.getBody();
+ body.on( ( (mode == 'text' && CKEDITOR.env.ie) || CKEDITOR.env.webkit ) ? 'paste' : 'beforepaste',
+ function( evt )
+ {
+ if ( depressBeforeEvent )
+ return;
+
+ getClipboardData.call( editor, evt, mode, function ( data )
+ {
+ // The very last guard to make sure the
+ // paste has successfully happened.
+ if ( !data )
+ return;
+
+ var dataTransfer = {};
+ dataTransfer[ mode ] = data;
+ editor.fire( 'paste', dataTransfer );
+ } );
+ });
+
+ body.on( 'beforecut', function() { !depressBeforeEvent && fixCut( editor ); } );
+ });
+
+ // If the "contextmenu" plugin is loaded, register the listeners.
+ if ( editor.contextMenu )
+ {
+ var depressBeforeEvent;
+ function stateFromNamedCommand( command )
+ {
+ // IE Bug: queryCommandEnabled('paste') fires also 'beforepaste(copy/cut)',
+ // guard to distinguish from the ordinary sources( either
+ // keyboard paste or execCommand ) (#4874).
+ CKEDITOR.env.ie && ( depressBeforeEvent = 1 );
+
+ var retval = editor.document.$.queryCommandEnabled( command ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
+ depressBeforeEvent = 0;
+ return retval;
+ }
+
+ editor.contextMenu.addListener( function( element, selection )
+ {
+ var readOnly = selection.getCommonAncestor().isReadOnly();
+ return {
+ cut : !readOnly && stateFromNamedCommand( 'Cut' ),
+ copy : stateFromNamedCommand( 'Copy' ),
+ paste : !readOnly && ( CKEDITOR.env.webkit ? CKEDITOR.TRISTATE_OFF : stateFromNamedCommand( 'Paste' ) )
+ };
+ });
+ }
+ }
+ });
+})();
+
+/**
+ * Fired when a clipboard operation is about to be taken into the editor.
+ * Listeners can manipulate the data to be pasted before having it effectively
+ * inserted into the document.
+ * @name CKEDITOR.editor#paste
+ * @since 3.1
+ * @event
+ * @param {String} [data.html] The HTML data to be pasted. If not available, e.data.text will be defined.
+ * @param {String} [data.text] The plain text data to be pasted, available when plain text operations are to used. If not available, e.data.html will be defined.
+ */
diff --git a/ckeditor/_source/plugins/colorbutton/plugin.js b/ckeditor/_source/plugins/colorbutton/plugin.js
new file mode 100644
index 0000000..305c44d
--- /dev/null
+++ b/ckeditor/_source/plugins/colorbutton/plugin.js
@@ -0,0 +1,251 @@
+/*
+Copyright (c) 2003-2010, 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(),
+ modes : { wysiwyg : 1 },
+
+ panel :
+ {
+ css : editor.skin.editor.css,
+ attributes : { role : 'listbox', 'aria-label' : lang.panelTitle }
+ },
+
+ onBlock : function( panel, block )
+ {
+ block.autoSize = true;
+ block.element.addClass( 'cke_colorblock' );
+ block.element.setHtml( renderColors( panel, type ) );
+ // The block should not have scrollbars (#5933, #6056)
+ block.element.getDocument().getBody().setStyle( 'overflow', 'hidden' );
+
+ var keys = block.keys;
+ var rtl = editor.lang.dir == 'rtl';
+ keys[ rtl ? 37 : 39 ] = 'next'; // ARROW-RIGHT
+ keys[ 40 ] = 'next'; // ARROW-DOWN
+ keys[ 9 ] = 'next'; // TAB
+ keys[ rtl ? 39 : 37 ] = 'prev'; // ARROW-LEFT
+ keys[ 38 ] = 'prev'; // ARROW-UP
+ keys[ CKEDITOR.SHIFT + 9 ] = 'prev'; // SHIFT + TAB
+ keys[ 32 ] = 'click'; // SPACE
+ }
+ });
+ }
+
+
+ function renderColors( panel, type )
+ {
+ var output = [],
+ colors = config.colorButton_colors.split( ',' ),
+ total = colors.length + ( config.colorButton_enableMore ? 2 : 1 );
+
+ var clickFn = CKEDITOR.tools.addFunction( function( color, type )
+ {
+ if ( color == '?' )
+ {
+ var applyColorStyle = arguments.callee;
+ function onColorDialogClose( evt )
+ {
+ this.removeListener( 'ok', onColorDialogClose );
+ this.removeListener( 'cancel', onColorDialogClose );
+
+ evt.name == 'ok' && applyColorStyle( this.getContentElement( 'picker', 'selectedColor' ).getValue(), type );
+ }
+
+ editor.openDialog( 'colordialog', function()
+ {
+ this.on( 'ok', onColorDialogClose );
+ this.on( 'cancel', onColorDialogClose );
+ } );
+
+ return;
+ }
+
+ editor.focus();
+
+ panel.hide();
+
+
+ editor.fire( 'saveSnapshot' );
+
+ // Clean up any conflicting style within the range.
+ new CKEDITOR.style( config['colorButton_' + type + 'Style'], { color : 'inherit' } ).remove( editor.document );
+
+ if ( color )
+ {
+ var colorStyle = config['colorButton_' + type + 'Style'];
+
+ colorStyle.childRule = type == 'back' ?
+ // It's better to apply background color as the innermost style. (#3599)
+ function(){ return false; } :
+ // Fore color style must be applied inside links instead of around it.
+ function( element ){ return element.getName() != 'a'; };
+
+ new CKEDITOR.style( colorStyle, { color : color } ).apply( editor.document );
+ }
+
+ editor.fire( 'saveSnapshot' );
+ });
+
+ // Render the "Automatic" button.
+ output.push(
+ '' +
+ '| ' + + '' + + ' | ' + + '', + lang.auto, + ' | ' + + '||||||
| ' + + '' + + '' + + '' + + ' | ' ); + } + + // Render the "More Colors" button. + if ( config.colorButton_enableMore ) + { + output.push( + '|||||||
| ' + + '', + lang.more, + '' + + ' | ' ); // It is later in the code. + } + + output.push( '|||||||
| 0 ) + html.push( 'style="', styles.join( '; ' ), '" ' ); + html.push( ' class="cke_dialog_ui_vbox_child">', childHtmlList[i], ' |
Note that this event is called only the first time a specific dialog is + * opened. Successive openings will use the cached dialog, and this event will + * not get fired.
+ * @name CKEDITOR#dialogDefinition + * @event + * @param {CKEDITOR.dialog.dialogDefinition} data The dialog defination that + * is being loaded. + * @param {CKEDITOR.editor} editor The editor instance that will use the + * dialog. + */ + +/** + * Fired when a tab is going to be selected in a dialog + * @name dialog#selectPage + * @event + * @param String page The id of the page that it's gonna be selected. + * @param String currentPage The id of the current page. + */ diff --git a/ckeditor/_source/plugins/dialogadvtab/plugin.js b/ckeditor/_source/plugins/dialogadvtab/plugin.js new file mode 100644 index 0000000..5feec9c --- /dev/null +++ b/ckeditor/_source/plugins/dialogadvtab/plugin.js @@ -0,0 +1,207 @@ +/* +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +(function() +{ + +function setupAdvParams( element ) +{ + var attrName = this.att; + + var value = element && element.hasAttribute( attrName ) && element.getAttribute( attrName ) || ''; + + if ( value !== undefined ) + this.setValue( value ); +} + +function commitAdvParams() +{ + // Dialogs may use different parameters in the commit list, so, by + // definition, we take the first CKEDITOR.dom.element available. + var element; + + for ( var i = 0 ; i < arguments.length ; i++ ) + { + if ( arguments[ i ] instanceof CKEDITOR.dom.element ) + { + element = arguments[ i ]; + break; + } + } + + if ( element ) + { + var attrName = this.att, + value = this.getValue(); + + if ( value ) + element.setAttribute( attrName, value ); + else + element.removeAttribute( attrName, value ); + } +} + +CKEDITOR.plugins.add( 'dialogadvtab', +{ + /** + * + * @param tabConfig + * id, dir, classes, styles + */ + createAdvancedTab : function( editor, tabConfig ) + { + if ( !tabConfig ) + tabConfig = { id:1, dir:1, classes:1, styles:1 }; + + var lang = editor.lang.common; + + var result = + { + id : 'advanced', + label : lang.advancedTab, + title : lang.advancedTab, + elements : + [ + { + type : 'vbox', + padding : 1, + children : [] + } + ] + }; + + var contents = []; + + if ( tabConfig.id || tabConfig.dir ) + { + if ( tabConfig.id ) + { + contents.push( + { + id : 'advId', + att : 'id', + type : 'text', + label : lang.id, + setup : setupAdvParams, + commit : commitAdvParams + }); + } + + if ( tabConfig.dir ) + { + contents.push( + { + id : 'advLangDir', + att : 'dir', + type : 'select', + label : lang.langDir, + 'default' : '', + style : 'width:100%', + items : + [ + [ lang.notSet, '' ], + [ lang.langDirLTR, 'ltr' ], + [ lang.langDirRTL, 'rtl' ] + ], + setup : setupAdvParams, + commit : commitAdvParams + }); + } + + result.elements[ 0 ].children.push( + { + type : 'hbox', + widths : [ '50%', '50%' ], + children : [].concat( contents ) + }); + } + + if ( tabConfig.styles || tabConfig.classes ) + { + contents = []; + + if ( tabConfig.styles ) + { + contents.push( + { + id : 'advStyles', + att : 'style', + type : 'text', + label : lang.styles, + 'default' : '', + + onChange : function(){}, + + getStyle : function( name, defaultValue ) + { + var match = this.getValue().match( new RegExp( name + '\\s*:\s*([^;]*)', 'i') ); + return match ? match[ 1 ] : defaultValue; + }, + + updateStyle : function( name, value ) + { + var styles = this.getValue(); + + // Remove the current value. + if ( styles ) + { + styles = styles + .replace( new RegExp( '\\s*' + name + '\s*:[^;]*(?:$|;\s*)', 'i' ), '' ) + .replace( /^[;\s]+/, '' ) + .replace( /\s+$/, '' ); + } + + if ( value ) + { + styles && !(/;\s*$/).test( styles ) && ( styles += '; ' ); + styles += name + ': ' + value; + } + + this.setValue( styles, true ); + + }, + + setup : setupAdvParams, + + commit : commitAdvParams + + }); + } + + if ( tabConfig.classes ) + { + contents.push( + { + type : 'hbox', + widths : [ '45%', '55%' ], + children : + [ + { + id : 'advCSSClasses', + att : 'class', + type : 'text', + label : lang.cssClasses, + 'default' : '', + setup : setupAdvParams, + commit : commitAdvParams + + } + ] + }); + } + + result.elements[ 0 ].children.push( + { + type : 'hbox', + widths : [ '50%', '50%' ], + children : [].concat( contents ) + }); + } + + return result; + } +}); + +})(); diff --git a/ckeditor/_source/plugins/dialogui/plugin.js b/ckeditor/_source/plugins/dialogui/plugin.js new file mode 100644 index 0000000..7875b5b --- /dev/null +++ b/ckeditor/_source/plugins/dialogui/plugin.js @@ -0,0 +1,1522 @@ +/* +Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved. +For licensing, see LICENSE.html or http://ckeditor.com/license +*/ + +/** @fileoverview The "dialogui" plugin. */ + +CKEDITOR.plugins.add( 'dialogui' ); + +(function() +{ + var initPrivateObject = function( elementDefinition ) + { + this._ || ( this._ = {} ); + this._['default'] = this._.initValue = elementDefinition['default'] || ''; + this._.required = elementDefinition[ 'required' ] || false; + var args = [ this._ ]; + for ( var i = 1 ; i < arguments.length ; i++ ) + args.push( arguments[i] ); + args.push( true ); + CKEDITOR.tools.extend.apply( CKEDITOR.tools, args ); + return this._; + }, + textBuilder = + { + build : function( dialog, elementDefinition, output ) + { + return new CKEDITOR.ui.dialog.textInput( dialog, elementDefinition, output ); + } + }, + commonBuilder = + { + build : function( dialog, elementDefinition, output ) + { + return new CKEDITOR.ui.dialog[elementDefinition.type]( dialog, elementDefinition, output ); + } + }, + containerBuilder = + { + build : function( dialog, elementDefinition, output ) + { + var children = elementDefinition.children, + child, + childHtmlList = [], + childObjList = []; + for ( var i = 0 ; ( i < children.length && ( child = children[i] ) ) ; i++ ) + { + var childHtml = []; + childHtmlList.push( childHtml ); + childObjList.push( CKEDITOR.dialog._.uiElementBuilders[ child.type ].build( dialog, child, childHtml ) ); + } + return new CKEDITOR.ui.dialog[ elementDefinition.type ]( dialog, childObjList, childHtmlList, output, elementDefinition ); + } + }, + commonPrototype = + { + isChanged : function() + { + return this.getValue() != this.getInitValue(); + }, + + reset : function( noChangeEvent ) + { + this.setValue( this.getInitValue(), noChangeEvent ); + }, + + setInitValue : function() + { + this._.initValue = this.getValue(); + }, + + resetInitValue : function() + { + this._.initValue = this._['default']; + }, + + getInitValue : function() + { + return this._.initValue; + } + }, + commonEventProcessors = CKEDITOR.tools.extend( {}, CKEDITOR.ui.dialog.uiElement.prototype.eventProcessors, + { + onChange : function( dialog, func ) + { + if ( !this._.domOnChangeRegistered ) + { + dialog.on( 'load', function() + { + this.getInputElement().on( 'change', function() + { + // Make sure 'onchange' doesn't get fired after dialog closed. (#5719) + if ( !dialog.parts.dialog.isVisible() ) + return; + + this.fire( 'change', { value : this.getValue() } ); + }, this ); + }, this ); + this._.domOnChangeRegistered = true; + } + + this.on( 'change', func ); + } + }, true ), + eventRegex = /^on([A-Z]\w+)/, + cleanInnerDefinition = function( def ) + { + // An inner UI element should not have the parent's type, title or events. + for ( var i in def ) + { + if ( eventRegex.test( i ) || i == 'title' || i == 'type' ) + delete def[i]; + } + return def; + }; + + CKEDITOR.tools.extend( CKEDITOR.ui.dialog, + /** @lends CKEDITOR.ui.dialog */ + { + /** + * Base class for all dialog elements with a textual label on the left. + * @constructor + * @example + * @extends CKEDITOR.ui.dialog.uiElement + * @param {CKEDITOR.dialog} dialog + * Parent dialog object. + * @param {CKEDITOR.dialog.uiElementDefinition} elementDefinition + * The element definition. Accepted fields: + *