      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
     24 (function ($, rf) {
     25
     26     rf.ui = rf.ui || {};
     27
     28     var __DEFAULT_OPTIONS = {
     29         expanded : false,
     30         stylePrefix : "rf-pm-gr",
     31         expandEvent: "click",
     32         collapseEvent: "click",
     33
     34         // TODO we should use selectionType = {none, selectable, unselectable}
     35         selectable : false,
     36         unselectable : false // unselectable can be only selectable item => if selectable == false than unselectable = false
     37     };
     38
     39     var EXPAND_ITEM = {
     40
     41         /**
     42          *
     43          * @return {void}
     44          * */
     45         exec : function (group, expand) {
     46             var mode = group.mode;
     47             if (mode == "server") {
     48                 return this.execServer(group);
     49             } else if (mode == "ajax") {
     50                 return this.execAjax(group);
     51             } else if (mode == "client" || mode == "none") {
     52                 return this.execClient(group, expand);
     53             } else {
     54                 rf.log.error("EXPAND_ITEM.exec : unknown mode (" + mode + ")");
     55             }
     56         },
     57
     58         /**
     59          * @protected
     60          *
     61          * @return {Boolean} false
     62          * */
     63         execServer : function (group) {
     64             group.__changeState();
     65             rf.submitForm(this.__getParentForm(group), group.options["ajax"]["parameters"] || {});
     66
     67             return false;
     68         },
     69
     70         /**
     71          * @protected
     72          *
     73          * @return {Boolean} false
     74          * */
     75         execAjax : function (group) {
     76             var oldState = group.__changeState();
     77             rf.ajax(group.id, null, $.extend({}, group.options["ajax"], {}));
     78             group.__restoreState(oldState);
     79
     80             return true;
     81         },
     82
     83         /**
     84          * @protected
     85          *
     86          * @param {PanelMenuGroup} group
     87          * @param {Boolean} expand
     88          * @return {undefined}
     89          *             - false - if process has been terminated
     90          *             - true  - in other cases
     91          * */
     92         execClient : function (group, expand) {
     93             if (expand) {
     94                 group.__expand();
     95             } else {
     96                 group.__collapse();
     97             }
     98
     99             return group.__fireEvent("switch");
    100         },
    101
    102         /**
    103          * @private
    104          * */
    105         __getParentForm : function (item) {
    106             return $($(rf.getDomElement(item.id)).parents("form")[0]);
    107         }
    108     };
    109
    110     rf.ui.PanelMenuGroup = rf.ui.PanelMenuItem.extendClass({
    111             // class name
    112             name:"PanelMenuGroup",
    113
    114             /**
    115              * @class PanelMenuGroup
    116              * @name PanelMenuGroup
    117              *
    118              * @constructor
    119              * @param {String} componentId - component id
    120              * @param {Hash} options - params
    121              * */
    122             init : function (componentId, options) {
    123                 $super.constructor.call(this, componentId, $.extend({}, __DEFAULT_OPTIONS, options || {}));
    124
    125                 this.options.bubbleSelection = this.__rfPanelMenu().options.bubbleSelection;
    126                 this.options.expandSingle = this.__rfPanelMenu().options.expandSingle;
    127
    128                 if (!this.options.disabled) {
    129                     var menuGroup = this;
    130
    131                     if (!this.options.selectable) {
    132
    133                         //TODO nick - this can be replaced by jQuery.delegate on menu itself
    134                         if (this.options.expandEvent == this.options.collapseEvent) {
    135                             this.__header().bind(this.options.expandEvent, function () {
    136                                 menuGroup.switchExpantion();
    137                             });
    138
    139                         } else {
    140                             this.__header().bind(this.options.expandEvent, function () {
    141                                 if (menuGroup.collapsed()) {
    142                                     return menuGroup.expand();
    143                                 }
    144                             });
    145
    146                             this.__header().bind(this.options.collapseEvent, function () {
    147                                 if (menuGroup.expanded()) {
    148                                     return menuGroup.collapse();
    149                                 }
    150                             });
    151                         }
    152                     } else {
    153
    154                         if (this.options.expandEvent == this.options.collapseEvent) {
    155                             if (this.options.expandEvent != 'click') {
    156                                 this.__header().bind(this.options.expandEvent, function () {
    157                                     menuGroup.switchExpantion();
    158                                 });
    159                             }
    160
    161                         } else {
    162                             if (this.options.expandEvent != 'click') {
    163                                 this.__header().bind(this.options.expandEvent, function () {
    164                                     if (menuGroup.collapsed()) {
    165                                         return menuGroup.expand();
    166                                     }
    167                                 });
    168                             }
    169
    170                             if (this.options.collapseEvent != 'click') {
    171                                 this.__header().bind(this.options.collapseEvent, function () {
    172                                     if (menuGroup.expanded()) {
    173                                         return menuGroup.collapse();
    174                                     }
    175                                 });
    176                             }
    177                         }
    178
    179                     }
    180
    181                     if (this.options.selectable || this.options.bubbleSelection) {
    182                         this.__content().bind("select", function (event) {
    183                             if (menuGroup.options.selectable && menuGroup.__isMyEvent(event)) {
    184                                 menuGroup.expand();
    185                             }
    186
    187                             if (menuGroup.options.bubbleSelection && !menuGroup.__isMyEvent(event)) {
    188                                 menuGroup.__select();
    189                                 if (!menuGroup.expanded()) {
    190                                     menuGroup.expand();
    191                                 }
    192                             }
    193                         });
    194
    195                         this.__content().bind("unselect", function (event) {
    196                             if (menuGroup.options.selectable && menuGroup.__isMyEvent(event)) {
    197                                 menuGroup.collapse();
    198                             }
    199
    200                             if (menuGroup.options.bubbleSelection && !menuGroup.__isMyEvent(event)) {
    201                                 menuGroup.__unselect();
    202                             }
    203                         });
    204                     }
    205
    206                     /*this.__addUserEventHandler("beforecollapse");
    207                      this.__addUserEventHandler("collapse");
    208                      this.__addUserEventHandler("beforeexpand");
    209                      this.__addUserEventHandler("expand");
    210                      this.__addUserEventHandler("beforeswitch");
    211                      this.__addUserEventHandler("switch");*/
    212                 }
    213             },
    214
    215             /***************************** Public Methods  ****************************************************************/
    216             expanded : function () {
    217                 // TODO check invariant in dev mode
    218                 // return this.__content().hasClass("rf-pm-exp")
    219                 return this.__getExpandValue();
    220             },
    221
    222             expand : function () {
    223                 if (this.expanded()) return;
    224                 if (!this.__fireEvent("beforeexpand")) {
    225                     return false;
    226                 }
    227
    228                 EXPAND_ITEM.exec(this, true);
    229             },
    230
    231             __expand : function () {
    232                 this.__updateStyles(true);
    233                 this.__collapseForExpandSingle();
    234
    235                 return this.__fireEvent("expand");
    236             },
    237
    238             collapsed : function () {
    239                 // TODO check invariant in dev mode
    240                 // return this.__content().hasClass("rf-pm-colps")
    241                 return !this.__getExpandValue();
    242             },
    243
    244             collapse : function () {
    245                 if (!this.expanded()) return;
    246                 if (!this.__fireEvent("beforecollapse")) {
    247                     return false;
    248                 }
    249
    250                 EXPAND_ITEM.exec(this, false);
    251             },
    252
    253             __collapse : function () {
    254                 this.__updateStyles(false);
    255
    256                 this.__childGroups().each(function(index, group) {
    257                     //TODO nick - why not group.collapse()?
    258                     rf.component(group.id).__collapse();
    259                 });
    260
    261                 return this.__fireEvent("collapse");
    262             },
    263
    264             __updateStyles : function (expand) {
    265                 if (expand) {
    266                     //expand
    267                     this.__content().removeClass("rf-pm-colps").addClass("rf-pm-exp");
    268                     this.__header().removeClass("rf-pm-hdr-colps").addClass("rf-pm-hdr-exp");
    269
    270                     this.__setExpandValue(true);
    271                 } else {
    272                     this.__content().addClass("rf-pm-colps").removeClass("rf-pm-exp");
    273                     this.__header().addClass("rf-pm-hdr-colps").removeClass("rf-pm-hdr-exp");
    274
    275                     this.__setExpandValue(false);
    276                 }
    277             },
    278
    279             /**
    280              * @methodOf
    281              * @name PanelMenuGroup#switch
    282              *
    283              * TODO ...
    284              *
    285              * @param {boolean} expand
    286              * @return {void} TODO ...
    287              */
    288             switchExpantion : function () { // TODO rename
    289                 var continueProcess = this.__fireEvent("beforeswitch");
    290                 if (!continueProcess) {
    291                     return false;
    292                 }
    293
    294                 if (this.expanded()) {
    295                     this.collapse();
    296                 } else {
    297                     this.expand();
    298                 }
    299             },
    300
    301             /**
    302              * please, remove this method when client side ajax events will be added
    303              *
    304              * */
    305             onCompleteHandler : function () {
    306                 if (this.options.selectable) {
    307                     $super.onCompleteHandler.call(this);
    308                 }
    309
    310                 EXPAND_ITEM.execClient(this, this.expanded());
    311             },
    312
    313             __switch : function (expand) {
    314                 if (expand) {
    315                     this.__expand();
    316                 } else {
    317                     this.__collapse();
    318                 }
    319                 return this.__fireEvent("switch");
    320             },
    321
    322             /***************************** Private Methods ****************************************************************/
    323             __childGroups : function () {
    324                 return this.__content().children(".rf-pm-gr")
    325             },
    326
    327             __group : function () {
    328                 return $(rf.getDomElement(this.id))
    329             },
    330
    331             __header : function () {
    332                 return $(rf.getDomElement(this.id + ":hdr"))
    333             },
    334
    335             __content : function () {
    336                 return $(rf.getDomElement(this.id + ":cnt"))
    337             },
    338
    339             __expandValueInput : function () {
    340                 return document.getElementById(this.id + ":expanded");
    341             },
    342
    343             __getExpandValue : function () {
    344                 return this.__expandValueInput().value == "true";
    345             },
    346
    347             __collapseForExpandSingle: function() {
    348                 if (this.options.expandSingle) {
    349                     this.__rfPanelMenu().__collapseGroups(this);
    350                 }
    351             },
    352
    353             /**
    354              * @methodOf
    355              * @name PanelMenuGroup#__setExpandValue
    356              *
    357              * @param {boolean} value - is group expanded?
    358              * @return {boolean} preview value
    359              */
    360             __setExpandValue : function (value) {
    361                 var input = this.__expandValueInput();
    362                 var oldValue = input.value;
    363
    364                 input.value = value;
    365
    366                 return oldValue;
    367             },
    368
    369             __changeState : function () {
    370                 if (!this.__getExpandValue()) {
    371                     this.__collapseForExpandSingle();
    372                 }
    373
    374                 var state = {};
    375                 state["expanded"] = this.__setExpandValue(!this.__getExpandValue());
    376                 if (this.options.selectable) {
    377                     state["itemName"] = this.__rfPanelMenu().selectedItem(this.itemName); // TODO bad function name for function which change component state
    378                 }
    379
    380                 return state;
    381             },
    382
    383             __restoreState : function (state) {
    384                 if (!state) {
    385                     return;
    386                 }
    387
    388                 if (state["expanded"]) {
    389                     this.__setExpandValue(state["expanded"]);
    390                 }
    391
    392                 if (state["itemName"]) {
    393                     this.__rfPanelMenu().selectedItem(state["itemName"]);
    394                 }
    395             },
    396
    397             __isMyEvent: function (event) {
    398                 return this.id == event.target.id;
    399             },
    400
    401             destroy: function () {
    402                 rf.Event.unbindById(this.id, "." + this.namespace);
    403
    404                 $super.destroy.call(this);
    405             }
    406         });
    407
    408     // define super class link
    409     var $super = rf.ui.PanelMenuGroup.$super;
    410 })(RichFaces.jQuery, RichFaces);
    411