new ckeditor
New ckeditor
This commit is contained in:
@@ -0,0 +1,566 @@
|
||||
/* global ToolbarConfigurator */
|
||||
|
||||
'use strict';
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
|
||||
if ( typeof Object.create != 'function' ) {
|
||||
( function() {
|
||||
var F = function() {};
|
||||
Object.create = function( o ) {
|
||||
if ( arguments.length > 1 ) {
|
||||
throw Error( 'Second argument not supported' );
|
||||
}
|
||||
if ( o === null ) {
|
||||
throw Error( 'Cannot set a null [[Prototype]]' );
|
||||
}
|
||||
if ( typeof o != 'object' ) {
|
||||
throw TypeError( 'Argument must be an object' );
|
||||
}
|
||||
F.prototype = o;
|
||||
return new F();
|
||||
};
|
||||
} )();
|
||||
}
|
||||
|
||||
// Copy of the divarea plugin (with some enhancements), so we always have some editable mode, regardless of the build's config.
|
||||
CKEDITOR.plugins.add( 'toolbarconfiguratorarea', {
|
||||
// Use afterInit to override wysiwygarea's mode. May still fail to override divarea, but divarea is nice.
|
||||
afterInit: function( editor ) {
|
||||
editor.addMode( 'wysiwyg', function( callback ) {
|
||||
var editingBlock = CKEDITOR.dom.element.createFromHtml( '<div class="cke_wysiwyg_div cke_reset" hidefocus="true"></div>' );
|
||||
|
||||
var contentSpace = editor.ui.space( 'contents' );
|
||||
contentSpace.append( editingBlock );
|
||||
|
||||
editingBlock = editor.editable( editingBlock );
|
||||
|
||||
editingBlock.detach = CKEDITOR.tools.override( editingBlock.detach,
|
||||
function( org ) {
|
||||
return function() {
|
||||
org.apply( this, arguments );
|
||||
this.remove();
|
||||
};
|
||||
} );
|
||||
|
||||
editor.setData( editor.getData( 1 ), callback );
|
||||
editor.fire( 'contentDom' );
|
||||
} );
|
||||
|
||||
// Additions to the divarea.
|
||||
|
||||
// Speed up data processing.
|
||||
editor.dataProcessor.toHtml = function( html ) {
|
||||
return html;
|
||||
};
|
||||
editor.dataProcessor.toDataFormat = function( html ) {
|
||||
return html;
|
||||
};
|
||||
|
||||
// End of the additions.
|
||||
}
|
||||
} );
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
||||
if ( !Object.keys ) {
|
||||
Object.keys = ( function() {
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
||||
hasDontEnumBug = !( { toString: null } ).propertyIsEnumerable( 'toString' ),
|
||||
dontEnums = [
|
||||
'toString',
|
||||
'toLocaleString',
|
||||
'valueOf',
|
||||
'hasOwnProperty',
|
||||
'isPrototypeOf',
|
||||
'propertyIsEnumerable',
|
||||
'constructor'
|
||||
],
|
||||
dontEnumsLength = dontEnums.length;
|
||||
|
||||
return function( obj ) {
|
||||
if ( typeof obj !== 'object' && ( typeof obj !== 'function' || obj === null ) )
|
||||
throw new TypeError( 'Object.keys called on non-object' );
|
||||
|
||||
var result = [], prop, i;
|
||||
|
||||
for ( prop in obj ) {
|
||||
if ( hasOwnProperty.call( obj, prop ) )
|
||||
result.push( prop );
|
||||
|
||||
}
|
||||
|
||||
if ( hasDontEnumBug ) {
|
||||
for ( i = 0; i < dontEnumsLength; i++ ) {
|
||||
if ( hasOwnProperty.call( obj, dontEnums[ i ] ) )
|
||||
result.push( dontEnums[ i ] );
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
}() );
|
||||
}
|
||||
|
||||
( function() {
|
||||
/**
|
||||
* @class ToolbarConfigurator.AbstractToolbarModifier
|
||||
* @param {String} editorId An id of modified editor
|
||||
* @constructor
|
||||
*/
|
||||
function AbstractToolbarModifier( editorId, cfg ) {
|
||||
this.cfg = cfg || {};
|
||||
this.hidden = false;
|
||||
this.editorId = editorId;
|
||||
this.fullToolbarEditor = new ToolbarConfigurator.FullToolbarEditor();
|
||||
|
||||
this.mainContainer = null;
|
||||
|
||||
this.originalConfig = null;
|
||||
this.actualConfig = null;
|
||||
|
||||
this.waitForReady = false;
|
||||
this.isEditableVisible = false;
|
||||
|
||||
this.toolbarContainer = null;
|
||||
this.toolbarButtons = [];
|
||||
}
|
||||
|
||||
// Expose the class.
|
||||
ToolbarConfigurator.AbstractToolbarModifier = AbstractToolbarModifier;
|
||||
|
||||
/**
|
||||
* @param {String} config
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.setConfig = function( config ) {
|
||||
this._onInit( undefined, config, true );
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Function} [callback]
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.init = function( callback ) {
|
||||
var that = this;
|
||||
|
||||
this.mainContainer = new CKEDITOR.dom.element( 'div' );
|
||||
|
||||
if ( this.fullToolbarEditor.editorInstance !== null ) {
|
||||
throw 'Only one instance of ToolbarModifier is allowed';
|
||||
}
|
||||
|
||||
if ( !this.editorInstance ) {
|
||||
// Do not refresh yet, let's wait for the full toolbar editor (see below).
|
||||
this._createEditor( false );
|
||||
}
|
||||
|
||||
this.editorInstance.once( 'loaded', function() {
|
||||
that.fullToolbarEditor.init( function() {
|
||||
that._onInit( callback );
|
||||
|
||||
if ( typeof that.onRefresh == 'function' ) {
|
||||
that.onRefresh();
|
||||
}
|
||||
}, that.editorInstance.config );
|
||||
} );
|
||||
|
||||
return this.mainContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called editor initialization finished.
|
||||
*
|
||||
* @param {Function} callback
|
||||
* @param {String} [actualConfig]
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._onInit = function( callback, actualConfig ) {
|
||||
this.originalConfig = this.editorInstance.config;
|
||||
|
||||
if ( !actualConfig ) {
|
||||
this.actualConfig = JSON.parse( JSON.stringify( this.originalConfig ) );
|
||||
} else {
|
||||
this.actualConfig = JSON.parse( actualConfig );
|
||||
}
|
||||
|
||||
if ( !this.actualConfig.toolbarGroups && !this.actualConfig.toolbar ) {
|
||||
this.actualConfig.toolbarGroups = getDefaultToolbarGroups( this.editorInstance );
|
||||
}
|
||||
|
||||
if ( typeof callback === 'function' )
|
||||
callback( this.mainContainer );
|
||||
|
||||
// Here we are going to keep only `name` and `groups` data from editor `toolbar` property.
|
||||
function getDefaultToolbarGroups( editor ) {
|
||||
var toolbarGroups = editor.toolbar,
|
||||
copy = [];
|
||||
|
||||
var max = toolbarGroups.length;
|
||||
for ( var i = 0; i < max; i++ ) {
|
||||
var group = toolbarGroups[ i ];
|
||||
|
||||
if ( typeof group == 'string' ) {
|
||||
copy.push( group ); // separator
|
||||
} else {
|
||||
copy.push( {
|
||||
name: group.name,
|
||||
groups: group.groups ? group.groups.slice() : []
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates DOM structure of tool.
|
||||
*
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._createModifier = function() {
|
||||
this.mainContainer.addClass( 'unselectable' );
|
||||
|
||||
if ( this.modifyContainer ) {
|
||||
this.modifyContainer.remove();
|
||||
}
|
||||
|
||||
this.modifyContainer = new CKEDITOR.dom.element( 'div' );
|
||||
this.modifyContainer.addClass( 'toolbarModifier' );
|
||||
|
||||
this.mainContainer.append( this.modifyContainer );
|
||||
|
||||
return this.mainContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find editable area in CKEditor instance DOM container
|
||||
*
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.getEditableArea = function() {
|
||||
var selector = ( '#' + this.editorInstance.id + '_contents' );
|
||||
|
||||
return this.editorInstance.container.findOne( selector );
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide editable area in modified editor by sets its height to 0.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._hideEditable = function() {
|
||||
var area = this.getEditableArea();
|
||||
|
||||
this.isEditableVisible = false;
|
||||
|
||||
this.lastEditableAreaHeight = area.getStyle( 'height' );
|
||||
area.setStyle( 'height', '0' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Show editable area in modified editor.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._showEditable = function() {
|
||||
this.isEditableVisible = true;
|
||||
|
||||
this.getEditableArea().setStyle( 'height', this.lastEditableAreaHeight || 'auto' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Toggle editable area visibility.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._toggleEditable = function() {
|
||||
if ( this.isEditableVisible )
|
||||
this._hideEditable();
|
||||
else
|
||||
this._showEditable();
|
||||
};
|
||||
|
||||
/**
|
||||
* Usually called when configuration changes.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._refreshEditor = function() {
|
||||
var that = this,
|
||||
status = this.editorInstance.status;
|
||||
|
||||
// Wait for ready only once.
|
||||
if ( this.waitForReady )
|
||||
return;
|
||||
|
||||
// Not ready.
|
||||
if ( status == 'unloaded' || status == 'loaded' ) {
|
||||
this.waitForReady = true;
|
||||
|
||||
this.editorInstance.once( 'instanceReady', function() {
|
||||
refresh();
|
||||
}, this );
|
||||
// Ready or destroyed.
|
||||
} else {
|
||||
refresh();
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
that.editorInstance.destroy();
|
||||
that._createEditor( true, that.getActualConfig() );
|
||||
that.waitForReady = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates editor that can be used to present the toolbar configuration.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._createEditor = function( doRefresh, configOverrides ) {
|
||||
var that = this;
|
||||
|
||||
this.editorInstance = CKEDITOR.replace( this.editorId );
|
||||
|
||||
this.editorInstance.on( 'configLoaded', function() {
|
||||
var config = that.editorInstance.config;
|
||||
|
||||
if ( configOverrides ) {
|
||||
CKEDITOR.tools.extend( config, configOverrides, true );
|
||||
}
|
||||
|
||||
AbstractToolbarModifier.extendPluginsConfig( config );
|
||||
} );
|
||||
|
||||
// Prevent creating any other space than the top one.
|
||||
this.editorInstance.on( 'uiSpace', function( evt ) {
|
||||
if ( evt.data.space != 'top' ) {
|
||||
evt.stop();
|
||||
}
|
||||
}, null, null, -999 );
|
||||
|
||||
this.editorInstance.once( 'loaded', function() {
|
||||
var btns = that.editorInstance.ui.instances;
|
||||
|
||||
for ( var i in btns ) {
|
||||
if ( btns[ i ] ) {
|
||||
btns[ i ].click = empty;
|
||||
btns[ i ].onClick = empty;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !that.isEditableVisible ) {
|
||||
that._hideEditable();
|
||||
}
|
||||
|
||||
if ( that.currentActive && that.currentActive.name ) {
|
||||
that._highlightGroup( that.currentActive.name );
|
||||
}
|
||||
|
||||
if ( that.hidden ) {
|
||||
that.hideUI();
|
||||
} else {
|
||||
that.showUI();
|
||||
}
|
||||
|
||||
if ( doRefresh && ( typeof that.onRefresh === 'function' ) ) {
|
||||
that.onRefresh();
|
||||
}
|
||||
} );
|
||||
|
||||
function empty() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Always returns copy of config.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.getActualConfig = function() {
|
||||
return JSON.parse( JSON.stringify( this.actualConfig ) );
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates toolbar in tool.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._createToolbar = function() {
|
||||
if ( !this.toolbarButtons.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.toolbarContainer = new CKEDITOR.dom.element( 'div' );
|
||||
this.toolbarContainer.addClass( 'toolbar' );
|
||||
|
||||
var max = this.toolbarButtons.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
this._createToolbarBtn( this.toolbarButtons[ i ] );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create toolbar button and add it to toolbar container
|
||||
*
|
||||
* @param {Object} cfg
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._createToolbarBtn = function( cfg ) {
|
||||
var btnText = ( typeof cfg.text === 'string' ? cfg.text : cfg.text.inactive ),
|
||||
btn = ToolbarConfigurator.FullToolbarEditor.createButton( btnText, cfg.cssClass );
|
||||
|
||||
this.toolbarContainer.append( btn );
|
||||
btn.data( 'group', cfg.group );
|
||||
btn.addClass( cfg.position );
|
||||
btn.on( 'click', function() {
|
||||
cfg.clickCallback.call( this, btn, cfg );
|
||||
}, this );
|
||||
|
||||
return btn;
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Object} config
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._fixGroups = function( config ) {
|
||||
var groups = config.toolbarGroups || [];
|
||||
|
||||
var max = groups.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var currentGroup = groups[ i ];
|
||||
|
||||
// separator, in config, is in raw format
|
||||
// need to make it more sophisticated to keep unique id
|
||||
// for each one
|
||||
if ( currentGroup == '/' ) {
|
||||
currentGroup = groups[ i ] = {};
|
||||
currentGroup.type = 'separator';
|
||||
currentGroup.name = ( 'separator' + CKEDITOR.tools.getNextNumber() );
|
||||
continue;
|
||||
}
|
||||
|
||||
// sometimes subgroups are not set (basic package), so need to
|
||||
// create them artifically
|
||||
currentGroup.groups = currentGroup.groups || [];
|
||||
|
||||
// when there is no subgroup with same name like its parent name
|
||||
// then it have to be added artificially
|
||||
// in order to maintain consistency between user interface and config
|
||||
if ( CKEDITOR.tools.indexOf( currentGroup.groups, currentGroup.name ) == -1 ) {
|
||||
this.editorInstance.ui.addToolbarGroup( currentGroup.name, currentGroup.groups[ currentGroup.groups.length - 1 ], currentGroup.name );
|
||||
currentGroup.groups.push( currentGroup.name );
|
||||
}
|
||||
|
||||
this._fixSubgroups( currentGroup );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform subgroup string to object literal
|
||||
* with keys: {String} name and {Number} totalBtns
|
||||
* Please note: this method modify Object provided in first argument
|
||||
*
|
||||
* input:
|
||||
* [
|
||||
* { groups: [ 'nameOne', 'nameTwo' ] }
|
||||
* ]
|
||||
*
|
||||
* output:
|
||||
* [
|
||||
* { groups: [ { name: 'nameOne', totalBtns: 3 }, { name: 'nameTwo', totalBtns: 5 } ] }
|
||||
* ]
|
||||
*
|
||||
* @param {Object} group
|
||||
* @private
|
||||
*/
|
||||
AbstractToolbarModifier.prototype._fixSubgroups = function( group ) {
|
||||
var subGroups = group.groups;
|
||||
|
||||
var max = subGroups.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var subgroupName = subGroups[ i ];
|
||||
|
||||
subGroups[ i ] = {
|
||||
name: subgroupName,
|
||||
totalBtns: ToolbarConfigurator.ToolbarModifier.getTotalSubGroupButtonsNumber( subgroupName, this.fullToolbarEditor )
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as JSON.stringify method but returned string is in one line
|
||||
*
|
||||
* @param {Object} json
|
||||
* @param {Object} opts
|
||||
* @param {Boolean} opts.addSpaces
|
||||
* @param {Boolean} opts.noQuotesOnKey
|
||||
* @param {Boolean} opts.singleQuotes
|
||||
* @returns {Object}
|
||||
*/
|
||||
AbstractToolbarModifier.stringifyJSONintoOneLine = function( json, opts ) {
|
||||
opts = opts || {};
|
||||
var stringJSON = JSON.stringify( json, null, '' );
|
||||
|
||||
// IE8 make new line characters
|
||||
stringJSON = stringJSON.replace( /\n/g, '' );
|
||||
|
||||
if ( opts.addSpaces ) {
|
||||
stringJSON = stringJSON.replace( /(\{|:|,|\[|\])/g, function( sentence ) {
|
||||
return sentence + ' ';
|
||||
} );
|
||||
|
||||
stringJSON = stringJSON.replace( /(\])/g, function( sentence ) {
|
||||
return ' ' + sentence;
|
||||
} );
|
||||
}
|
||||
|
||||
if ( opts.noQuotesOnKey ) {
|
||||
stringJSON = stringJSON.replace( /"(\w*)":/g, function( sentence, word ) {
|
||||
return word + ':';
|
||||
} );
|
||||
}
|
||||
|
||||
if ( opts.singleQuotes ) {
|
||||
stringJSON = stringJSON.replace( /\"/g, '\'' );
|
||||
}
|
||||
|
||||
return stringJSON;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide toolbar configurator
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.hideUI = function() {
|
||||
this.hidden = true;
|
||||
this.mainContainer.hide();
|
||||
if ( this.editorInstance.container ) {
|
||||
this.editorInstance.container.hide();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Show toolbar configurator
|
||||
*/
|
||||
AbstractToolbarModifier.prototype.showUI = function() {
|
||||
this.hidden = false;
|
||||
this.mainContainer.show();
|
||||
if ( this.editorInstance.container ) {
|
||||
this.editorInstance.container.show();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extends plugins setttings in the specified config with settings useful for
|
||||
* the toolbar configurator.
|
||||
*
|
||||
* @static
|
||||
*/
|
||||
AbstractToolbarModifier.extendPluginsConfig = function( config ) {
|
||||
var extraPlugins = config.extraPlugins;
|
||||
|
||||
// Enable the special, lightweight area to replace wysiwygarea.
|
||||
config.extraPlugins = ( extraPlugins ? extraPlugins + ',' : '' ) + 'toolbarconfiguratorarea';
|
||||
};
|
||||
} )();
|
||||
365
ckeditor/samples/toolbarconfigurator/js/fulltoolbareditor.js
Normal file
365
ckeditor/samples/toolbarconfigurator/js/fulltoolbareditor.js
Normal file
@@ -0,0 +1,365 @@
|
||||
/* exported ToolbarConfigurator */
|
||||
/* global ToolbarConfigurator */
|
||||
|
||||
'use strict';
|
||||
|
||||
window.ToolbarConfigurator = {};
|
||||
|
||||
( function() {
|
||||
/**
|
||||
* @class ToolbarConfigurator.FullToolbarEditor
|
||||
* @constructor
|
||||
*/
|
||||
function FullToolbarEditor() {
|
||||
this.instanceid = 'fte' + CKEDITOR.tools.getNextId();
|
||||
this.textarea = new CKEDITOR.dom.element( 'textarea' );
|
||||
this.textarea.setAttributes( {
|
||||
id: this.instanceid,
|
||||
name: this.instanceid,
|
||||
contentEditable: true
|
||||
} );
|
||||
|
||||
this.buttons = null;
|
||||
this.editorInstance = null;
|
||||
}
|
||||
|
||||
// Expose the class.
|
||||
ToolbarConfigurator.FullToolbarEditor = FullToolbarEditor;
|
||||
|
||||
/**
|
||||
* @param {Function} callback
|
||||
* @param {Object} cfg
|
||||
*/
|
||||
FullToolbarEditor.prototype.init = function( callback ) {
|
||||
var that = this;
|
||||
|
||||
document.body.appendChild( this.textarea.$ );
|
||||
|
||||
CKEDITOR.replace( this.instanceid );
|
||||
|
||||
this.editorInstance = CKEDITOR.instances[ this.instanceid ];
|
||||
|
||||
this.editorInstance.once( 'configLoaded', function( e ) {
|
||||
var cfg = e.editor.config;
|
||||
|
||||
// We want all the buttons.
|
||||
delete cfg.removeButtons;
|
||||
delete cfg.toolbarGroups;
|
||||
delete cfg.toolbar;
|
||||
ToolbarConfigurator.AbstractToolbarModifier.extendPluginsConfig( cfg );
|
||||
|
||||
e.editor.once( 'loaded', function() {
|
||||
that.buttons = FullToolbarEditor.toolbarToButtons( that.editorInstance.toolbar );
|
||||
|
||||
that.buttonsByGroup = FullToolbarEditor.groupButtons( that.buttons );
|
||||
|
||||
that.buttonNamesByGroup = that.groupButtonNamesByGroup( that.buttons );
|
||||
|
||||
e.editor.container.hide();
|
||||
|
||||
if ( typeof callback === 'function' )
|
||||
callback( that.buttons );
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Group array of button names by their group parents.
|
||||
*
|
||||
* @param {Array} buttons
|
||||
* @returns {Object}
|
||||
*/
|
||||
FullToolbarEditor.prototype.groupButtonNamesByGroup = function( buttons ) {
|
||||
var that = this,
|
||||
groups = FullToolbarEditor.groupButtons( buttons );
|
||||
|
||||
for ( var groupName in groups ) {
|
||||
var currGroup = groups[ groupName ];
|
||||
|
||||
groups[ groupName ] = FullToolbarEditor.map( currGroup, function( button ) {
|
||||
return that.getCamelCasedButtonName( button.name );
|
||||
} );
|
||||
}
|
||||
|
||||
return groups;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns group literal.
|
||||
*
|
||||
* @param {String} name
|
||||
* @returns {Object}
|
||||
*/
|
||||
FullToolbarEditor.prototype.getGroupByName = function( name ) {
|
||||
var groups = this.editorInstance.config.toolbarGroups || this.getFullToolbarGroupsConfig();
|
||||
|
||||
var max = groups.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
if ( groups[ i ].name === name )
|
||||
return groups[ i ];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} name
|
||||
* @returns {String | null}
|
||||
*/
|
||||
FullToolbarEditor.prototype.getCamelCasedButtonName = function( name ) {
|
||||
var items = this.editorInstance.ui.items;
|
||||
|
||||
for ( var key in items ) {
|
||||
if ( items[ key ].name == name )
|
||||
return key;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns full toolbarGroups config value which is used when
|
||||
* there is no toolbarGroups field in config.
|
||||
*
|
||||
* @param {Boolean} [pickSeparators=false]
|
||||
* @returns {Array}
|
||||
*/
|
||||
FullToolbarEditor.prototype.getFullToolbarGroupsConfig = function( pickSeparators ) {
|
||||
pickSeparators = ( pickSeparators === true ? true : false );
|
||||
|
||||
var result = [],
|
||||
toolbarGroups = this.editorInstance.toolbar;
|
||||
|
||||
var max = toolbarGroups.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var currentGroup = toolbarGroups[ i ],
|
||||
copiedGroup = {};
|
||||
|
||||
if ( typeof currentGroup.name != 'string' ) {
|
||||
// this is not a group
|
||||
if ( pickSeparators ) {
|
||||
result.push( '/' );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
copiedGroup.name = currentGroup.name;
|
||||
if ( currentGroup.groups )
|
||||
copiedGroup.groups = Array.prototype.slice.call( currentGroup.groups );
|
||||
|
||||
result.push( copiedGroup );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters array items based on checker provided in second argument.
|
||||
* Returns new array.
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @param {Function} checker
|
||||
* @returns {Array}
|
||||
*/
|
||||
FullToolbarEditor.filter = function( arr, checker ) {
|
||||
var max = ( arr && arr.length ? arr.length : 0 ),
|
||||
result = [];
|
||||
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
if ( checker( arr[ i ] ) )
|
||||
result.push( arr[ i ] );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Simplified http://underscorejs.org/#map functionality
|
||||
*
|
||||
* @param {Array | Object} enumerable
|
||||
* @param {Function} modifier
|
||||
* @returns {Array | Object}
|
||||
*/
|
||||
FullToolbarEditor.map = function( enumerable, modifier ) {
|
||||
var result;
|
||||
|
||||
if ( CKEDITOR.tools.isArray( enumerable ) ) {
|
||||
result = [];
|
||||
|
||||
var max = enumerable.length;
|
||||
for ( var i = 0; i < max; i += 1 )
|
||||
result.push( modifier( enumerable[ i ] ) );
|
||||
} else {
|
||||
result = {};
|
||||
|
||||
for ( var key in enumerable )
|
||||
result[ key ] = modifier( enumerable[ key ] );
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Group buttons by their parent names.
|
||||
*
|
||||
* @static
|
||||
* @param {Array} buttons
|
||||
* @returns {Object} The object (`name => group`) representing CKEDITOR.ui.button or CKEDITOR.ui.richCombo
|
||||
*/
|
||||
FullToolbarEditor.groupButtons = function( buttons ) {
|
||||
var groups = {};
|
||||
|
||||
var max = buttons.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var currBtn = buttons[ i ],
|
||||
currBtnGroupName = currBtn.toolbar.split( ',' )[ 0 ];
|
||||
|
||||
groups[ currBtnGroupName ] = groups[ currBtnGroupName ] || [];
|
||||
|
||||
groups[ currBtnGroupName ].push( currBtn );
|
||||
}
|
||||
|
||||
return groups;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pick all buttons from toolbar.
|
||||
*
|
||||
* @static
|
||||
* @param {Array} groups
|
||||
* @returns {Array}
|
||||
*/
|
||||
FullToolbarEditor.toolbarToButtons = function( groups ) {
|
||||
var buttons = [];
|
||||
|
||||
var max = groups.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var currentGroup = groups[ i ];
|
||||
|
||||
if ( typeof currentGroup == 'object' )
|
||||
buttons = buttons.concat( FullToolbarEditor.groupToButtons( groups[ i ] ) );
|
||||
}
|
||||
|
||||
return buttons;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates HTML button representation for view.
|
||||
*
|
||||
* @static
|
||||
* @param {CKEDITOR.ui.button | CKEDITOR.ui.richCombo} button
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
*/
|
||||
FullToolbarEditor.createToolbarButton = function( button ) {
|
||||
var $button = new CKEDITOR.dom.element( 'a' ),
|
||||
icon = FullToolbarEditor.createIcon( button.name, button.icon, button.command );
|
||||
|
||||
$button.setStyle( 'float', 'none' );
|
||||
|
||||
$button.addClass( 'cke_' + ( CKEDITOR.lang.dir == 'rtl' ? 'rtl' : 'ltr' ) );
|
||||
|
||||
if ( button instanceof CKEDITOR.ui.button ) {
|
||||
$button.addClass( 'cke_button' );
|
||||
$button.addClass( 'cke_toolgroup' );
|
||||
|
||||
$button.append( icon );
|
||||
} else if ( CKEDITOR.ui.richCombo && button instanceof CKEDITOR.ui.richCombo ) {
|
||||
var comboLabel = new CKEDITOR.dom.element( 'span' ),
|
||||
comboOpen = new CKEDITOR.dom.element( 'span' ),
|
||||
comboArrow = new CKEDITOR.dom.element( 'span' );
|
||||
|
||||
$button.addClass( 'cke_combo_button' );
|
||||
|
||||
comboLabel.addClass( 'cke_combo_text' );
|
||||
comboLabel.addClass( 'cke_combo_inlinelabel' );
|
||||
comboLabel.setText( button.label );
|
||||
|
||||
comboOpen.addClass( 'cke_combo_open' );
|
||||
comboArrow.addClass( 'cke_combo_arrow' );
|
||||
comboOpen.append( comboArrow );
|
||||
|
||||
$button.append( comboLabel );
|
||||
$button.append( comboOpen );
|
||||
}
|
||||
|
||||
return $button;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and return icon element.
|
||||
*
|
||||
* @param {String} name
|
||||
* @param {String} icon
|
||||
* @param {String} command
|
||||
* @static
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
*/
|
||||
FullToolbarEditor.createIcon = function( name, icon, command ) {
|
||||
var iconStyle = CKEDITOR.skin.getIconStyle( name, ( CKEDITOR.lang.dir == 'rtl' ) );
|
||||
|
||||
// We don't know exactly how to get icon style. Especially for extra plugins,
|
||||
// Which definition may vary.
|
||||
iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( icon, ( CKEDITOR.lang.dir == 'rtl' ) );
|
||||
iconStyle = iconStyle || CKEDITOR.skin.getIconStyle( command, ( CKEDITOR.lang.dir == 'rtl' ) );
|
||||
|
||||
var iconElement = new CKEDITOR.dom.element( 'span' );
|
||||
|
||||
iconElement.addClass( 'cke_button_icon' );
|
||||
iconElement.addClass( 'cke_button__' + name + '_icon' );
|
||||
iconElement.setAttribute( 'style', iconStyle );
|
||||
iconElement.setStyle( 'float', 'none' );
|
||||
|
||||
return iconElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create and return button element
|
||||
*
|
||||
* @param {String} text
|
||||
* @param {String} cssClasses
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
*/
|
||||
FullToolbarEditor.createButton = function( text, cssClasses ) {
|
||||
var $button = new CKEDITOR.dom.element( 'button' );
|
||||
|
||||
$button.addClass( 'button-a' );
|
||||
|
||||
$button.setAttribute( 'type', 'button' );
|
||||
|
||||
if ( typeof cssClasses == 'string' ) {
|
||||
cssClasses = cssClasses.split( ' ' );
|
||||
|
||||
var i = cssClasses.length;
|
||||
while ( i-- ) {
|
||||
$button.addClass( cssClasses[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
$button.setHtml( text );
|
||||
|
||||
return $button;
|
||||
};
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param {Object} group
|
||||
* @returns {Array} representing HTML buttons for view
|
||||
*/
|
||||
FullToolbarEditor.groupToButtons = function( group ) {
|
||||
var buttons = [],
|
||||
items = group.items;
|
||||
|
||||
var max = items ? items.length : 0;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var item = items[ i ];
|
||||
|
||||
if ( item instanceof CKEDITOR.ui.button || CKEDITOR.ui.richCombo && item instanceof CKEDITOR.ui.richCombo ) {
|
||||
item.$ = FullToolbarEditor.createToolbarButton( item );
|
||||
buttons.push( item );
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
};
|
||||
|
||||
} )();
|
||||
1366
ckeditor/samples/toolbarconfigurator/js/toolbarmodifier.js
Normal file
1366
ckeditor/samples/toolbarconfigurator/js/toolbarmodifier.js
Normal file
File diff suppressed because it is too large
Load Diff
623
ckeditor/samples/toolbarconfigurator/js/toolbartextmodifier.js
Normal file
623
ckeditor/samples/toolbarconfigurator/js/toolbartextmodifier.js
Normal file
@@ -0,0 +1,623 @@
|
||||
/* global CodeMirror, ToolbarConfigurator */
|
||||
|
||||
'use strict';
|
||||
|
||||
( function() {
|
||||
var AbstractToolbarModifier = ToolbarConfigurator.AbstractToolbarModifier,
|
||||
FullToolbarEditor = ToolbarConfigurator.FullToolbarEditor;
|
||||
|
||||
/**
|
||||
* @class ToolbarConfigurator.ToolbarTextModifier
|
||||
* @param {String} editorId An id of modified editor
|
||||
* @extends AbstractToolbarModifier
|
||||
* @constructor
|
||||
*/
|
||||
function ToolbarTextModifier( editorId ) {
|
||||
AbstractToolbarModifier.call( this, editorId );
|
||||
|
||||
this.codeContainer = null;
|
||||
this.hintContainer = null;
|
||||
}
|
||||
|
||||
// Expose the class.
|
||||
ToolbarConfigurator.ToolbarTextModifier = ToolbarTextModifier;
|
||||
|
||||
ToolbarTextModifier.prototype = Object.create( AbstractToolbarModifier.prototype );
|
||||
|
||||
/**
|
||||
* @param {Function} callback
|
||||
* @param {String} [config]
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._onInit = function( callback, config ) {
|
||||
AbstractToolbarModifier.prototype._onInit.call( this, undefined, config );
|
||||
|
||||
this._createModifier( config ? this.actualConfig : undefined );
|
||||
|
||||
if ( typeof callback === 'function' )
|
||||
callback( this.mainContainer );
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates HTML main container of modifier.
|
||||
*
|
||||
* @param {String} cfg
|
||||
* @returns {CKEDITOR.dom.element}
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._createModifier = function( cfg ) {
|
||||
var that = this;
|
||||
|
||||
this._createToolbar();
|
||||
|
||||
if ( this.toolbarContainer ) {
|
||||
this.mainContainer.append( this.toolbarContainer );
|
||||
}
|
||||
|
||||
AbstractToolbarModifier.prototype._createModifier.call( this );
|
||||
|
||||
this._setupActualConfig( cfg );
|
||||
|
||||
var toolbarCfg = this.actualConfig.toolbar,
|
||||
cfgValue;
|
||||
|
||||
if ( CKEDITOR.tools.isArray( toolbarCfg ) ) {
|
||||
var stringifiedToolbar = '[\n\t\t' + FullToolbarEditor.map( toolbarCfg, function( json ) {
|
||||
return AbstractToolbarModifier.stringifyJSONintoOneLine( json, {
|
||||
addSpaces: true,
|
||||
noQuotesOnKey: true,
|
||||
singleQuotes: true
|
||||
} );
|
||||
} ).join( ',\n\t\t' ) + '\n\t]';
|
||||
|
||||
cfgValue = '\tconfig.toolbar = ' + stringifiedToolbar + ';';
|
||||
} else {
|
||||
cfgValue = 'config.toolbar = [];';
|
||||
}
|
||||
|
||||
cfgValue = [
|
||||
'CKEDITOR.editorConfig = function( config ) {\n',
|
||||
cfgValue,
|
||||
'\n};'
|
||||
].join( '' );
|
||||
|
||||
function hint( cm ) {
|
||||
var data = setupData( cm );
|
||||
|
||||
if ( data.charsBetween === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var unused = that.getUnusedButtonsArray( that.actualConfig.toolbar, true, data.charsBetween ),
|
||||
to = cm.getCursor(),
|
||||
from = CodeMirror.Pos( to.line, ( to.ch - ( data.charsBetween.length ) ) ),
|
||||
token = cm.getTokenAt( to ),
|
||||
prevToken = cm.getTokenAt( { line: to.line, ch: token.start } );
|
||||
|
||||
// determine that we are at beginning of group,
|
||||
// so first key is "name"
|
||||
if ( prevToken.string === '{' )
|
||||
unused = [ 'name' ];
|
||||
|
||||
// preventing close with special character and move cursor forward
|
||||
// when no autocomplete
|
||||
if ( unused.length === 0 )
|
||||
return;
|
||||
|
||||
return new HintData( from, to, unused );
|
||||
}
|
||||
|
||||
function HintData( from, to, list ) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.list = list;
|
||||
this._handlers = [];
|
||||
}
|
||||
|
||||
function setupData( cm, character ) {
|
||||
var result = {};
|
||||
|
||||
result.cur = cm.getCursor();
|
||||
result.tok = cm.getTokenAt( result.cur );
|
||||
|
||||
result[ 'char' ] = character || result.tok.string.charAt( result.tok.string.length - 1 );
|
||||
|
||||
// Getting string between begin of line and cursor.
|
||||
var curLineTillCur = cm.getRange( CodeMirror.Pos( result.cur.line, 0 ), result.cur );
|
||||
|
||||
// Reverse string.
|
||||
var currLineTillCurReversed = curLineTillCur.split( '' ).reverse().join( '' );
|
||||
|
||||
// Removing proper string definitions :
|
||||
// FROM:
|
||||
// R' ,'odeR' ,'odnU' [ :smeti{
|
||||
// ^^^^^^ ^^^^^^
|
||||
// TO:
|
||||
// R' , [ :smeti{
|
||||
currLineTillCurReversed = currLineTillCurReversed.replace( /(['|"]\w*['|"])/g, '' );
|
||||
|
||||
// Matching letters till ' or " character and end string char.
|
||||
// R' , [ :smeti{
|
||||
// ^
|
||||
result.charsBetween = currLineTillCurReversed.match( /(^\w*)(['|"])/ );
|
||||
|
||||
if ( result.charsBetween ) {
|
||||
result.endChar = result.charsBetween[ 2 ];
|
||||
|
||||
// And reverse string (bring to original state).
|
||||
result.charsBetween = result.charsBetween[ 1 ].split( '' ).reverse().join( '' );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function complete( cm ) {
|
||||
setTimeout( function() {
|
||||
if ( !cm.state.completionActive ) {
|
||||
CodeMirror.showHint( cm, hint, {
|
||||
hintsClass: 'toolbar-modifier',
|
||||
completeSingle: false
|
||||
} );
|
||||
}
|
||||
}, 100 );
|
||||
|
||||
return CodeMirror.Pass;
|
||||
}
|
||||
|
||||
var codeMirrorWrapper = new CKEDITOR.dom.element( 'div' );
|
||||
codeMirrorWrapper.addClass( 'codemirror-wrapper' );
|
||||
this.modifyContainer.append( codeMirrorWrapper );
|
||||
this.codeContainer = CodeMirror( codeMirrorWrapper.$, {
|
||||
mode: { name: 'javascript', json: true },
|
||||
// For some reason (most likely CM's bug) gutter breaks CM's height.
|
||||
// Refreshing CM does not help.
|
||||
lineNumbers: false,
|
||||
lineWrapping: true,
|
||||
// Trick to make CM autogrow. http://codemirror.net/demo/resize.html
|
||||
viewportMargin: Infinity,
|
||||
value: cfgValue,
|
||||
smartIndent: false,
|
||||
indentWithTabs: true,
|
||||
indentUnit: 4,
|
||||
tabSize: 4,
|
||||
theme: 'neo',
|
||||
extraKeys: {
|
||||
'Left': complete,
|
||||
'Right': complete,
|
||||
"'''": complete,
|
||||
"'\"'": complete,
|
||||
Backspace: complete,
|
||||
Delete: complete,
|
||||
'Shift-Tab': 'indentLess'
|
||||
}
|
||||
} );
|
||||
|
||||
this.codeContainer.on( 'endCompletion', function( cm, completionData ) {
|
||||
var data = setupData( cm );
|
||||
|
||||
// preventing close with special character and move cursor forward
|
||||
// when no autocomplete
|
||||
if ( completionData === undefined )
|
||||
return;
|
||||
|
||||
cm.replaceSelection( data.endChar );
|
||||
} );
|
||||
|
||||
this.codeContainer.on( 'change', function() {
|
||||
var value = that.codeContainer.getValue();
|
||||
|
||||
value = that._evaluateValue( value );
|
||||
|
||||
if ( value !== null ) {
|
||||
that.actualConfig.toolbar = ( value.toolbar ? value.toolbar : that.actualConfig.toolbar );
|
||||
|
||||
that._fillHintByUnusedElements();
|
||||
that._refreshEditor();
|
||||
|
||||
that.mainContainer.removeClass( 'invalid' );
|
||||
} else {
|
||||
that.mainContainer.addClass( 'invalid' );
|
||||
}
|
||||
} );
|
||||
|
||||
this.hintContainer = new CKEDITOR.dom.element( 'div' );
|
||||
this.hintContainer.addClass( 'toolbarModifier-hints' );
|
||||
|
||||
this._fillHintByUnusedElements();
|
||||
this.hintContainer.insertBefore( codeMirrorWrapper );
|
||||
};
|
||||
|
||||
/**
|
||||
* Create DOM string and set to hint container,
|
||||
* show proper information when no unused element left.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._fillHintByUnusedElements = function() {
|
||||
var unused = this.getUnusedButtonsArray( this.actualConfig.toolbar, true );
|
||||
unused = this.groupButtonNamesByGroup( unused );
|
||||
|
||||
var unusedElements = FullToolbarEditor.map( unused, function( elem ) {
|
||||
var buttonsList = FullToolbarEditor.map( elem.buttons, function( buttonName ) {
|
||||
return '<code>' + buttonName + '</code> ';
|
||||
} ).join( '' );
|
||||
|
||||
return [
|
||||
'<dt>',
|
||||
'<code>', elem.name, '</code>',
|
||||
'</dt>',
|
||||
'<dd>',
|
||||
buttonsList,
|
||||
'</dd>'
|
||||
].join( '' );
|
||||
} ).join( ' ' );
|
||||
|
||||
var listHeader = [
|
||||
'<dt class="list-header">Toolbar group</dt>',
|
||||
'<dd class="list-header">Unused items</dd>'
|
||||
].join( '' );
|
||||
|
||||
var header = '<h3>Unused toolbar items</h3>';
|
||||
|
||||
if ( !unused.length ) {
|
||||
listHeader = '<p>All items are in use.</p>';
|
||||
}
|
||||
|
||||
this.codeContainer.refresh();
|
||||
|
||||
this.hintContainer.setHtml( header + '<dl>' + listHeader + unusedElements + '</dl>' );
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} buttonName
|
||||
* @returns {String}
|
||||
*/
|
||||
ToolbarTextModifier.prototype.getToolbarGroupByButtonName = function( buttonName ) {
|
||||
var buttonNames = this.fullToolbarEditor.buttonNamesByGroup;
|
||||
|
||||
for ( var groupName in buttonNames ) {
|
||||
var buttons = buttonNames[ groupName ];
|
||||
|
||||
var i = buttons.length;
|
||||
while ( i-- ) {
|
||||
if ( buttonName === buttons[ i ] ) {
|
||||
return groupName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter all available toolbar elements by array of elements provided in first argument.
|
||||
* Returns elements which are not used.
|
||||
*
|
||||
* @param {Object} toolbar
|
||||
* @param {Boolean} [sorted=false]
|
||||
* @param {String} prefix
|
||||
* @returns {Array}
|
||||
*/
|
||||
ToolbarTextModifier.prototype.getUnusedButtonsArray = function( toolbar, sorted, prefix ) {
|
||||
sorted = ( sorted === true ? true : false );
|
||||
var providedElements = ToolbarTextModifier.mapToolbarCfgToElementsList( toolbar ),
|
||||
allElements = Object.keys( this.fullToolbarEditor.editorInstance.ui.items );
|
||||
|
||||
// get rid of "-" elements
|
||||
allElements = FullToolbarEditor.filter( allElements, function( elem ) {
|
||||
var isSeparator = ( elem === '-' ),
|
||||
matchPrefix = ( prefix === undefined || elem.toLowerCase().indexOf( prefix.toLowerCase() ) === 0 );
|
||||
|
||||
return !isSeparator && matchPrefix;
|
||||
} );
|
||||
|
||||
var elementsNotUsed = FullToolbarEditor.filter( allElements, function( elem ) {
|
||||
return CKEDITOR.tools.indexOf( providedElements, elem ) == -1;
|
||||
} );
|
||||
|
||||
if ( sorted )
|
||||
elementsNotUsed.sort();
|
||||
|
||||
return elementsNotUsed;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Array} buttons
|
||||
* @returns {Array}
|
||||
*/
|
||||
ToolbarTextModifier.prototype.groupButtonNamesByGroup = function( buttons ) {
|
||||
var result = [],
|
||||
groupedBtns = JSON.parse( JSON.stringify( this.fullToolbarEditor.buttonNamesByGroup ) );
|
||||
|
||||
for ( var groupName in groupedBtns ) {
|
||||
var currGroup = groupedBtns[ groupName ];
|
||||
currGroup = FullToolbarEditor.filter( currGroup, function( btnName ) {
|
||||
return CKEDITOR.tools.indexOf( buttons, btnName ) !== -1;
|
||||
} );
|
||||
|
||||
if ( currGroup.length ) {
|
||||
result.push( {
|
||||
name: groupName,
|
||||
buttons: currGroup
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map toolbar config value to flat items list.
|
||||
*
|
||||
* input:
|
||||
* [
|
||||
* { name: "basicstyles", items: ["Bold", "Italic"] },
|
||||
* { name: "advancedstyles", items: ["Bold", "Outdent", "Indent"] }
|
||||
* ]
|
||||
*
|
||||
* output:
|
||||
* ["Bold", "Italic", "Outdent", "Indent"]
|
||||
*
|
||||
* @param {Object} toolbar
|
||||
* @returns {Array}
|
||||
*/
|
||||
ToolbarTextModifier.mapToolbarCfgToElementsList = function( toolbar ) {
|
||||
var elements = [];
|
||||
|
||||
var max = toolbar.length;
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
if ( !toolbar[ i ] || typeof toolbar[ i ] === 'string' )
|
||||
continue;
|
||||
|
||||
elements = elements.concat( FullToolbarEditor.filter( toolbar[ i ].items, checker ) );
|
||||
}
|
||||
|
||||
function checker( elem ) {
|
||||
return elem !== '-';
|
||||
}
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} cfg
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._setupActualConfig = function( cfg ) {
|
||||
cfg = cfg || this.editorInstance.config;
|
||||
|
||||
// if toolbar already exists in config, there is nothing to do
|
||||
if ( CKEDITOR.tools.isArray( cfg.toolbar ) )
|
||||
return;
|
||||
|
||||
// if toolbar group not present, we need to pick them from full toolbar instance
|
||||
if ( !cfg.toolbarGroups )
|
||||
cfg.toolbarGroups = this.fullToolbarEditor.getFullToolbarGroupsConfig( true );
|
||||
|
||||
this._fixGroups( cfg );
|
||||
|
||||
cfg.toolbar = this._mapToolbarGroupsToToolbar( cfg.toolbarGroups, this.actualConfig.removeButtons );
|
||||
|
||||
this.actualConfig.toolbar = cfg.toolbar;
|
||||
this.actualConfig.removeButtons = '';
|
||||
};
|
||||
|
||||
/**
|
||||
* **Please note:** This method modify element provided in first argument.
|
||||
*
|
||||
* @param {Array} toolbarGroups
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._mapToolbarGroupsToToolbar = function( toolbarGroups, removedBtns ) {
|
||||
removedBtns = removedBtns || this.editorInstance.config.removedBtns;
|
||||
removedBtns = typeof removedBtns == 'string' ? removedBtns.split( ',' ) : [];
|
||||
|
||||
// from the end, because array indexes may change
|
||||
var i = toolbarGroups.length;
|
||||
while ( i-- ) {
|
||||
var mappedSubgroup = this._mapToolbarSubgroup( toolbarGroups[ i ], removedBtns );
|
||||
|
||||
if ( toolbarGroups[ i ].type === 'separator' ) {
|
||||
toolbarGroups[ i ] = '/';
|
||||
continue;
|
||||
}
|
||||
|
||||
// don't want empty groups
|
||||
if ( CKEDITOR.tools.isArray( mappedSubgroup ) && mappedSubgroup.length === 0 ) {
|
||||
toolbarGroups.splice( i, 1 );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( typeof mappedSubgroup == 'string' )
|
||||
toolbarGroups[ i ] = mappedSubgroup;
|
||||
else {
|
||||
toolbarGroups[ i ] = {
|
||||
name: toolbarGroups[ i ].name,
|
||||
items: mappedSubgroup
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return toolbarGroups;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String|Object} group
|
||||
* @param {Array} removedBtns
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._mapToolbarSubgroup = function( group, removedBtns ) {
|
||||
var totalBtns = 0;
|
||||
if ( typeof group == 'string' )
|
||||
return group;
|
||||
|
||||
var max = group.groups ? group.groups.length : 0,
|
||||
result = [];
|
||||
for ( var i = 0; i < max; i += 1 ) {
|
||||
var currSubgroup = group.groups[ i ];
|
||||
|
||||
var buttons = this.fullToolbarEditor.buttonsByGroup[ typeof currSubgroup === 'string' ? currSubgroup : currSubgroup.name ] || [];
|
||||
buttons = this._mapButtonsToButtonsNames( buttons, removedBtns );
|
||||
var currTotalBtns = buttons.length;
|
||||
totalBtns += currTotalBtns;
|
||||
result = result.concat( buttons );
|
||||
|
||||
if ( currTotalBtns )
|
||||
result.push( '-' );
|
||||
}
|
||||
|
||||
if ( result[ result.length - 1 ] == '-' )
|
||||
result.pop();
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Array} buttons
|
||||
* @param {Array} removedBtns
|
||||
* @returns {Array}
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._mapButtonsToButtonsNames = function( buttons, removedBtns ) {
|
||||
var i = buttons.length;
|
||||
while ( i-- ) {
|
||||
var currBtn = buttons[ i ],
|
||||
camelCasedName;
|
||||
|
||||
if ( typeof currBtn === 'string' ) {
|
||||
camelCasedName = currBtn;
|
||||
} else {
|
||||
camelCasedName = this.fullToolbarEditor.getCamelCasedButtonName( currBtn.name );
|
||||
}
|
||||
|
||||
if ( CKEDITOR.tools.indexOf( removedBtns, camelCasedName ) !== -1 ) {
|
||||
buttons.splice( i, 1 );
|
||||
continue;
|
||||
}
|
||||
|
||||
buttons[ i ] = camelCasedName;
|
||||
}
|
||||
|
||||
return buttons;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String} val
|
||||
* @returns {Object}
|
||||
* @private
|
||||
*/
|
||||
ToolbarTextModifier.prototype._evaluateValue = function( val ) {
|
||||
var parsed;
|
||||
|
||||
try {
|
||||
var config = {};
|
||||
( function() {
|
||||
var CKEDITOR = Function( 'var CKEDITOR = {}; ' + val + '; return CKEDITOR;' )();
|
||||
|
||||
CKEDITOR.editorConfig( config );
|
||||
parsed = config;
|
||||
} )();
|
||||
|
||||
// CKEditor does not handle empty arrays in configuration files
|
||||
// on IE8
|
||||
var i = parsed.toolbar.length;
|
||||
while ( i-- )
|
||||
if ( !parsed.toolbar[ i ] ) parsed.toolbar.splice( i, 1 );
|
||||
|
||||
} catch ( e ) {
|
||||
parsed = null;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} toolbar
|
||||
* @returns {{toolbarGroups: Array, removeButtons: string}}
|
||||
*/
|
||||
ToolbarTextModifier.prototype.mapToolbarToToolbarGroups = function( toolbar ) {
|
||||
var usedGroups = {},
|
||||
removeButtons = [],
|
||||
toolbarGroups = [];
|
||||
|
||||
var max = toolbar.length;
|
||||
for ( var i = 0; i < max; i++ ) {
|
||||
if ( toolbar[ i ] === '/' ) {
|
||||
toolbarGroups.push( '/' );
|
||||
continue;
|
||||
}
|
||||
|
||||
var items = toolbar[ i ].items;
|
||||
|
||||
var toolbarGroup = {};
|
||||
toolbarGroup.name = toolbar[ i ].name;
|
||||
toolbarGroup.groups = [];
|
||||
|
||||
var max2 = items.length;
|
||||
for ( var j = 0; j < max2; j++ ) {
|
||||
var item = items[ j ];
|
||||
|
||||
if ( item === '-' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var groupName = this.getToolbarGroupByButtonName( item );
|
||||
|
||||
var groupIndex = toolbarGroup.groups.indexOf( groupName );
|
||||
if ( groupIndex === -1 ) {
|
||||
toolbarGroup.groups.push( groupName );
|
||||
}
|
||||
|
||||
usedGroups[ groupName ] = usedGroups[ groupName ] || {};
|
||||
|
||||
var buttons = ( usedGroups[ groupName ].buttons = usedGroups[ groupName ].buttons || {} );
|
||||
|
||||
buttons[ item ] = buttons[ item ] || { used: 0, origin: toolbarGroup.name };
|
||||
buttons[ item ].used++;
|
||||
}
|
||||
|
||||
toolbarGroups.push( toolbarGroup );
|
||||
}
|
||||
|
||||
// Handling removed buttons
|
||||
removeButtons = prepareRemovedButtons( usedGroups, this.fullToolbarEditor.buttonNamesByGroup );
|
||||
|
||||
function prepareRemovedButtons( usedGroups, buttonNames ) {
|
||||
var removed = [];
|
||||
|
||||
for ( var groupName in usedGroups ) {
|
||||
var group = usedGroups[ groupName ];
|
||||
var allButtonsInGroup = buttonNames[ groupName ].slice();
|
||||
|
||||
removed = removed.concat( removeStuffFromArray( allButtonsInGroup, Object.keys( group.buttons ) ) );
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
function removeStuffFromArray( array, stuff ) {
|
||||
array = array.slice();
|
||||
var i = stuff.length;
|
||||
|
||||
while ( i-- ) {
|
||||
var atIndex = array.indexOf( stuff[ i ] );
|
||||
if ( atIndex !== -1 ) {
|
||||
array.splice( atIndex, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
return { toolbarGroups: toolbarGroups, removeButtons: removeButtons.join( ',' ) };
|
||||
};
|
||||
|
||||
return ToolbarTextModifier;
|
||||
} )();
|
||||
Reference in New Issue
Block a user