Skip to content

Commit

Permalink
Merge branch 't/10280' into major
Browse files Browse the repository at this point in the history
  • Loading branch information
Reinmar committed Jul 10, 2013
2 parents 8ac6a22 + 9ce223f commit d20c978
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 102 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CKEditor 4 Changelog
* [#10027](http://dev.ckeditor.com/ticket/10027): Separated list and block indentation.
* [#8244](http://dev.ckeditor.com/ticket/8244): Use (SHIFT+)TAB to indent and outdent lists.
* [#8031](http://dev.ckeditor.com/ticket/8031): Handle `required` attributes on `textareas` - introduced `editor#required` event.
* [#10280](http://dev.ckeditor.com/ticket/10280): Ability to replace `textarea` with inline editor.

## CKEditor 4.1.3

Expand Down
52 changes: 43 additions & 9 deletions core/creators/inline.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
* ...
* CKEDITOR.inline( 'content' );
*
* It is also possible to create inline editor from textarea element. If you do so
* an additional `div` with editable content will be created directly after the
* `textarea` element and that `textarea` element will be hidden.
*
* @param {Object/String} element The DOM element or its ID.
* @param {Object} [instanceConfig] The specific configurations to apply to this editor instance.
* See {@link CKEDITOR.config}.
Expand All @@ -30,11 +34,30 @@
if ( element.getEditor() )
throw 'The editor instance "' + element.getEditor().name + '" is already attached to the provided element.';

var editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE );

// Initial editor data is simply loaded from the page element content to make
// data retrieval possible immediately after the editor creation.
editor.setData( element.getHtml(), null, true );
var editor = new CKEDITOR.editor( instanceConfig, element, CKEDITOR.ELEMENT_MODE_INLINE ),
textarea = element.is( 'textarea' ) ? element : null;

if ( textarea ) {
editor.setData( textarea.getValue(), null, true );

//Change element from textarea to div
element = CKEDITOR.dom.element.createFromHtml(
'<div contenteditable="' + !!editor.readOnly + '" class="cke_textarea_inline">' +
textarea.getValue() +
'</div>',
CKEDITOR.document );

element.insertAfter( textarea );
textarea.hide();

// Attaching the concrete form.
if ( textarea.$.form )
editor._attachToForm();
} else {
// Initial editor data is simply loaded from the page element content to make
// data retrieval possible immediately after the editor creation.
editor.setData( element.getHtml(), null, true );
}

// Once the editor is loaded, start the UI.
editor.on( 'loaded', function() {
Expand All @@ -53,6 +76,7 @@
editor.resetDirty();

editor.fire( 'contentDom' );

// Inline editing defaults to "wysiwyg" mode, so plugins don't
// need to make special handling for this "mode-less" environment.
editor.mode = 'wysiwyg';
Expand All @@ -68,9 +92,18 @@

// Handle editor destroying.
editor.on( 'destroy', function() {
// Remove container from DOM if inline-textarea editor.
// Show <textarea> back again.
if ( textarea ) {
editor.container.clearCustomData();
editor.container.remove();
textarea.show();
}

editor.element.clearCustomData();

delete editor.element;
});
} );

return editor;
};
Expand All @@ -94,7 +127,9 @@
// the instance settings and eventually cancel the creation.

data = {
element: el, config: {} };
element: el,
config: {}
};

if ( CKEDITOR.fire( 'inline', data ) !== false )
CKEDITOR.inline( el, data.config );
Expand All @@ -105,10 +140,9 @@

CKEDITOR.domReady( function() {
!CKEDITOR.disableAutoInline && CKEDITOR.inlineAll();
});
} );
})();


