1 /*
  2  * JBoss, Home of Professional Open Source
  3  * Copyright ${year}, Red Hat, Inc. and individual contributors
  4  * by the @authors tag. See the copyright.txt in the distribution for a
  5  * full listing of individual contributors.
  6  *
  7  * This is free software; you can redistribute it and/or modify it
  8  * under the terms of the GNU Lesser General Public License as
  9  * published by the Free Software Foundation; either version 2.1 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * This software 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 GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this software; if not, write to the Free
 19  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 20  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 21  */
 22 
 23 (function ($, rf) {
 24 
 25     rf.ui = rf.ui || {};
 26 
 27     /* SIMPLE INNER CLASS for handle switch operation*/
 28     function SwitchItems(comp) {
 29         this.comp = comp;
 30     }
 31 
 32     SwitchItems.prototype = {
 33 
 34         /**
 35          * @param {TogglePanelItem} oldPanel
 36          * @param {TogglePanelItem} newPanel
 37          *
 38          * @return {void}
 39          * */
 40         exec : function (oldPanel, newPanel) {
 41             if (newPanel.switchMode == "server") {
 42                 return this.execServer(oldPanel, newPanel);
 43             } else if (newPanel.switchMode == "ajax") {
 44                 return this.execAjax(oldPanel, newPanel);
 45             } else if (newPanel.switchMode == "client") {
 46                 return this.execClient(oldPanel, newPanel);
 47             } else {
 48                 rf.log.error("SwitchItems.exec : unknown switchMode (" + this.comp.switchMode + ")");
 49             }
 50         },
 51 
 52         /**
 53          * @protected
 54          * @param {TogglePanelItem} oldPanel
 55          * @param {TogglePanelItem} newPanel
 56          *
 57          * @return {Boolean} false
 58          * */
 59         execServer : function (oldPanel, newPanel) {
 60             if (oldPanel) {
 61                 var continueProcess = oldPanel.__leave();
 62                 if (!continueProcess) {
 63                     return false;
 64                 }
 65             }
 66 
 67             this.__setActiveItem(newPanel.getName());
 68 
 69             rf.submitForm(this.__getParentForm());
 70 
 71             return false;
 72         },
 73 
 74         /**
 75          * @protected
 76          * @param {TogglePanelItem} oldPanel
 77          * @param {TogglePanelItem} newPanel
 78          *
 79          * @return {Boolean} false
 80          * */
 81         execAjax : function (oldPanel, newPanel) {
 82             var options = $.extend({}, this.comp.options["ajax"], {}/*this.getParameters(newPanel)*/);
 83 
 84             this.__setActiveItem(newPanel.getName());
 85             rf.ajax(this.comp.id, null, options);
 86 
 87             if (oldPanel) {
 88                 this.__setActiveItem(oldPanel.getName());
 89             }
 90 
 91             return false;
 92         },
 93 
 94         /**
 95          * @protected
 96          * @param {TogglePanelItem} oldPanel
 97          * @param {TogglePanelItem} newPanel
 98          *
 99          * @return {undefined}
100          *             - false - if process has been terminated
101          *             - true  - in other cases
102          * */
103         execClient : function (oldPanel, newPanel) {
104             if (oldPanel) {
105                 var continueProcess = oldPanel.__leave();
106                 if (!continueProcess) {
107                     return false;
108                 }
109             }
110 
111             this.__setActiveItem(newPanel.getName());
112 
113             newPanel.__enter();
114             this.comp.__fireItemChange(oldPanel, newPanel);
115 
116             return true;
117         },
118 
119         /**
120          * @private
121          * */
122         __getParentForm : function () {
123             return $(rf.getDomElement(this.comp.id)).parents('form:first');
124         },
125 
126         /**
127          * @private
128          * */
129         __setActiveItem : function (name) {
130             rf.getDomElement(this.__getValueInputId()).value = name;
131             this.comp.activeItem = name;
132         },
133 
134         /**
135          * @private
136          * */
137         __getValueInputId: function () {
138             return this.comp.id + "-value"
139         }
140     };
141 
142     /**
143      * @class TogglePanel
144      * @name TogglePanel
145      *
146      * @constructor
147      * @param {String} componentId - component id
148      * @param {Hash} options - params
149      * */
150     rf.ui.TogglePanel = rf.BaseComponent.extendClass({
151 
152             // class name
153             name:"TogglePanel",
154 
155             init : function (componentId, options) {
156                 $super.constructor.call(this, componentId);
157                 this.attachToDom();
158 
159                 this.items = [];
160 
161                 this.options = $.extend(this.options, options || {});
162                 this.activeItem = this.options.activeItem;
163 
164                 this.__addUserEventHandler("itemchange");
165                 this.__addUserEventHandler("beforeitemchange");
166             },
167 
168             /***************************** Public Methods  ****************************************************************/
169 
170             /**
171              * @methodOf
172              *
173              * @name TogglePanel#getSelectItem
174              *
175              * @return {String} name of current selected panel item
176              */
177             getSelectItem: function () {
178                 return this.activeItem;
179             },
180 
181             /**
182              * @methodOf
183              * @name TogglePanel#switchToItem
184              *
185              * @param {String} name - panel item name to switch
186              *           we can use meta names @first, @prev, @next and @last
187              * @return {Boolean} - false if something wrong and true if all is ok
188              */
189             switchToItem: function (name) {
190                 var newPanel = this.getNextItem(name);
191                 if (newPanel == null) {
192                     rf.log.warn("TogglePanel.switchToItems(" + name + "): item with name '" + name + "' not found");
193                     return false;
194                 }
195 
196                 var oldPanel = this.__getItemByName(this.getSelectItem());
197 
198                 var continueProcess = this.__fireBeforeItemChange(oldPanel, newPanel);
199                 if (!continueProcess) {
200                     rf.log.warn("TogglePanel.switchToItems(" + name + "): switch has been canceled by beforeItemChange event");
201                     return false
202                 }
203 
204                 return this.__itemsSwitcher().exec(oldPanel, newPanel);
205             },
206 
207             /**
208              * @methodOf
209              * @name TogglePanel#getNextItem
210              *
211              * @param {String} name of TogglePanelItem or meta name (@first | @prev | @next | @last)
212              * @return {TogglePanelItem} null if item not found
213              */
214             getNextItem : function (name) {
215                 if (name) {
216                     var newItemIndex = this.__ITEMS_META_NAMES[name];
217                     if (newItemIndex) {
218                         return this.__getItem(newItemIndex(this));
219                     } else {
220                         return this.__getItemByName(name);
221                     }
222                 } else {
223                     return this.__getItemByName(this.nextItem());
224                 }
225             },
226 
227             /**
228              * please, remove this method when client side ajax events will be added
229              *
230              * */
231             onCompleteHandler : function (newItemName) {
232                 var oldItem = this.__getItemByName(this.activeItem);
233                 var newItem = this.__getItemByName(newItemName);
234 
235                 // Don't do like this and remove it ASAP
236                 this.__itemsSwitcher().execClient(oldItem, newItem);
237                 $(document.getElementById(newItem.getTogglePanel().id)).trigger("resize");
238             },
239 
240             /**
241              * @methodOf
242              * @name TogglePanel#getItems
243              *
244              * @return {TogglePanelItem[]} all defined panel items
245              */
246             getItems : function () {
247                 return this.items;
248             },
249 
250             /**
251              * @methodOf
252              * @name TogglePanel#getItemsNames
253              *
254              * @return {String[]} names of all defined items
255              */
256             getItemsNames: function () {
257                 var res = [];
258                 for (var i = 0; i < this.items.length; i++) {
259                     res.push(this.items[i].getName());
260                 }
261 
262                 return res;
263             },
264 
265             /**
266              * @methodOf
267              * @name TogglePanel#nextItem
268              *
269              * @param {String} [itemName = activeItem]
270              * @return {String} name of next panel item
271              */
272             nextItem: function (itemName) {
273                 var itemIndex = this.__getItemIndex(itemName || this.activeItem);
274                 if (itemIndex == -1) {
275                     return null;
276                 }
277 
278                 return this.__getItemName(itemIndex + 1);
279             },
280 
281             /**
282              * @methodOf
283              * @name TogglePanel#firstItem
284              *
285              * @return {String} name of first panel item
286              */
287             firstItem: function () {
288                 return this.__getItemName(0);
289             },
290 
291             /**
292              * @methodOf
293              * @name TogglePanel#lastItem
294              *
295              * @return {String} name of last panel item
296              */
297             lastItem: function () {
298                 return this.__getItemName(this.items.length - 1);
299             },
300 
301             /**
302              * @methodOf
303              * @name TogglePanel#prevItem
304              *
305              * @param {String} itemName
306              * @return {String} name of prev panel item
307              *                  null if it is first item
308              */
309             prevItem: function (itemName) {
310                 var itemIndex = this.__getItemIndex(itemName || this.activeItem);
311                 if (!this.options.cycledSwitching && itemIndex < 1) {
312                     return null;
313                 }
314 
315                 return this.__getItemName(itemIndex - 1);
316             },
317 
318             /////////////////////////////////////////////////////////////////////////////////
319             //// Private
320             /////////////////////////////////////////////////////////////////////////////////
321 
322             /********************* Methods *************************/
323 
324             __itemsSwitcher : function () {
325                 return new SwitchItems(this);
326             },
327 
328             __ITEMS_META_NAMES : (function () {
329                 function goFrom(comp, ind, step) {
330                     var res = ind;
331                     while ((!comp.items[res] || comp.items[res].disabled) && res < comp.items.length && res > 0) {
332                         res += step;
333                     }
334                     return res;
335                 }
336 
337 
338                 return {
339                     "@first" : function (comp) {
340                         return goFrom(comp, 0, 1);
341                     },
342 
343                     "@prev"  : function (comp) {
344                         return goFrom(comp, parseInt(comp.__getItemIndex(comp.activeItem)) - 1, -1);
345                     },
346 
347                     "@next"  : function (comp) {
348                         return goFrom(comp, parseInt(comp.__getItemIndex(comp.activeItem)) + 1, 1);
349                     },
350 
351                     "@last"  : function (comp) {
352                         return goFrom(comp, comp.items.length - 1, -1);
353                     }
354                 }
355             })(),
356 
357             /**
358              * @private
359              * */
360             __getItemIndex : function (itemName) {
361                 var item;
362                 for (var i = 0; i < this.items.length; i++) {
363                     item = this.items[i];
364                     if (!item.disabled && item.getName() === itemName) {
365                         return i;
366                     }
367                 }
368 
369                 rf.log.info("TogglePanel.getItemIndex: item with name '" + itemName + "' not found");
370                 return -1;
371             },
372 
373             /**
374              * @private
375              * */
376             __addUserEventHandler : function (name) {
377                 var handler = this.options["on" + name];
378                 if (handler) {
379                     rf.Event.bindById(this.id, name, handler);
380                 }
381             },
382 
383             /**
384              * @private
385              * @param {Number} index - array index
386              *
387              * @return {TogglePanelItem}
388              *    null - if item not found
389              * */
390             __getItem : function (index) {
391                 if (this.options.cycledSwitching) {
392                     var size = this.items.length;
393                     return this.items[(size + index) % size]
394                 } else if (index >= 0 && index < this.items.length) {
395                     return this.items[index]
396                 } else {
397                     return null;
398                 }
399             },
400 
401             __getItemByName : function (name) {
402                 return this.__getItem(this.__getItemIndex(name));
403             },
404 
405             __getItemName : function (index) {
406                 var item = this.__getItem(index);
407                 if (item == null) {
408                     return null;
409                 }
410 
411                 return item.getName();
412             },
413 
414             /**
415              * Fire Concealable Event
416              * */
417 
418             __fireItemChange : function (oldItem, newItem) {
419                 return new rf.Event.fireById(this.id, "itemchange", {
420                         id: this.id,
421                         oldItem : oldItem,
422                         newItem : newItem
423                     });
424             },
425 
426             __fireBeforeItemChange : function (oldItem, newItem) {
427                 return rf.Event.fireById(this.id, "beforeitemchange", {
428                         id: this.id,
429                         oldItem : oldItem,
430                         newItem : newItem
431                     });
432             }
433         });
434 
435     // define super class link
436     var $super = rf.ui.TogglePanel.$super;
437 })(RichFaces.jQuery, RichFaces);
438