123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /* 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';
- };
- } )();
|