diff options
Diffstat (limited to 'sources/samples/toolbarconfigurator/js/toolbartextmodifier.js')
-rw-r--r-- | sources/samples/toolbarconfigurator/js/toolbartextmodifier.js | 623 |
1 files changed, 623 insertions, 0 deletions
diff --git a/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js b/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js new file mode 100644 index 0000000..4c14dd2 --- /dev/null +++ b/sources/samples/toolbarconfigurator/js/toolbartextmodifier.js | |||
@@ -0,0 +1,623 @@ | |||
1 | /* global CodeMirror, ToolbarConfigurator */ | ||
2 | |||
3 | 'use strict'; | ||
4 | |||
5 | ( function() { | ||
6 | var AbstractToolbarModifier = ToolbarConfigurator.AbstractToolbarModifier, | ||
7 | FullToolbarEditor = ToolbarConfigurator.FullToolbarEditor; | ||
8 | |||
9 | /** | ||
10 | * @class ToolbarConfigurator.ToolbarTextModifier | ||
11 | * @param {String} editorId An id of modified editor | ||
12 | * @extends AbstractToolbarModifier | ||
13 | * @constructor | ||
14 | */ | ||
15 | function ToolbarTextModifier( editorId ) { | ||
16 | AbstractToolbarModifier.call( this, editorId ); | ||
17 | |||
18 | this.codeContainer = null; | ||
19 | this.hintContainer = null; | ||
20 | } | ||
21 | |||
22 | // Expose the class. | ||
23 | ToolbarConfigurator.ToolbarTextModifier = ToolbarTextModifier; | ||
24 | |||
25 | ToolbarTextModifier.prototype = Object.create( AbstractToolbarModifier.prototype ); | ||
26 | |||
27 | /** | ||
28 | * @param {Function} callback | ||
29 | * @param {String} [config] | ||
30 | * @private | ||
31 | */ | ||
32 | ToolbarTextModifier.prototype._onInit = function( callback, config ) { | ||
33 | AbstractToolbarModifier.prototype._onInit.call( this, undefined, config ); | ||
34 | |||
35 | this._createModifier( config ? this.actualConfig : undefined ); | ||
36 | |||
37 | if ( typeof callback === 'function' ) | ||
38 | callback( this.mainContainer ); | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * Creates HTML main container of modifier. | ||
43 | * | ||
44 | * @param {String} cfg | ||
45 | * @returns {CKEDITOR.dom.element} | ||
46 | * @private | ||
47 | */ | ||
48 | ToolbarTextModifier.prototype._createModifier = function( cfg ) { | ||
49 | var that = this; | ||
50 | |||
51 | this._createToolbar(); | ||
52 | |||
53 | if ( this.toolbarContainer ) { | ||
54 | this.mainContainer.append( this.toolbarContainer ); | ||
55 | } | ||
56 | |||
57 | AbstractToolbarModifier.prototype._createModifier.call( this ); | ||
58 | |||
59 | this._setupActualConfig( cfg ); | ||
60 | |||
61 | var toolbarCfg = this.actualConfig.toolbar, | ||
62 | cfgValue; | ||
63 | |||
64 | if ( CKEDITOR.tools.isArray( toolbarCfg ) ) { | ||
65 | var stringifiedToolbar = '[\n\t\t' + FullToolbarEditor.map( toolbarCfg, function( json ) { | ||
66 | return AbstractToolbarModifier.stringifyJSONintoOneLine( json, { | ||
67 | addSpaces: true, | ||
68 | noQuotesOnKey: true, | ||
69 | singleQuotes: true | ||
70 | } ); | ||
71 | } ).join( ',\n\t\t' ) + '\n\t]'; | ||
72 | |||
73 | cfgValue = '\tconfig.toolbar = ' + stringifiedToolbar + ';'; | ||
74 | } else { | ||
75 | cfgValue = 'config.toolbar = [];'; | ||
76 | } | ||
77 | |||
78 | cfgValue = [ | ||
79 | 'CKEDITOR.editorConfig = function( config ) {\n', | ||
80 | cfgValue, | ||
81 | '\n};' | ||
82 | ].join( '' ); | ||
83 | |||
84 | function hint( cm ) { | ||
85 | var data = setupData( cm ); | ||
86 | |||
87 | if ( data.charsBetween === null ) { | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | var unused = that.getUnusedButtonsArray( that.actualConfig.toolbar, true, data.charsBetween ), | ||
92 | to = cm.getCursor(), | ||
93 | from = CodeMirror.Pos( to.line, ( to.ch - ( data.charsBetween.length ) ) ), | ||
94 | token = cm.getTokenAt( to ), | ||
95 | prevToken = cm.getTokenAt( { line: to.line, ch: token.start } ); | ||
96 | |||
97 | // determine that we are at beginning of group, | ||
98 | // so first key is "name" | ||
99 | if ( prevToken.string === '{' ) | ||
100 | unused = [ 'name' ]; | ||
101 | |||
102 | // preventing close with special character and move cursor forward | ||
103 | // when no autocomplete | ||
104 | if ( unused.length === 0 ) | ||
105 | return; | ||
106 | |||
107 | return new HintData( from, to, unused ); | ||
108 | } | ||
109 | |||
110 | function HintData( from, to, list ) { | ||
111 | this.from = from; | ||
112 | this.to = to; | ||
113 | this.list = list; | ||
114 | this._handlers = []; | ||
115 | } | ||
116 | |||
117 | function setupData( cm, character ) { | ||
118 | var result = {}; | ||
119 | |||
120 | result.cur = cm.getCursor(); | ||
121 | result.tok = cm.getTokenAt( result.cur ); | ||
122 | |||
123 | result[ 'char' ] = character || result.tok.string.charAt( result.tok.string.length - 1 ); | ||
124 | |||
125 | // Getting string between begin of line and cursor. | ||
126 | var curLineTillCur = cm.getRange( CodeMirror.Pos( result.cur.line, 0 ), result.cur ); | ||
127 | |||
128 | // Reverse string. | ||
129 | var currLineTillCurReversed = curLineTillCur.split( '' ).reverse().join( '' ); | ||
130 | |||
131 | // Removing proper string definitions : | ||
132 | // FROM: | ||
133 | // R' ,'odeR' ,'odnU' [ :smeti{ | ||
134 | // ^^^^^^ ^^^^^^ | ||
135 | // TO: | ||
136 | // R' , [ :smeti{ | ||
137 | currLineTillCurReversed = currLineTillCurReversed.replace( /(['|"]\w*['|"])/g, '' ); | ||
138 | |||
139 | // Matching letters till ' or " character and end string char. | ||
140 | // R' , [ :smeti{ | ||
141 | // ^ | ||
142 | result.charsBetween = currLineTillCurReversed.match( /(^\w*)(['|"])/ ); | ||
143 | |||
144 | if ( result.charsBetween ) { | ||
145 | result.endChar = result.charsBetween[ 2 ]; | ||
146 | |||
147 | // And reverse string (bring to original state). | ||
148 | result.charsBetween = result.charsBetween[ 1 ].split( '' ).reverse().join( '' ); | ||
149 | } | ||
150 | |||
151 | return result; | ||
152 | } | ||
153 | |||
154 | function complete( cm ) { | ||
155 | setTimeout( function() { | ||
156 | if ( !cm.state.completionActive ) { | ||
157 | CodeMirror.showHint( cm, hint, { | ||
158 | hintsClass: 'toolbar-modifier', | ||
159 | completeSingle: false | ||
160 | } ); | ||
161 | } | ||
162 | }, 100 ); | ||
163 | |||
164 | return CodeMirror.Pass; | ||
165 | } | ||
166 | |||
167 | var codeMirrorWrapper = new CKEDITOR.dom.element( 'div' ); | ||
168 | codeMirrorWrapper.addClass( 'codemirror-wrapper' ); | ||
169 | this.modifyContainer.append( codeMirrorWrapper ); | ||
170 | this.codeContainer = CodeMirror( codeMirrorWrapper.$, { | ||
171 | mode: { name: 'javascript', json: true }, | ||
172 | // For some reason (most likely CM's bug) gutter breaks CM's height. | ||
173 | // Refreshing CM does not help. | ||
174 | lineNumbers: false, | ||
175 | lineWrapping: true, | ||
176 | // Trick to make CM autogrow. http://codemirror.net/demo/resize.html | ||
177 | viewportMargin: Infinity, | ||
178 | value: cfgValue, | ||
179 | smartIndent: false, | ||
180 | indentWithTabs: true, | ||
181 | indentUnit: 4, | ||
182 | tabSize: 4, | ||
183 | theme: 'neo', | ||
184 | extraKeys: { | ||
185 | 'Left': complete, | ||
186 | 'Right': complete, | ||
187 | "'''": complete, | ||
188 | "'\"'": complete, | ||
189 | Backspace: complete, | ||
190 | Delete: complete, | ||
191 | 'Shift-Tab': 'indentLess' | ||
192 | } | ||
193 | } ); | ||
194 | |||
195 | this.codeContainer.on( 'endCompletion', function( cm, completionData ) { | ||
196 | var data = setupData( cm ); | ||
197 | |||
198 | // preventing close with special character and move cursor forward | ||
199 | // when no autocomplete | ||
200 | if ( completionData === undefined ) | ||
201 | return; | ||
202 | |||
203 | cm.replaceSelection( data.endChar ); | ||
204 | } ); | ||
205 | |||
206 | this.codeContainer.on( 'change', function() { | ||
207 | var value = that.codeContainer.getValue(); | ||
208 | |||
209 | value = that._evaluateValue( value ); | ||
210 | |||
211 | if ( value !== null ) { | ||
212 | that.actualConfig.toolbar = ( value.toolbar ? value.toolbar : that.actualConfig.toolbar ); | ||
213 | |||
214 | that._fillHintByUnusedElements(); | ||
215 | that._refreshEditor(); | ||
216 | |||
217 | that.mainContainer.removeClass( 'invalid' ); | ||
218 | } else { | ||
219 | that.mainContainer.addClass( 'invalid' ); | ||
220 | } | ||
221 | } ); | ||
222 | |||
223 | this.hintContainer = new CKEDITOR.dom.element( 'div' ); | ||
224 | this.hintContainer.addClass( 'toolbarModifier-hints' ); | ||
225 | |||
226 | this._fillHintByUnusedElements(); | ||
227 | this.hintContainer.insertBefore( codeMirrorWrapper ); | ||
228 | }; | ||
229 | |||
230 | /** | ||
231 | * Create DOM string and set to hint container, | ||
232 | * show proper information when no unused element left. | ||
233 | * | ||
234 | * @private | ||
235 | */ | ||
236 | ToolbarTextModifier.prototype._fillHintByUnusedElements = function() { | ||
237 | var unused = this.getUnusedButtonsArray( this.actualConfig.toolbar, true ); | ||
238 | unused = this.groupButtonNamesByGroup( unused ); | ||
239 | |||
240 | var unusedElements = FullToolbarEditor.map( unused, function( elem ) { | ||
241 | var buttonsList = FullToolbarEditor.map( elem.buttons, function( buttonName ) { | ||
242 | return '<code>' + buttonName + '</code> '; | ||
243 | } ).join( '' ); | ||
244 | |||
245 | return [ | ||
246 | '<dt>', | ||
247 | '<code>', elem.name, '</code>', | ||
248 | '</dt>', | ||
249 | '<dd>', | ||
250 | buttonsList, | ||
251 | '</dd>' | ||
252 | ].join( '' ); | ||
253 | } ).join( ' ' ); | ||
254 | |||
255 | var listHeader = [ | ||
256 | '<dt class="list-header">Toolbar group</dt>', | ||
257 | '<dd class="list-header">Unused items</dd>' | ||
258 | ].join( '' ); | ||
259 | |||
260 | var header = '<h3>Unused toolbar items</h3>'; | ||
261 | |||
262 | if ( !unused.length ) { | ||
263 | listHeader = '<p>All items are in use.</p>'; | ||
264 | } | ||
265 | |||
266 | this.codeContainer.refresh(); | ||
267 | |||
268 | this.hintContainer.setHtml( header + '<dl>' + listHeader + unusedElements + '</dl>' ); | ||
269 | }; | ||
270 | |||
271 | /** | ||
272 | * @param {String} buttonName | ||
273 | * @returns {String} | ||
274 | */ | ||
275 | ToolbarTextModifier.prototype.getToolbarGroupByButtonName = function( buttonName ) { | ||
276 | var buttonNames = this.fullToolbarEditor.buttonNamesByGroup; | ||
277 | |||
278 | for ( var groupName in buttonNames ) { | ||
279 | var buttons = buttonNames[ groupName ]; | ||
280 | |||
281 | var i = buttons.length; | ||
282 | while ( i-- ) { | ||
283 | if ( buttonName === buttons[ i ] ) { | ||
284 | return groupName; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | } | ||
289 | |||
290 | return null; | ||
291 | }; | ||
292 | |||
293 | /** | ||
294 | * Filter all available toolbar elements by array of elements provided in first argument. | ||
295 | * Returns elements which are not used. | ||
296 | * | ||
297 | * @param {Object} toolbar | ||
298 | * @param {Boolean} [sorted=false] | ||
299 | * @param {String} prefix | ||
300 | * @returns {Array} | ||
301 | */ | ||
302 | ToolbarTextModifier.prototype.getUnusedButtonsArray = function( toolbar, sorted, prefix ) { | ||
303 | sorted = ( sorted === true ? true : false ); | ||
304 | var providedElements = ToolbarTextModifier.mapToolbarCfgToElementsList( toolbar ), | ||
305 | allElements = Object.keys( this.fullToolbarEditor.editorInstance.ui.items ); | ||
306 | |||
307 | // get rid of "-" elements | ||
308 | allElements = FullToolbarEditor.filter( allElements, function( elem ) { | ||
309 | var isSeparator = ( elem === '-' ), | ||
310 | matchPrefix = ( prefix === undefined || elem.toLowerCase().indexOf( prefix.toLowerCase() ) === 0 ); | ||
311 | |||
312 | return !isSeparator && matchPrefix; | ||
313 | } ); | ||
314 | |||
315 | var elementsNotUsed = FullToolbarEditor.filter( allElements, function( elem ) { | ||
316 | return CKEDITOR.tools.indexOf( providedElements, elem ) == -1; | ||
317 | } ); | ||
318 | |||
319 | if ( sorted ) | ||
320 | elementsNotUsed.sort(); | ||
321 | |||
322 | return elementsNotUsed; | ||
323 | }; | ||
324 | |||
325 | /** | ||
326 | * | ||
327 | * @param {Array} buttons | ||
328 | * @returns {Array} | ||
329 | */ | ||
330 | ToolbarTextModifier.prototype.groupButtonNamesByGroup = function( buttons ) { | ||
331 | var result = [], | ||
332 | groupedBtns = JSON.parse( JSON.stringify( this.fullToolbarEditor.buttonNamesByGroup ) ); | ||
333 | |||
334 | for ( var groupName in groupedBtns ) { | ||
335 | var currGroup = groupedBtns[ groupName ]; | ||
336 | currGroup = FullToolbarEditor.filter( currGroup, function( btnName ) { | ||
337 | return CKEDITOR.tools.indexOf( buttons, btnName ) !== -1; | ||
338 | } ); | ||
339 | |||
340 | if ( currGroup.length ) { | ||
341 | result.push( { | ||
342 | name: groupName, | ||
343 | buttons: currGroup | ||
344 | } ); | ||
345 | } | ||
346 | |||
347 | } | ||
348 | |||
349 | return result; | ||
350 | }; | ||
351 | |||
352 | /** | ||
353 | * Map toolbar config value to flat items list. | ||
354 | * | ||
355 | * input: | ||
356 | * [ | ||
357 | * { name: "basicstyles", items: ["Bold", "Italic"] }, | ||
358 | * { name: "advancedstyles", items: ["Bold", "Outdent", "Indent"] } | ||
359 | * ] | ||
360 | * | ||
361 | * output: | ||
362 | * ["Bold", "Italic", "Outdent", "Indent"] | ||
363 | * | ||
364 | * @param {Object} toolbar | ||
365 | * @returns {Array} | ||
366 | */ | ||
367 | ToolbarTextModifier.mapToolbarCfgToElementsList = function( toolbar ) { | ||
368 | var elements = []; | ||
369 | |||
370 | var max = toolbar.length; | ||
371 | for ( var i = 0; i < max; i += 1 ) { | ||
372 | if ( !toolbar[ i ] || typeof toolbar[ i ] === 'string' ) | ||
373 | continue; | ||
374 | |||
375 | elements = elements.concat( FullToolbarEditor.filter( toolbar[ i ].items, checker ) ); | ||
376 | } | ||
377 | |||
378 | function checker( elem ) { | ||
379 | return elem !== '-'; | ||
380 | } | ||
381 | |||
382 | return elements; | ||
383 | }; | ||
384 | |||
385 | /** | ||
386 | * @param {String} cfg | ||
387 | * @private | ||
388 | */ | ||
389 | ToolbarTextModifier.prototype._setupActualConfig = function( cfg ) { | ||
390 | cfg = cfg || this.editorInstance.config; | ||
391 | |||
392 | // if toolbar already exists in config, there is nothing to do | ||
393 | if ( CKEDITOR.tools.isArray( cfg.toolbar ) ) | ||
394 | return; | ||
395 | |||
396 | // if toolbar group not present, we need to pick them from full toolbar instance | ||
397 | if ( !cfg.toolbarGroups ) | ||
398 | cfg.toolbarGroups = this.fullToolbarEditor.getFullToolbarGroupsConfig( true ); | ||
399 | |||
400 | this._fixGroups( cfg ); | ||
401 | |||
402 | cfg.toolbar = this._mapToolbarGroupsToToolbar( cfg.toolbarGroups, this.actualConfig.removeButtons ); | ||
403 | |||
404 | this.actualConfig.toolbar = cfg.toolbar; | ||
405 | this.actualConfig.removeButtons = ''; | ||
406 | }; | ||
407 | |||
408 | /** | ||
409 | * **Please note:** This method modify element provided in first argument. | ||
410 | * | ||
411 | * @param {Array} toolbarGroups | ||
412 | * @returns {Array} | ||
413 | * @private | ||
414 | */ | ||
415 | ToolbarTextModifier.prototype._mapToolbarGroupsToToolbar = function( toolbarGroups, removedBtns ) { | ||
416 | removedBtns = removedBtns || this.editorInstance.config.removedBtns; | ||
417 | removedBtns = typeof removedBtns == 'string' ? removedBtns.split( ',' ) : []; | ||
418 | |||
419 | // from the end, because array indexes may change | ||
420 | var i = toolbarGroups.length; | ||
421 | while ( i-- ) { | ||
422 | var mappedSubgroup = this._mapToolbarSubgroup( toolbarGroups[ i ], removedBtns ); | ||
423 | |||
424 | if ( toolbarGroups[ i ].type === 'separator' ) { | ||
425 | toolbarGroups[ i ] = '/'; | ||
426 | continue; | ||
427 | } | ||
428 | |||
429 | // don't want empty groups | ||
430 | if ( CKEDITOR.tools.isArray( mappedSubgroup ) && mappedSubgroup.length === 0 ) { | ||
431 | toolbarGroups.splice( i, 1 ); | ||
432 | continue; | ||
433 | } | ||
434 | |||
435 | if ( typeof mappedSubgroup == 'string' ) | ||
436 | toolbarGroups[ i ] = mappedSubgroup; | ||
437 | else { | ||
438 | toolbarGroups[ i ] = { | ||
439 | name: toolbarGroups[ i ].name, | ||
440 | items: mappedSubgroup | ||
441 | }; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | return toolbarGroups; | ||
446 | }; | ||
447 | |||
448 | /** | ||
449 | * | ||
450 | * @param {String|Object} group | ||
451 | * @param {Array} removedBtns | ||
452 | * @returns {Array} | ||
453 | * @private | ||
454 | */ | ||
455 | ToolbarTextModifier.prototype._mapToolbarSubgroup = function( group, removedBtns ) { | ||
456 | var totalBtns = 0; | ||
457 | if ( typeof group == 'string' ) | ||
458 | return group; | ||
459 | |||
460 | var max = group.groups ? group.groups.length : 0, | ||
461 | result = []; | ||
462 | for ( var i = 0; i < max; i += 1 ) { | ||
463 | var currSubgroup = group.groups[ i ]; | ||
464 | |||
465 | var buttons = this.fullToolbarEditor.buttonsByGroup[ typeof currSubgroup === 'string' ? currSubgroup : currSubgroup.name ] || []; | ||
466 | buttons = this._mapButtonsToButtonsNames( buttons, removedBtns ); | ||
467 | var currTotalBtns = buttons.length; | ||
468 | totalBtns += currTotalBtns; | ||
469 | result = result.concat( buttons ); | ||
470 | |||
471 | if ( currTotalBtns ) | ||
472 | result.push( '-' ); | ||
473 | } | ||
474 | |||
475 | if ( result[ result.length - 1 ] == '-' ) | ||
476 | result.pop(); | ||
477 | |||
478 | return result; | ||
479 | }; | ||
480 | |||
481 | /** | ||
482 | * | ||
483 | * @param {Array} buttons | ||
484 | * @param {Array} removedBtns | ||
485 | * @returns {Array} | ||
486 | * @private | ||
487 | */ | ||
488 | ToolbarTextModifier.prototype._mapButtonsToButtonsNames = function( buttons, removedBtns ) { | ||
489 | var i = buttons.length; | ||
490 | while ( i-- ) { | ||
491 | var currBtn = buttons[ i ], | ||
492 | camelCasedName; | ||
493 | |||
494 | if ( typeof currBtn === 'string' ) { | ||
495 | camelCasedName = currBtn; | ||
496 | } else { | ||
497 | camelCasedName = this.fullToolbarEditor.getCamelCasedButtonName( currBtn.name ); | ||
498 | } | ||
499 | |||
500 | if ( CKEDITOR.tools.indexOf( removedBtns, camelCasedName ) !== -1 ) { | ||
501 | buttons.splice( i, 1 ); | ||
502 | continue; | ||
503 | } | ||
504 | |||
505 | buttons[ i ] = camelCasedName; | ||
506 | } | ||
507 | |||
508 | return buttons; | ||
509 | }; | ||
510 | |||
511 | /** | ||
512 | * @param {String} val | ||
513 | * @returns {Object} | ||
514 | * @private | ||
515 | */ | ||
516 | ToolbarTextModifier.prototype._evaluateValue = function( val ) { | ||
517 | var parsed; | ||
518 | |||
519 | try { | ||
520 | var config = {}; | ||
521 | ( function() { | ||
522 | var CKEDITOR = Function( 'var CKEDITOR = {}; ' + val + '; return CKEDITOR;' )(); | ||
523 | |||
524 | CKEDITOR.editorConfig( config ); | ||
525 | parsed = config; | ||
526 | } )(); | ||
527 | |||
528 | // CKEditor does not handle empty arrays in configuration files | ||
529 | // on IE8 | ||
530 | var i = parsed.toolbar.length; | ||
531 | while ( i-- ) | ||
532 | if ( !parsed.toolbar[ i ] ) parsed.toolbar.splice( i, 1 ); | ||
533 | |||
534 | } catch ( e ) { | ||
535 | parsed = null; | ||
536 | } | ||
537 | |||
538 | return parsed; | ||
539 | }; | ||
540 | |||
541 | /** | ||
542 | * @param {Array} toolbar | ||
543 | * @returns {{toolbarGroups: Array, removeButtons: string}} | ||
544 | */ | ||
545 | ToolbarTextModifier.prototype.mapToolbarToToolbarGroups = function( toolbar ) { | ||
546 | var usedGroups = {}, | ||
547 | removeButtons = [], | ||
548 | toolbarGroups = []; | ||
549 | |||
550 | var max = toolbar.length; | ||
551 | for ( var i = 0; i < max; i++ ) { | ||
552 | if ( toolbar[ i ] === '/' ) { | ||
553 | toolbarGroups.push( '/' ); | ||
554 | continue; | ||
555 | } | ||
556 | |||
557 | var items = toolbar[ i ].items; | ||
558 | |||
559 | var toolbarGroup = {}; | ||
560 | toolbarGroup.name = toolbar[ i ].name; | ||
561 | toolbarGroup.groups = []; | ||
562 | |||
563 | var max2 = items.length; | ||
564 | for ( var j = 0; j < max2; j++ ) { | ||
565 | var item = items[ j ]; | ||
566 | |||
567 | if ( item === '-' ) { | ||
568 | continue; | ||
569 | } | ||
570 | |||
571 | var groupName = this.getToolbarGroupByButtonName( item ); | ||
572 | |||
573 | var groupIndex = toolbarGroup.groups.indexOf( groupName ); | ||
574 | if ( groupIndex === -1 ) { | ||
575 | toolbarGroup.groups.push( groupName ); | ||
576 | } | ||
577 | |||
578 | usedGroups[ groupName ] = usedGroups[ groupName ] || {}; | ||
579 | |||
580 | var buttons = ( usedGroups[ groupName ].buttons = usedGroups[ groupName ].buttons || {} ); | ||
581 | |||
582 | buttons[ item ] = buttons[ item ] || { used: 0, origin: toolbarGroup.name }; | ||
583 | buttons[ item ].used++; | ||
584 | } | ||
585 | |||
586 | toolbarGroups.push( toolbarGroup ); | ||
587 | } | ||
588 | |||
589 | // Handling removed buttons | ||
590 | removeButtons = prepareRemovedButtons( usedGroups, this.fullToolbarEditor.buttonNamesByGroup ); | ||
591 | |||
592 | function prepareRemovedButtons( usedGroups, buttonNames ) { | ||
593 | var removed = []; | ||
594 | |||
595 | for ( var groupName in usedGroups ) { | ||
596 | var group = usedGroups[ groupName ]; | ||
597 | var allButtonsInGroup = buttonNames[ groupName ].slice(); | ||
598 | |||
599 | removed = removed.concat( removeStuffFromArray( allButtonsInGroup, Object.keys( group.buttons ) ) ); | ||
600 | } | ||
601 | |||
602 | return removed; | ||
603 | } | ||
604 | |||
605 | function removeStuffFromArray( array, stuff ) { | ||
606 | array = array.slice(); | ||
607 | var i = stuff.length; | ||
608 | |||
609 | while ( i-- ) { | ||
610 | var atIndex = array.indexOf( stuff[ i ] ); | ||
611 | if ( atIndex !== -1 ) { | ||
612 | array.splice( atIndex, 1 ); | ||
613 | } | ||
614 | } | ||
615 | |||
616 | return array; | ||
617 | } | ||
618 | |||
619 | return { toolbarGroups: toolbarGroups, removeButtons: removeButtons.join( ',' ) }; | ||
620 | }; | ||
621 | |||
622 | return ToolbarTextModifier; | ||
623 | } )(); | ||