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