1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366 |
- /* global ToolbarConfigurator, alert */
- 'use strict';
- ( function() {
- var AbstractToolbarModifier = ToolbarConfigurator.AbstractToolbarModifier;
- /**
- * @class ToolbarConfigurator.ToolbarModifier
- * @param {String} editorId An id of modified editor
- * @param {Object} cfg
- * @extends AbstractToolbarModifier
- * @constructor
- */
- function ToolbarModifier( editorId, cfg ) {
- AbstractToolbarModifier.call( this, editorId, cfg );
- this.removedButtons = null;
- this.originalConfig = null;
- this.actualConfig = null;
- this.emptyVisible = false;
- // edit, paste, config
- this.state = 'edit';
- this.toolbarButtons = [
- {
- text: {
- active: 'Hide empty toolbar groups',
- inactive: 'Show empty toolbar groups'
- },
- group: 'edit',
- position: 'left',
- cssClass: 'button-a-soft',
- clickCallback: function( button, buttonDefinition ) {
- var className = 'button-a-background';
- button[ button.hasClass( className ) ? 'removeClass' : 'addClass' ]( className );
- this._toggleVisibilityEmptyElements();
- if ( this.emptyVisible ) {
- button.setText( buttonDefinition.text.active );
- } else {
- button.setText( buttonDefinition.text.inactive );
- }
- }
- },
- {
- text: 'Add row separator',
- group: 'edit',
- position: 'left',
- cssClass: 'button-a-soft',
- clickCallback: function() {
- this._addSeparator();
- }
- },
- /*{
- text: 'Paste config',
- group: 'edit',
- position: 'left',
- clickCallback: function() {
- this.state = 'paste';
- this.modifyContainer.addClass( 'hidden' );
- this.configContainer.removeClass( 'hidden' );
- this.configContainer.setHtml( '<textarea></textarea>' );
- this.showToolbarBtnsByGroupName( 'config' );
- }
- },*/
- {
- text: 'Select config',
- group: 'config',
- position: 'left',
- cssClass: 'button-a-soft',
- clickCallback: function() {
- this.configContainer.findOne( 'textarea' ).$.select();
- }
- },
- {
- text: 'Back to configurator',
- group: 'config',
- position: 'right',
- cssClass: 'button-a-background',
- clickCallback: function() {
- if ( this.state === 'paste' ) {
- var cfg = this.configContainer.findOne( 'textarea' ).getValue();
- cfg = ToolbarModifier.evaluateToolbarGroupsConfig( cfg );
- if ( cfg ) {
- this.setConfig( cfg );
- } else {
- alert( 'Your pasted config is wrong.' );
- }
- }
- this.state = 'edit';
- this._showConfigurationTool();
- this.showToolbarBtnsByGroupName( this.state );
- }
- },
- {
- text: 'Get toolbar <span class="highlight">config</span>',
- group: 'edit',
- position: 'right',
- cssClass: 'button-a-background icon-pos-left icon-download',
- clickCallback: function() {
- this.state = 'config';
- this._showConfig();
- this.showToolbarBtnsByGroupName( this.state );
- }
- }
- ];
- this.cachedActiveElement = null;
- }
- // Expose the class.
- ToolbarConfigurator.ToolbarModifier = ToolbarModifier;
- ToolbarModifier.prototype = Object.create( ToolbarConfigurator.AbstractToolbarModifier.prototype );
- /**
- * @returns {Object}
- */
- ToolbarModifier.prototype.getActualConfig = function() {
- var copy = AbstractToolbarModifier.prototype.getActualConfig.call( this );
- if ( copy.toolbarGroups ) {
- var max = copy.toolbarGroups.length;
- for ( var i = 0; i < max; i += 1 ) {
- var currentGroup = copy.toolbarGroups[ i ];
- copy.toolbarGroups[ i ] = ToolbarModifier.parseGroupToConfigValue( currentGroup );
- }
- }
- return copy;
- };
- /**
- * @param {Function} callback
- * @param {String} [config]
- * @param {Boolean} [forceKeepRemoveButtons=false]
- * @private
- */
- ToolbarModifier.prototype._onInit = function( callback, config, forceKeepRemoveButtons ) {
- forceKeepRemoveButtons = ( forceKeepRemoveButtons === true );
- AbstractToolbarModifier.prototype._onInit.call( this, undefined, config );
- this.removedButtons = [];
- if ( forceKeepRemoveButtons ) {
- if ( this.actualConfig.removeButtons ) {
- this.removedButtons = this.actualConfig.removeButtons.split( ',' );
- } else {
- this.removedButtons = [];
- }
- } else {
- if ( !( 'removeButtons' in this.originalConfig ) ) {
- this.originalConfig.removeButtons = '';
- this.removedButtons = [];
- } else {
- this.removedButtons = this.originalConfig.removeButtons ? this.originalConfig.removeButtons.split( ',' ) : [];
- }
- }
- if ( !this.actualConfig.toolbarGroups )
- this.actualConfig.toolbarGroups = this.fullToolbarEditor.getFullToolbarGroupsConfig();
- this._fixGroups( this.actualConfig );
- this._calculateTotalBtns();
- this._createModifier();
- this._refreshMoveBtnsAvalibility();
- this._refreshBtnTabIndexes();
- if ( typeof callback === 'function' )
- callback( this.mainContainer );
- };
- /**
- * @private
- */
- ToolbarModifier.prototype._showConfigurationTool = function() {
- this.configContainer.addClass( 'hidden' );
- this.modifyContainer.removeClass( 'hidden' );
- };
- /**
- * Show configuration file in tool
- *
- * @private
- */
- ToolbarModifier.prototype._showConfig = function() {
- var that = this,
- actualConfig = this.getActualConfig(),
- cfg = {};
- if ( actualConfig.toolbarGroups ) {
- cfg.toolbarGroups = actualConfig.toolbarGroups;
- var groups = prepareGroups( actualConfig.toolbarGroups, this.cfg.trimEmptyGroups );
- cfg.toolbarGroups = '\n\t\t' + groups.join( ',\n\t\t' );
- }
- function prepareGroups( toolbarGroups, trimEmptyGroups ) {
- var groups = [],
- max = toolbarGroups.length;
- for ( var i = 0; i < max; i++ ) {
- var group = toolbarGroups[ i ];
- if ( group === '/' ) {
- groups.push( '\'/\'' );
- continue;
- }
- if ( trimEmptyGroups ) {
- var max2 = group.groups.length;
- while ( max2-- ) {
- var subgroup = group.groups[ max2 ];
- if ( ToolbarModifier.getTotalSubGroupButtonsNumber( subgroup, that.fullToolbarEditor ) === 0 ) {
- group.groups.splice( max2, 1 );
- }
- }
- }
- if ( !( trimEmptyGroups && group.groups.length === 0 ) ) {
- groups.push( AbstractToolbarModifier.stringifyJSONintoOneLine( group, {
- addSpaces: true,
- noQuotesOnKey: true,
- singleQuotes: true
- } ) );
- }
- }
- return groups;
- }
- if ( actualConfig.removeButtons ) {
- cfg.removeButtons = actualConfig.removeButtons;
- }
- var content = [
- '<textarea class="configCode" readonly>',
- 'CKEDITOR.editorConfig = function( config ) {\n',
- ( cfg.toolbarGroups ? '\tconfig.toolbarGroups = [' + cfg.toolbarGroups + '\n\t];' : '' ),
- ( cfg.removeButtons ? '\n\n' : '' ),
- ( cfg.removeButtons ? '\tconfig.removeButtons = \'' + cfg.removeButtons + '\';' : '' ),
- '\n};',
- '</textarea>'
- ].join( '' );
- this.modifyContainer.addClass( 'hidden' );
- this.configContainer.removeClass( 'hidden' );
- this.configContainer.setHtml( content );
- };
- /**
- * Toggle empty groups and subgroups visibility.
- *
- * @private
- */
- ToolbarModifier.prototype._toggleVisibilityEmptyElements = function() {
- if ( this.modifyContainer.hasClass( 'empty-visible' ) ) {
- this.modifyContainer.removeClass( 'empty-visible' );
- this.emptyVisible = false;
- } else {
- this.modifyContainer.addClass( 'empty-visible' );
- this.emptyVisible = true;
- }
- this._refreshMoveBtnsAvalibility();
- };
- /**
- * Creates HTML main container of modifier.
- *
- * @returns {CKEDITOR.dom.element}
- * @private
- */
- ToolbarModifier.prototype._createModifier = function() {
- var that = this;
- AbstractToolbarModifier.prototype._createModifier.call( this );
- this.modifyContainer.setHtml( this._toolbarConfigToListString() );
- var groupLi = this.modifyContainer.find( 'li[data-type="group"]' );
- this.modifyContainer.on( 'mouseleave', function() {
- this._dehighlightActiveToolGroup();
- }, this );
- var max = groupLi.count();
- for ( var i = 0; i < max; i += 1 ) {
- groupLi.getItem( i ).on( 'mouseenter', onGroupHover );
- }
- function onGroupHover() {
- that._highlightGroup( this.data( 'name' ) );
- }
- CKEDITOR.document.on( 'keypress', function( e ) {
- var nativeEvent = e.data.$,
- keyCode = nativeEvent.keyCode,
- spaceOrEnter = ( keyCode === 32 || keyCode === 13 ),
- active = new CKEDITOR.dom.element( CKEDITOR.document.$.activeElement );
- var mainContainer = active.getAscendant( function( node ) {
- return node.$ === that.mainContainer.$;
- } );
- if ( !mainContainer || !spaceOrEnter ) {
- return;
- }
- if ( active.data( 'type' ) === 'button' ) {
- active.findOne( 'input' ).$.click();
- }
- } );
- this.modifyContainer.on( 'click', function( e ) {
- var origEvent = e.data.$,
- target = new CKEDITOR.dom.element( ( origEvent.target || origEvent.srcElement ) ),
- relativeGroupOrSeparatorLi = ToolbarModifier.getGroupOrSeparatorLiAncestor( target );
- if ( !relativeGroupOrSeparatorLi ) {
- return;
- }
- that.cachedActiveElement = document.activeElement;
- // checkbox clicked
- if ( target.$ instanceof HTMLInputElement )
- that._handleCheckboxClicked( target );
- // link clicked
- else if ( target.$ instanceof HTMLButtonElement ) {
- if ( origEvent.preventDefault )
- origEvent.preventDefault();
- else
- origEvent.returnValue = false;
- var result = that._handleAnchorClicked( target.$ );
- if ( result && result.action == 'remove' )
- return;
- }
- var elementType = relativeGroupOrSeparatorLi.data( 'type' ),
- elementName = relativeGroupOrSeparatorLi.data( 'name' );
- that._setActiveElement( elementType, elementName );
- if ( that.cachedActiveElement )
- that.cachedActiveElement.focus();
- } );
- if ( !this.toolbarContainer ) {
- this._createToolbar();
- this.toolbarContainer.insertBefore( this.mainContainer.getChildren().getItem( 0 ) );
- }
- this.showToolbarBtnsByGroupName( 'edit' );
- if ( !this.configContainer ) {
- this.configContainer = new CKEDITOR.dom.element( 'div' );
- this.configContainer.addClass( 'configContainer' );
- this.configContainer.addClass( 'hidden' );
- this.mainContainer.append( this.configContainer );
- }
- return this.mainContainer;
- };
- /**
- * Show toolbar buttons related to group name provided in argument
- * and hide other buttons
- * Please note: this method works on toolbar in tool, which is located
- * on top of the tool
- *
- * @param {String} groupName
- */
- ToolbarModifier.prototype.showToolbarBtnsByGroupName = function( groupName ) {
- if ( !this.toolbarContainer ) {
- return;
- }
- var allButtons = this.toolbarContainer.find( 'button' );
- var max = allButtons.count();
- for ( var i = 0; i < max; i += 1 ) {
- var currentBtn = allButtons.getItem( i );
- if ( currentBtn.data( 'group' ) == groupName )
- currentBtn.removeClass( 'hidden' );
- else
- currentBtn.addClass( 'hidden' );
- }
- };
- /**
- * Parse group "model" to configuration value
- *
- * @param {Object} group
- * @returns {Object}
- * @private
- */
- ToolbarModifier.parseGroupToConfigValue = function( group ) {
- if ( group.type == 'separator' ) {
- return '/';
- }
- var groups = group.groups,
- max = groups.length;
- delete group.totalBtns;
- for ( var i = 0; i < max; i += 1 ) {
- groups[ i ] = groups[ i ].name;
- }
- return group;
- };
- /**
- * Find closest Li ancestor in DOM tree which is group or separator element
- *
- * @param {CKEDITOR.dom.element} element
- * @returns {CKEDITOR.dom.element}
- */
- ToolbarModifier.getGroupOrSeparatorLiAncestor = function( element ) {
- if ( element.$ instanceof HTMLLIElement && element.data( 'type' ) == 'group' )
- return element;
- else {
- return ToolbarModifier.getFirstAncestor( element, function( ancestor ) {
- var type = ancestor.data( 'type' );
- return ( type == 'group' || type == 'separator' );
- } );
- }
- };
- /**
- * Set active element in tool by provided type and name.
- *
- * @param {String} type
- * @param {String} name
- */
- ToolbarModifier.prototype._setActiveElement = function( type, name ) {
- // clear current active element
- if ( this.currentActive )
- this.currentActive.elem.removeClass( 'active' );
- if ( type === null ) {
- this._dehighlightActiveToolGroup();
- this.currentActive = null;
- return;
- }
- var liElem = this.mainContainer.findOne( 'ul[data-type=table-body] li[data-type="' + type + '"][data-name="' + name + '"]' );
- liElem.addClass( 'active' );
- // setup model
- this.currentActive = {
- type: type,
- name: name,
- elem: liElem
- };
- // highlight group in toolbar
- if ( type == 'group' )
- this._highlightGroup( name );
- if ( type == 'separator' )
- this._dehighlightActiveToolGroup();
- };
- /**
- * @returns {CKEDITOR.dom.element|null}
- */
- ToolbarModifier.prototype.getActiveToolGroup = function() {
- if ( this.editorInstance.container )
- return this.editorInstance.container.findOne( '.cke_toolgroup.active, .cke_toolbar.active' );
- else
- return null;
- };
- /**
- * @private
- */
- ToolbarModifier.prototype._dehighlightActiveToolGroup = function() {
- var currentActive = this.getActiveToolGroup();
- if ( currentActive )
- currentActive.removeClass( 'active' );
- // @see ToolbarModifier.prototype._highlightGroup.
- if ( this.editorInstance.container ) {
- this.editorInstance.container.removeClass( 'some-toolbar-active' );
- }
- };
- /**
- * Highlight group by its name, and dehighlight current group.
- *
- * @param {String} name
- */
- ToolbarModifier.prototype._highlightGroup = function( name ) {
- if ( !this.editorInstance.container )
- return;
- var foundBtnName = this.getFirstEnabledButtonInGroup( name ),
- foundBtn = this.editorInstance.container.findOne( '.cke_button__' + foundBtnName + ', .cke_combo__' + foundBtnName );
- this._dehighlightActiveToolGroup();
- // Helpful to dim other toolbar groups if one is highlighted.
- if ( this.editorInstance.container ) {
- this.editorInstance.container.addClass( 'some-toolbar-active' );
- }
- if ( foundBtn ) {
- var btnToolbar = ToolbarModifier.getFirstAncestor( foundBtn, function( ancestor ) {
- return ancestor.hasClass( 'cke_toolbar' );
- } );
- if ( btnToolbar )
- btnToolbar.addClass( 'active' );
- }
- };
- /**
- * @param {String} groupName
- * @return {String|null}
- */
- ToolbarModifier.prototype.getFirstEnabledButtonInGroup = function( groupName ) {
- var groups = this.actualConfig.toolbarGroups,
- groupIndex = this.getGroupIndex( groupName ),
- group = groups[ groupIndex ];
- if ( groupIndex === -1 ) {
- return null;
- }
- var max = group.groups ? group.groups.length : 0;
- for ( var i = 0; i < max; i += 1 ) {
- var currSubgroupName = group.groups[ i ].name,
- firstEnabled = this.getFirstEnabledButtonInSubgroup( currSubgroupName );
- if ( firstEnabled )
- return firstEnabled;
- }
- return null;
- };
- /**
- * @param {String} subgroupName
- * @returns {String|null}
- */
- ToolbarModifier.prototype.getFirstEnabledButtonInSubgroup = function( subgroupName ) {
- var subgroupBtns = this.fullToolbarEditor.buttonsByGroup[ subgroupName ];
- var max = subgroupBtns ? subgroupBtns.length : 0;
- for ( var i = 0; i < max; i += 1 ) {
- var currBtnName = subgroupBtns[ i ].name;
- if ( !this.isButtonRemoved( currBtnName ) )
- return currBtnName;
- }
- return null;
- };
- /**
- * Sets up parameters and call adequate action.
- *
- * @param {CKEDITOR.dom.element} checkbox
- * @private
- */
- ToolbarModifier.prototype._handleCheckboxClicked = function( checkbox ) {
- var closestLi = checkbox.getAscendant( 'li' ),
- elementName = closestLi.data( 'name' ),
- aboutToAddToRemoved = !checkbox.$.checked;
- if ( aboutToAddToRemoved )
- this._addButtonToRemoved( elementName );
- else
- this._removeButtonFromRemoved( elementName );
- };
- /**
- * Sets up parameters and call adequate action.
- *
- * @param {HTMLAnchorElement} anchor
- * @private
- */
- ToolbarModifier.prototype._handleAnchorClicked = function( anchor ) {
- var anchorDOM = new CKEDITOR.dom.element( anchor ),
- relativeLi = anchorDOM.getAscendant( 'li' ),
- relativeUl = relativeLi.getAscendant( 'ul' ),
- elementType = relativeLi.data( 'type' ),
- elementName = relativeLi.data( 'name' ),
- direction = anchorDOM.data( 'direction' ),
- nearestLi = ( direction === 'up' ? relativeLi.getPrevious() : relativeLi.getNext() ),
- groupName,
- subgroupName,
- newIndex;
- // nothing to do
- if ( anchorDOM.hasClass( 'disabled' ) )
- return null;
- // remove separator and nothing else
- if ( anchorDOM.hasClass( 'remove' ) ) {
- relativeLi.remove();
- this._removeSeparator( relativeLi.data( 'name' ) );
- this._setActiveElement( null );
- return { action: 'remove' };
- }
- if ( !anchorDOM.hasClass( 'move' ) || !nearestLi )
- return { action: null };
- // move group or separator
- if ( elementType === 'group' || elementType === 'separator' ) {
- groupName = elementName;
- newIndex = this._moveGroup( direction, groupName );
- }
- // move subgroup
- if ( elementType === 'subgroup' ) {
- subgroupName = elementName;
- groupName = relativeLi.getAscendant( 'li' ).data( 'name' );
- newIndex = this._moveSubgroup( direction, groupName, subgroupName );
- }
- // Visual effect
- if ( direction === 'up' )
- relativeLi.insertBefore( relativeUl.getChild( newIndex ) );
- if ( direction === 'down' )
- relativeLi.insertAfter( relativeUl.getChild( newIndex ) );
- // Should know whether there is next li element after modifications.
- var nextLi = relativeLi;
- // We are looking for next li element in list (to check whether current one is the last one)
- var found;
- while ( nextLi = ( direction === 'up' ? nextLi.getPrevious() : nextLi.getNext() ) ) {
- if ( !this.emptyVisible && nextLi.hasClass( 'empty' ) ) {
- continue;
- }
- found = nextLi;
- break;
- }
- // If not found, it means that we reached end.
- if ( !found ) {
- var selector = ( '[data-direction="' + ( direction === 'up' ? 'down' : 'up' ) + '"]' );
- // Shifting direction.
- this.cachedActiveElement = anchorDOM.getParent().findOne( selector );
- }
- this._refreshMoveBtnsAvalibility();
- this._refreshBtnTabIndexes();
- return {
- action: 'move'
- };
- };
- /**
- * First element can not be moved up, and last element can not be moved down,
- * so they are disabled.
- */
- ToolbarModifier.prototype._refreshMoveBtnsAvalibility = function() {
- var that = this,
- disabledBtns = this.mainContainer.find( 'ul[data-type=table-body] li > p > span > button.move.disabled' );
- // enabling all disabled buttons
- var max = disabledBtns.count();
- for ( var i = 0; i < max; i += 1 ) {
- var currentBtn = disabledBtns.getItem( i );
- currentBtn.removeClass( 'disabled' );
- }
- function disableElementsInLists( ulList ) {
- var max = ulList.count();
- for ( i = 0; i < max; i += 1 ) {
- that._disableElementsInList( ulList.getItem( i ) );
- }
- }
- // Disable buttons in toolbars.
- disableElementsInLists( this.mainContainer.find( 'ul[data-type=table-body]' ) );
- // Disable buttons in toolbar groups.
- disableElementsInLists( this.mainContainer.find( 'ul[data-type=table-body] > li > ul' ) );
- };
- /**
- * @private
- */
- ToolbarModifier.prototype._refreshBtnTabIndexes = function() {
- var tabindexed = this.mainContainer.find( '[data-tab="true"]' );
- var max = tabindexed.count();
- for ( var i = 0; i < max; i++ ) {
- var item = tabindexed.getItem( i ),
- disabled = item.hasClass( 'disabled' );
- item.setAttribute( 'tabindex', disabled ? -1 : i );
- }
- };
- /**
- * Disable buttons to move elements up and down which should be disabled.
- *
- * @param {CKEDITOR.dom.element} ul
- * @private
- */
- ToolbarModifier.prototype._disableElementsInList = function( ul ) {
- var liList = ul.getChildren();
- if ( !liList.count() )
- return;
- var firstDisabled, lastDisabled;
- if ( this.emptyVisible ) {
- firstDisabled = ul.getFirst();
- lastDisabled = ul.getLast();
- } else {
- firstDisabled = ul.getFirst( isNotEmptyChecker );
- lastDisabled = ul.getLast( isNotEmptyChecker );
- }
- function isNotEmptyChecker( element ) {
- return !element.hasClass( 'empty' );
- }
- if ( firstDisabled )
- var firstDisabledBtn = firstDisabled.findOne( 'p button[data-direction="up"]' );
- if ( lastDisabled )
- var lastDisabledBtn = lastDisabled.findOne( 'p button[data-direction="down"]' );
- if ( firstDisabledBtn ) {
- firstDisabledBtn.addClass( 'disabled' );
- firstDisabledBtn.setAttribute( 'tabindex', '-1' );
- }
- if ( lastDisabledBtn ) {
- lastDisabledBtn.addClass( 'disabled' );
- lastDisabledBtn.setAttribute( 'tabindex', '-1' );
- }
- };
- /**
- * Gets group index in actual config toolbarGroups
- *
- * @param {String} name
- * @returns {Number}
- */
- ToolbarModifier.prototype.getGroupIndex = function( name ) {
- var groups = this.actualConfig.toolbarGroups;
- var max = groups.length;
- for ( var i = 0; i < max; i += 1 ) {
- if ( groups[ i ].name === name )
- return i;
- }
- return -1;
- };
- /**
- * Handle adding separator.
- *
- * @private
- */
- ToolbarModifier.prototype._addSeparator = function() {
- var separatorIndex = this._determineSeparatorToAddIndex(),
- separator = ToolbarModifier.createSeparatorLiteral(),
- domSeparator = CKEDITOR.dom.element.createFromHtml( ToolbarModifier.getToolbarSeparatorString( separator ) );
- this.actualConfig.toolbarGroups.splice( separatorIndex, 0, separator );
- domSeparator.insertBefore( this.modifyContainer.findOne( 'ul[data-type=table-body]' ).getChild( separatorIndex ) );
- this._setActiveElement( 'separator', separator.name );
- this._refreshMoveBtnsAvalibility();
- this._refreshBtnTabIndexes();
- this._refreshEditor();
- };
- /**
- * Handle removing separator.
- *
- * @param {String} name
- */
- ToolbarModifier.prototype._removeSeparator = function( name ) {
- var separatorIndex = CKEDITOR.tools.indexOf( this.actualConfig.toolbarGroups, function( group ) {
- return group.type == 'separator' && group.name == name;
- } );
- this.actualConfig.toolbarGroups.splice( separatorIndex, 1 );
- this._refreshMoveBtnsAvalibility();
- this._refreshBtnTabIndexes();
- this._refreshEditor();
- };
- /**
- * Determine index where separator should be added, based on currently selected element.
- *
- * @returns {Number}
- * @private
- */
- ToolbarModifier.prototype._determineSeparatorToAddIndex = function() {
- if ( !this.currentActive )
- return 0;
- var groupLi;
- if ( this.currentActive.elem.data( 'type' ) == 'group' || this.currentActive.elem.data( 'type' ) == 'separator' )
- groupLi = this.currentActive.elem;
- else
- groupLi = this.currentActive.elem.getAscendant( 'li' );
- return groupLi.getIndex();
- };
- /**
- * @param {Array} elementsArray
- * @param {Number} elementIndex
- * @param {String} direction
- * @returns {Number}
- * @private
- */
- ToolbarModifier.prototype._moveElement = function( elementsArray, elementIndex, direction ) {
- var nextIndex;
- if ( this.emptyVisible )
- nextIndex = ( direction == 'down' ? elementIndex + 1 : elementIndex - 1 );
- else {
- // When empty elements are not visible, there is need to skip them.
- nextIndex = ToolbarModifier.getFirstElementIndexWith( elementsArray, elementIndex, direction, isEmptyOrSeparatorChecker );
- }
- function isEmptyOrSeparatorChecker( element ) {
- return element.totalBtns || element.type == 'separator';
- }
- var offset = nextIndex - elementIndex;
- return ToolbarModifier.moveTo( offset, elementsArray, elementIndex );
- };
- /**
- * Moves group located in config level up or down and refresh editor.
- *
- * @param {String} direction
- * @param {String} groupName
- * @returns {Number}
- */
- ToolbarModifier.prototype._moveGroup = function( direction, groupName ) {
- var groupIndex = this.getGroupIndex( groupName ),
- groups = this.actualConfig.toolbarGroups,
- newIndex = this._moveElement( groups, groupIndex, direction );
- this._refreshMoveBtnsAvalibility();
- this._refreshBtnTabIndexes();
- this._refreshEditor();
- return newIndex;
- };
- /**
- * Moves subgroup located in config level up or down and refresh editor.
- *
- * @param {String} direction
- * @param {String} groupName
- * @param {String} subgroupName
- * @private
- */
- ToolbarModifier.prototype._moveSubgroup = function( direction, groupName, subgroupName ) {
- var groupIndex = this.getGroupIndex( groupName ),
- groups = this.actualConfig.toolbarGroups,
- group = groups[ groupIndex ],
- subgroupIndex = CKEDITOR.tools.indexOf( group.groups, function( subgroup ) {
- return subgroup.name == subgroupName;
- } ),
- newIndex = this._moveElement( group.groups, subgroupIndex, direction );
- this._refreshEditor();
- return newIndex;
- };
- /**
- * Set `totalBtns` property in `actualConfig.toolbarGroups` elements.
- *
- * @private
- */
- ToolbarModifier.prototype._calculateTotalBtns = function() {
- var groups = this.actualConfig.toolbarGroups;
- var i = groups.length;
- // from the end
- while ( i-- ) {
- var currentGroup = groups[ i ],
- totalBtns = ToolbarModifier.getTotalGroupButtonsNumber( currentGroup, this.fullToolbarEditor );
- if ( currentGroup.type == 'separator' ) {
- // nothing to do with separator
- continue;
- }
- currentGroup.totalBtns = totalBtns;
- }
- };
- /**
- * Add button to removeButtons field in config and refresh editor.
- *
- * @param {String} buttonName
- * @private
- */
- ToolbarModifier.prototype._addButtonToRemoved = function( buttonName ) {
- if ( CKEDITOR.tools.indexOf( this.removedButtons, buttonName ) != -1 )
- throw 'Button already added to removed';
- this.removedButtons.push( buttonName );
- this.actualConfig.removeButtons = this.removedButtons.join( ',' );
- this._refreshEditor();
- };
- /**
- * Remove button from removeButtons field in config and refresh editor.
- *
- * @param {String} buttonName
- * @private
- */
- ToolbarModifier.prototype._removeButtonFromRemoved = function( buttonName ) {
- var foundAtIndex = CKEDITOR.tools.indexOf( this.removedButtons, buttonName );
- if ( foundAtIndex === -1 )
- throw 'Trying to remove button from removed, but not found';
- this.removedButtons.splice( foundAtIndex, 1 );
- this.actualConfig.removeButtons = this.removedButtons.join( ',' );
- this._refreshEditor();
- };
- /**
- * Parse group "model" to configuration value
- *
- * @param {Object} group
- * @returns {Object}
- * @static
- */
- ToolbarModifier.parseGroupToConfigValue = function( group ) {
- if ( group.type == 'separator' ) {
- return '/';
- }
- var groups = group.groups,
- max = groups.length;
- delete group.totalBtns;
- for ( var i = 0; i < max; i += 1 ) {
- groups[ i ] = groups[ i ].name;
- }
- return group;
- };
- /**
- * Find closest Li ancestor in DOM tree which is group or separator element
- *
- * @param {CKEDITOR.dom.element} element
- * @returns {CKEDITOR.dom.element}
- * @static
- */
- ToolbarModifier.getGroupOrSeparatorLiAncestor = function( element ) {
- if ( element.$ instanceof HTMLLIElement && element.data( 'type' ) == 'group' )
- return element;
- else {
- return ToolbarModifier.getFirstAncestor( element, function( ancestor ) {
- var type = ancestor.data( 'type' );
- return ( type == 'group' || type == 'separator' );
- } );
- }
- };
- /**
- * Create separator literal with unique id.
- *
- * @public
- * @static
- * @return {Object}
- */
- ToolbarModifier.createSeparatorLiteral = function() {
- return {
- type: 'separator',
- name: ( 'separator' + CKEDITOR.tools.getNextNumber() )
- };
- };
- /**
- * Creates HTML unordered list string based on toolbarGroups field in config.
- *
- * @returns {String}
- * @static
- */
- ToolbarModifier.prototype._toolbarConfigToListString = function() {
- var groups = this.actualConfig.toolbarGroups || [],
- listString = '<ul data-type="table-body">';
- var max = groups.length;
- for ( var i = 0; i < max; i += 1 ) {
- var currentGroup = groups[ i ];
- if ( currentGroup.type === 'separator' )
- listString += ToolbarModifier.getToolbarSeparatorString( currentGroup );
- else
- listString += this._getToolbarGroupString( currentGroup );
- }
- listString += '</ul>';
- var headerString = ToolbarModifier.getToolbarHeaderString();
- return headerString + listString;
- };
- /**
- * Created HTML group list element based on group field in config.
- *
- * @param {Object} group
- * @returns {String}
- * @private
- */
- ToolbarModifier.prototype._getToolbarGroupString = function( group ) {
- var subgroups = group.groups,
- groupString = '';
- groupString += [
- '<li ',
- 'data-type="group" ',
- 'data-name="', group.name, '" ',
- ( group.totalBtns ? '' : 'class="empty"' ),
- '>'
- ].join( '' );
- groupString += ToolbarModifier.getToolbarElementPreString( group ) + '<ul>';
- var max = subgroups.length;
- for ( var i = 0; i < max; i += 1 ) {
- var currentSubgroup = subgroups[ i ],
- subgroupBtns = this.fullToolbarEditor.buttonsByGroup[ currentSubgroup.name ];
- groupString += this._getToolbarSubgroupString( currentSubgroup, subgroupBtns );
- }
- groupString += '</ul></li>';
- return groupString;
- };
- /**
- * @param {Object} separator
- * @returns {String}
- * @static
- */
- ToolbarModifier.getToolbarSeparatorString = function( separator ) {
- return [
- '<li ',
- 'data-type="', separator.type , '" ',
- 'data-name="', separator.name , '"',
- '>',
- ToolbarModifier.getToolbarElementPreString( 'row separator' ),
- '</li>'
- ].join( '' );
- };
- /**
- * @returns {string}
- */
- ToolbarModifier.getToolbarHeaderString = function() {
- return '<ul data-type="table-header">' +
- '<li data-type="header">' +
- '<p>Toolbars</p>' +
- '<ul>' +
- '<li>' +
- '<p>Toolbar groups</p>' +
- '<p>Toolbar group items</p>' +
- '</li>' +
- '</ul>' +
- '</li>' +
- '</ul>';
- };
- /**
- * Find and return first ancestor of element provided in first argument
- * which match the criteria checked in function provided in second argument.
- *
- * @param {CKEDITOR.dom.element} element
- * @param {Function} checker
- * @returns {CKEDITOR.dom.element|null}
- */
- ToolbarModifier.getFirstAncestor = function( element, checker ) {
- var ancestors = element.getParents(),
- i = ancestors.length;
- while ( i-- ) {
- if ( checker( ancestors[ i ] ) )
- return ancestors[ i ];
- }
- return null;
- };
- /**
- * Looking through array elements start from index provided in second argument
- * and go 'up' or 'down' in array
- * last argument is condition checker which should return Boolean value
- *
- * User cases:
- *
- * ToolbarModifier.getFirstElementIndexWith( [3, 4, 8, 1, 4], 2, 'down', function( elem ) { return elem == 4; } ); // 4
- * ToolbarModifier.getFirstElementIndexWith( [3, 4, 8, 1, 4], 2, 'up', function( elem ) { return elem == 4; } ); // 1
- *
- * @param {Array} array
- * @param {Number} i
- * @param {String} direction 'up' or 'down'
- * @param {Function} conditionChecker
- * @static
- * @returns {Number} index of found element
- */
- ToolbarModifier.getFirstElementIndexWith = function( array, i, direction, conditionChecker ) {
- function whileChecker() {
- var result;
- if ( direction === 'up' )
- result = i--;
- else
- result = ( ++i < array.length );
- return result;
- }
- while ( whileChecker() ) {
- if ( conditionChecker( array[ i ] ) )
- return i;
- }
- return -1;
- };
- /**
- * Moves array element at index level up or down.
- *
- * @static
- * @param {String} direction
- * @param {Array} array
- * @param {Number} index
- * @returns {Number}
- */
- ToolbarModifier.moveTo = function( offset, array, index ) {
- var element, newIndex;
- if ( index !== -1 )
- element = array.splice( index, 1 )[ 0 ];
- newIndex = index + offset;
- array.splice( newIndex, 0, element );
- return newIndex;
- };
- /**
- * @static
- * @param {Object} subgroup
- * @returns {Number}
- */
- ToolbarModifier.getTotalSubGroupButtonsNumber = function( subgroup, fullToolbarEditor ) {
- var subgroupName = ( typeof subgroup == 'string' ? subgroup : subgroup.name ),
- subgroupBtns = fullToolbarEditor.buttonsByGroup[ subgroupName ];
- return ( subgroupBtns ? subgroupBtns.length : 0 );
- };
- /**
- * Returns all buttons number in group which are nested in subgroups also.
- *
- * @param {Object} group
- * @param {ToolbarModifier.FullToolbarEditor}
- * @static
- * @returns {Number}
- */
- ToolbarModifier.getTotalGroupButtonsNumber = function( group, fullToolbarEditor ) {
- var total = 0,
- subgroups = group.groups;
- var max = subgroups ? subgroups.length : 0;
- for ( var i = 0; i < max; i += 1 )
- total += ToolbarModifier.getTotalSubGroupButtonsNumber( subgroups[ i ], fullToolbarEditor );
- return total;
- };
- /**
- * Creates HTML subgroup list element based on subgroup field in config.
- *
- * @param {Object} subgroup
- * @param {Array} groupBtns
- * @returns {String}
- * @private
- */
- ToolbarModifier.prototype._getToolbarSubgroupString = function( subgroup, groupBtns ) {
- var subgroupString = '';
- subgroupString += [
- '<li ',
- 'data-type="subgroup" ',
- 'data-name="', subgroup.name, '" ',
- ( subgroup.totalBtns ? '' : 'class="empty" ' ),
- '>'
- ].join( '' );
- subgroupString += ToolbarModifier.getToolbarElementPreString( subgroup.name );
- subgroupString += '<ul>';
- var max = groupBtns ? groupBtns.length : 0;
- for ( var i = 0; i < max; i += 1 )
- subgroupString += this.getButtonString( groupBtns[ i ] );
- subgroupString += '</ul>';
- subgroupString += '</li>';
- return subgroupString;
- };
- /**
- * @param {String} buttonName
- * @returns {String|null}
- * @private
- */
- ToolbarModifier.prototype._getConfigButtonName = function( buttonName ) {
- var items = this.fullToolbarEditor.editorInstance.ui.items;
- var name;
- for ( name in items ) {
- if ( items[ name ].name == buttonName )
- return name;
- }
- return null;
- };
- /**
- * @param {String} buttonName
- * @returns {Boolean}
- */
- ToolbarModifier.prototype.isButtonRemoved = function( buttonName ) {
- return CKEDITOR.tools.indexOf( this.removedButtons, this._getConfigButtonName( buttonName ) ) != -1;
- };
- /**
- * @param {CKEDITOR.ui.button/CKEDITOR.ui.richCombo} button
- * @returns {String}
- * @public
- */
- ToolbarModifier.prototype.getButtonString = function( button ) {
- var checked = ( this.isButtonRemoved( button.name ) ? '' : 'checked="checked"' );
- return [
- '<li data-tab="true" data-type="button" data-name="', this._getConfigButtonName( button.name ), '">',
- '<label title="', button.label, '" >',
- '<input ',
- 'tabindex="-1"',
- 'type="checkbox"',
- checked,
- '/>',
- button.$.getOuterHtml(),
- '</label>',
- '</li>'
- ].join( '' );
- };
- /**
- * Creates group header string.
- *
- * @param {Object|String} group
- * @returns {String}
- * @static
- */
- ToolbarModifier.getToolbarElementPreString = function( group ) {
- var name = ( group.name ? group.name : group );
- return [
- '<p>',
- '<span>',
- '<button title="Move element upward" data-tab="true" data-direction="up" class="move icon-up-big"></button>',
- '<button title="Move element downward" data-tab="true" data-direction="down" class="move icon-down-big"></button>',
- ( name == 'row separator' ? '<button title="Remove element" data-tab="true" class="remove icon-trash"></button>' : '' ),
- name,
- '</span>',
- '</p>'
- ].join( '' );
- };
- /**
- * @static
- * @param {String} cfg
- * @returns {String}
- */
- ToolbarModifier.evaluateToolbarGroupsConfig = function( cfg ) {
- cfg = ( function( cfg ) {
- var config = {}, result;
- /*jshint -W002 */
- try {
- result = eval( '(' + cfg + ')' );
- } catch ( e ) {
- try {
- result = eval( cfg );
- } catch ( e ) {
- return null;
- }
- }
- /*jshint +W002 */
- if ( config.toolbarGroups && typeof config.toolbarGroups.length === 'number' ) {
- return JSON.stringify( config );
- } else if ( result && typeof result.length === 'number' ) {
- return JSON.stringify( { toolbarGroups: result } );
- } else if ( result && result.toolbarGroups ) {
- return JSON.stringify( result );
- } else {
- return null;
- }
- }( cfg ) );
- return cfg;
- };
- return ToolbarModifier;
- } )();
|