/**
* Avoid creating editor automatically on element which has attribute
* `contenteditable` set to the value `true`.
Expand Down
45 changes: 2 additions & 43 deletions core/creators/themedui.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ CKEDITOR.replaceClass = 'ckeditor';
loadTheme( editor );

if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE && editor.config.autoUpdateElement )
attachToForm( editor );
if ( element.$.form )
editor._attachToForm();

editor.setMode( editor.config.startupMode, function() {
// Clean on startup.
Expand Down Expand Up @@ -372,48 +373,6 @@ CKEDITOR.replaceClass = 'ckeditor';
editor.fireOnce( 'uiReady' );
}

function attachToForm( editor ) {
var element = editor.element;

// If are replacing a textarea, we must
if ( editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE && element.is( 'textarea' ) ) {
var form = element.$.form && new CKEDITOR.dom.element( element.$.form );
if ( form ) {
function onSubmit( evt ) {
editor.updateElement();

// #8031 If textarea had required attribute and editor is empty fire 'required' event and if
// it was cancelled, prevent submitting the form.
if ( editor._.required && !element.getValue() && editor.fire( 'required' ) === false )
evt.data.preventDefault();
}
form.on( 'submit', onSubmit );

// Setup the submit function because it doesn't fire the
// "submit" event.
if ( !form.$.submit.nodeName && !form.$.submit.length ) {
form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit ) {
return function( evt ) {
onSubmit( new CKEDITOR.dom.event( evt ) );

// For IE, the DOM submit function is not a
// function, so we need third check.
if ( originalSubmit.apply )
originalSubmit.apply( this, arguments );
else
originalSubmit();
};
});
}

// Remove 'submit' events registered on form element before destroying.(#3988)
editor.on( 'destroy', function() {
form.removeListener( 'submit', onSubmit );
});
}
}
}

// Replace all textareas with the default class name.
CKEDITOR.domReady( function() {
CKEDITOR.replaceClass && CKEDITOR.replaceAll( CKEDITOR.replaceClass );
Expand Down
88 changes: 80 additions & 8 deletions core/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,12 @@
else if ( !mode )
throw new Error( 'One of the element modes must be specified.' );

if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && mode == CKEDITOR.ELEMENT_MODE_INLINE ) {
if ( CKEDITOR.env.ie && CKEDITOR.env.quirks && mode == CKEDITOR.ELEMENT_MODE_INLINE )
throw new Error( 'Inline element mode is not supported on IE quirks.' );
}

// Asserting element DTD depending on mode.
if ( mode == CKEDITOR.ELEMENT_MODE_INLINE && !element.is( CKEDITOR.dtd.$editable ) || mode == CKEDITOR.ELEMENT_MODE_REPLACE && element.is( CKEDITOR.dtd.$nonBodyContent ) )
if ( !isSupportedElement( element, mode ) )
throw new Error( 'The specified element mode is not supported on element: "' + element.getName() + '".' );


/**
* The original host page element upon which the editor is created, it's only
* supposed to be provided by the concrete editor creator and is not subjected to
Expand Down Expand Up @@ -194,6 +191,15 @@
return name;
}

// Asserting element DTD depending on mode.
function isSupportedElement( element, mode ) {
if ( mode == CKEDITOR.ELEMENT_MODE_INLINE )
return element.is( CKEDITOR.dtd.$editable ) || element.is( 'textarea' );
else if ( mode == CKEDITOR.ELEMENT_MODE_REPLACE )
return !element.is( CKEDITOR.dtd.$nonBodyContent );
return 1;
}

function updateCommands() {
var commands = this.commands,
name;
Expand Down Expand Up @@ -312,7 +318,20 @@
* @property {Boolean}
* @see CKEDITOR.editor#setReadOnly
*/
editor.readOnly = !!( editor.config.readOnly || ( editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ? editor.element.isReadOnly() : editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ? editor.element.getAttribute( 'disabled' ) : false ) );
editor.readOnly = !!(
editor.config.readOnly || (
editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ?
editor.element.is( 'textarea' ) ?
editor.element.hasAttribute( 'disabled' )
:
editor.element.isReadOnly()
:
editor.elementMode == CKEDITOR.ELEMENT_MODE_REPLACE ?
editor.element.hasAttribute( 'disabled' )
:
false
)
);

/**
* Indicates that the editor is running into an environment where
Expand All @@ -321,7 +340,9 @@
* @readonly
* @property {Boolean}
*/
editor.blockless = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE && !CKEDITOR.dtd[ editor.element.getName() ][ 'p' ];
editor.blockless = editor.elementMode == CKEDITOR.ELEMENT_MODE_INLINE ?
!( editor.element.is( 'textarea' ) || CKEDITOR.dtd[ editor.element.getName() ][ 'p' ] ) :
false;

/**
* The [tabbing navigation](http://en.wikipedia.org/wiki/Tabbing_navigation) order determined for this editor instance.
Expand Down Expand Up @@ -636,6 +657,56 @@
return this.commands[ commandName ] = cmd;
},

/**
* Attaches editor to form to call {@link #updateElement} before form submit.
* This method is called by both creators ({@link CKEDITOR#replace replace} and
* {@link CKEDITOR#inline inline}) so there is no reason to call it manually.
*
* @private
*/
_attachToForm: function() {
var editor = this,
element = editor.element,
form = new CKEDITOR.dom.element( element.$.form );

// If are replacing a textarea, we must
if ( element.is( 'textarea' ) ) {
if ( form ) {
function onSubmit( evt ) {
editor.updateElement();

// #8031 If textarea had required attribute and editor is empty fire 'required' event and if
// it was cancelled, prevent submitting the form.
if ( editor._.required && !element.getValue() && editor.fire( 'required' ) === false )
evt.data.preventDefault();
}
form.on( 'submit', onSubmit );

// Setup the submit function because it doesn't fire the
// "submit" event.
if ( !form.$.submit.nodeName && !form.$.submit.length ) {
form.$.submit = CKEDITOR.tools.override( form.$.submit, function( originalSubmit ) {
return function( evt ) {
onSubmit( new CKEDITOR.dom.event( evt ) );

// For IE, the DOM submit function is not a
// function, so we need third check.
if ( originalSubmit.apply )
originalSubmit.apply( this, arguments );
else
originalSubmit();
};
} );
}

// Remove 'submit' events registered on form element before destroying.(#3988)
editor.on( 'destroy', function() {
form.removeListener( 'submit', onSubmit );
} );
}
}
},

/**
* Destroys the editor instance, releasing all resources used by it.
* If the editor replaced an element, the element will be recovered.
Expand Down Expand Up @@ -966,7 +1037,8 @@
* the current data available in the editor.
*
* **Note:** This method will only affect those editor instances created
* with {@link CKEDITOR#ELEMENT_MODE_REPLACE} element mode.
* with {@link CKEDITOR#ELEMENT_MODE_REPLACE} element mode or inline instances
* bound to `<textarea>` elements.
*
* CKEDITOR.instances.editor1.updateElement();
* alert( document.getElementById( 'editor1' ).value ); // The current editor data.
Expand Down
Loading

0 comments on commit d20c978

Please sign in to comment.