/*\r
-Copyright (c) 2003-2010, CKSource - Frederico Knabben. All rights reserved.\r
+Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.\r
For licensing, see LICENSE.html or http://ckeditor.com/license\r
*/\r
\r
|| element.isBlockBoundary() && CKEDITOR.dtd.$empty[ element.getName() ];\r
}\r
\r
- function checkReadOnly( selection )\r
- {\r
- if ( selection.getType() == CKEDITOR.SELECTION_ELEMENT )\r
- return selection.getSelectedElement().isReadOnly();\r
- else\r
- return selection.getCommonAncestor().isReadOnly();\r
- }\r
-\r
\r
function onInsert( insertFunc )\r
{\r
{\r
this.focus();\r
\r
- var selection = this.getSelection();\r
- if ( checkReadOnly( selection ) )\r
- return;\r
-\r
this.fire( 'saveSnapshot' );\r
\r
insertFunc.call( this, evt.data );\r
if ( this.dataProcessor )\r
data = this.dataProcessor.toHtml( data );\r
\r
- var selection = this.getSelection();\r
+ // HTML insertion only considers the first range.\r
+ var selection = this.getSelection(),\r
+ range = selection.getRanges()[ 0 ];\r
+\r
+ if ( range.checkReadOnly() )\r
+ return;\r
+\r
if ( CKEDITOR.env.ie )\r
{\r
var selIsLocked = selection.isLocked;\r
// Delete control selections to avoid IE bugs on pasteHTML.\r
if ( $sel.type == 'Control' )\r
$sel.clear();\r
- else if ( selection.getType() == CKEDITOR.SELECTION_TEXT )\r
+ else if ( selection.getType() == CKEDITOR.SELECTION_TEXT )\r
{\r
// Due to IE bugs on handling contenteditable=false blocks\r
// (#6005), we need to make some checks and eventually\r
// delete the selection first.\r
\r
- var range = selection.getRanges()[0],\r
- endContainer = range && range.endContainer;\r
+ range = selection.getRanges()[ 0 ];\r
+ var endContainer = range && range.endContainer;\r
\r
if ( endContainer &&\r
endContainer.type == CKEDITOR.NODE_ELEMENT &&\r
{\r
$sel.createRange().pasteHTML( data );\r
}\r
- catch (e) {}\r
+ catch (e) {}\r
\r
if ( selIsLocked )\r
this.getSelection().lock();\r
- }\r
+ }\r
else\r
this.document.$.execCommand( 'inserthtml', false, data );\r
\r
{\r
range = ranges[ i ];\r
\r
- // Remove the original contents.\r
- range.deleteContents();\r
+ if ( !range.checkReadOnly() )\r
+ {\r
+ // Remove the original contents, merge splitted nodes.\r
+ range.deleteContents( 1 );\r
\r
- clone = !i && element || element.clone( 1 );\r
+ clone = !i && element || element.clone( 1 );\r
\r
- // If we're inserting a block at dtd-violated position, split\r
- // the parent blocks until we reach blockLimit.\r
- var current, dtd;\r
- if ( isBlock )\r
- {\r
- while ( ( current = range.getCommonAncestor( 0, 1 ) )\r
- && ( dtd = CKEDITOR.dtd[ current.getName() ] )\r
- && !( dtd && dtd [ elementName ] ) )\r
- {\r
- // Split up inline elements.\r
- if ( current.getName() in CKEDITOR.dtd.span )\r
- range.splitElement( current );\r
- // If we're in an empty block which indicate a new paragraph,\r
- // simply replace it with the inserting block.(#3664)\r
- else if ( range.checkStartOfBlock()\r
- && range.checkEndOfBlock() )\r
+ // If we're inserting a block at dtd-violated position, split\r
+ // the parent blocks until we reach blockLimit.\r
+ var current, dtd;\r
+ if ( isBlock )\r
{\r
- range.setStartBefore( current );\r
- range.collapse( true );\r
- current.remove();\r
+ while ( ( current = range.getCommonAncestor( 0, 1 ) )\r
+ && ( dtd = CKEDITOR.dtd[ current.getName() ] )\r
+ && !( dtd && dtd [ elementName ] ) )\r
+ {\r
+ // Split up inline elements.\r
+ if ( current.getName() in CKEDITOR.dtd.span )\r
+ range.splitElement( current );\r
+ // If we're in an empty block which indicate a new paragraph,\r
+ // simply replace it with the inserting block.(#3664)\r
+ else if ( range.checkStartOfBlock()\r
+ && range.checkEndOfBlock() )\r
+ {\r
+ range.setStartBefore( current );\r
+ range.collapse( true );\r
+ current.remove();\r
+ }\r
+ else\r
+ range.splitBlock();\r
+ }\r
}\r
- else\r
- range.splitBlock();\r
- }\r
- }\r
\r
- // Insert the new node.\r
- range.insertNode( clone );\r
+ // Insert the new node.\r
+ range.insertNode( clone );\r
\r
- // Save the last element reference so we can make the\r
- // selection later.\r
- if ( !lastElement )\r
- lastElement = clone;\r
- }\r
+ // Save the last element reference so we can make the\r
+ // selection later.\r
+ if ( !lastElement )\r
+ lastElement = clone;\r
+ }\r
+ }\r
\r
- range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );\r
+ if ( lastElement )\r
+ {\r
+ range.moveToPosition( lastElement, CKEDITOR.POSITION_AFTER_END );\r
\r
- // If we're inserting a block element immediatelly followed by\r
- // another block element, the selection must move there. (#3100,#5436)\r
- if ( isBlock )\r
- {\r
- var next = lastElement.getNext( notWhitespaceEval ),\r
- nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();\r
+ // If we're inserting a block element immediatelly followed by\r
+ // another block element, the selection must move there. (#3100,#5436)\r
+ if ( isBlock )\r
+ {\r
+ var next = lastElement.getNext( notWhitespaceEval ),\r
+ nextName = next && next.type == CKEDITOR.NODE_ELEMENT && next.getName();\r
\r
- // Check if it's a block element that accepts text.\r
- if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )\r
- range.moveToElementEditStart( next );\r
- }\r
+ // Check if it's a block element that accepts text.\r
+ if ( nextName && CKEDITOR.dtd.$block[ nextName ] && CKEDITOR.dtd[ nextName ]['#'] )\r
+ range.moveToElementEditStart( next );\r
+ }\r
+ }\r
\r
- selection.selectRanges( [ range ] );\r
+ selection.selectRanges( [ range ] );\r
\r
if ( selIsLocked )\r
this.getSelection().lock();\r
var win = editor.window,\r
doc = editor.document,\r
body = editor.document.getBody(),\r
+ bodyFirstChild = body.getFirst(),\r
bodyChildsNum = body.getChildren().count();\r
\r
- if ( !bodyChildsNum || ( bodyChildsNum == 1&& body.getFirst().hasAttribute( '_moz_editor_bogus_node' ) ) )\r
+ if ( !bodyChildsNum\r
+ || bodyChildsNum == 1\r
+ && bodyFirstChild.type == CKEDITOR.NODE_ELEMENT\r
+ && bodyFirstChild.hasAttribute( '_moz_editor_bogus_node' ) )\r
{\r
restoreDirty( editor );\r
\r
body = editor.document.getBody(),\r
enterMode = editor.config.enterMode;\r
\r
- CKEDITOR.env.gecko && activateEditing( editor );\r
+ if ( CKEDITOR.env.gecko )\r
+ {\r
+ activateEditing( editor );\r
+\r
+ // Ensure bogus br could help to move cursor (out of styles) to the end of block. (#7041)\r
+ var pathBlock = path.block || path.blockLimit,\r
+ lastNode = pathBlock && pathBlock.getLast( isNotEmpty );\r
+\r
+ // In case it's not ended with block element and doesn't have bogus yet. (#7467)\r
+ if ( pathBlock\r
+ && !( lastNode && lastNode.type == CKEDITOR.NODE_ELEMENT && lastNode.isBlockBoundary() )\r
+ && !pathBlock.is( 'pre' )\r
+ && !pathBlock.getBogus() )\r
+ {\r
+ editor.fire( 'updateSnapshot' );\r
+ restoreDirty( editor );\r
+ pathBlock.appendBogus();\r
+ }\r
+ }\r
\r
// When enterMode set to block, we'll establing new paragraph only if we're\r
// selecting inline contents right under body. (#3657)\r
}\r
\r
range.select();\r
- // Notify non-IE that selection has changed.\r
- if ( !CKEDITOR.env.ie )\r
- editor.selectionChange();\r
+ // Cancel this selection change in favor of the next (correct). (#6811)\r
+ evt.cancel();\r
}\r
\r
// All browsers are incapable to moving cursor out of certain non-exitable\r
data.dialog && editor.openDialog( data.dialog );\r
});\r
\r
+ // Prevent automatic submission in IE #6336\r
+ CKEDITOR.env.ie && domDocument.on( 'click', function( evt )\r
+ {\r
+ var element = evt.data.getTarget();\r
+ if ( element.is( 'input' ) )\r
+ {\r
+ var type = element.getAttribute( 'type' );\r
+ if ( type == 'submit' || type == 'reset' )\r
+ evt.data.preventDefault();\r
+ }\r
+ });\r
+\r
// Gecko/Webkit need some help when selecting control type elements. (#3448)\r
if ( !( CKEDITOR.env.ie || CKEDITOR.env.opera ) )\r
{\r
// Webkit: avoid from editing form control elements content.\r
if ( CKEDITOR.env.webkit )\r
{\r
+ // Mark that cursor will right blinking (#7113).\r
+ domDocument.on( 'mousedown', function() { wasFocused = 1; } );\r
// Prevent from tick checkbox/radiobox/select\r
domDocument.on( 'click', function( ev )\r
{\r
} );\r
}\r
\r
- domWindow.on( 'blur', function()\r
+ var focusTarget = CKEDITOR.env.ie ? iframe : domWindow;\r
+ focusTarget.on( 'blur', function()\r
{\r
editor.focusManager.blur();\r
});\r
\r
var wasFocused;\r
\r
- domWindow.on( 'focus', function()\r
+ focusTarget.on( 'focus', function()\r
{\r
var doc = editor.document;\r
\r
}\r
} );\r
}\r
+\r
+ // Prevent IE from leaving new paragraph after deleting all contents in body. (#6966)\r
+ editor.config.enterMode != CKEDITOR.ENTER_P\r
+ && domDocument.on( 'selectionchange', function()\r
+ {\r
+ var body = domDocument.getBody(),\r
+ range = editor.getSelection().getRanges()[ 0 ];\r
+\r
+ if ( body.getHtml().match( /^<p> <\/p>$/i )\r
+ && range.startContainer.equals( body ) )\r
+ {\r
+ // Avoid the ambiguity from a real user cursor position.\r
+ setTimeout( function ()\r
+ {\r
+ range = editor.getSelection().getRanges()[ 0 ];\r
+ if ( !range.startContainer.equals ( 'body' ) )\r
+ {\r
+ body.getFirst().remove( 1 );\r
+ range.moveToElementEditEnd( body );\r
+ range.select( 1 );\r
+ }\r
+ }, 0 );\r
+ }\r
+ });\r
}\r
\r
// Adds the document body as a context menu target.\r
}, 0 );\r
\r
// IE, Opera and Safari may not support it and throw errors.\r
- try { editor.document.$.execCommand( 'enableObjectResizing', false, !editor.config.disableObjectResizing ) ; } catch(e) {}\r
- try { editor.document.$.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ) ; } catch(e) {}\r
+ try { editor.document.$.execCommand( 'enableInlineTableEditing', false, !editor.config.disableNativeTableHandles ); } catch(e) {}\r
+ if ( editor.config.disableObjectResizing )\r
+ {\r
+ try\r
+ {\r
+ editor.document.$.execCommand( 'enableObjectResizing', false, false );\r
+ }\r
+ catch(e)\r
+ {\r
+ // For browsers in which the above method failed, we can cancel the resizing on the fly (#4208)\r
+ editor.document.getBody().on( CKEDITOR.env.ie ? 'resizestart' : 'resize', function( evt )\r
+ {\r
+ evt.data.preventDefault();\r
+ });\r
+ }\r
+ }\r
\r
/*\r
* IE BUG: IE might have rendered the iframe with invisible contents.\r
loadData : function( data )\r
{\r
isLoadingData = true;\r
+ editor._.dataStore = { id : 1 };\r
\r
var config = editor.config,\r
fullPage = config.fullPage,\r
'</html>';\r
}\r
\r
+ // Distinguish bogus to normal BR at the end of document for Mozilla. (#5293).\r
+ if ( CKEDITOR.env.gecko )\r
+ data = data.replace( /<br \/>(?=\s*<\/(:?html|body)>)/, '$&<br type="_moz" />' );\r
+\r
data += activationScript;\r
\r
\r
? doc.getDocumentElement().getOuterHtml()\r
: doc.getBody().getHtml();\r
\r
+ // BR at the end of document is bogus node for Mozilla. (#5293).\r
+ if ( CKEDITOR.env.gecko )\r
+ data = data.replace( /<br>(?=\s*(:?$|<\/body>))/, '' );\r
+\r
if ( editor.dataProcessor )\r
data = editor.dataProcessor.toDataFormat( data, fixForBody );\r
\r
editor.document.$.title = frameLabel;\r
});\r
\r
- // IE8 stricts mode doesn't have 'contentEditable' in effect\r
+ // IE>=8 stricts mode doesn't have 'contentEditable' in effect\r
// on element unless it has layout. (#5562)\r
- if ( CKEDITOR.env.ie8Compat )\r
+ if ( CKEDITOR.document.$.documentMode >= 8 )\r
{\r
editor.addCss( 'html.CSS1Compat [contenteditable=false]{ min-height:0 !important;}' );\r
\r
{\r
editor.focus();\r
} );\r
+\r
+ editor.focusGrabber = focusGrabber;\r
} );\r
editor.on( 'destroy', function()\r
{\r
CKEDITOR.tools.removeFunction( contentDomReadyHandler );\r
focusGrabber.clearCustomData();\r
+ delete editor.focusGrabber;\r
} );\r
}\r
\r
if ( element.type == CKEDITOR.NODE_ELEMENT\r
&& ( element.is( 'input' ) || element.is( 'textarea' ) ) )\r
{\r
+ // We should flag that the element was locked by our code so\r
+ // it'll be editable by the editor functions (#6046).\r
if ( !element.isReadOnly() )\r
- {\r
- element.setAttribute( 'contentEditable', false );\r
- // We should flag that the element was locked by our code so\r
- // it'll be editable by the editor functions (#6046).\r
- element.setCustomData( '_cke_notReadOnly', 1 );\r
- }\r
+ element.data( 'cke-editable', element.hasAttribute( 'contenteditable' ) ? 'true' : '1' );\r
+ element.setAttribute( 'contentEditable', false );\r
}\r
});\r
\r
CKEDITOR.config.disableNativeTableHandles = true;\r
\r
/**\r
- * Disables the built-in spell checker while typing natively available in the\r
- * browser (currently Firefox and Safari only).<br /><br />\r
+ * Disables the built-in words spell checker if browser provides one.<br /><br />\r
*\r
- * Even if word suggestions will not appear in the CKEditor context menu, this\r
- * feature is useful to help quickly identifying misspelled words.<br /><br />\r
+ * <strong>Note:</strong> Although word suggestions provided by browsers (natively) will not appear in CKEditor's default context menu,\r
+ * users can always reach the native context menu by holding the <em>Ctrl</em> key when right-clicking if {@link CKEDITOR.config.browserContextMenuOnCtrl}\r
+ * is enabled or you're simply not using the context menu plugin.\r
*\r
- * This setting is currently compatible with Firefox only due to limitations in\r
- * other browsers.\r
* @type Boolean\r
* @default true\r
* @example\r
* @name CKEDITOR.editor#dataReady\r
* @event\r
*/\r
+\r
+/**\r
+ * Fired when some elements are added to the document\r
+ * @name CKEDITOR.editor#ariaWidget\r
+ * @event\r
+ * @param {Object} element The element being added\r
+ */\r