1 /*!
  2 * This file is part of Aloha Editor Project http://aloha-editor.org
  3 * Copyright © 2010-2011 Gentics Software GmbH, aloha@gentics.com
  4 * Contributors http://aloha-editor.org/contribution.php 
  5 * Licensed unter the terms of http://www.aloha-editor.org/license.html
  6 *//*
  7 * Aloha Editor is free software: you can redistribute it and/or modify
  8 * it under the terms of the GNU Affero General Public License as published by
  9 * the Free Software Foundation, either version 3 of the License, or
 10 * (at your option) any later version.*
 11 *
 12 * Aloha Editor is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15 * GNU Affero General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU Affero General Public License
 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 19 */
 20 
 21 define(
 22 ['aloha/core', 'util/class', 'aloha/jquery', 'aloha/floatingmenu', 'aloha/ext', 'aloha/console', 'i18n!aloha/nls/i18n'],
 23 function(Aloha, Class, jQuery, FloatingMenu, Ext, console, i18n) {
 24 	"use strict";
 25 	
 26 	var
 27 //		$ = jQuery,
 28 //		Aloha = window.Aloha,
 29 //		Ext = window.Ext,
 30 //		Class = window.Class;
 31 	GENTICS = window.GENTICS;
 32 
 33 	// Ensure Namespace
 34 	Aloha.ui = Aloha.ui || {};
 35 	
 36 	// internationalize ext js message box buttons
 37 	Ext.MessageBox.buttonText.yes = i18n.t('yes');
 38 	Ext.MessageBox.buttonText.no = i18n.t('no');
 39 	Ext.MessageBox.buttonText.cancel = i18n.t('cancel');
 40 
 41 	/**
 42 	 * This is the Gentics Version of the ExtJS Menu. It is necessary to extend the
 43 	 * Ext.menu.Menu in order to stop propagation of the mousedown event on the DOM
 44 	 * element of the menu, because a click in the menu shall not deactivate the
 45 	 * editable.
 46 	 */
 47 	Ext.ux.GENTICSMenu = Ext.extend(Ext.menu.Menu, {
 48 		/**
 49          * overwrite onRender
 50          */
 51 		onRender: function() {
 52             // call the super method
 53             Ext.ux.GENTICSMenu.superclass.onRender.apply(this, arguments);
 54 
 55             // stop propagation of the mousedown event
 56             jQuery(this.el.dom).mousedown(function (e) {
 57                 e.stopPropagation();
 58             });
 59 		}
 60 	});
 61 
 62 /**
 63  * Constructor for an Aloha button.
 64  * @namespace Aloha.ui
 65  66  * @class Button
 67  * @param {Object} properties Properties of the button:
 68  * - label: Label that is displayed on the button.
 69  * - onclick: Callback function of the button when activated.
 70  * - menu: Array of Aloha.ui.Button elements that are displayed as drop-down menu.
 71  * - iconClass: Icon displayed on the button.
 72  * - icon: URL to an icon that is displayed on the button.
 73  * - toggle: Boolean that indicates if the button is a toggle button.
 74  */
 75 Aloha.ui.Button = Class.extend({
 76 	_constructor: function(properties) {
 77 		this.init(properties);
 78 	},
 79 
 80 	/**
 81 	 * Init method for an Aloha button.
 82 	 * This method is necessary due to JS specific initalization.
 83 	 * @namespace Aloha.ui
 84  85 	 * @class Button
 86 	 * @param {Object} properties Properties of the button:
 87 	 * - label: Label that is displayed on the button.
 88 	 * - onclick: Callback function of the button when activated.
 89 	 * - menu: Array of Aloha.ui.Button elements that are displayed as drop-down menu.
 90 	 * - iconClass: Icon displayed on the button.
 91 	 * - icon: URL to an icon that is displayed on the button.
 92 	 * - toggle: Boolean that indicates if the button is a toggle button.
 93 	 */
 94 	init: function(properties) {
 95 		/**
 96 		 * Label that is displayed on the button
 97 		 * @hide
 98 		 */
 99 		this.label = false;
100 
101 		/**
102 		 * Name for the button
103 		 */
104 		this.name = false;
105 		
106 		/**
107 		 * CSS class for an icon on the button
108 		 * @hide
109 		 */
110 		this.iconClass = false;
111 
112 		/**
113 		 * URL to an icon to display on the button
114 		 * @hide
115 		 */
116 		this.icon = false;
117 
118 		/**
119 		 * Callback function when the button is activated.
120 		 * The "this" variable refers to the button inside the callback function.
121 		 * @hide
122 		 */
123 		this.onclick = false;
124 
125 		/**
126 		 * Array of buttons that are displayed in a drop down menu.
127 		 * If a menu is provided and no onclick callback then clicking the button also opens the menu
128 		 * @hide
129 		 */
130 		this.menu = null;
131 
132 		/**
133 		 * Indicates if the button is a toggle button
134 		 * @hide
135 		 */
136 		this.toggle = false;
137 
138 		/**
139 		 * Property that indicates if the button is in pressed state
140 		 * @hide
141 		 */
142 		this.pressed = false;
143 
144 		/**
145 		 * Property that indicates whether the button is currently visible
146 		 * @hide
147 		 */
148 		this.visible = true;
149 
150 		/**
151 		 * Property that indicates whether the button is currently enabled
152 		 * @hide
153 		 */
154 		this.enabled = true;
155 
156 		/**
157 		 * Tooltip text
158 		 * @hide
159 		 */
160 		this.tooltip = false;
161 
162 		/**
163 		 * holds the ext object of the button
164 		 * @hide
165 		 */
166 		this.extButton = null;
167 
168 		/**
169 		 * holds the listeners of the button
170 		 * @hide
171 		 */
172 		this.listenerQueue = [];
173 
174 		GENTICS.Utils.applyProperties(this, properties);
175 
176 		// use icon class as a fallback for name		
177 		if (this.name === false) {
178 			this.name = this.iconClass;
179 		}
180 
181 		/**
182 		 * Unique Id of the button
183 		 * @hide
184 		 */
185 		this.id = this.generateId();
186 	},
187 
188 	/**
189 	 * Generate a unique id for the button
190 	 * @return unique id
191 	 * @hide
192 	 */
193 	generateId: function () {
194 		Aloha.ui.Button.idCounter = Aloha.ui.Button.idCounter + 1;
195 		return 'aloha-button' + Aloha.ui.Button.idCounter;
196 	},
197 
198 	/**
199 	 * Set the 'pressed' state of the button if it is a toggle button
200 	 * @param {bool} pressed true when the button shall be 'pressed', false if not
201 	 */
202 	setPressed: function(pressed) {
203 		if (this.toggle) {
204 			this.pressed = pressed;
205 			if (typeof this.extButton === 'object' && this.extButton != null && this.extButton.pressed != pressed) {
206 				this.extButton.toggle(this.pressed);
207 			}
208 		}
209 	},
210 
211 	/**
212 	 * Indicates if the button is currently in "pressed" state.
213 	 * This is only relevant if the button is a toggle button.
214 	 * If the button is no toggle button this function always returns false.
215 	 * @return {bool} True if the button is pressed, false otherwise.
216 	 */
217 	isPressed: function() {
218 		if (this.toggle) {
219 			return this.pressed;
220 		}
221 		return false;
222 	},
223 
224 	/**
225 	 * Show the button. When this button is added to the FloatingMenu, it is
226 	 * necessary to call FloatingMenu.doLayout() after the visibility
227 	 * of the button is changed
228 	 */
229 	show: function() {
230 		this.visible = true;
231 	},
232 
233 	/**
234 	 * Hide the button. When this button is added to the FloatingMenu, it is
235 	 * necessary to call FloatingMenu.doLayout() after the visibility
236 	 * of the button is changed
237 	 */
238 	hide: function() {
239 		this.visible = false;
240 	},
241 
242 	/**
243 	 * Check whether the button is visible or not
244 	 * @return true when the button is visible, false if not
245 	 */
246 	isVisible: function() {
247 		return this.visible;
248 	},
249 
250 	/**
251 	 * Enable the button - make it clickable
252 	 */
253 	enable: function() {
254 		this.enabled = true;
255 		if (typeof this.extButton === 'object') {
256 			this.extButton.enable();
257 		}
258 	},
259 
260 	/**
261 	 * Disable the button
262 	 */
263 	disable: function() {
264 		this.enabled = false;
265 		if (typeof this.extButton === 'object') {
266 			this.extButton.disable();
267 		}
268 	},
269 
270 	/**
271 	 * Check whether the button is currently enabled
272 	 * @return true when the button is enabled, false if it is disabled
273 	 */
274 	isEnabled: function() {
275 		return this.enabled;
276 	},
277 
278 	/**
279 	 * Get the Ext menu from this button
280 	 * @return Ext menu
281 	 * @hide
282 	 */
283 	getExtMenu: function() {
284 		var menu, i, entry;
285 		if ( this.menu && typeof this.menu === 'object') {
286 			// build the drop down menu
287 			menu = new Ext.ux.GENTICSMenu();
288 			for (i = 0; i < this.menu.length; ++i) {
289 				entry = this.menu[i];
290 				menu.addItem(new Ext.menu.Item(entry.getExtMenuConfigProperties()));
291 			}
292 		}
293 		return menu;
294 	},
295 
296 	/**
297 	 * Get the config properties for this button as menu entry
298 	 * @return config properties for this button as menu entry
299 	 * @hide
300 	 */
301 	getExtMenuConfigProperties: function() {
302 		var me = this,
303 			submenu = this.getExtMenu();
304 
305 		return {
306 			text: this.label,
307 			icon: this.icon,
308 			iconCls: this.iconClass,
309 			handler: function () {
310 				if (typeof me.onclick == 'function') {
311 					me.onclick();
312 				}
313 			},
314 			menu: submenu
315 		};
316 	},
317 
318 	/**
319 	 * Return an object containing the config properties to generate this button
320 	 * @return config properties
321 	 * @hide
322 	 */
323 	getExtConfigProperties: function() {
324 		var me = this,
325 			menu = this.getExtMenu(),
326 
327 		// configuration for the button
328 			buttonConfig = {
329 			text : this.label,
330 			enableToggle: this.toggle,
331 			pressed : this.pressed,
332 			icon: this.icon,
333 			iconCls: this.iconClass,
334 			scale : this.scale||this.size,
335 			width : this.width||undefined,
336 			rowspan : this.rowspan || ((this.size == 'large' || this.size == 'medium') ? 2 : 1),
337 			menu : menu,
338 			handler : function(element, event) {
339 				if (typeof me.onclick === 'function') {
340 					me.onclick.apply(me, [element, event]);
341 				}
342 				if ( me.toggle ) {
343 					me.pressed = !me.pressed;
344 				}
345 			},
346 			xtype : (menu && typeof this.onclick == 'function') ? 'splitbutton' : 'button',
347 			tooltipType : 'qtip',
348 			tooltip : this.tooltip,
349 			id : this.id,
350 		    arrowAlign: this.arrowAlign || (this.size == 'large' || this.size == 'small' ? 'right' : 'bottom')
351 		};
352 
353 		return buttonConfig;
354 	}
355 });
356 
357 /**
358  * id counter, for generation of unique id's for the buttons
359  * @hide
360  */
361 Aloha.ui.Button.idCounter = 0;
362 
363 /**
364  * extJS Multi Split Button
365  *
366  * Display a Word-like formatting selection button
367  * Selection images are typically 52*42 in size
368  *
369  * Example configuration
370  * xtype : 'genticsmultisplitbutton',
371  * items : [{
372  *   'name'  : 'normal', // the buttons name, used to identify it
373  *   'title' : 'Basic Text', // the buttons title, which will be displayed
374  *	 'icon'  : 'img/icon.jpg', // source for the icon
375  *	 'click' : function() { alert('normal'); } // callback if the button is clicked
376  *   'wide'  : false // wether it's a wide button, which would be dispalyed at the bottom
377  * }]
378  *
379  * you might want to check out the tutorial at
380  * http://www.extjs.com/learn/Tutorial:Creating_new_UI_controls
381  * @hide
382  */
383 Ext.ux.MultiSplitButton = Ext.extend(Ext.Component, {
384 	initComponent: function() {
385 		var me = this;
386 		this.on('beforehide', function() {
387 			me.closePanel();
388 		});
389 	},
390 	/**
391 	 * add a css class to the wrapper-div autogenerated by extjs
392 	 * @hide
393 	 */
394 	autoEl: {
395 		cls: 'aloha-multisplit-wrapper'
396 	},
397 
398 	/**
399 	 * will contain a reference to the ul dom object
400 	 * @hide
401 	 */
402 	ulObj: null,
403 
404 	/**
405 	 * holds a reference to the expand button
406 	 * @hide
407 	 */
408 	panelButton: null,
409 
410 	/**
411 	 * hold a reference to the wrapper div
412 	 * @hide
413 	 */
414 	wrapper: null,
415 
416 	/**
417 	 * true if the panel is expanded
418 	 * @hide
419 	 */
420 	panelOpened: false,
421 
422 	/**
423 	 * get items for the multisplit button according to config
424 	 * configuration for a multisplit button has to be stored
425 	 * within an array:
426 	 *
427 	 *		Aloha.settings.components.[MULTISPLITBUTTON-NAME] = [ 'item1', 'item2' ];
428 	 *
429 	 * An example for that would be:
430 	 *
431 	 *		// settings for phrasing element for the format plugin
432 	 *		Aloha.settings.components.phrasing = [ 'h1', 'h2', 'h3', 'removeFormat' ];
433 	 *
434 	 * if there is no config available, it will just use all items available
435 	 * @return button items for this multisplit button
436 	 */
437 	_getItems: function() {
438 		var that = this,
439 			items = [],
440 			i, length;
441 		
442 		if (Aloha.settings.components &&
443 			Aloha.settings.components[this.name] &&
444 			typeof Aloha.settings.components[this.name] === 'object') {
445 			// iterate over all buttons in our config...
446 			jQuery.each(Aloha.settings.components[this.name], function (idx, button) {
447 				for (i = 0, length = that.items.length; i < length; i++) {
448 					if (that.items[i].name === button) {
449 						// ... and find the appropriate internal button
450 						items.push(that.items[i]);
451 						break;
452 					}
453 				}
454 			});
455 			return items;
456 		} else {
457 			return this.items;
458 		}
459 	},
460 
461 	/**
462 	 * render the multisplit button
463 	 * @return void
464 	 * @hide
465 	 */
466 	onRender: function() {
467 		Ext.ux.MultiSplitButton.superclass.onRender.apply(this, arguments);
468 		// create a reference to this elements dom object
469 		this.wrapper = jQuery(this.el.dom);
470 
471 		var
472 			me = this,
473 			i,
474 			item,
475 			items,
476 			html = '<ul class="aloha-multisplit">';
477 
478 		items = this._getItems(); 
479 
480 		// add a new button to the list for each configured item
481 		for (i=0; i<items.length; i++) {
482 			item = items[i];
483 			if (typeof item.visible == 'undefined') {
484 				item.visible = true;
485 			}
486 			// wide buttons will always be rendered at the bottom of the list
487 			if (item.wide) {
488 				continue;
489 			}
490 			html += '<li>' +
491 				'<button xmlns:ext="http://www.extjs.com/" class="' + item.iconClass + '" ext:qtip="' + item.tooltip + '" gtxmultisplititem="' + i + '"> </button>' +
492 				'</li>';
493 		}
494 
495         // now add the wide buttons at the bottom of the list
496 		for (i=0; i<items.length; i++) {
497 			item = items[i];
498 			// now only wide buttons will be rendered
499 			if (!item.wide) {
500 				continue;
501 			}
502 
503 			html += '<li>' +
504 				'<button xmlns:ext="http://www.extjs.com/" class="aloha-multisplit-wide ' + item.iconClass + '" ext:qtip="' + item.tooltip + '" gtxmultisplititem="' + i + '">' +
505 				item.text + '</button>' +
506 				'</li>';
507 		}
508 509 
		html += '</ul>';
510 
511 		// register on move event, which occurs when the panel was dragged
512 		// this should be done within the constructor, but ist not possible there
513 		// since the extTabPanel will not be initialized at this moment
514 		FloatingMenu.extTabPanel.on('move', function () {
515 			me.closePanel();
516 		});
517 		FloatingMenu.extTabPanel.on('tabchange', function () {
518 			me.closePanel();
519 		});
520 
521 		// add onclick event handler
522 		this.ulObj = jQuery(this.el.createChild(html).dom)
523 		.click(function (event) {
524 			me.onClick(event);
525 		});
526 
527 		// add the expand button
528 		this.panelButton = jQuery(
529 			this.el.createChild('<button class="aloha-multisplit-toggle aloha-multisplit-toggle-open"> </button>').dom
530 		)
531 		.click(function () {
532 			me.togglePanel();
533 		});
534   },
535 
536 	/**
537 	 * callback if a button has been clicked
538 	 * @param event jquery event object
539 	 * @return void
540 	 * @hide
541 	 */
542   onClick: function(event) {
543 		// check if the element has a gtxmultisplititem attribute assigned
544 		if (!event.target.attributes.gtxmultisplititem) {
545 			return;
546 		}
547 		var el = jQuery(event.target);
548 
549 		// collapse the panel
550 		this.closePanel();
551 
552 		// wide buttons cannot become the active element
553 		if (!el.hasClass('aloha-multisplit-wide')) {
554 			this.setActiveDOMElement(el);
555 		}
556 
557 		// invoke the items function
558 		this.items[event.target.attributes.gtxmultisplititem.value].click();
559   },
560 
561 	/**
562 	 * set the active item specified by its name
563 	 * @param name the name of the item to be marked as active
564 	 * @return void
565 	 * @hide
566 	 */
567 	setActiveItem: function(name) {
568 		var button;
569 
570 		// collapse the panel
571 		this.closePanel();
572 
573 		button = jQuery('#' + this.id + ' .aloha-button-' + name);
574 		if (button.length === 1) {
575 			this.setActiveDOMElement(button);
576 			this.activeItem = name;
577 		} else {
578 			this.setActiveDOMElement(null);
579 			this.activeItem = null;
580 		}
581     },
582 
583 	/**
584 	 * mark an item as active
585 	 * @param el jquery obj for item to be marked as active
586 	 * @return void
587 	 * @hide
588 	 */
589 	setActiveDOMElement: function(el) {
590 		// when the component (or one of its owners) is currently hidden, we need to set the active item later
591 		var ct = this, top;
592 		while (typeof ct !== 'undefined') {
593 			if (ct.hidden) {
594 				this.activeDOMElement = el;
595 				return;
596 			}
597 			ct = ct.ownerCt;
598 		}
599 
600 		jQuery(this.ulObj).find('.aloha-multisplit-activeitem').removeClass('aloha-multisplit-activeitem');
601 		if(el) {
602 			el.parent().addClass('aloha-multisplit-activeitem');
603 		}
604 
605 		if ( !el || el.parent().is(':hidden')) {
606 			return;
607 		}
608 
609 		// reposition multisplit contents to the active item
610 		if ( el && this.ulObj ) {
611 			this.ulObj.css('margin-top', 0);
612 			top = el.position().top;
613 			this.ulObj.css({
614 				'margin-top': - top + 6,
615 				'height': 46 + top - 6
616 			});
617 		}
618 
619 		this.activeDOMElement = undefined;
620     },
621 	/**
622 	 * toggle the panel display from closed to expanded or vice versa
623 	 * @return void
624 	 * @hide
625 	 */
626 	togglePanel: function() {
627 		if (this.panelOpened) {
628 			this.closePanel();
629 		} else {
630 			this.openPanel();
631 		}
632     },
633 
634     /**
635      * expand the button panel
636      * @return void
637      * @hide
638      */
639     openPanel: function() {
640 		if (this.panelOpened) {
641 			return;
642 		}
643 
644 		var o = this.wrapper.offset();
645 
646 		// detach the ul element and reattach it onto the body
647 		this.ulObj
648 			.appendTo(jQuery('body'))
649 			.addClass('aloha-multisplit-expanded')
650 			.mousedown(function (e) {
651 				e.stopPropagation();
652 			})
653 			.css({
654 				// relocate the ul
655 				'top': o.top - 1,
656 				'left': o.left - 1
657 			})
658 			.animate({
659 				// display expand animation
660 				height: (this.ulObj.prop)?this.ulObj.prop('scrollHeight'):this.ulObj.attr('scrollHeight')
661 			});
662 
663 		// TODO change to css
664 		this.panelButton
665 			.removeClass('aloha-multisplit-toggle-open')
666 			.addClass('aloha-multisplit-toggle-close');
667 		this.panelOpened = true;
668     },
669 
670     /**
671      * collapses the panel
672      * @return void
673      * @hide
674      */
675     closePanel: function() {
676 		if (!this.panelOpened) {
677 			return;
678 		}
679 
680 		this.ulObj
681 			.removeClass('aloha-multisplit-expanded')
682 			.appendTo(this.wrapper);
683 
684 		// TODO change to css
685 		this.panelButton
686 			.addClass('aloha-multisplit-toggle-open')
687 			.removeClass('aloha-multisplit-toggle-close');
688 		this.panelOpened = false;
689 	},
690 
691 	/**
692 	 * hides a multisplit item
693 	 * @return void
694 	 * @hide
695 	 */
696 	hideItem: function(name) {
697 		for (var i = 0; i<this.items.length; i++) {
698 			if (this.items[i].name == name) {
699 				this.items[i].visible = false;
700 				// hide the corresponding dom object
701 				jQuery('#' + this.id + ' [gtxmultisplititem=' + i + ']').parent().hide();
702 				return;
703 			}
704 		}
705 	},
706 
707 	/**
708 	 * shows an item
709 	 * @return void
710 	 * @hide
711 	 */
712 	showItem: function(name) {
713 		for (var i = 0; i<this.items.length; i++) {
714 			if (this.items[i].name == name) {
715 				this.items[i].visible = true;
716 				// hide the corresponding dom object
717 				jQuery('#' + this.id + ' [gtxmultisplititem=' + i + ']').parent().show();
718 				return;
719 			}
720 		}
721 	}
722 });
723 Ext.reg('alohamultisplitbutton', Ext.ux.MultiSplitButton);
724 
725 /**
726  * Aloha MultiSplit Button
727  * @namespace Aloha.ui
728  * @class MultiSplitButton
729  * @param {Object} properties properties object for the new multisplit button
730  *		however you just have to fill out the items property of this object
731  *		items : [{
732  *			'name'  : 'normal', // the buttons name, used to identify it
733  *			'tooltip' : 'Basic Text', // the buttons tooltip, which will be displayed on hover
734  *			'text'	: 'Basic Text', // text to display on wide buttons
735  *			'icon'  : 'img/icon.jpg', // source for the icon
736  *			'click' : function() { alert('normal'); } // callback if the button is clicked
737  *			'wide'  : false // whether it's a wide button, which would be dispalyed at the bottom
738  *		}]
739  */
740 Aloha.ui.MultiSplitButton = Class.extend({
741 	_constructor: function(properties) {
742 		/**
743 		 * Items in the Multisplit Button
744 		 * @hide
745 		 */
746 		this.items = [];
747 		GENTICS.Utils.applyProperties(this, properties);
748 
749 		/**
750 		 * unique id for all buttons
751 		 * @hide
752 		 */
753 		this.id = this.generateId();
754 	},
755 
756 	/**
757 	 * Generate a unique id for the button
758 	 * @return unique id
759 	 * @hide
760 	 */
761 	generateId: function () {
762 		Aloha.ui.MultiSplitButton.idCounter = Aloha.ui.MultiSplitButton.idCounter + 1;
763 		return 'aloha-multisplitbutton' + Aloha.ui.MultiSplitButton.idCounter;
764 	},
765 
766 	/**
767 	 * Return an object containing the config properties to generate this button
768 	 * @return config properties
769 	 * @hide
770 	 */
771 	getExtConfigProperties: function() {
772 		return {
773 			'xtype' : 'alohamultisplitbutton',
774 			'items' : this.items,
775 			'name' : this.name,
776 			'id' : this.id
777 		};
778 	},
779 
780 	/**
781 	 * Set the active item of the multisplitbutton
782 	 * @param {String} name	name of the item to be set active
783 	 */
784 	setActiveItem: function(name) {
785 		if (this.extButton && typeof name !== 'undefined') {
786 			this.extButton.setActiveItem(name);
787 		}
788 	},
789 
790 	/**
791 	 * check whether the multisplit button is visible
792 	 * @return boolean true if visible
793 	 */
794 	isVisible: function() {
795 		// if all items are hidden, disable this item
796 		for (var i=0; i<this.items.length; i++) {
797 			// if just one item is visible that's enough
798 			if (this.items[i].visible) {
799 				return true;
800 			}
801 		}
802 		return false;
803 	},
804 
805 	/**
806 	 * shows an item of the multisplit button
807 	 * @param {String} name the item's name
808 	 */
809 	showItem: function(name) {
810 		if (typeof this.extButton === 'undefined') {
811 			return;
812 		}
813 		this.extButton.showItem(name);
814 	},
815 
816 	/**
817 	 * hides an item of the multisplit button
818 	 * @param {String} name the item's name
819 	 */
820 	hideItem: function(name) {
821 		if (typeof this.extButton === 'undefined') {
822 			return;
823 		}
824 		this.extButton.hideItem(name);
825 	}
826 });
827 
828 /**
829  * Method to access translations
830  * @deprecated
831  * This will be removed in one of the next version
832  */
833 Aloha.i18n = function(component, key, replacements) {
834 	console.deprecated ('Aloha', 'i18n() is deprecated. Use module "i18n!aloha/nls/i18n" instead.');
835 	return key;
836 };
837 
838 
839 /**
840  * Displays a message according to it's type
841  * @method
842  * @param {Aloha.Message} message the Aloha.Message object to be displayed
843  */
844 Aloha.showMessage = function (message) {
845 
846 	if (FloatingMenu.obj) {
847 		FloatingMenu.obj.css('z-index', 8900);
848 	}
849 
850 851 	switch (message.type) {
852 		case Aloha.Message.Type.ALERT:
853 			Ext.MessageBox.alert(message.title, message.text, message.callback);
854 			break;
855 		case Aloha.Message.Type.CONFIRM:
856 			Ext.MessageBox.confirm(message.title, message.text, message.callback);
857 			break;
858 		case Aloha.Message.Type.WAIT:
859 			Ext.MessageBox.wait(message.text, message.title);
860 			break;
861 862 		default:
863 			Aloha.log('warn', this, 'Unknown message type for message {' + message.toString() + '}');
864 			break;
865 	}
866 };
867 
868 /**
869  * Hides the currently active modal, which was displayed by showMessage()
870  * @method
871  */
872 Aloha.hideMessage = function () {
873 	Ext.MessageBox.hide();
874 };
875 
876 /**
877  * checks if a modal dialog is visible right now
878  * @method
879  * @return true if a modal is currently displayed
880  */
881 Aloha.isMessageVisible = function () {
882 	return Ext.MessageBox.isVisible();
883 };
884 
885 /**
886  * id counter, for generation of unique id's for the buttons
887  * @hide
888  */
889 Aloha.ui.MultiSplitButton.idCounter = 0;
890 
891 return Aloha.ui;
892 
893 });
894