Skip to content

Instantly share code, notes, and snippets.

@Reinmar
Created September 28, 2014 19:36
Show Gist options
  • Save Reinmar/1acce88add99964be1c6 to your computer and use it in GitHub Desktop.
Save Reinmar/1acce88add99964be1c6 to your computer and use it in GitHub Desktop.
Plugin for CKEditor which changes enter key behaviour so it keeps the block's style.
( function() {
'use strict';
CKEDITOR.plugins.add( 'enterkeepstyles', {
init: function( editor ) {
var comboStyles = [];
/**
* Block styles defined in {@link CKEDITOR.config#stylesSet editor's style set}.
*
* @property {CKEDITOR.style[]}
*/
this.comboStyles = comboStyles;
/**
* Formats defined in {@link CKEDITOR.config#format_tags}.
*
* @property {CKEDITOR.style[]}
*/
this.formatStyles = this.getFormatStyles( editor.config );
// We can only get combo styles asynchronously.
editor.on( 'stylesSet', function( evt ) {
var stylesDefinitions = evt.data.styles,
style;
for ( var i = 0; i < stylesDefinitions.length; i++ ) {
style = new CKEDITOR.style( stylesDefinitions[ i ] );
if ( style.type == CKEDITOR.STYLE_BLOCK ) {
comboStyles.push( style );
}
}
} );
this.attachEnterListeners( editor );
},
/**
* Attaches listeners to the `enter` command to change its behaviour.
*
* One of the listeners will be called right before `enter` command is executed and will memorise
* active styles. Second one will be called after `enter` command is executed and will
* apply the memorised styles.
*
* @param {CKEDITOR.editor} editor
*/
attachEnterListeners: function( editor ) {
var activeStyles = [],
that = this;
// Memorise which styles have been active before
// enter command is executed.
editor.on( 'beforeCommandExec', function( evt ) {
if ( evt.data.name != 'enter' ) {
return;
}
activeStyles = that.getActiveStyles( editor );
} );
// Apply the memorised styles after enter command was executed.
// Make sure that we don't create a new undo snapshot for these changes.
editor.on( 'afterCommandExec', function( evt ) {
if ( evt.data.name != 'enter' ) {
return;
}
if ( activeStyles.length ) {
// Lock undo manager while we are applying styles/
// so any changes to the DOM will be merged into the previous snapshot
// meaning that enter key plus these changes will be just a one undo step.
editor.fire( 'lockSnapshot', {
forceUpdate: true
} );
while ( activeStyles.length ) {
editor.applyStyle( activeStyles.pop() );
}
editor.fire( 'unlockSnapshot' );
}
} );
},
/**
* Returns an array of active styles.
*
* Styles that are going to be checked:
*
* * {@link #comboStyles} &mdash; it is possible that more than one of these styles
* is active at the same moment, so more than one may be returned.
* * {@link #formatStyles} &mdash; if none of the {@link #comboStyles} is active
* one of formats may be returned.
*
* **Note:** If any of the combo's styles is active formats will not be checked, because
* the first style already defines the element name.
*
* @param {CKEDITOR.editor} editor
* @returns {CKEDITOR.style[]} The array of active styles.
*/
getActiveStyles: function( editor ) {
var elementPath = editor.elementPath(),
i,
activeStyles = [];
for ( i = 0; i < this.comboStyles.length; ++i ) {
if ( this.comboStyles[ i ].checkActive( elementPath, editor ) ) {
activeStyles.push( this.comboStyles[ i ] );
}
}
// In all correct cases it doesn't make sense to check formats if one of combo styles
// is active, because it already defines the element name.
if ( activeStyles.length ) {
return activeStyles;
}
for ( i = 0; i < this.formatStyles.length; ++i ) {
if ( this.formatStyles[ i ].checkActive( elementPath, editor ) ) {
return [ this.formatStyles[ i ] ];
}
}
return [];
},
/**
* Parses {@link CKEDITOR.config#format_tags} and related `format_*` options and returns
* an array of format styles.
*
* @param {CKEDITOR.config}
* @returns {CKEDITOR.style[]}
*/
getFormatStyles: function( config ) {
var tags = config.format_tags,
tag,
styles = [];
if ( !tags ) {
return [];
}
tags = tags.split( ';' );
while ( ( tag = tags.pop() ) ) {
styles.push( new CKEDITOR.style( config[ 'format_' + tag ] ) );
}
return styles;
}
} );
} )();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment