1if (!PrimeFaces.dialog) { 2 3 PrimeFaces.dialog = {}; 4 5 PrimeFaces.dialog.DialogHandler = { 6 7 openDialog: function(cfg) { 8 var rootWindow = this.findRootWindow(), 9 dialogId = cfg.sourceComponentId + '_dlg'; 10 11 if(rootWindow.document.getElementById(dialogId)) { 12 return; 13 } 14 15 // The widget that opens a dialog can be nested inside of a frame which might be nested again. 16 // The dialog is put in the outermost frame to be able to fill the whole browser tab, 17 // so we traverse upwards to find the root window and put the dialog DOM in there. 18 // When a dialog is closed, we need to clean up the global variables and notify the source widget for the dialog return feature. 19 // Accessing a component nested within frames requires recursive resolving of frames. 20 // Every frame has it's own contentWindow and thus also it's own document object. 21 // To be able to access a DOM element from an outer frame, one needs to first resolve the containing frame, 22 // and then resolve the element from the contentWindow. With nested frames, nested frame resolving has to be done. 23 // In order to do this, we traverse up the window frameElement until we reach the top window. 24 // While traversing up, we construct a selector for finding the frameElement from within the parent window. 25 // We build up the selectors backwards as we traverse up. Imagine the example 26 // 27 // -------------------------------------------------- 28 // | Frame 1 | 29 // | ------------------------------- | 30 // | | Frame 1_1 | | 31 // | | | | 32 // | | ------------ | | 33 // | | | Button 1 | | | 34 // | | ------------ | | 35 // | | | | 36 // | ------------------------------- | 37 // |------------------------------------------------| 38 // | Frame 2 | 39 // | | 40 // | | 41 // | | 42 // -------------------------------------------------- 43 // 44 // Here "Button 1" is our source widget that opened the dialog. 45 // The root window contains two frames "Frame 1" and "Frame 2". 46 // The "Frame 1" contains another frame "Frame 1_1" within which the widget lives. 47 // Since we have to install the dialog in the root window, we need to be able to get access 48 // to the source widget when closing the dialog. 49 // The only way to find the DOM node, is by traversing into "Frame 1" then into "Frame 1_1" and look it up there. 50 // So from the root window we do e.g. `$(rootWindow.document).find("#frame1").contentWindow` to get into "Frame 1". 51 // We do the same to get into "Frame 1_1" e.g. `$(frame1Window.document).find("#frame1_1").contentWindow`. 52 // Finally, we can look up the source widget `$(frame1_1Window.document).find("#sourceWidgetId")`. 53 54 var sourceFrames = function() { 55 var w = window; 56 var sourceFrames = []; 57 // Traverse up frameElement i.e. while we are in frames 58 while(w.frameElement) { 59 var parent = w.parent; 60 if (parent.PF === undefined) { 61 break; 62 } 63 64 // Since we traverse DOM elements upwards, we build the selector backwards i.e. from target to source. 65 // This is why we use `unshift` which is like an `addAtIndex(0, object)`. 66 // If an element has an id, we can use that to uniquely identify the DOM element and can jump to the next parent window. 67 // If we can't find an id, we collect class names and the tag name of an element. 68 // If that doesn't uniquely identify an element within it's parent, we also append the node index via the `:eq(index)` selector. 69 // We connect selectors for each DOM element with the `>` operator. 70 var e = w.frameElement; 71 var pieces = []; 72 73 // Traverse up tags from the frameElement to generate an identifying selector 74 for (; e && e.tagName !== undefined; e = e.parentNode) { 75 if (e.id && !/\s/.test(e.id)) { 76 // If we find a parent with an id, we can use that as basis and stop there 77 pieces.unshift(e.id); 78 pieces.unshift('#'); 79 pieces.unshift(' > '); 80 break; 81 } else if (e.className) {
82 // Without an id, we try to use a combination of :eq, class names and tag name and hope a parent has an id 83 var classes = e.className.split(' '); 84 var classSelectorPieces = []; 85 for (var i in classes) { 86 if (classes.hasOwnProperty(i) && classes[i]) { 87 classSelectorPieces.unshift(classes[i]); 88 classSelectorPieces.unshift('.'); 89 } 90 } 91 classSelectorPieces.unshift(e.tagName); 92 93 var classSelector = classSelectorPieces.join(''); 94 var elems = $(e.parentNode).find(classSelector); 95 if (elems.length > 1) { 96 pieces.unshift(":eq(" + elems.index(e) + ")"); 97 } 98 pieces.unshift(classSelector); 99 } else {
100 // Without classes, we try to work with :eq and the tag name 101 var elems = $(e.parentNode).find(e.tagName); 102 if (elems.length > 1) { 103 pieces.unshift(":eq(" + elems.index(e) + ")"); 104 } 105 pieces.unshift(e.tagName); 106 } 107 pieces.unshift(' > '); 108 } 109 110 var s = pieces.slice(1).join(''); 111 112 sourceFrames.unshift(s); 113 w = parent; 114 }; 115 116 return sourceFrames; 117 }(); 118 119 var dialogWidgetVar = cfg.options.widgetVar; 120 if (!dialogWidgetVar) { 121 dialogWidgetVar = cfg.sourceComponentId.replace(/:/g, '_') + '_dlgwidget'; 122 } 123 124 var styleClass = cfg.options.styleClass||'', 125 dialogDOM = $('<div id="' + dialogId + '" class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-shadow ui-hidden-container ui-overlay-hidden ' + styleClass + '"' + 126 ' data-pfdlgcid="' + PrimeFaces.escapeHTML(cfg.pfdlgcid) + '" data-widget="' + dialogWidgetVar + '"></div>') 127 .append('<div class="ui-dialog-titlebar ui-widget-header ui-helper-clearfix ui-corner-top"><span id="' + dialogId + '_title" class="ui-dialog-title"></span></div>'); 128 129 var titlebar = dialogDOM.children('.ui-dialog-titlebar'); 130 if(cfg.options.closable !== false) { 131 titlebar.append('<a class="ui-dialog-titlebar-icon ui-dialog-titlebar-close ui-corner-all" href="#" role="button"><span class="ui-icon ui-icon-closethick"></span></a>'); 132 } 133 134 if(cfg.options.minimizable) { 135 titlebar.append('<a class="ui-dialog-titlebar-icon ui-dialog-titlebar-minimize ui-corner-all" href="#" role="button"><span class="ui-icon ui-icon-minus"></span></a>'); 136 } 137 138 if(cfg.options.maximizable) { 139 titlebar.append('<a class="ui-dialog-titlebar-icon ui-dialog-titlebar-maximize ui-corner-all" href="#" role="button"><span class="ui-icon ui-icon-extlink"></span></a>'); 140 } 141 142 dialogDOM.append('<div class="ui-dialog-content ui-widget-content ui-df-content" style="height: auto;">' + 143 '<iframe style="border:0 none" frameborder="0"></iframe>' + 144 '</div>'); 145 146 dialogDOM.appendTo(rootWindow.document.body); 147 148 var dialogFrame = dialogDOM.find('iframe'), 149 symbol = cfg.url.indexOf('?') === -1 ? '?' : '&', 150 frameURL = cfg.url.indexOf('pfdlgcid') === -1 ? cfg.url + symbol + 'pfdlgcid=' + cfg.pfdlgcid: cfg.url, 151 frameWidth = cfg.options.contentWidth||640; 152 153 dialogFrame.width(frameWidth); 154 155 if(cfg.options.iframeTitle) { 156 dialogFrame.attr('title', cfg.options.iframeTitle); 157 } 158 159 dialogFrame.on('load', function() { 160 var $frame = $(this), 161 headerElement = $frame.contents().find('title'), 162 isCustomHeader = false;
163 164 if(cfg.options.headerElement) { 165 var customHeaderId = PrimeFaces.escapeClientId(cfg.options.headerElement), 166 customHeaderElement = dialogFrame.contents().find(customHeaderId); 167 168 if(customHeaderElement.length) { 169 headerElement = customHeaderElement; 170 isCustomHeader = true; 171 } 172 } 173 174 if(!$frame.data('initialized')) { 175 PrimeFaces.cw.call(rootWindow.PrimeFaces, 'DynamicDialog', dialogWidgetVar, { 176 id: dialogId, 177 position: cfg.options.position||'center', 178 sourceFrames: sourceFrames, 179 sourceComponentId: cfg.sourceComponentId, 180 sourceWidgetVar: cfg.sourceWidgetVar, 181 onHide: function() { 182 var $dialogWidget = this, 183 dialogFrame = this.content.children('iframe'); 184 185 if(dialogFrame.get(0).contentWindow.PrimeFaces) { 186 this.destroyIntervalId = setInterval(function() { 187 if(dialogFrame.get(0).contentWindow.PrimeFaces.ajax.Queue.isEmpty()) { 188 clearInterval($dialogWidget.destroyIntervalId); 189 dialogFrame.attr('src','about:blank'); 190 $dialogWidget.jq.remove(); 191 } 192 }, 10); 193 } 194 else { 195 dialogFrame.attr('src','about:blank'); 196 $dialogWidget.jq.remove(); 197 } 198 199 rootWindow.PrimeFaces.widgets[dialogWidgetVar] = undefined; 200 }, 201 modal: cfg.options.modal, 202 blockScroll: cfg.options.blockScroll, 203 resizable: cfg.options.resizable, 204 hasIframe: true, 205 draggable: cfg.options.draggable, 206 width: cfg.options.width, 207 height: cfg.options.height, 208 minimizable: cfg.options.minimizable, 209 maximizable: cfg.options.maximizable, 210 headerElement: cfg.options.headerElement, 211 responsive: cfg.options.responsive, 212 closeOnEscape: cfg.options.closeOnEscape, 213 focus: cfg.options.focus 214 }); 215 } 216 217 var title = rootWindow.PF(dialogWidgetVar).titlebar.children('span.ui-dialog-title'); 218 if(headerElement.length > 0) { 219 if(isCustomHeader) { 220 title.append(headerElement); 221 headerElement.show(); 222 } 223 else { 224 title.text(headerElement.text()); 225 } 226 227 dialogFrame.attr('title', title.text()); 228 } 229 230 //adjust height 231 var frameHeight = null; 232 if(cfg.options.contentHeight) 233 frameHeight = cfg.options.contentHeight; 234 else 235 frameHeight = $frame.get(0).contentWindow.document.body.scrollHeight + (PrimeFaces.env.browser.webkit ? 5 : 25); 236 237 $frame.css('height', frameHeight); 238 239 // fix #1290 - dialogs are not centered vertically 240 dialogFrame.data('initialized', true); 241 rootWindow.PF(dialogWidgetVar).show(); 242 }) 243 .attr('src', frameURL); 244 }, 245 246 closeDialog: function(cfg) { 247 var rootWindow = this.findRootWindow(), 248 dlgs = $(rootWindow.document.body).children('div.ui-dialog[data-pfdlgcid="' + $.escapeSelector(cfg.pfdlgcid) +'"]').not('[data-queuedforremoval]'), 249 dlgsLength = dlgs.length, 250 dlg = dlgs.eq(dlgsLength - 1), 251 parentDlg = dlgsLength > 1 ? dlgs.eq(dlgsLength - 2) : null, 252 dlgWidget = rootWindow.PF(dlg.data('widget')),
253 sourceWidgetVar = dlgWidget.cfg.sourceWidgetVar, 254 sourceComponentId = dlgWidget.cfg.sourceComponentId, 255 dialogReturnBehavior = null, 256 windowContext = null; 257 258 dlg.attr('data-queuedforremoval', true); 259 260 if(parentDlg) { 261 var parentDlgFrame = parentDlg.find('> .ui-dialog-content > iframe').get(0), 262 windowContext = parentDlgFrame.contentWindow||parentDlgFrame; 263 sourceWidget = windowContext.PF(sourceWidgetVar); 264 } 265 else { 266 // We have to resolve the frames from the root window to the source widget to invoke the dialog return behavior 267 // Each source frame element is a selector. We step into every nested frame until we are in the source widget frame. 268 windowContext = rootWindow; 269 var frames = dlgWidget.cfg.sourceFrames; 270 for (var i = 0; i < frames.length; i++) { 271 windowContext = $(windowContext.document).find(frames[i]).get(0).contentWindow; 272 } 273 } 274 275 if(sourceWidgetVar) { 276 var sourceWidget = windowContext.PF(sourceWidgetVar); 277 dialogReturnBehavior = sourceWidget.cfg.behaviors ? sourceWidget.cfg.behaviors['dialogReturn']: null; 278 } 279 else if(sourceComponentId) { 280 var dialogReturnBehaviorStr = $(windowContext.document.getElementById(sourceComponentId)).data('dialogreturn'); 281 if(dialogReturnBehaviorStr) { 282 dialogReturnBehavior = windowContext.eval('(function(ext){this.' + dialogReturnBehaviorStr + '})'); 283 } 284 } 285 286 if(dialogReturnBehavior) { 287 var ext = { 288 params: [ 289 {name: sourceComponentId + '_pfdlgcid', value: cfg.pfdlgcid} 290 ] 291 }; 292 293 dialogReturnBehavior.call(windowContext, ext); 294 } 295 296 dlgWidget.hide(); 297 }, 298 299 showMessageInDialog: function(msg) { 300 if(!this.messageDialog) { 301 var messageDialogDOM = $('<div id="primefacesmessagedlg" class="ui-message-dialog ui-dialog ui-widget ui-widget-content ui-corner-all ui-shadow ui-hidden-container"></div>') 302 .append('<div class="ui-dialog-titlebar ui-widget-header ui-helper-clearfix ui-corner-top"><span class="ui-dialog-title"></span>' + 303 '<a class="ui-dialog-titlebar-icon ui-dialog-titlebar-close ui-corner-all" href="#" role="button"><span class="ui-icon ui-icon-closethick"></span></a></div>' + 304 '<div class="ui-dialog-content ui-widget-content" style="height: auto;"></div>') 305 .appendTo(document.body); 306 307 PrimeFaces.cw('Dialog', 'primefacesmessagedialog', { 308 id: 'primefacesmessagedlg', 309 modal:true, 310 draggable: false, 311 resizable: false, 312 showEffect: 'fade', 313 hideEffect: 'fade' 314 }); 315 this.messageDialog = PF('primefacesmessagedialog'); 316 this.messageDialog.titleContainer = this.messageDialog.titlebar.children('span.ui-dialog-title'); 317 } 318 319 var escape = msg.escape !== false; 320 var summaryHtml = msg.summary ? msg.summary.split(/\r\n|\n|\r/g).map(function(line) { return escape ? PrimeFaces.escapeHTML(line) : line; }).join("<br>") : ""; 321 this.messageDialog.titleContainer.html(summaryHtml); 322 323 var detailHtml = msg.detail ? msg.detail.split(/\r\n|\n|\r/g).map(function(line) { return escape ? PrimeFaces.escapeHTML(line) : line; }).join("<br>") : ""; 324 this.messageDialog.content.html('').append('<span class="ui-dialog-message ui-messages-' + msg.severity.split(' ')[0].toLowerCase() + '-icon"></span>').append(detailHtml); 325 this.messageDialog.show(); 326 }, 327 328 confirm: function(msg) { 329 if(PrimeFaces.confirmDialog) { 330 PrimeFaces.confirmSource = (typeof(msg.source) === 'string') ? $(PrimeFaces.escapeClientId(msg.source)) : $(msg.source); 331 PrimeFaces.confirmDialog.showMessage(msg); 332 } 333 else { 334 PrimeFaces.warn('No global confirmation dialog available.'); 335 } 336 }, 337 338 findRootWindow: function() { 339 // Note that the determination of the sourceFrames is tightly coupled to the same traversing logic, so keep both in sync 340 var w = window; 341 while(w.frameElement) { 342 var parent = w.parent; 343 if (parent.PF === undefined) { 344 break; 345 } 346 w = parent; 347 }; 348 349 return w; 350 } 351 }; 352} 353 354 /** 355 * PrimeFaces Accordion Panel Widget 356 */ 357PrimeFaces.widget.AccordionPanel = PrimeFaces.widget.BaseWidget.extend({ 358 359 init: function(cfg) { 360 this._super(cfg); 361 362 this.stateHolder = $(this.jqId + '_active'); 363 this.headers = this.jq.children('.ui-accordion-header'); 364 this.panels = this.jq.children('.ui-accordion-content'); 365 this.cfg.rtl = this.jq.hasClass('ui-accordion-rtl'); 366 this.cfg.expandedIcon = 'ui-icon-triangle-1-s'; 367 this.cfg.collapsedIcon = this.cfg.rtl ? 'ui-icon-triangle-1-w' : 'ui-icon-triangle-1-e'; 368 369 this.initActive(); 370 this.bindEvents(); 371
372 if(this.cfg.dynamic && this.cfg.cache) { 373 this.markLoadedPanels(); 374 } 375 }, 376 377 initActive: function() { 378 if(this.cfg.multiple) { 379 this.cfg.active = []; 380 381 if (this.stateHolder.val().length > 0) { 382 var indexes = this.stateHolder.val().split(','); 383 for(var i = 0; i < indexes.length; i++) { 384 this.cfg.active.push(parseInt(indexes[i])); 385 } 386 } 387 } 388 else { 389 this.cfg.active = parseInt(this.stateHolder.val()); 390 } 391 }, 392 393 bindEvents: function() { 394 var $this = this; 395 396 this.headers.mouseover(function() { 397 var element = $(this); 398 if(!element.hasClass('ui-state-active')&&!element.hasClass('ui-state-disabled')) { 399 element.addClass('ui-state-hover'); 400 } 401 }).mouseout(function() { 402 var element = $(this); 403 if(!element.hasClass('ui-state-active')&&!element.hasClass('ui-state-disabled')) { 404 element.removeClass('ui-state-hover'); 405 } 406 }).click(function(e) { 407 var element = $(this); 408 if(!element.hasClass('ui-state-disabled')) { 409 var tabIndex = $this.headers.index(element); 410 411 if(element.hasClass('ui-state-active')) { 412 $this.unselect(tabIndex); 413 } 414 else { 415 $this.select(tabIndex); 416 $(this).trigger('focus.accordion'); 417 } 418 } 419 420 e.preventDefault(); 421 }); 422 423 this.bindKeyEvents(); 424 }, 425 426 bindKeyEvents: function() { 427 this.headers.on('focus.accordion', function(){ 428 $(this).addClass('ui-tabs-outline'); 429 }) 430 .on('blur.accordion', function(){ 431 $(this).removeClass('ui-tabs-outline'); 432 }) 433 .on('keydown.accordion', function(e) { 434 var keyCode = $.ui.keyCode, 435 key = e.which; 436 437 if(key === keyCode.SPACE || key === keyCode.ENTER) { 438 $(this).trigger('click'); 439 e.preventDefault(); 440 } 441 }); 442 }, 443 444 markLoadedPanels: function() { 445 if(this.cfg.multiple) { 446 for(var i = 0; i < this.cfg.active.length; i++) { 447 if(this.cfg.active[i] >= 0) 448 this.markAsLoaded(this.panels.eq(this.cfg.active[i])); 449 } 450 } else { 451 if(this.cfg.active >= 0) 452 this.markAsLoaded(this.panels.eq(this.cfg.active)); 453 } 454 }, 455 456 /** 457 * Activates a tab with given index 458 */ 459 select: function(index) { 460 var panel = this.panels.eq(index); 461 462 //Call user onTabChange callback 463 if(this.cfg.onTabChange) { 464 var result = this.cfg.onTabChange.call(this, panel); 465 if(result === false) 466 return false; 467 } 468 469 var shouldLoad = this.cfg.dynamic && !this.isLoaded(panel); 470 471 //update state 472 if(this.cfg.multiple) 473 this.addToSelection(index); 474 else 475 this.cfg.active = index; 476 477 this.saveState(); 478 479 if(shouldLoad) { 480 this.loadDynamicTab(panel); 481 } 482 else { 483 if(this.cfg.controlled) { 484 this.fireTabChangeEvent(panel); 485 } 486 else { 487 this.show(panel); 488 489 this.fireTabChangeEvent(panel); 490 } 491 492 } 493 494 return true; 495 }, 496 497 /** 498 * Deactivates a tab with given index 499 */ 500 unselect: function(index) { 501 if(this.cfg.controlled) { 502 this.fireTabCloseEvent(index); 503 } 504 else { 505 this.hide(index); 506 507 this.fireTabCloseEvent(index); 508 } 509 }, 510 511 show: function(panel) { 512 var _self = this; 513 514 //deactivate current 515 if(!this.cfg.multiple) { 516 var oldHeader = this.headers.filter('.ui-state-active'); 517 oldHeader.children('.ui-icon').removeClass(this.cfg.expandedIcon).addClass(this.cfg.collapsedIcon); 518 oldHeader.attr('aria-selected', false); 519 oldHeader.attr('aria-expanded', false).removeClass('ui-state-active ui-corner-top').addClass('ui-corner-all')
520 .next().attr('aria-hidden', true).slideUp(function(){ 521 if(_self.cfg.onTabClose) 522 _self.cfg.onTabClose.call(_self, panel); 523 }); 524 } 525 526 //activate selected 527 var newHeader = panel.prev(); 528 newHeader.attr('aria-selected', true); 529 newHeader.attr('aria-expanded', true).addClass('ui-state-active ui-corner-top').removeClass('ui-state-hover ui-corner-all') 530 .children('.ui-icon').removeClass(this.cfg.collapsedIcon).addClass(this.cfg.expandedIcon); 531 532 panel.attr('aria-hidden', false).slideDown('normal', function() { 533 _self.postTabShow(panel); 534 }); 535 }, 536 537 hide: function(index) { 538 var _self = this, 539 panel = this.panels.eq(index), 540 header = panel.prev(); 541 542 header.attr('aria-selected', false); 543 header.attr('aria-expanded', false).children('.ui-icon').removeClass(this.cfg.expandedIcon).addClass(this.cfg.collapsedIcon); 544 header.removeClass('ui-state-active ui-corner-top').addClass('ui-corner-all'); 545 panel.attr('aria-hidden', true).slideUp(function(){ 546 if(_self.cfg.onTabClose) 547 _self.cfg.onTabClose.call(_self, panel); 548 }); 549 550 this.removeFromSelection(index); 551 this.saveState(); 552 }, 553 554 loadDynamicTab: function(panel) { 555 var $this = this, 556 options = { 557 source: this.id, 558 process: this.id, 559 update: this.id, 560 params: [ 561 {name: this.id + '_contentLoad', value: true}, 562 {name: this.id + '_newTab', value: panel.attr('id')}, 563 {name: this.id + '_tabindex', value: parseInt(panel.index() / 2)} 564 ], 565 onsuccess: function(responseXML, status, xhr) { 566 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 567 widget: $this, 568 handle: function(content) { 569 panel.html(content); 570 571 if(this.cfg.cache) { 572 this.markAsLoaded(panel); 573 } 574 } 575 }); 576 577 return true; 578 }, 579 oncomplete: function() { 580 $this.show(panel); 581 } 582 }; 583 584 if(this.hasBehavior('tabChange')) { 585 this.callBehavior('tabChange', options); 586 } 587 else { 588 PrimeFaces.ajax.Request.handle(options); 589 } 590 }, 591 592 fireTabChangeEvent : function(panel) { 593 if(this.hasBehavior('tabChange')) { 594 var ext = { 595 params: [ 596 {name: this.id + '_newTab', value: panel.attr('id')}, 597 {name: this.id + '_tabindex', value: parseInt(panel.index() / 2)} 598 ] 599 }; 600 601 if(this.cfg.controlled) { 602 var $this = this; 603 ext.oncomplete = function(xhr, status, args, data) { 604 if(args.access && !args.validationFailed) { 605 $this.show(panel); 606 } 607 }; 608 } 609 610 this.callBehavior('tabChange', ext); 611 } 612 }, 613 614 fireTabCloseEvent : function(index) { 615 if(this.hasBehavior('tabClose')) { 616 var panel = this.panels.eq(index), 617 ext = { 618 params: [ 619 {name: this.id + '_tabId', value: panel.attr('id')}, 620 {name: this.id + '_tabindex', value: parseInt(index)} 621 ] 622 }; 623 624 if(this.cfg.controlled) { 625 var $this = this; 626 ext.oncomplete = function(xhr, status, args, data) { 627 if(args.access && !args.validationFailed) { 628 $this.hide(index); 629 } 630 }; 631 } 632 633 this.callBehavior('tabClose', ext); 634 } 635 }, 636 637 markAsLoaded: function(panel) { 638 panel.data('loaded', true); 639 }, 640 641 isLoaded: function(panel) { 642 return panel.data('loaded') == true; 643 }, 644 645 addToSelection: function(nodeId) { 646 this.cfg.active.push(nodeId); 647 }, 648 649 removeFromSelection: function(nodeId) { 650 this.cfg.active = $.grep(this.cfg.active, function(r) { 651 return r != nodeId; 652 }); 653 }, 654 655 saveState: function() { 656 if(this.cfg.multiple) 657 this.stateHolder.val(this.cfg.active.join(',')); 658 else 659 this.stateHolder.val(this.cfg.active); 660 }, 661 662 postTabShow: function(newPanel) { 663 //Call user onTabShow callback 664 if(this.cfg.onTabShow) { 665 this.cfg.onTabShow.call(this, newPanel); 666 } 667 668 PrimeFaces.invokeDeferredRenders(this.id); 669 } 670 671}); 672 673/** 674 * PrimeFaces AutoComplete Widget 675 */ 676PrimeFaces.widget.AutoComplete = PrimeFaces.widget.BaseWidget.extend({ 677 678 init: function(cfg) { 679 this._super(cfg); 680 681 this.panelId = this.jqId + '_panel'; 682 this.input = $(this.jqId + '_input'); 683 this.hinput = $(this.jqId + '_hinput'); 684 this.panel = this.jq.children(this.panelId); 685 this.dropdown = this.jq.children('.ui-button'); 686 this.active = true; 687 this.cfg.pojo = this.hinput.length == 1; 688 this.cfg.minLength = this.cfg.minLength != undefined ? this.cfg.minLength : 1;
689 this.cfg.cache = this.cfg.cache||false; 690 this.cfg.resultsMessage = this.cfg.resultsMessage||' results are available, use up and down arrow keys to navigate'; 691 this.cfg.ariaEmptyMessage = this.cfg.emptyMessage||'No search results are available.'; 692 this.cfg.dropdownMode = this.cfg.dropdownMode||'blank'; 693 this.cfg.autoHighlight = (this.cfg.autoHighlight === undefined) ? true : this.cfg.autoHighlight; 694 this.cfg.myPos = this.cfg.myPos||'left top'; 695 this.cfg.atPos = this.cfg.atPos||'left bottom'; 696 this.cfg.active = (this.cfg.active === false) ? false : true; 697 this.cfg.dynamic = this.cfg.dynamic === true ? true : false; 698 this.cfg.autoSelection = this.cfg.autoSelection === false ? false : true; 699 this.cfg.escape = this.cfg.escape === false ? false : true; 700 this.suppressInput = true; 701 this.touchToDropdownButton = false; 702 this.isTabPressed = false; 703 this.isDynamicLoaded = false; 704 this.currentInputValue = ''; 705 706 this.cfg.onChange = this.input.prop('onchange'); 707 this.input.prop('onchange', null).off('change'); 708 709 if(this.cfg.cache) { 710 this.initCache(); 711 } 712 713 if (this.cfg.queryMode !== 'server') { 714 this.fetchItems(); 715 } 716 717 //pfs metadata 718 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 719 this.hinput.data(PrimeFaces.CLIENT_ID_DATA, this.id); 720 721 this.placeholder = this.input.attr('placeholder'); 722 723 if(this.cfg.multiple) { 724 this.setupMultipleMode(); 725 726 this.multiItemContainer.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 727 728 if(this.cfg.selectLimit >= 0 && this.multiItemContainer.children('li.ui-autocomplete-token').length === this.cfg.selectLimit) { 729 this.input.hide(); 730 this.disableDropdown(); 731 } 732 } 733 else { 734 //visuals 735 PrimeFaces.skinInput(this.input); 736 737 this.input.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 738 this.dropdown.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 739 } 740 741 //core events 742 this.bindStaticEvents(); 743 744 //client Behaviors 745 if(this.cfg.behaviors) { 746 PrimeFaces.attachBehaviors(this.input, this.cfg.behaviors); 747 } 748 749 //force selection 750 if(this.cfg.forceSelection) { 751 this.setupForceSelection(); 752 } 753 754 //Panel management 755 if(this.panel.length) { 756 this.appendPanel(); 757 } 758 759 //itemtip 760 if(this.cfg.itemtip) { 761 this.itemtip = $('<div id="' + this.id + '_itemtip" class="ui-autocomplete-itemtip ui-state-highlight ui-widget ui-corner-all ui-shadow"></div>').appendTo(document.body); 762 this.cfg.itemtipMyPosition = this.cfg.itemtipMyPosition||'left top'; 763 this.cfg.itemtipAtPosition = this.cfg.itemtipAtPosition||'right bottom'; 764 this.cfg.checkForScrollbar = (this.cfg.itemtipAtPosition.indexOf('right') !== -1); 765 } 766 767 //aria 768 this.input.attr('aria-autocomplete', 'list'); 769 this.jq.attr('role', 'application'); 770 this.jq.append('<span role="status" aria-live="polite" class="ui-autocomplete-status ui-helper-hidden-accessible"></span>'); 771 this.status = this.jq.children('.ui-autocomplete-status'); 772 }, 773 774 //@override 775 refresh: function(cfg) { 776 this._super(cfg); 777 }, 778 779 appendPanel: function() { 780 PrimeFaces.utils.registerDynamicOverlay(this, this.panel, this.id + '_panel'); 781 }, 782 783 initCache: function() { 784 this.cache = {}; 785 var $this=this; 786 787 this.cacheTimeout = setInterval(function(){ 788 $this.clearCache(); 789 }
789, this.cfg.cacheTimeout); 790 }, 791 792 clearCache: function() { 793 this.cache = {}; 794 }, 795 796 /** 797 * Binds events for multiple selection mode 798 */ 799 setupMultipleMode: function() { 800 var $this = this; 801 this.multiItemContainer = this.jq.children('ul'); 802 this.inputContainer = this.multiItemContainer.children('.ui-autocomplete-input-token'); 803 804 this.multiItemContainer.hover(function() { 805 $(this).addClass('ui-state-hover'); 806 }, 807 function() { 808 $(this).removeClass('ui-state-hover'); 809 } 810 ).click(function() { 811 $this.input.focus(); 812 }); 813 814 //delegate events to container 815 this.input.focus(function() { 816 $this.multiItemContainer.addClass('ui-state-focus'); 817 }).blur(function(e) { 818 $this.multiItemContainer.removeClass('ui-state-focus'); 819 }); 820 821 var closeSelector = '> li.ui-autocomplete-token > .ui-autocomplete-token-icon'; 822 this.multiItemContainer.off('click', closeSelector).on('click', closeSelector, null, function(event) { 823 if($this.multiItemContainer.children('li.ui-autocomplete-token').length === $this.cfg.selectLimit) { 824 $this.input.css('display', 'inline'); 825 $this.enableDropdown(); 826 } 827 $this.removeItem(event, $(this).parent()); 828 }); 829 }, 830 831 bindStaticEvents: function() { 832 var $this = this; 833 834 this.bindKeyEvents(); 835 836 this.bindDropdownEvents(); 837 838 if(PrimeFaces.env.browser.mobile) { 839 this.dropdown.bind('touchstart', function() { 840 $this.touchToDropdownButton = true; 841 }); 842 } 843 844 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.panel, 845 function() { return $this.itemtip; }, 846 function(e, eventTarget) { 847 if(!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { 848 $this.hide(); 849 } 850 }); 851 852 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { 853 $this.alignPanel(); 854 }); 855 }, 856 857 bindDropdownEvents: function() { 858 var $this = this; 859 860 PrimeFaces.skinButton(this.dropdown); 861 862 this.dropdown.mouseup(function() { 863 if($this.active) { 864 $this.searchWithDropdown(); 865 $this.input.focus(); 866 } 867 }).keyup(function(e) { 868 var keyCode = $.ui.keyCode, 869 key = e.which; 870 871 if(key === keyCode.SPACE || key === keyCode.ENTER) { 872 $this.searchWithDropdown(); 873 $this.input.focus(); 874 e.preventDefault(); 875 e.stopPropagation(); 876 } 877 }); 878 }, 879 880 disableDropdown: function() { 881 if(this.dropdown.length) { 882 this.dropdown.off().prop('disabled', true).addClass('ui-state-disabled'); 883 } 884 }, 885 886 enableDropdown: function() { 887 if(this.dropdown.length && this.dropdown.prop('disabled')) { 888 this.bindDropdownEvents(); 889 this.dropdown.prop('disabled', false).removeClass('ui-state-disabled'); 890 } 891 }, 892 893 bindKeyEvents: function() { 894 var $this = this; 895 896 if(this.cfg.queryEvent !== 'enter') { 897 this.input.on('input propertychange', function(e) { 898 $this.processKeyEvent(e); 899 }); 900 } 901 902 this.input.on('keyup.autoComplete', function(e) { 903 var keyCode = $.ui.keyCode, 904 key = e.which; 905 906 if(PrimeFaces.env.isIE(9) && (key === keyCode.BACKSPACE || key === keyCode.DELETE)) { 907 $this.processKeyEvent(e); 908 } 909 910 if($this.cfg.queryEvent === 'enter' && (key === keyCode.ENTER)) { 911 if($this.itemSelectedWithEnter) 912 $this.itemSelectedWithEnter = false; 913 else 914 $this.search($this.input.val()); 915 } 916 917 if($this.panel.is(':visible')) { 918 if(key === keyCode.ESCAPE) { 919 $this.hide(); 920 } 921 else if(key === keyCode.UP || key === keyCode.DOWN) { 922 var highlightedItem = $this.items.filter('.ui-state-highlight'); 923 if(highlightedItem.length) { 924 $this.displayAriaStatus(highlightedItem.data('item-label')); 925 } 926 } 927 } 928 929 $this.checkMatchedItem = true; 930 $this.isTabPressed = false;
931 932 }).on('keydown.autoComplete', function(e) { 933 var keyCode = $.ui.keyCode; 934 935 $this.suppressInput = false; 936 if($this.panel.is(':visible')) { 937 var highlightedItem = $this.items.filter('.ui-state-highlight'); 938 939 switch(e.which) { 940 case keyCode.UP: 941 var prev = highlightedItem.length == 0 ? $this.items.eq(0) : highlightedItem.prevAll('.ui-autocomplete-item:first'); 942 943 if(prev.length == 1) { 944 highlightedItem.removeClass('ui-state-highlight'); 945 prev.addClass('ui-state-highlight'); 946 947 if($this.cfg.scrollHeight) { 948 PrimeFaces.scrollInView($this.panel, prev); 949 } 950 951 if($this.cfg.itemtip) { 952 $this.showItemtip(prev); 953 } 954 } 955 956 e.preventDefault(); 957 break; 958 959 case keyCode.DOWN: 960 var next = highlightedItem.length == 0 ? $this.items.eq(0) : highlightedItem.nextAll('.ui-autocomplete-item:first'); 961 962 if(next.length == 1) { 963 highlightedItem.removeClass('ui-state-highlight'); 964 next.addClass('ui-state-highlight'); 965 966 if($this.cfg.scrollHeight) { 967 PrimeFaces.scrollInView($this.panel, next); 968 } 969 970 if($this.cfg.itemtip) { 971 $this.showItemtip(next); 972 } 973 } 974 975 e.preventDefault(); 976 break; 977 978 case keyCode.ENTER: 979 if ($this.timeout) { 980 $this.deleteTimeout(); 981 } 982 983 if (highlightedItem.length > 0) { 984 $this.preventInputChangeEvent = true; 985 highlightedItem.trigger('click'); 986 $this.itemSelectedWithEnter = true; 987 } 988 989 e.preventDefault(); 990 e.stopPropagation(); 991 992 break; 993 994 case 18: //keyCode.ALT: 995 case 224: 996 break; 997 998 case keyCode.TAB: 999 if(highlightedItem.length && $this.cfg.autoSelection) { 1000 highlightedItem.trigger('click'); 1001 } else { 1002 $this.hide(); 1003 if ($this.timeout) { 1004 $this.deleteTimeout(); 1005 } 1006 } 1007 $this.isTabPressed = true; 1008 break; 1009 } 1010 } 1011 else { 1012 switch(e.which) { 1013 case keyCode.TAB: 1014 if ($this.timeout) { 1015 $this.deleteTimeout(); 1016 } 1017 $this.isTabPressed = true; 1018 break; 1019 1020 case keyCode.ENTER: 1021 if($this.cfg.queryEvent === 'enter' || ($this.timeout > 0) || $this.querying) { 1022 e.preventDefault(); 1023 } 1024 1025 if($this.cfg.queryEvent !== 'enter') { 1026 $this.isValid($(this).val()); 1027 } 1028 break; 1029 1030 case keyCode.BACKSPACE: 1031 if ($this.cfg.multiple && !$this.input.val().length) { 1032 $this.removeItem(e, $(this).parent().prev()); 1033 1034 e.preventDefault(); 1035 } 1036 break; 1037 }; 1038 } 1039 1040 }).on('paste.autoComplete', function() { 1041 $this.suppressInput = false;
1042 $this.checkMatchedItem = true; 1043 }).on('change.autoComplete', function(e) { 1044 var value = e.currentTarget.value, 1045 valid = $this.isValid(value); 1046 1047 if ($this.cfg.forceSelection && $this.currentInputValue === '' && !valid) { 1048 $this.preventInputChangeEvent = true; 1049 } 1050 1051 if ($this.cfg.onChange && !$this.preventInputChangeEvent) { 1052 $this.cfg.onChange.call(this); 1053 } 1054 1055 $this.currentInputValue = $this.cfg.forceSelection && !valid ? '' : value; 1056 $this.preventInputChangeEvent = false; 1057 }); 1058 }, 1059 1060 bindDynamicEvents: function() { 1061 var $this = this; 1062 1063 //visuals and click handler for items 1064 this.items.on('mouseover', function() { 1065 var item = $(this); 1066 1067 if(!item.hasClass('ui-state-highlight')) { 1068 $this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); 1069 item.addClass('ui-state-highlight'); 1070 1071 if($this.cfg.itemtip) { 1072 $this.showItemtip(item); 1073 } 1074 } 1075 }) 1076 .on('click', function(event) { 1077 var item = $(this), 1078 isMoreText = item.hasClass('ui-autocomplete-moretext'); 1079 1080 if(isMoreText) { 1081 $this.input.focus(); 1082 $this.invokeMoreTextBehavior(); 1083 } 1084 else { 1085 var itemValue = item.attr('data-item-value'); 1086 1087 if($this.cfg.multiple) { 1088 var found = false; 1089 if($this.cfg.unique) { 1090 found = $this.multiItemContainer.children("li[data-token-value='" + $.escapeSelector(itemValue) + "']").length != 0; 1091 } 1092 1093 if(!found) { 1094 var itemStyleClass = item.attr('data-item-class'); 1095 var itemDisplayMarkup = '<li data-token-value="' + PrimeFaces.escapeHTML(itemValue); 1096 itemDisplayMarkup += '"class="ui-autocomplete-token ui-state-active ui-corner-all ui-helper-hidden'; 1097 itemDisplayMarkup += (itemStyleClass === '' ? '' : ' '+itemStyleClass) + '">'; 1098 itemDisplayMarkup += '<span class="ui-autocomplete-token-icon ui-icon ui-icon-close"></span>'; 1099 itemDisplayMarkup += '<span class="ui-autocomplete-token-label">' + PrimeFaces.escapeHTML(item.attr('data-item-label')) + '</span></li>'; 1100 1101 $this.inputContainer.before(itemDisplayMarkup); 1102 $this.multiItemContainer.children('.ui-helper-hidden').fadeIn(); 1103 $this.input.val(''); 1104 $this.input.removeAttr('placeholder'); 1105 1106 $this.hinput.append('<option value="' + PrimeFaces.escapeHTML(itemValue) + '" selected="selected"></option>'); 1107 if($this.multiItemContainer.children('li.ui-autocomplete-token').length >= $this.cfg.selectLimit) { 1108 $this.input.css('display', 'none').blur(); 1109 $this.disableDropdown(); 1110 } 1111 1112 $this.invokeItemSelectBehavior(event, itemValue); 1113 } 1114 } 1115 else { 1116 $this.input.val(item.attr('data-item-label')); 1117 1118 this.currentText = $this.input.val(); 1119 this.previousText = $this.input.val(); 1120 1121 if($this.cfg.pojo) { 1122 $this.hinput.val(itemValue); 1123 } 1124 1125 if(PrimeFaces.env.isLtIE(10)) { 1126 var length = $this.input.val().length; 1127 $this.input.setSelection(length,length); 1128 } 1129 1130 $this.invokeItemSelectBehavior(event, itemValue); 1131 } 1132 1133 if ($this.cfg.onChange) { 1134 $this.cfg.onChange.call(this); 1135 } 1136 1137 if (!$this.isTabPressed) { 1138 $this.input.focus(); 1139 } 1140 } 1141 1142 $this.hide(); 1143 }) 1144 .on('mousedown', function() { 1145 $this.preventInputChangeEvent = true; 1146 $this.checkMatchedItem = false;
1147 }); 1148 1149 if(PrimeFaces.env.browser.mobile) { 1150 this.items.bind('touchstart', function() { 1151 if(!$this.touchToDropdownButton) { 1152 $this.itemClick = true; 1153 } 1154 }); 1155 } 1156 }, 1157 1158 processKeyEvent: function(e) { 1159 var $this = this; 1160 1161 if($this.suppressInput) { 1162 e.preventDefault(); 1163 return; 1164 } 1165 1166 // for touch event on mobile 1167 if(PrimeFaces.env.browser.mobile) { 1168 $this.touchToDropdownButton = false; 1169 if($this.itemClick) { 1170 $this.itemClick = false; 1171 return; 1172 } 1173 } 1174 1175 var value = $this.input.val(); 1176 1177 if($this.cfg.pojo && !$this.cfg.multiple) { 1178 $this.hinput.val(value); 1179 } 1180 1181 if(!value.length) { 1182 $this.hide(); 1183 $this.deleteTimeout(); 1184 } 1185 1186 if(value.length >= $this.cfg.minLength) { 1187 if($this.timeout) { 1188 $this.deleteTimeout(); 1189 } 1190 1191 var delay = $this.cfg.delay; 1192 $this.timeout = setTimeout(function() { 1193 $this.timeout = null; 1194 $this.search(value); 1195 }, delay); 1196 } 1197 else if(value.length === 0) { 1198 if($this.timeout) { 1199 $this.deleteTimeout(); 1200 } 1201 $this.fireClearEvent(); 1202 } 1203 }, 1204 1205 showItemtip: function(item) { 1206 if(item.hasClass('ui-autocomplete-moretext')) { 1207 this.itemtip.hide(); 1208 } 1209 else { 1210 var content; 1211 if(item.is('li')) { 1212 content = item.next('.ui-autocomplete-itemtip-content'); 1213 } else { 1214 if(item.children('td:last').hasClass('ui-autocomplete-itemtip-content')) { 1215 content = item.children('td:last'); 1216 } else { 1217 this.itemtip.hide(); 1218 return; 1219 } 1220 } 1221 1222 this.itemtip.html(content.html()) 1223 .css({ 1224 'left':'', 1225 'top':'', 1226 'z-index': ++PrimeFaces.zindex, 1227 'width': content.outerWidth() 1228 }) 1229 .position({ 1230 my: this.cfg.itemtipMyPosition 1231 ,at: this.cfg.itemtipAtPosition 1232 ,of: item 1233 }); 1234 1235 //scrollbar offset 1236 if(this.cfg.checkForScrollbar) { 1237 if(this.panel.innerHeight() < this.panel.children('.ui-autocomplete-items').outerHeight(true)) { 1238 var panelOffset = this.panel.offset(); 1239 this.itemtip.css('left', panelOffset.left + this.panel.outerWidth()); 1240 } 1241 } 1242 1243 this.itemtip.show(); 1244 } 1245 }, 1246 1247 showSuggestions: function(query) { 1248 this.items = this.panel.find('.ui-autocomplete-item'); 1249 this.items.attr('role', 'option'); 1250 1251 if(this.cfg.grouping) { 1252 this.groupItems(); 1253 } 1254 1255 this.bindDynamicEvents(); 1256 1257 var $this=this, 1258 hidden = this.panel.is(':hidden'); 1259 1260 if(hidden) { 1261 this.show(); 1262 } 1263 else { 1264 this.alignPanel(); 1265 } 1266 1267 if(this.items.length > 0) { 1268 var firstItem = this.items.eq(0); 1269 1270 //highlight first item 1271 if(this.cfg.autoHighlight && firstItem.length) { 1272 firstItem.addClass('ui-state-highlight'); 1273 } 1274 1275 //highlight query string 1276 if(this.panel.children().is('ul') && query.length > 0) { 1277 this.items.filter(':not(.ui-autocomplete-moretext)').each(function() { 1278 var item = $(this); 1279 var text = $this.cfg.escape ? item.html() : item.text(); 1280 var re = new RegExp(PrimeFaces.escapeRegExp(query), 'gi'), 1281 highlighedText = text.replace(re, '<span class="ui-autocomplete-query">$&</span>'); 1282 1283 item.html(highlighedText); 1284 }); 1285 } 1286 1287 if(this.cfg.forceSelection) { 1288 this.currentItems = []; 1289 this.items.each(function(i, item) { 1290 $this.currentItems.push($(item).attr('data-item-label')); 1291 }); 1292 } 1293 1294 //show itemtip if defined 1295 if(this.cfg.autoHighlight && this.cfg.itemtip && firstItem.length === 1) { 1296 this.showItemtip(firstItem); 1297 } 1298 1299 this.displayAriaStatus(this.items.length + this.cfg.resultsMessage); 1300 } 1301 else { 1302 if(this.cfg.emptyMessage) { 1303 var emptyText = '<div class="ui-autocomplete-emptyMessage ui-widget">' + PrimeFaces.escapeHTML(this.cfg.emptyMessage) + '</div>'; 1304 this.panel.html(emptyText); 1305 } 1306 else { 1307 this.panel.hide(); 1308 } 1309 1310 this.displayAriaStatus(this.cfg.ariaEmptyMessage); 1311 } 1312 }, 1313 1314 searchWithDropdown: function() { 1315 this.isSearchWithDropdown = true; 1316 1317 if(this.cfg.dropdownMode === 'current') 1318 this.search(this.input.val()); 1319 else 1320 this.search(''); 1321 }, 1322 1323 search: function(query) { 1324 //allow empty string but not undefined or null 1325 if (!this.cfg.active || query === undefined || query === null) { 1326 return; 1327 } 1328
1329 if (this.cfg.cache && !(this.cfg.dynamic && !this.isDynamicLoaded)) { 1330 if (this.cache[query]) { 1331 this.panel.html(this.cache[query]); 1332 this.showSuggestions(query); 1333 return; 1334 } 1335 else if (this.cfg.queryMode === 'client') { 1336 if (this.isSearchWithDropdown) { 1337 var suggestions = this.wrapperStartTag, 1338 re = new RegExp(this.wrapperStartTag + '|' + this.wrapperEndTag, 'g'); 1339 Object.entries(this.cache).map(function(item) { 1340 suggestions += item[1].replace(re, ''); 1341 }); 1342 suggestions += this.wrapperEndTag; 1343 1344 this.panel.html(suggestions); 1345 1346 this.isSearchWithDropdown = false; 1347 } 1348 else { 1349 this.panel.empty(); 1350 } 1351 1352 this.showSuggestions(query); 1353 return; 1354 } 1355 } 1356 1357 if (!this.active) { 1358 return; 1359 } 1360 1361 this.querying = true; 1362 1363 var $this = this; 1364 1365 if (this.cfg.itemtip) { 1366 this.itemtip.hide(); 1367 } 1368 1369 var options = { 1370 source: this.id, 1371 process: this.id, 1372 update: this.id, 1373 formId: this.cfg.formId, 1374 onsuccess: function(responseXML, status, xhr) { 1375 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 1376 widget: $this, 1377 handle: function(content) { 1378 if(this.cfg.dynamic && !this.isDynamicLoaded) { 1379 this.panel = $(content); 1380 this.appendPanel(); 1381 content = this.panel.get(0).innerHTML; 1382 } 1383 else { 1384 this.panel.html(content); 1385 } 1386 1387 if (this.cfg.cache) { 1388 if (this.cfg.queryMode !== 'server' && !this.isDynamicLoaded && this.cache[query]) { 1389 this.panel.html(this.cache[query]); 1390 } 1391 else { 1392 this.cache[query] = content; 1393 } 1394 } 1395 1396 this.showSuggestions(query); 1397 } 1398 }); 1399 1400 return true; 1401 }, 1402 oncomplete: function() { 1403 $this.querying = false; 1404 $this.isDynamicLoaded = true; 1405 } 1406 }; 1407 1408 options.params = [ 1409 {name: this.id + '_query', value: query} 1410 ]; 1411 1412 if (this.cfg.queryMode === 'hybrid') { 1413 options.params.push({name: this.id + '_clientCache', value: true}); 1414 } 1415 1416 if (this.cfg.dynamic && !this.isDynamicLoaded) { 1417 options.params.push({name: this.id + '_dynamicload', value: true}); 1418 } 1419 1420 if (this.hasBehavior('query')) { 1421 this.callBehavior('query', options); 1422 } 1423 else { 1424 PrimeFaces.ajax.Request.handle(options); 1425 } 1426 }, 1427 1428 show: function() { 1429 this.alignPanel(); 1430 1431 if(this.cfg.effect) 1432 this.panel.show(this.cfg.effect, {}, this.cfg.effectDuration); 1433 else 1434 this.panel.show(); 1435 }, 1436 1437 hide: function() { 1438 this.panel.hide(); 1439 this.panel.css('height', 'auto'); 1440 1441 if(this.cfg.itemtip) { 1442 this.itemtip.hide(); 1443 } 1444 }, 1445 1446 invokeItemSelectBehavior: function(event, itemValue) { 1447 if(this.hasBehavior('itemSelect')) { 1448 var ext = { 1449 params : [ 1450 {name: this.id + '_itemSelect', value: itemValue} 1451 ] 1452 }; 1453 1454 this.callBehavior('itemSelect', ext); 1455 } 1456 }, 1457 1458 invokeItemUnselectBehavior: function(event, itemValue) { 1459 if(this.hasBehavior('itemUnselect')) { 1460 var ext = { 1461 params : [ 1462 {name: this.id + '_itemUnselect', value: itemValue} 1463 ] 1464 }; 1465 1466 this.callBehavior('itemUnselect', ext); 1467 } 1468 }, 1469 1470 invokeMoreTextBehavior: function() { 1471 if(this.hasBehavior('moreText')) { 1472 var ext = { 1473 params : [ 1474 {name: this.id + '_moreText', value: true} 1475 ] 1476 }; 1477 1478 this.callBehavior('moreText', ext); 1479 } 1480 }, 1481 1482 removeItem: function(event, item) { 1483 var itemValue = item.attr('data-token-value'), 1484 itemIndex = this.multiItemContainer.children('li.ui-autocomplete-token').index(item), 1485 $this = this; 1486 1487 //remove from options 1488 this.hinput.children('option').eq(itemIndex).remove(); 1489 1490 //remove from items 1491 item.fadeOut('fast', function() { 1492 var token = $(this); 1493 1494 token.remove(); 1495 1496 $this.invokeItemUnselectBehavior(event, itemValue); 1497 }); 1498 1499 // if empty return placeholder 1500 if (this.placeholder && this.hinput.children('option').length === 0) { 1501 this.input.attr('placeholder', this.placeholder); 1502 } 1503 }, 1504 1505 setupForceSelection: function() { 1506 this.currentItems = [this.input.val()]; 1507 var $this = this; 1508 1509 this.input.blur(function() { 1510 var value = $(this).val(), 1511 valid = $this.isValid(value); 1512 1513 if($this.cfg.autoSelection && valid && $this.checkMatchedItem && $this.items && !$this.isTabPressed && !$this.itemSelectedWithEnter) { 1514 var selectedItem = $this.items.filter('[data-item-label="' + $.escapeSelector(value) + '"]'); 1515 if (selectedItem.length) { 1516 selectedItem.click(); 1517 } 1518 } 1519 1520 $this.checkMatchedItem = false;
1521 }); 1522 }, 1523 1524 disable: function() { 1525 this.input.addClass('ui-state-disabled').prop('disabled', true); 1526 1527 if(this.dropdown.length) { 1528 this.dropdown.addClass('ui-state-disabled').prop('disabled', true); 1529 } 1530 }, 1531 1532 enable: function() { 1533 this.input.removeClass('ui-state-disabled').prop('disabled', false); 1534 1535 if(this.dropdown.length) { 1536 this.dropdown.removeClass('ui-state-disabled').prop('disabled', false); 1537 } 1538 }, 1539 1540 close: function() { 1541 this.hide(); 1542 }, 1543 1544 deactivate: function() { 1545 this.active = false; 1546 }, 1547 1548 activate: function() { 1549 this.active = true; 1550 }, 1551 1552 alignPanel: function() { 1553 var panelWidth = null; 1554 1555 if(this.cfg.multiple) { 1556 panelWidth = this.multiItemContainer.outerWidth(); 1557 } 1558 else { 1559 if(this.panel.is(':visible')) { 1560 panelWidth = this.panel.children('.ui-autocomplete-items').outerWidth(); 1561 } 1562 else { 1563 this.panel.css({'visibility':'hidden','display':'block'}); 1564 panelWidth = this.panel.children('.ui-autocomplete-items').outerWidth(); 1565 this.panel.css({'visibility':'visible','display':'none'}); 1566 } 1567 1568 var inputWidth = this.input.outerWidth(); 1569 if(panelWidth < inputWidth) { 1570 panelWidth = inputWidth; 1571 } 1572 } 1573 1574 if(this.cfg.scrollHeight) { 1575 var heightConstraint = this.panel.is(':hidden') ? this.panel.height() : this.panel.children().height(); 1576 if(heightConstraint > this.cfg.scrollHeight) 1577 this.panel.height(this.cfg.scrollHeight); 1578 else 1579 this.panel.css('height', 'auto'); 1580 } 1581 1582 this.panel.css({'left':'', 1583 'top':'', 1584 'width': panelWidth, 1585 'z-index': ++PrimeFaces.zindex 1586 }); 1587 1588 if(this.panel.parent().is(this.jq)) { 1589 this.panel.css({ 1590 left: 0, 1591 top: this.jq.innerHeight() 1592 }); 1593 } 1594 else { 1595 this.panel.position({ 1596 my: this.cfg.myPos 1597 ,at: this.cfg.atPos 1598 ,of: this.cfg.multiple ? this.jq : this.input 1599 ,collision: 'flipfit' 1600 }); 1601 } 1602 }, 1603 1604 displayAriaStatus: function(text) { 1605 this.status.html('<div>' + PrimeFaces.escapeHTML(text) + '</div>'); 1606 }, 1607 1608 groupItems: function() { 1609 var $this = this; 1610 1611 if(this.items.length) { 1612 this.itemContainer = this.panel.children('.ui-autocomplete-items'); 1613 1614 var firstItem = this.items.eq(0); 1615 if(!firstItem.hasClass('ui-autocomplete-moretext')) { 1616 this.currentGroup = firstItem.data('item-group'); 1617 var currentGroupTooltip = firstItem.data('item-group-tooltip'); 1618 1619 firstItem.before(this.getGroupItem($this.currentGroup, $this.itemContainer, currentGroupTooltip)); 1620 } 1621 1622 this.items.filter(':not(.ui-autocomplete-moretext)').each(function(i) { 1623 var item = $this.items.eq(i), 1624 itemGroup = item.data('item-group'), 1625 itemGroupTooltip = item.data('item-group-tooltip'); 1626 1627 if($this.currentGroup !== itemGroup) { 1628 $this.currentGroup = itemGroup; 1629 item.before($this.getGroupItem(itemGroup, $this.itemContainer, itemGroupTooltip)); 1630 } 1631 }); 1632 } 1633 }, 1634 1635 getGroupItem: function(group, container, tooltip) { 1636 var element = null; 1637 1638 if(container.is('.ui-autocomplete-table')) { 1639 if(!this.colspan) { 1640 this.colspan = this.items.eq(0).children('td').length; 1641 } 1642 1643 element = $('<tr class="ui-autocomplete-group ui-widget-header"><td colspan="' + this.colspan + '">' + group + '</td></tr>'); 1644 } 1645 else { 1646 element = $('<li class="ui-autocomplete-group ui-autocomplete-list-item ui-widget-header">' + group + '</li>'); 1647 } 1648 1649 if(element) { 1650 element.attr('title', tooltip); 1651 } 1652 1653 return element; 1654 }, 1655 1656 deleteTimeout: function() { 1657 clearTimeout(this.timeout); 1658 this.timeout = null; 1659 }, 1660 1661 fireClearEvent: function() { 1662 this.callBehavior('clear'); 1663 }, 1664 1665 isValid: function(value) { 1666 if(!this.cfg.forceSelection) { 1667 return; 1668 } 1669
1670 var valid = false; 1671 1672 for(var i = 0; i < this.currentItems.length; i++) { 1673 var stripedItem = this.currentItems[i]; 1674 if (stripedItem) { 1675 stripedItem = stripedItem.replace(/\r?\n/g, ''); 1676 } 1677 1678 if(stripedItem === value) { 1679 valid = true; 1680 break; 1681 } 1682 } 1683 1684 if(!valid) { 1685 this.input.val(''); 1686 if(!this.cfg.multiple) { 1687 this.hinput.val(''); 1688 } 1689 this.fireClearEvent(); 1690 } 1691 1692 return valid; 1693 }, 1694 1695 fetchItems: function() { 1696 var $this = this; 1697 1698 var options = { 1699 source: this.id, 1700 process: this.id, 1701 update: this.id, 1702 formId: this.cfg.formId, 1703 global: false, 1704 params: [{name: this.id + '_clientCache', value: true}], 1705 onsuccess: function(responseXML, status, xhr) { 1706 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 1707 widget: $this, 1708 handle: function(content) { 1709 $this.setCache($(content)); 1710 } 1711 }); 1712 1713 return true; 1714 } 1715 }; 1716 1717 PrimeFaces.ajax.Request.handle(options); 1718 }, 1719 1720 setCache: function(wrapper) { 1721 var $this = this, 1722 items = wrapper.find('.ui-autocomplete-item'), 1723 prevKey = null; 1724 1725 if (!this.wrapperStartTag || !this.wrapperEndTag) { 1726 this.findWrapperTag(wrapper); 1727 } 1728 1729 for (var i = 0; i < items.length; i++) { 1730 var item = items.eq(i), 1731 key = item.data('item-key'); 1732 1733 this.cache[key] = (this.cache[key] || this.wrapperStartTag) + item.get(0).outerHTML; 1734 1735 if ((prevKey !== null && prevKey !== key) || (i === items.length - 1)) { 1736 this.cache[prevKey] += $this.wrapperEndTag; 1737 } 1738 1739 prevKey = key; 1740 } 1741 }, 1742 1743 findWrapperTag: function(wrapper) { 1744 if (wrapper.is('ul')) { 1745 this.wrapperStartTag = '<ul class="ui-autocomplete-items ui-autocomplete-list ui-widget-content ui-widget ui-corner-all ui-helper-reset">'; 1746 this.wrapperEndTag = '</ul>'; 1747 } 1748 else { 1749 var header = wrapper.find('> table > thead'); 1750 this.wrapperStartTag = '<table class="ui-autocomplete-items ui-autocomplete-table ui-widget-content ui-widget ui-corner-all ui-helper-reset">' + 1751 (header.length ? header.eq(0).outherHTML : '') + 1752 '<tbody>'; 1753 this.wrapperEndTag = '</tbody></table>'; 1754 } 1755 } 1756 1757}); 1758 1759/** 1760 * PrimeFaces BlockUI Widget 1761 */ 1762PrimeFaces.widget.BlockUI = PrimeFaces.widget.BaseWidget.extend({ 1763 1764 init: function(cfg) { 1765 this.cfg = cfg; 1766 this.id = this.cfg.id; 1767 this.jqId = PrimeFaces.escapeClientId(this.id); 1768 this.block = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.block); 1769 this.content = $(this.jqId); 1770 this.cfg.animate = (this.cfg.animate === false)? false : true; 1771 this.cfg.blocked = (this.cfg.blocked === true)? true : false; 1772 1773 this.render(); 1774 1775 if(this.cfg.triggers) { 1776 this.bindTriggers(); 1777 } 1778 1779 if(this.cfg.blocked) { 1780 this.show(); 1781 } 1782 1783 this.removeScriptElement(this.id); 1784 }, 1785 1786 refresh: function(cfg) { 1787 this.blocker.remove(); 1788 this.block.children('.ui-blockui-content').remove(); 1789 $(document).off('pfAjaxSend.' + this.id + ' pfAjaxComplete.' + this.id); 1790 1791 this._super(cfg); 1792 }, 1793 1794 bindTriggers: function() { 1795 var $this = this; 1796 1797 //listen global ajax send and complete callbacks 1798 $(document).on('pfAjaxSend.' + this.id, function(e, xhr, settings) { 1799 var sourceId = $.type(settings.source) === 'string' ? settings.source : settings.source.name; 1800 // we must evaluate it each time as the DOM might has been changed 1801 var triggers = PrimeFaces.expressions.SearchExpressionFacade.resolve
1801Components($this.cfg.triggers); 1802 1803 if($.inArray(sourceId, triggers) !== -1 && !$this.cfg.blocked) { 1804 $this.show(); 1805 } 1806 }); 1807 1808 $(document).on('pfAjaxComplete.' + this.id, function(e, xhr, settings) { 1809 var sourceId = $.type(settings.source) === 'string' ? settings.source : settings.source.name; 1810 // we must evaluate it each time as the DOM might has been changed 1811 var triggers = PrimeFaces.expressions.SearchExpressionFacade.resolveComponents($this.cfg.triggers); 1812 1813 if($.inArray(sourceId, triggers) !== -1 && !$this.cfg.blocked) { 1814 $this.hide(); 1815 } 1816 }); 1817 }, 1818 1819 /** 1820 * Show the component with optional duration animation. 1821 * 1822 * @param [duration] Durations are given in milliseconds; higher values indicate slower animations, not faster ones. 1823 * The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, 1824 * respectively. 1825 */ 1826 show: function(duration) { 1827 this.blocker.css('z-index', ++PrimeFaces.zindex); 1828 1829 //center position of content 1830 for(var i = 0; i < this.block.length; i++) { 1831 var blocker = $(this.blocker[i]), 1832 content = $(this.content[i]); 1833 1834 content.css({ 1835 'left': (blocker.width() - content.outerWidth()) / 2, 1836 'top': (blocker.height() - content.outerHeight()) / 2, 1837 'z-index': ++PrimeFaces.zindex 1838 }); 1839 } 1840 1841 var animated = this.cfg.animate; 1842 if(animated) 1843 this.blocker.fadeIn(duration); 1844 else 1845 this.blocker.show(duration); 1846 1847 if(this.hasContent()) { 1848 if(animated) 1849 this.content.fadeIn(duration); 1850 else 1851 this.content.show(duration); 1852 } 1853 1854 this.block.attr('aria-busy', true); 1855 }, 1856 1857 /** 1858 * Hide the component with optional duration animation. 1859 * 1860 * @param [duration] Durations are given in milliseconds; higher values indicate slower animations, not faster ones. 1861 * The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, 1862 * respectively. 1863 */ 1864 hide: function(duration) { 1865 var animated = this.cfg.animate; 1866 1867 if(animated) 1868 this.blocker.fadeOut(duration); 1869 else 1870 this.blocker.hide(duration); 1871 1872 if(this.hasContent()) { 1873 if(animated) 1874 this.content.fadeOut(duration); 1875 else 1876 this.content.hide(duration); 1877 } 1878 1879 this.block.attr('aria-busy', false); 1880 }, 1881 1882 render: function() { 1883 this.blocker = $('<div id="' + this.id + '_blocker" class="ui-blockui ui-widget-overlay ui-helper-hidden"></div>'); 1884 1885 if(this.cfg.styleClass) { 1886 this.blocker.addClass(this.cfg.styleClass); 1887 } 1888 1889 if(this.block.hasClass('ui-corner-all')) { 1890 this.blocker.addClass('ui-corner-all'); 1891 } 1892 1893 if(this.block.length > 1) { 1894 this.content = this.content.clone(); 1895 } 1896 1897 this.block.css('position', 'relative').attr('aria-busy', this.cfg.blocked).append(this.blocker).append(this.content); 1898 1899 if(this.block.length > 1) { 1900 this.blocker = $(PrimeFaces.escapeClientId(this.id + '_blocker')); 1901 this.content = this.block.children('.ui-blockui-content'); 1902 } 1903 }, 1904 1905 hasContent: function() { 1906 return this.content.contents().length > 0; 1907 } 1908 1909}); 1910/** 1911 * PrimeFaces Calendar Widget 1912 */ 1913PrimeFaces.widget.Calendar = PrimeFaces.widget.BaseWidget.extend({ 1914 1915 init: function(cfg) { 1916 this._super(cfg); 1917 1918 this.input = $(this.jqId + '_input'); 1919 this.jqEl = this.cfg.popup ? this.input : $(this.jqId + '_inline'); 1920 var $this = this; 1921 1922 //i18n and l7n 1923 this.configureLocale(); 1924 1925 //events 1926 this.bindDateSelectListener(); 1927 this.bindViewChangeListener(); 1928 this.bindCloseListener(); 1929 1930 //disabled dates 1931 this.cfg.beforeShowDay = function(date) { 1932 if($this.cfg.preShowDay) { 1933 return $this.cfg.preShowDay(date); 1934 } 1935 else if($this.cfg.disabledWeekends) { 1936 return $.datepicker.noWeekends(date); 1937 } 1938 else { 1939 return [true,'']; 1940 } 1941 } 1942 1943 //Setup timepicker 1944 var hasTimePicker = this.hasTimePicker(); 1945 if(hasTimePicker) { 1946 this.configureTimePicker(); 1947 } 1948 1949 //Client behaviors, input skinning and z-index 1950 if(this.cfg.popup) { 1951 PrimeFaces.skinInput(this.jqEl); 1952 1953 if(this.cfg.behaviors) { 1954 PrimeFaces.attachBehaviors(this.jqEl, this.cfg.behaviors); 1955 } 1956 1957 this.cfg.beforeShow = function(input, inst) { 1958 if($this.refocusInput) { 1959 $this.refocusInput = false;
1960 return false; 1961 } 1962 1963 //display on top 1964 setTimeout(function() { 1965 $('#ui-datepicker-div').addClass('ui-input-overlay').css('z-index', ++PrimeFaces.zindex); 1966 1967 if ($this.cfg.showTodayButton === false) { 1968 $(input).datepicker("widget").find(".ui-datepicker-current").hide(); 1969 } 1970 1971 $this.alignPanel(); 1972 }, 1); 1973 1974 // touch support - prevents keyboard popup 1975 if(PrimeFaces.env.touch && !$this.input.attr("readonly") && $this.cfg.showOn && $this.cfg.showOn === 'button') { 1976 $(this).prop("readonly", true); 1977 } 1978 1979 //user callback 1980 var preShow = $this.cfg.preShow; 1981 if(preShow) { 1982 return $this.cfg.preShow.call($this, input, inst); 1983 } 1984 }; 1985 1986 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $('#ui-datepicker-div'), function() { 1987 $this.alignPanel(); 1988 }); 1989 } 1990 1991 // touch support - prevents keyboard popup 1992 if (PrimeFaces.env.touch && !this.input.attr("readonly") && this.cfg.showOn && this.cfg.showOn === 'button') { 1993 var fireCloseEvent = this.cfg.onClose; 1994 this.cfg.onClose = function(dateText, inst) { 1995 $(this).attr("readonly", false); 1996 1997 if (fireCloseEvent) { 1998 fireCloseEvent(); 1999 } 2000 }; 2001 } 2002 2003 //Initialize calendar 2004 if(hasTimePicker) { 2005 if(this.cfg.timeOnly) 2006 this.jqEl.timepicker(this.cfg); 2007 else 2008 this.jqEl.datetimepicker(this.cfg); 2009 } 2010 else { 2011 this.jqEl.datepicker(this.cfg); 2012 } 2013 2014 //extensions 2015 if(this.cfg.popup && this.cfg.showOn) { 2016 var triggerButton = this.jqEl.siblings('.ui-datepicker-trigger:button'); 2017 triggerButton.attr('aria-label',PrimeFaces.getAriaLabel('calendar.BUTTON')).attr('aria-haspopup', true).html('').addClass('ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only') 2018 .append('<span class="ui-button-icon-left ui-icon ui-icon-calendar"></span><span class="ui-button-text">ui-button</span>'); 2019 2020 var title = this.jqEl.attr('title'); 2021 if(title) { 2022 triggerButton.attr('title', title); 2023 } 2024 2025 if(this.cfg.disabled) { 2026 triggerButton.addClass('ui-state-disabled'); 2027 } 2028 2029 var buttonIndex = this.cfg.buttonTabindex||this.jqEl.attr('tabindex'); 2030 if(buttonIndex) { 2031 triggerButton.attr('tabindex', buttonIndex); 2032 } 2033 2034 PrimeFaces.skinButton(triggerButton); 2035 $('#ui-datepicker-div').addClass('ui-shadow'); 2036 this.jq.addClass('ui-trigger-calendar'); 2037 } 2038 2039 //mark target and descandants of target as a trigger for a primefaces overlay 2040 if(this.cfg.popup) { 2041 this.jq.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 2042 } 2043 2044 if (!this.cfg.popup && this.cfg.showTodayButton === false) { 2045 this.jqEl.parent().find(".ui-datepicker-current").hide(); 2046 } 2047 2048 //pfs metadata 2049 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 2050 2051 if (this.cfg.mask) { 2052 var maskCfg = { 2053 placeholder:this.cfg.maskSlotChar||'_', 2054 autoclear:this.cfg.maskAutoClear 2055 }; 2056 this.input.mask(this.cfg.mask, maskCfg); 2057 } 2058 }, 2059 2060 alignPanel: function () { 2061 if($.datepicker._lastInput && (this.id + '_input') === $.datepicker._lastInput.id) { 2062 $('#ui-datepicker-div').css({left: '', top: ''}).position({ 2063 my: 'left top' 2064 , at: 'left bottom' 2065 , of: this.input 2066 , collision: 'flipfit' 2067 }); 2068 } 2069 }, 2070 2071 refresh: function(cfg) { 2072 if(cfg.popup && $.datepicker._lastInput && (cfg.id + '_input') === $.datepicker._lastInput.id) { 2073 $.datepicker._hideDatepicker(); 2074 } 2075 2076 this._super(cfg); 2077 }, 2078 2079 configureLocale: function() { 2080 var localeSettings = PrimeFaces.locales[this.cfg.locale]; 2081 2082 if(localeSettings) { 2083 for(var setting in localeSettings) { 2084 this.cfg[setting] = localeSettings[setting]; 2085 } 2086 } 2087 }, 2088 2089 bindDateSelectListener: function() { 2090 var $this = this; 2091 2092 this.cfg.onSelect = function() { 2093 if($this.cfg.popup) { 2094 $this.fireDateSelectEvent(); 2095 2096 if($this.cfg.focusOnSelect) { 2097 $this.refocusInput = true; 2098 $this.jqEl.focus(); 2099 if(!($this.cfg.showOn && $this.cfg.showOn === 'button')) { 2100 $this.jqEl.off('click.calendar').on('click.calendar', function() { 2101 $(this).datepicker("show"); 2102 }); 2103 } 2104 2105 setTimeout(function() { 2106 $this.refocusInput = false;
2107 }, 10); 2108 } 2109 } 2110 else { 2111 // GitHub #3760 Pass the config settings to TimePicker 2112 var settingsObj = { 2113 settings : $this.cfg 2114 }; 2115 var newDate = $this.cfg.timeOnly ? '' : $.datepicker.formatDate($this.cfg.dateFormat, $this.getDate(), $.datepicker._getFormatConfig(settingsObj)); 2116 if($this.cfg.timeFormat) { 2117 newDate += ' ' + $this.jqEl.find('.ui_tpicker_time_input')[0].value; 2118 } 2119 2120 $this.input.val(newDate); 2121 $this.fireDateSelectEvent(); 2122 } 2123 }; 2124 }, 2125 2126 fireDateSelectEvent: function() { 2127 this.callBehavior('dateSelect'); 2128 }, 2129 2130 bindViewChangeListener: function() { 2131 if(this.hasBehavior('viewChange')) { 2132 var $this = this; 2133 this.cfg.onChangeMonthYear = function(year, month) { 2134 $this.fireViewChangeEvent(year, month); 2135 }; 2136 } 2137 }, 2138 2139 fireViewChangeEvent: function(year, month) { 2140 if(this.hasBehavior('viewChange')) { 2141 var ext = { 2142 params: [ 2143 {name: this.id + '_month', value: month}, 2144 {name: this.id + '_year', value: year} 2145 ] 2146 }; 2147 2148 this.callBehavior('viewChange', ext); 2149 } 2150 }, 2151 2152 bindCloseListener: function() { 2153 if(this.hasBehavior('close')) { 2154 var $this = this; 2155 this.cfg.onClose = function() { 2156 $this.fireCloseEvent(); 2157 }; 2158 } 2159 }, 2160 2161 fireCloseEvent: function() { 2162 this.callBehavior('close'); 2163 }, 2164 2165 configureTimePicker: function() { 2166 var pattern = this.cfg.dateFormat, 2167 timeSeparatorIndex = pattern.toLowerCase().indexOf('h'); 2168 2169 this.cfg.dateFormat = pattern.substring(0, timeSeparatorIndex - 1); 2170 this.cfg.timeFormat = pattern.substring(timeSeparatorIndex, pattern.length); 2171 2172 //ampm 2173 if(this.cfg.timeFormat.indexOf('TT') != -1) { 2174 this.cfg.ampm = true; 2175 } 2176 2177 // GitHub #4366 pass date and time settings for min/max date 2178 var timeSettings = { 2179 settings : this.cfg 2180 }; 2181 var parseSettings = $.datepicker._getFormatConfig(timeSettings); 2182 2183 //restraints 2184 if(this.cfg.minDate) { 2185 this.cfg.minDate = $.datepicker.parseDateTime(this.cfg.dateFormat, this.cfg.timeFormat, this.cfg.minDate, parseSettings, this.cfg); 2186 } 2187 2188 if(this.cfg.maxDate) { 2189 this.cfg.maxDate = $.datepicker.parseDateTime(this.cfg.dateFormat, this.cfg.timeFormat, this.cfg.maxDate, parseSettings, this.cfg); 2190 } 2191 2192 if(!this.cfg.showButtonPanel) { 2193 this.cfg.showButtonPanel = false; 2194 } 2195 2196 if(this.cfg.controlType == 'custom' && this.cfg.timeControlObject) { 2197 this.cfg.controlType = this.cfg.timeControlObject; 2198 } 2199 2200 if(this.cfg.showHour) { 2201 this.cfg.showHour = (this.cfg.showHour == "true") ? true : false; 2202 } 2203 2204 if(this.cfg.showMinute) { 2205 this.cfg.showMinute = (this.cfg.showMinute == "true") ? true : false; 2206 } 2207 2208 if(this.cfg.showSecond) { 2209 this.cfg.showSecond = (this.cfg.showSecond == "true") ? true : false; 2210 } 2211 2212 if(this.cfg.showMillisec) { 2213 this.cfg.showMillisec = (this.cfg.showMillisec == "true") ? true : false; 2214 } 2215 }, 2216 2217 hasTimePicker: function() { 2218 return this.cfg.dateFormat.toLowerCase().indexOf('h') != -1; 2219 }, 2220 2221 setDate: function(date) { 2222 this.jqEl.datetimepicker('setDate', date); 2223 }, 2224 2225 getDate: function() { 2226 return this.jqEl.datetimepicker('getDate'); 2227 }, 2228 2229 enable: function() { 2230 this.jqEl.datetimepicker('enable'); 2231 }, 2232 2233 disable: function() { 2234 this.jqEl.datetimepicker('disable'); 2235 } 2236 2237}); 2238 2239/** 2240 * PrimeFaces Carousel Widget 2241 */ 2242PrimeFaces.widget.Carousel = PrimeFaces.widget.DeferredWidget.extend({ 2243 2244 init: function(cfg) { 2245 this._super(cfg); 2246 this.viewport = this.jq.children('.ui-carousel-viewport'); 2247 this.itemsContainer = this.viewport.children('.ui-carousel-items'); 2248 this.items = this.itemsContainer.children('li'); 2249 this.itemsCount = this.items.length; 2250 this.header = this.jq.children('.ui-carousel-header'); 2251 this.prevNav = this.header.children('.ui-carousel-prev-button'); 2252 this.nextNav = this.header.children('.ui-carousel-next-button'); 2253 this.pageLinks = this.header.find('> .ui-carousel-page-links > .ui-carousel-page-link'); 2254 this.dropdown = this.header.children('.ui-carousel-dropdown'); 2255 this.responsiveDropdown = this.header.children('.ui-carousel-dropdown-responsive'); 2256 this.stateholder = $(this.jqId + '_page'); 2257 2258 if(this.cfg.toggleable) { 2259 this.toggler = $(this.jqId + '_toggler'); 2260 this.toggleStateHolder = $(this.jqId + '_collapsed'); 2261 this.toggleableContent = this.jq.find(' > .ui-carousel-viewport > .ui-carousel-items, > .ui-carousel-footer'); 2262 } 2263 2264 this.cfg.numVisible = this.cfg.numVisible||3; 2265 this.cfg.firstVisible = this.cfg.firstVisible||0; 2266 this.columns = this.cfg.numVisible; 2267 this.first = this.cfg.firstVisible; 2268 this.cfg.effectDuration = this.cfg.effectDuration||500; 2269 this.cfg.circular = this.cfg.circular||false; 2270 this.cfg.breakpoint = this.cfg.breakpoint||640; 2271 this.page = parseInt(this.first/this.columns); 2272 this.totalPages = Math.ceil(this.itemsCount/this.cfg.numVisible); 2273 2274 if(this.cfg.stateful) { 2275 this.stateKey = 'carousel-' + this.id; 2276 2277 this.restoreState(); 2278 } 2279 2280 this.renderDeferred(); 2281 }, 2282 2283 _render: function() { 2284 this.updateNavigators(); 2285 this.bindEvents(); 2286 2287 if(this.cfg.vertical) { 2288 this.calculateItemHeights(); 2289 } 2290 else if(this.cfg.responsive) { 2291 this.refreshDimensions(); 2292 } 2293 else { 2294 this.calculateItemWidths(this.columns); 2295 this.jq.width(this.jq.width()); 2296 this.updateNavigators(); 2297 } 2298 2299 if(this.cfg.collapsed) { 2300 this.toggleableContent.hide(); 2301 } 2302 }, 2303 2304 calculateItemWidths: function() { 2305 var firstItem = this.items.eq(0); 2306 if(firstItem.length) { 2307 var itemFrameWidth = firstItem.outerWidth(true) - firstItem.width(); //sum of margin, border and padding 2308 this.items.width((this.viewport.innerWidth() - itemFrameWidth * this.columns) / this.columns); 2309 } 2310 }, 2311 2312 calculateItemHeights: function() { 2313 var firstItem = this.items.eq(0); 2314 if(firstItem.length) { 2315 if(!this.cfg.responsive) { 2316 this.items.width(firstItem.width()); 2317 this.jq.width(this.jq.width()); 2318 var maxHeight = 0; 2319 for(var i = 0; i < this.items.length; i++) { 2320 var item = this.items.eq(i), 2321 height = item.height(); 2322 2323 if(maxHeight < height) { 2324 maxHeight = height; 2325 } 2326 } 2327 this.items.height(maxHeight); 2328 } 2329 var totalMargins = ((firstItem.outerHeight(true) - firstItem.outerHeight()) / 2) * (this.cfg.numVisible); 2330 this.viewport.height((firstItem.outerHeight() * this.cfg.numVisible) + totalMargins); 2331 this.updateNavigators(); 2332 this.itemsContainer.css('top', -1 * (this.viewport.innerHe
2332ight() * this.page)); 2333 } 2334 }, 2335 2336 refreshDimensions: function() { 2337 var win = $(window); 2338 if(win.width() <= this.cfg.breakpoint) { 2339 this.columns = 1; 2340 this.calculateItemWidths(this.columns); 2341 this.totalPages = this.itemsCount; 2342 this.responsiveDropdown.show(); 2343 this.pageLinks.hide(); 2344 } 2345 else { 2346 this.columns = this.cfg.numVisible; 2347 this.calculateItemWidths(); 2348 this.totalPages = Math.ceil(this.itemsCount / this.cfg.numVisible); 2349 this.responsiveDropdown.hide(); 2350 this.pageLinks.show(); 2351 } 2352 2353 this.page = parseInt(this.first / this.columns); 2354 this.updateNavigators(); 2355 this.itemsContainer.css('left', (-1 * (this.viewport.innerWidth() * this.page))); 2356 }, 2357 2358 bindEvents: function() { 2359 var $this = this; 2360 2361 this.prevNav.on('click', function() { 2362 if($this.page !== 0) { 2363 $this.setPage($this.page - 1); 2364 } 2365 else if($this.cfg.circular) { 2366 $this.setPage($this.totalPages - 1); 2367 } 2368 }); 2369 2370 this.nextNav.on('click', function() { 2371 var lastPage = ($this.page === ($this.totalPages - 1)); 2372 2373 if(!lastPage) { 2374 $this.setPage($this.page + 1); 2375 } 2376 else if($this.cfg.circular) { 2377 $this.setPage(0); 2378 } 2379 }); 2380 2381 this.itemsContainer.swipe({ 2382 swipeLeft:function(event) { 2383 if($this.page === ($this.totalPages - 1)) { 2384 if($this.cfg.circular) 2385 $this.setPage(0); 2386 } 2387 else { 2388 $this.setPage($this.page + 1); 2389 } 2390 }, 2391 swipeRight: function(event) { 2392 if($this.page === 0) { 2393 if($this.cfg.circular) 2394 $this.setPage($this.totalPages - 1); 2395 } 2396 else { 2397 $this.setPage($this.page - 1); 2398 } 2399 }, 2400 excludedElements: PrimeFaces.utils.excludedSwipeElements() 2401 }); 2402 2403 if(this.pageLinks.length) { 2404 this.pageLinks.on('click', function(e) { 2405 $this.setPage($(this).index()); 2406 e.preventDefault(); 2407 }); 2408 } 2409 2410 this.header.children('select').on('change', function() { 2411 $this.setPage(parseInt($(this).val()) - 1); 2412 }); 2413 2414 if(this.cfg.autoplayInterval) { 2415 this.cfg.circular = true; 2416 this.startAutoplay(); 2417 } 2418 2419 if(this.cfg.responsive) { 2420 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', null, function() { 2421 if($this.cfg.vertical) { 2422 $this.calculateItemHeights(); 2423 } 2424 else { 2425 $this.refreshDimensions(); 2426 } 2427 }); 2428 } 2429 2430 if(this.cfg.toggleable) { 2431 this.toggler.on('mouseover.carouselToggler',function() { 2432 $(this).addClass('ui-state-hover'); 2433 }).on('mouseout.carouselToggler',function() { 2434 $(this).removeClass('ui-state-hover'); 2435 }).on('click.carouselToggler', function(e) { 2436 $this.toggle(); 2437 e.preventDefault(); 2438 }); 2439 } 2440 }, 2441 2442 updateNavigators: function() { 2443 if(!this.cfg.circular) { 2444 if(this.page === 0) { 2445 this.prevNav.addClass('ui-state-disabled'); 2446 this.nextNav.removeClass('ui-state-disabled'); 2447 } 2448 else if(this.page === (this.totalPages - 1)) { 2449 this.prevNav.removeClass('ui-state-disabled'); 2450 this.nextNav.addClass('ui-state-disabled'); 2451 } 2452 else { 2453 this.prevNav.removeClass('ui-state-disabled'); 2454 this.nextNav.removeClass('ui-state-disabled'); 2455 } 2456 } 2457 2458 if(this.pageLinks.length) { 2459 this.pageLinks.filter('.ui-icon-radio-on').removeClass('ui-icon-radio-on'); 2460 this.pageLinks.eq(this.page).addClass('ui-icon-radio-on'); 2461 } 2462 2463 if(this.dropdown.length) { 2464 this.dropdown.val(this.page + 1); 2465 } 2466 2467 if(this.responsiveDropdown.length) { 2468 this.responsiveDropdown.val(this.page + 1); 2469 } 2470 }, 2471 2472 setPage: function(p) { 2473 if(p !== this.page && !this.itemsContainer.is(':animated')) { 2474 var $this = this, 2475 animationProps = this.cfg.vertical ? {top: -1 * (this.viewport.innerHe
2475ight() * p)} : {left: -1 * (this.viewport.innerWidth() * p)}; 2476 animationProps.easing = this.cfg.easing; 2477 2478 this.itemsContainer.animate(animationProps, 2479 { 2480 duration: this.cfg.effectDuration, 2481 easing: this.cfg.easing, 2482 complete: function() { 2483 $this.page = p; 2484 $this.first = $this.page * $this.columns; 2485 $this.updateNavigators(); 2486 $this.stateholder.val($this.page); 2487 if($this.cfg.stateful) { 2488 $this.saveState(); 2489 } 2490 } 2491 }); 2492 } 2493 }, 2494 2495 startAutoplay: function() { 2496 var $this = this; 2497 2498 this.interval = setInterval(function() { 2499 if($this.page === ($this.totalPages - 1)) 2500 $this.setPage(0); 2501 else 2502 $this.setPage($this.page + 1); 2503 }, this.cfg.autoplayInterval); 2504 }, 2505 2506 stopAutoplay: function() { 2507 clearInterval(this.interval); 2508 }, 2509 2510 toggle: function() { 2511 if(this.cfg.collapsed) { 2512 this.expand(); 2513 } 2514 else { 2515 this.collapse(); 2516 } 2517 2518 PrimeFaces.invokeDeferredRenders(this.id); 2519 }, 2520 2521 expand: function() { 2522 this.toggleState(false, 'ui-icon-plusthick', 'ui-icon-minusthick'); 2523 2524 this.slideDown(); 2525 }, 2526 2527 collapse: function() { 2528 this.toggleState(true, 'ui-icon-minusthick', 'ui-icon-plusthick'); 2529 2530 this.slideUp(); 2531 }, 2532 2533 slideUp: function() { 2534 this.toggleableContent.slideUp(this.cfg.toggleSpeed, 'easeInOutCirc'); 2535 }, 2536 2537 slideDown: function() { 2538 this.toggleableContent.slideDown(this.cfg.toggleSpeed, 'easeInOutCirc'); 2539 }, 2540 2541 toggleState: function(collapsed, removeIcon, addIcon) { 2542 this.toggler.children('span.ui-icon').removeClass(removeIcon).addClass(addIcon); 2543 this.cfg.collapsed = collapsed; 2544 this.toggleStateHolder.val(collapsed); 2545 2546 if(this.cfg.stateful) { 2547 this.saveState(); 2548 } 2549 }, 2550 2551 restoreState: function() { 2552 var carouselStateAsString = PrimeFaces.getCookie(this.stateKey) || "first: null, collapsed: null"; 2553 this.carouselState = PrimeFaces.csp.evalResult('({' + carouselStateAsString + '})'); 2554 2555 this.first = this.carouselState.first||this.first; 2556 this.page = parseInt(this.first/this.columns); 2557 2558 this.stateholder.val(this.page); 2559 2560 if(this.cfg.toggleable && (this.carouselState.collapsed === false || this.carouselState.collapsed === true)) { 2561 this.cfg.collapsed = !this.carouselState.collapsed; 2562 this.toggle(); 2563 } 2564 }, 2565 2566 saveState: function() { 2567 var carouselStateAsString = "first:" + this.first; 2568 2569 if(this.cfg.toggleable) { 2570 carouselStateAsString += ", collapsed: " + this.toggleStateHolder.val(); 2571 } 2572 2573 PrimeFaces.setCookie(this.stateKey, carouselStateAsString, {path:'/'}); 2574 }, 2575 2576 clearState: function() { 2577 if(this.cfg.stateful) { 2578 PrimeFaces.deleteCookie(this.stateKey, {path:'/'}); 2579 } 2580 } 2581 2582}); 2583/** 2584 * PrimeFaces ColumnToggler Widget 2585 */ 2586PrimeFaces.widget.ColumnToggler = PrimeFaces.widget.DeferredWidget.extend({ 2587 2588 init: function(cfg) { 2589 this._super(cfg); 2590 this.table = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.datasource); 2591 this.trigger = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.trigger); 2592 this.tableId = this.table.attr('id'); 2593 this.hasFrozenColumn = this.table.hasClass('ui-datatable-frozencolumn'); 2594 this.hasStickyHeader = this.table.hasClass('ui-datatable-sticky'); 2595 var clientId = PrimeFaces.escapeClientId(this.tableId); 2596 2597 if(this.hasFrozenColumn) { 2598 this.thead = $(clientId + '_frozenThead,' + clientId + '_scrollableThead'); 2599 this.tbody = $(clientId + '_frozenTbody,' + clientId + '_scrollableTbody'); 2600 this.tfoot = $(clientId + '_frozenTfoot,' + clientId + '_scrollableTfoot'); 2601 this.frozenColumnCount = this.thead.eq(0).find('th').length; 2602 } 2603 else { 2604 this.thead = $(clientId + '_head'); 2605 this.tbody = $(clientId + '_data'); 2606 this.tfoot = $(clientId + '_foot'); 2607 } 2608 this.visible = false;
2609 2610 this.render(); 2611 this.bindEvents(); 2612 }, 2613 2614 //@override 2615 refresh: function(cfg) { 2616 var jqs = $('[id=' + cfg.id.replace(/:/g,"\\:") + ']'); 2617 if(jqs.length > 1) { 2618 $(document.body).children(this.jqId).remove(); 2619 } 2620 2621 this.widthAligned = false; 2622 2623 this._super(cfg); 2624 }, 2625 2626 render: function() { 2627 this.columns = this.thead.find('> tr > th:not(.ui-static-column)'); 2628 this.panel = $(PrimeFaces.escapeClientId(this.cfg.id)).attr('role', 'dialog').addClass('ui-columntoggler ui-widget ui-widget-content ui-shadow ui-corner-all') 2629 .append('<ul class="ui-columntoggler-items" role="group"></ul>').appendTo(document.body); 2630 this.itemContainer = this.panel.children('ul'); 2631 2632 var stateHolderId = this.tableId + "_columnTogglerState"; 2633 this.togglerStateHolder = $('<input type="hidden" id="' + stateHolderId + '" name="' + stateHolderId + '" autocomplete="off"></input>'); 2634 this.table.append(this.togglerStateHolder); 2635 this.togglerState = []; 2636 2637 //items 2638 for(var i = 0; i < this.columns.length; i++) { 2639 var column = this.columns.eq(i), 2640 hidden = column.hasClass('ui-helper-hidden'), 2641 boxClass = hidden ? 'ui-chkbox-box ui-widget ui-corner-all ui-state-default' : 'ui-chkbox-box ui-widget ui-corner-all ui-state-default ui-state-active', 2642 iconClass = (hidden) ? 'ui-chkbox-icon ui-icon ui-icon-blank' : 'ui-chkbox-icon ui-icon ui-icon-check', 2643 columnChildren = column.children('.ui-column-title'), 2644 columnTitle = columnChildren.text(), 2645 columnTogglerCheckboxId = this.tableId + "_columnTogglerChkbx" + i; 2646 2647 var label = columnChildren.find('label'); 2648 if (label.length) { 2649 columnTitle = label.text(); 2650 } 2651 2652 this.hasPriorityColumns = column.is('[class*="ui-column-p-"]'); 2653 2654 var item = $('<li class="ui-columntoggler-item">' + 2655 '<div class="ui-chkbox ui-widget">' + 2656 '<div role="checkbox" tabindex="0" aria-checked="'+ !hidden + '" aria-labelledby="'+ columnTogglerCheckboxId + '" class="' + boxClass + '">' + 2657 '<span class="' + iconClass + '"></span></div></div>' + 2658 '<label id="' + columnTogglerCheckboxId + '">' + PrimeFaces.escapeHTML(columnTitle) + '</label></li>').data('column', column.attr('id')); 2659 2660 if(this.hasPriorityColumns) { 2661 var columnClasses = column.attr('class').split(' '); 2662 for(var j = 0; j < columnClasses.length; j++) { 2663 var columnClass = columnClasses[j], 2664 pindex = columnClass.indexOf('ui-column-p-'); 2665 if(pindex !== -1) { 2666 item.addClass(columnClass.substring(pindex , pindex + 13)); 2667 } 2668 } 2669 } 2670 2671 item.appendTo(this.itemContainer); 2672 2673 this.togglerState.push(column.attr('id') + '_' + !hidden); 2674 } 2675 2676 this.togglerStateHolder.val(this.togglerState.join(',')); 2677 2678 //close icon 2679 this.closer = $('<a href="#" class="ui-columntoggler-close"><span class="ui-icon ui-icon-close"></span></a>') 2680 .attr('aria-label', PrimeFaces.getAriaLabel('columntoggler.CLOSE')).prependTo(this.panel); 2681 2682 if(this.panel.outerHeight() > 200) { 2683 this.panel.height(200); 2684 } 2685 this.hide(); 2686 }, 2687 2688 bindEvents: function() { 2689 var $this = this; 2690 2691 //trigger 2692 this.trigger.off('click.ui-columntoggler').on('click.ui-columntoggler', function(e) { 2693 if($this.visible) 2694 $this.hide(); 2695 else 2696 $this.show(); 2697 }); 2698 2699 //checkboxes 2700 this.itemContainer.find('> .ui-columntoggler-item > .ui-chkbox > .ui-chkbox-box').on('mouseover.columnToggler', function() { 2701 var item = $(this); 2702 if(!item.hasClass('ui-state-active')) { 2703 item.addClass('ui-state-hover'); 2704 } 2705 }) 2706 .on('mouseout.columnToggler', function() { 2707 $(this).removeClass('ui-state-hover'); 2708 }) 2709 .on('click.columnToggler', function(e) { 2710 $this.toggle($(this)); 2711 e.preventDefault(); 2712 }); 2713 2714 //labels 2715 this.itemContainer.find('> .ui-columntoggler-item > label').on('click.selectCheckboxMenu', function(e) { 2716 $this.toggle($(this).prev().children('.ui-chkbox-box')); 2717 PrimeFaces.clearSelection(); 2718 e.preventDefault(); 2719 }); 2720 2721 //closer 2722 this.closer.on('click', function(e) { 2723 $this.hide(); 2724 $this.trigger.focus(); 2725 e.preventDefault(); 2726 }); 2727 2728 this.bindKeyEvents(); 2729 2730 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.panel, 2731 function() { return $this.trigger; }, 2732 function(e, eventTarget) { 2733 if(!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { 2734 $this.hide(); 2735 } 2736 }); 2737 2738 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { 2739 $this.alignPanel(); 2740 }); 2741 }, 2742 2743 bindKeyEvents: function() { 2744 var $this = this, 2745 inputs = this.itemContainer.find('> li > div.ui-chkbox > div.ui-chkbox-box'); 2746 2747 this.trigger.on('focus.columnToggler', function() { 2748 $(this).addClass('ui-state-focus'); 2749 }) 2750 .on('blur.columnToggler', function() { 2751 $(this).removeClass('ui-state-focus'); 2752 }) 2753 .on('keydown.columnToggler', function(e) { 2754 var keyCode = $.ui.keyCode, 2755 key = e.which; 2756 2757 switch(key) { 2758 case keyCode.ENTER: 2759 if($this.visible) 2760 $this.hide(); 2761 else 2762 $this.show(); 2763 2764 e.preventDefault(); 2765 break; 2766 2767 case keyCode.TAB: 2768 if($this.visible) { 2769 $this.itemContainer.children('li:not(.ui-state-disabled):first').find('div.ui-chkbox-box').trigger('focus'); 2770 e.preventDefault(); 2771 } 2772 break; 2773 }; 2774 }); 2775 2776 inputs.on('focus.columnToggler', function() { 2777 $(this).addClass('ui-state-focus'); 2778 //PrimeFaces.scrollInView($this.panel, box); 2779 }) 2780 .on('blur.columnToggler', function(e) { 2781 $(this).removeClass('ui-state-focus'); 2782 }) 2783 .on('keydown.columnToggler', function(e) { 2784 var keyCode = $.ui.keyCode, 2785 key = e.which; 2786 2787 switch(key) { 2788 case keyCode.TAB: 2789 var index = $(this).closest('li').index(); 2790 if(e.shiftKey) { 2791 if(index === 0) 2792 $this.closer.focus(); 2793 else 2794 inputs.eq(index - 1).focus(); 2795 } 2796 else { 2797 if(index === ($this.columns.length - 1) && !e.shiftKey) 2798 $this.closer.focus(); 2799 else 2800 inputs.eq(index + 1).focus(); 2801 } 2802 2803 e.preventDefault(); 2804 break; 2805 case keyCode.ENTER: 2806 case keyCode.SPACE: 2807 $this.toggle($(this)); 2808 e.preventDefault(); 2809 break; 2810 } 2811 }) 2812 .on('change.columnToggler', function(e) { 2813 if($(this).attr('aria-checked')) { 2814 $this.check(box); 2815 $(this).removeClass('ui-state-active'); 2816 } 2817 else { 2818 $this.uncheck(box); 2819 } 2820 }); 2821 2822 this.closer.on('keydown.columnToggler', function(e) { 2823 var key = e.which, 2824 keyCode = $.ui.keyCode; 2825 2826 if((key === keyCode.ENTER)) { 2827 $this.hide(); 2828 $this.trigger.focus(); 2829 e.preventDefault(); 2830 } 2831 else if(key === keyCode.TAB) { 2832 if(e.shiftKey) 2833 inputs.eq($this.columns.length - 1).focus(); 2834 else 2835 inputs.eq(0).focus(); 2836 2837 e.preventDefault(); 2838 } 2839 }); 2840 }, 2841 2842 toggle: function(chkbox) { 2843 if(chkbox.hasClass('ui-state-active')) { 2844 this.uncheck(chkbox); 2845 } 2846 else { 2847 this.check(chkbox); 2848 } 2849 }, 2850 2851 check: function(chkbox) { 2852 chkbox.addClass('ui-state-active').removeClass('ui-state-hover').children('.ui-chkbox-icon').addClass('ui-icon-check').removeClass('ui-icon-blank'); 2853 2854 var column = $(document.getElementById(chkbox.closest('li.ui-columntoggler-item').data('column'))), 2855 index = column.index() + 1, 2856 thead = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.thead.eq(0) : this.thead.eq(1)) : this.thead, 2857 tbody = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tbody.eq(0) : this.tbody.eq(1)) : this.tbody, 2858 tfoot = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tfoot.eq(0) : this.tfoot.eq(1)) : this.tfoot; 2859 2860 var rowHeader = thead.children('tr'), 2861 columnHeader = rowHeader.find('th:nth-child(' + index + ')'); 2862 2863 chkbox.attr('aria-checked', true); 2864 columnHeader.removeClass('ui-helper-hidden'); 2865 $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).removeClass('ui-helper-hidden'); 2866 tbody.children('tr').find('td:nth-child(' + index + ')').removeClass('ui-helper-hidden'); 2867 tfoot.children('tr').find('td:nth-child(' + index + ')').removeClass('ui-helper-hidden'); 2868 2869 if(this.hasFrozenColumn) { 2870 var headers = rowHeader.children('th'); 2871 if(headers.length !== headers.filter('.ui-helper-hidden').length) { 2872 thead.closest('td').removeClass('ui-helper-hidden'); 2873 } 2874 2875 if(!column.hasClass('ui-frozen-column')) { 2876 index += this.frozenColumnCount; 2877 } 2878 } 2879 2880 if(this.hasStickyHeader) { 2881 $(PrimeFaces.escapeClientId(columnHeader.attr('id'))).removeClass('ui-helper-hidden'); 2882 } 2883 2884 this.changeTogglerState(column, true); 2885 this.fireToggleEvent(true, (index - 1)); 2886 this.updateColspan(); 2887 }, 2888 2889 uncheck: function(chkbox) { 2890 chkbox.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 2891 2892 var column = $(document.getElementById(chkbox.closest('li.ui-columntoggler-item').data('column'))), 2893 index = column.index() + 1, 2894 thead = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.thead.eq(0) : this.thead.eq(1)) : this.thead, 2895 tbody = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tbody.eq(0) : this.tbody.eq(1)) : this.tbody, 2896 tfoot = this.hasFrozenColumn ? (column.hasClass('ui-frozen-column') ? this.tfoot.eq(0) : this.tfoot.eq(1)) : this.tfoot; 2897 2898 var rowHeader = thead.children('tr'), 2899 columnHeader = rowHeader.find('th:nth-child(' + index + ')'); 2900 2901 chkbox.attr('aria-checked', false); 2902 columnHeader.addClass('ui-helper-hidden'); 2903 $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).addClass('ui-helper-hidden'); 2904 tbody.children('tr').find('td:nth-child(' + index + ')').addClass('ui-helper-hidden'); 2905 tfoot.children('tr').find('td:nth-child(' + index + ')').addClass('ui-helper-hidden'); 2906 2907 if(this.hasFrozenColumn) { 2908 var headers = rowHeader.children('th'); 2909 if(headers.length === headers.filter(':hidden').length) { 2910 thead.closest('td').addClass('ui-helper-hidden'); 2911 } 2912 2913 if(!column.hasClass('ui-frozen-column')) { 2914 index += this.frozenColumnCount; 2915 } 2916 } 2917 2918 if(this.hasStickyHeader) { 2919 $(PrimeFaces.escapeClientId(columnHeader.attr('id'))).addClass('ui-helper-hidden'); 2920 } 2921 2922 this.changeTogglerState(column, false); 2923 this.fireToggleEvent(false, (index - 1)); 2924 this.updateColspan(); 2925 }, 2926 2927 alignPanel: function() { 2928 this.panel.css({'left':'', 'top':'', 'z-index': ++PrimeFaces.zindex}).position({ 2929 my: 'left top' 2930 ,at: 'left bottom' 2931 ,of: this.trigger 2932 }); 2933 2934 if(this.hasPriorityColumns) { 2935 if(this.panel.outerWidth() <= this.trigger.outerWidth()) { 2936 this.panel.css('width','auto'); 2937 } 2938 2939 this.widthAligned = false;
2940 } 2941 2942 if(!this.widthAligned && (this.panel.outerWidth() < this.trigger.outerWidth())) { 2943 this.panel.width(this.trigger.width()); 2944 this.widthAligned = true; 2945 } 2946 }, 2947 2948 show: function() { 2949 this.alignPanel(); 2950 this.panel.show(); 2951 this.visible = true; 2952 this.trigger.attr('aria-expanded', true); 2953 this.closer.trigger('focus'); 2954 }, 2955 2956 hide: function() { 2957 this.panel.fadeOut('fast'); 2958 this.visible = false; 2959 this.trigger.attr('aria-expanded', false); 2960 }, 2961 2962 fireToggleEvent: function(visible, index) { 2963 if(this.hasBehavior('toggle')) { 2964 var ext = { 2965 params: [ 2966 {name: this.id + '_visibility', value: visible ? 'VISIBLE' : 'HIDDEN'}, 2967 {name: this.id + '_index', value: index} 2968 ] 2969 }; 2970 2971 this.callBehavior('toggle', ext); 2972 } 2973 }, 2974 2975 calculateColspan: function() { 2976 return this.itemContainer.find('> .ui-columntoggler-item > .ui-chkbox > .ui-chkbox-box.ui-state-active').length; 2977 }, 2978 2979 updateRowColspan: function(row, colspanValue) { 2980 colspanValue = colspanValue || this.calculateColspan(); 2981 if(colspanValue) { 2982 row.children('td').removeClass('ui-helper-hidden').attr('colspan', colspanValue); 2983 } 2984 else { 2985 row.children('td').addClass('ui-helper-hidden'); 2986 } 2987 }, 2988 2989 updateColspan: function() { 2990 var emptyRow = this.tbody.children('tr:first'); 2991 if(emptyRow && emptyRow.hasClass('ui-datatable-empty-message')) { 2992 this.updateRowColspan(emptyRow); 2993 } 2994 else { 2995 var colspanValue = this.calculateColspan(), 2996 $this = this; 2997 this.tbody.children('.ui-expanded-row-content').each(function() { 2998 $this.updateRowColspan($(this), colspanValue); 2999 }); 3000 } 3001 }, 3002 3003 changeTogglerState: function(column, isHidden) { 3004 if(column && column.length) { 3005 var stateVal = this.togglerStateHolder.val(), 3006 columnId = column.attr('id'), 3007 oldColState = columnId + "_" + !isHidden, 3008 newColState = columnId + "_" + isHidden; 3009 this.togglerStateHolder.val(stateVal.replace(oldColState, newColState)); 3010 } 3011 } 3012 3013}); 3014 3015/** 3016 * PrimeFaces Dashboard Widget 3017 */ 3018PrimeFaces.widget.Dashboard = PrimeFaces.widget.BaseWidget.extend({ 3019 3020 init: function(cfg) { 3021 this._super(cfg); 3022 3023 this.cfg.connectWith = this.jqId + ' .ui-dashboard-column'; 3024 this.cfg.placeholder = 'ui-state-hover'; 3025 this.cfg.forcePlaceholderSize = true; 3026 this.cfg.revert=false; 3027 this.cfg.handle='.ui-panel-titlebar'; 3028 3029 var $this = this; 3030 3031 if(this.hasBehavior('reorder')) { 3032 this.cfg.update = function(e, ui) { 3033 if(this === ui.item.parent()[0]) { 3034 var itemIndex = ui.item.parent().children().filter(':not(script):visible').index(ui.item), 3035 receiverColumnIndex = ui.item.parent().parent().children().index(ui.item.parent()); 3036 3037 var ext = { 3038 params: [ 3039 {name: $this.id + '_reordered', value: true}, 3040 {name: $this.id + '_widgetId', value: ui.item.attr('id')}, 3041 {name: $this.id + '_itemIndex', value: itemIndex}, 3042 {name: $this.id + '_receiverColumnIndex', value: receiverColumnIndex} 3043 ] 3044 }; 3045 3046 if(ui.sender) { 3047 ext.params.push({name: $this.id + '_senderColumnIndex', value: ui.sender.parent().children().index(ui.sender)}); 3048 } 3049 3050 $this.callBehavior('reorder', ext); 3051 } 3052 }; 3053 } 3054 3055 $(this.jqId + ' .ui-dashboard-column').sortable(this.cfg); 3056 } 3057 3058}); 3059/** 3060 * PrimeFaces DataGrid Widget 3061 */ 3062PrimeFaces.widget.DataGrid = PrimeFaces.widget.BaseWidget.extend({ 3063 3064 init: function(cfg) { 3065 this._super(cfg); 3066 3067 this.cfg.formId = $(this.jqId).closest('form').attr('id'); 3068 this.content = $(this.jqId + '_content'); 3069 3070 if(this.cfg.paginator) { 3071 this.setupPaginator(); 3072 } 3073 }, 3074 3075 setupPaginator: function() { 3076 var $this = this; 3077 this.cfg.paginator.paginate = function(newState) { 3078 $this.handlePagination(newState); 3079 }; 3080 3081 this.paginator = new PrimeFaces.widget.Paginator(this.cfg.paginator); 3082 }, 3083 3084 handlePagination: function(newState) { 3085 var $this = this, 3086 options = { 3087 source: this.id, 3088 update: this.id, 3089 process: this.id, 3090 formId: this.cfg.formId, 3091 params: [ 3092 {name: this.id + '_pagination', value: true}, 3093 {name: this.id + '_skipChildren', value: true}, 3094 {name: this.id + '_first', value: newState.first}, 3095 {name: this.id + '_rows', value: newState.rows} 3096 ], 3097 onsuccess: function(responseXML, status, xhr) { 3098 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 3099 widget: $this, 3100 handle: function(content) { 3101 this.content.html(content); 3102 } 3103 }); 3104 3105 return true; 3106 }, 3107 oncomplete: function() { 3108 $this.paginator.cfg.page = newState.page; 3109 $this.paginator.updateUI(); 3110 } 3111 }; 3112 3113 if(this.hasBehavior('page')) { 3114 this.callBehavior('page', options); 3115 } 3116 else { 3117 PrimeFaces.ajax.Request.handle(options); 3118 } 3119 }, 3120 3121 getPaginator: function() { 3122 return this.paginator; 3123 } 3124 3125}); 3126/** 3127 * PrimeFaces DataList Widget 3128 */ 3129PrimeFaces.widget.DataList = PrimeFaces.widget.BaseWidget.extend({ 3130 3131 init: function(cfg) { 3132 this._super(cfg); 3133 3134 this.cfg.formId = $(this.jqId).parents('form:first').attr('id'); 3135 this.content = $(this.jqId + '_content'); 3136 3137 if(this.cfg.paginator) { 3138 this.setupPaginator(); 3139 } 3140 }, 3141 3142 setupPaginator: function() { 3143 var $this = this; 3144 this.cfg.paginator.paginate = function(newState) { 3145 $this.handlePagination(newState); 3146 }; 3147 3148 this.paginator = new PrimeFaces.widget.Paginator(this.cfg.paginator); 3149 }, 3150 3151 handlePagination: function(newState) { 3152 var $this = this, 3153 options = { 3154 source: this.id, 3155 update: this.id, 3156 process: this.id, 3157 formId: this.cfg.formId, 3158 params: [ 3159 {name: this.id + '_pagination', value: true}, 3160 {name: this.id + '_skipChildren', value: true}, 3161 {name: this.id + '_first', value: newState.first}, 3162 {name: this.id + '_rows', value: newState.rows} 3163 ], 3164 onsuccess: function(responseXML, status, xhr) { 3165 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 3166 widget: $this, 3167 handle: function(content) { 3168 this.content.html(content); 3169 } 3170 }); 3171 3172 return true; 3173 }, 3174 oncomplete: function() { 3175 $this.paginator.cfg.page = newState.page; 3176 $this.paginator.updateUI(); 3177 } 3178 }; 3179 3180 if(this.hasBehavior('page')) { 3181 this.callBehavior('page', options); 3182 } 3183 else { 3184 PrimeFaces.ajax.Request.handle(options); 3185 } 3186 }, 3187 3188 getPaginator: function() { 3189 return this.paginator; 3190 } 3191 3192}); 3193/** 3194 * PrimeFaces DataScroller Widget 3195 */ 3196PrimeFaces.widget.DataScroller = PrimeFaces.widget.BaseWidget.extend({ 3197 3198 init: function(cfg) { 3199 this._super(cfg); 3200 this.content = this.jq.children('div.ui-datascroller-content'); 3201 this.list = this.cfg.virtualScroll ? this.content.children('div').children('ul') : this.content.children('ul'); 3202 this.loaderContainer = this.content.children('div.ui-datascroller-loader'); 3203 this.loadStatus = $('<div class="ui-datascroller-loading"></div>'); 3204 this.loading = false;
3205 this.allLoaded = false; 3206 this.cfg.offset = 0; 3207 this.cfg.mode = this.cfg.mode||'document'; 3208 this.cfg.buffer = (100 - this.cfg.buffer) / 100; 3209 3210 if(this.cfg.loadEvent === 'scroll') { 3211 this.bindScrollListener(); 3212 } 3213 else { 3214 this.loadTrigger = this.loaderContainer.children(); 3215 this.bindManualLoader(); 3216 } 3217 }, 3218 3219 bindScrollListener: function() { 3220 var $this = this; 3221 3222 if(this.cfg.mode === 'document') { 3223 var win = $(window), 3224 doc = $(document), 3225 $this = this; 3226 3227 PrimeFaces.utils.registerScrollHandler(this, 'scroll.' + this.id + '_align', function() { 3228 if (win.scrollTop() >= ((doc.height() * $this.cfg.buffer) - win.height()) && $this.shouldLoad()) { 3229 $this.load(); 3230 } 3231 }); 3232 } 3233 else { 3234 this.itemHeight = 0; 3235 3236 if(this.cfg.virtualScroll) { 3237 var item = this.list.children('li.ui-datascroller-item'); 3238 if(item) { 3239 this.itemHeight = item.outerHeight(); 3240 this.content.children('div').css('min-height', parseFloat((this.cfg.totalSize * this.itemHeight) + 'px')); 3241 } 3242 3243 if (this.cfg.startAtBottom) { 3244 var pageHeight = this.itemHeight * this.cfg.chunkSize, 3245 virtualListHeight = parseFloat(this.cfg.totalSize * this.itemHeight), 3246 viewportHeight = this.content.height(), 3247 pageCount = Math.floor(virtualListHeight / pageHeight)||1, 3248 page = (this.cfg.totalSize % this.cfg.chunkSize) == 0 ? pageCount - 2 : pageCount - 1, 3249 top = (virtualListHeight < viewportHeight) ? (viewportHeight - virtualListHeight) : (Math.max(page, 0) * pageHeight); 3250 3251 this.list.css('top', top); 3252 this.content.scrollTop(this.content[0].scrollHeight); 3253 } 3254 } 3255 else if (this.cfg.startAtBottom) { 3256 this.content.scrollTop(this.content[0].scrollHeight); 3257 this.cfg.offset = this.cfg.totalSize > this.cfg.chunkSize ? this.cfg.totalSize - this.cfg.chunkSize : this.cfg.totalSize; 3258 3259 var paddingTop = ''; 3260 if (this.content.height() > this.list.height()) { 3261 paddingTop = (this.getInnerContentHeight() - this.list.outerHeight() - this.loaderContainer.outerHeight()); 3262 } 3263 3264 this.list.css('padding-top', paddingTop); 3265 } 3266 3267 this.content.on('scroll', function () { 3268 if($this.cfg.virtualScroll) { 3269 var virtualScrollContent = this; 3270 3271 clearTimeout($this.scrollTimeout); 3272 $this.scrollTimeout = setTimeout(function() { 3273 var viewportHeight = $this.content.outerHeight(), 3274 listHeight = $this.list.outerHeight() + Math.ceil(viewportHeight - $this.content.height()), 3275 pageHeight = $this.itemHeight * $this.cfg.chunkSize, 3276 virtualListHeight = parseFloat($this.cfg.totalSize * $this.itemHeight), 3277 pageCount = (virtualListHeight / pageHeight)||1; 3278 3279 if(virtualScrollContent.scrollTop + viewportHeight > parseFloat($this.list.css('top')) + listHeight || virtualScrollContent.scrollTop < parseFloat($this.list.css('top'))) { 3280 var page = Math.floor((virtualScrollContent.scrollTop * pageCount) / (virtualScrollContent.scrollHeight)) + 1; 3281 $this.loadRowsWithVirtualScroll(page, function () { 3282 $this.list.css('top', ((page - 1) * pageHeight) + 'px'); 3283 }); 3284 } 3285 }, 200); 3286 } 3287 else { 3288 var scrollTop = this.scrollTop, 3289 scrollHeight = this.scrollHeight,
3290 viewportHeight = this.clientHeight, 3291 shouldLoad = $this.shouldLoad() && ($this.cfg.startAtBottom ? 3292 (scrollTop <= (scrollHeight - (scrollHeight * $this.cfg.buffer))) && ($this.cfg.totalSize > $this.cfg.chunkSize) 3293 : 3294 (scrollTop >= ((scrollHeight * $this.cfg.buffer) - viewportHeight))); 3295 if (shouldLoad) { 3296 $this.load(); 3297 } 3298 } 3299 }); 3300 } 3301 }, 3302 3303 loadRowsWithVirtualScroll: function(page, callback) { 3304 if(this.virtualScrollActive) { 3305 return; 3306 } 3307 3308 this.virtualScrollActive = true; 3309 3310 var $this = this, 3311 first = (page - 1) * this.cfg.chunkSize, 3312 options = { 3313 source: this.id, 3314 process: this.id, 3315 update: this.id, 3316 formId: this.cfg.formId, 3317 params: [{name: this.id + '_virtualScrolling', value: true}, 3318 {name: this.id + '_first', value: first}], 3319 onsuccess: function(responseXML, status, xhr) { 3320 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 3321 widget: $this, 3322 handle: function(content) { 3323 //insert new rows 3324 this.updateData(content); 3325 callback(); 3326 this.virtualScrollActive = false; 3327 } 3328 }); 3329 3330 return true; 3331 }, 3332 oncomplete: function(xhr, status, args) { 3333 if(typeof args.totalSize !== 'undefined') { 3334 $this.cfg.totalSize = args.totalSize; 3335 } 3336 } 3337 }; 3338 3339 PrimeFaces.ajax.Request.handle(options); 3340 }, 3341 3342 updateData: function(data, clear, pre) { 3343 var empty = (clear === undefined) ? true: clear; 3344 3345 if(empty) 3346 this.list.html(data); 3347 else if (pre) 3348 this.list.prepend(data); 3349 else 3350 this.list.append(data); 3351 }, 3352 3353 bindManualLoader: function() { 3354 var $this = this; 3355 3356 this.loadTrigger.on('click.dataScroller', function(e) { 3357 $this.load(); 3358 e.preventDefault(); 3359 }); 3360 }, 3361 3362 load: function() { 3363 this.loading = true; 3364 this.cfg.offset += (this.cfg.chunkSize * (this.cfg.startAtBottom ? -1 : 1)); 3365 3366 this.loadStatus.appendTo(this.loaderContainer); 3367 if(this.loadTrigger) { 3368 this.loadTrigger.hide(); 3369 } 3370 3371 var $this = this, 3372 options = { 3373 source: this.id, 3374 process: this.id, 3375 update: this.id, 3376 global: false, 3377 params: [{name: this.id + '_load', value: true},{name: this.id + '_offset', value: this.cfg.offset}], 3378 onsuccess: function(responseXML, status, xhr) { 3379 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 3380 widget: $this, 3381 handle: function(content) { 3382 this.updateData(content, false, $this.cfg.startAtBottom); 3383 } 3384 }); 3385 3386 return true; 3387 }, 3388 oncomplete: function() { 3389 if ($this.cfg.offset < 0) { 3390 $this.cfg.offset = 0; 3391 } 3392 3393 $this.loading = false; 3394 $this.allLoaded = ($this.cfg.startAtBottom) ? $this.cfg.offset == 0 : ($this.cfg.offset + $this.cfg.chunkSize) >= $this.cfg.totalSize; 3395 3396 $this.loadStatus.remove(); 3397 3398 if($this.loadTrigger && !$this.allLoaded) { 3399 $this.loadTrigger.show(); 3400 } 3401 } 3402 }; 3403 3404 PrimeFaces.ajax.Request.handle(options); 3405 }, 3406 3407 shouldLoad: function() { 3408 return (!this.loading && !this.allLoaded); 3409 }, 3410 3411 getInnerContentHeight: function() { 3412 return (this.content.innerHeight() - parseFloat(this.content.css('padding-top')) - parseFloat(this.content.css('padding-bottom'))); 3413 } 3414 3415}); 3416/** 3417 * PrimeFaces DataTable Widget 3418 */ 3419PrimeFaces.widget.DataTable = PrimeFaces.widget.DeferredWidget.extend({ 3420 3421 SORT_ORDER: { 3422 ASCENDING: 1, 3423 DESCENDING: -1, 3424 UNSORTED: 0 3425 }, 3426 3427 init: function(cfg) { 3428 this._super(cfg); 3429 3430 this.thead = this.getThead(); 3431 this.tbody = this.getTbody(); 3432 this.tfoot = this.getTfoot(); 3433 3434 if(this.cfg.paginator) { 3435 this.bindPaginator(); 3436 } 3437 3438 this.bindSortEvents(); 3439 3440 if(this.cfg.rowHover) { 3441 this.setupRowHover(); 3442 } 3443 3444 if(this.cfg.selectionMode) { 3445 this.setupSelection(); 3446 } 3447 3448 if(this.cfg.filter) { 3449 this.setupFiltering(); 3450 } 3451 3452 if(this.cfg.expansion) { 3453 this.expansionProcess = []; 3454 this.bindExpansionEvents(); 3455 } 3456 3457 if(this.cfg.editable) { 3458 this.bindEditEvents(); 3459 } 3460 3461 if(this.cfg.draggableRows) { 3462 this.makeRowsDraggable(); 3463 } 3464 3465 if(this.cfg.reflow) { 3466 this.initReflow(); 3467 } 3468 3469 if(this.cfg.multiViewState && this.cfg.resizableColumns) { 3470 this.resizableStateHolder = $(this.jqId + '_resizableColumnState'); 3471 this.resizableState = []; 3472 3473 if(this.resizableStateHolder.attr('value')) { 3474 this.resizableState = this.resizableStateHolder.val().split(','); 3475 } 3476 } 3477 3478 this.updateEmptyColspan(); 3479 this.renderDeferred(); 3480 }, 3481 3482 _render: function() { 3483 this.isRTL = this.jq.hasClass('ui-datatable-rtl'); 3484 this.cfg.partialUpdate = (this.cfg.partialUpdate === false) ? false : true; 3485 3486 if(this.cfg.scrollable) { 3487 this.setupScrolling(); 3488 } 3489 3490 if(this.cfg.groupColumnIndexes) { 3491 this.groupRows(); 3492 this.bindToggleRowGroupEvents(); 3493 } 3494 3495 if(this.cfg.resizableColumns) { 3496 this.setupResizableColumns(); 3497 } 3498 3499 if(this.cfg.draggableColumns) { 3500 this.setupDraggableColumns(); 3501 } 3502 3503 if(this.cfg.stickyHeader) { 3504 this.setupStickyHeader(); 3505 } 3506 3507 if(this.cfg.onRowClick) { 3508 this.bindRowClick(); 3509 } 3510 3511 if(this.cfg.expansion) { 3512 this.updateExpandedRowsColspan(); 3513 } 3514 }, 3515 3516 getThead: function() { 3517 return $(this.jqId + '_head'); 3518 }, 3519 3520 getTbody: function() { 3521 return $(this.jqId + '_data'); 3522 }, 3523 3524 getTfoot: function() { 3525 return $(this.jqId + '_foot'); 3526 }, 3527 3528 updateData: function(data, clear) { 3529 var empty = (clear === undefined) ? true: clear; 3530 3531 if(empty) 3532 this.tbody.html(data); 3533 else 3534 this.tbody.append(data); 3535 3536 this.postUpdateData(); 3537 }, 3538 3539 postUpdateData: function() { 3540 if(this.cfg.draggableRows) { 3541 this.makeRowsDraggable(); 3542 } 3543 3544 if(this.cfg.reflow) { 3545 this.initReflow(); 3546 } 3547 3548 if(this.cfg.groupColumnIndexes) { 3549 this.groupRows(); 3550 this.bindToggleRowGroupEvents(); 3551 } 3552 }, 3553 3554 //@override 3555 refresh: function(cfg) { 3556 this.columnWidthsFixed = false;
3557 this.ignoreRowHoverEvent = false; 3558 3559 this.unbindEvents(); 3560 3561 this._super(cfg); 3562 }, 3563 3564 /** 3565 * Unbinds events needed if refreshing to prevent multiple sort and pagination events. 3566 */ 3567 unbindEvents: function() { 3568 if (this.sortableColumns) { 3569 this.sortableColumns.off(); 3570 } 3571 if (this.paginator) { 3572 this.paginator.unbindEvents(); 3573 } 3574 }, 3575 3576 /** 3577 * Binds the change event listener and renders the paginator 3578 */ 3579 bindPaginator: function() { 3580 var _self = this; 3581 this.cfg.paginator.paginate = function(newState) { 3582 if(_self.cfg.clientCache) { 3583 _self.loadDataWithCache(newState); 3584 } 3585 else { 3586 _self.paginate(newState); 3587 } 3588 }; 3589 3590 this.paginator = new PrimeFaces.widget.Paginator(this.cfg.paginator); 3591 this.paginator.bindSwipeEvents(this.jq); 3592 3593 3594 if(this.cfg.clientCache) { 3595 this.cacheRows = this.paginator.getRows(); 3596 var newState = { 3597 first: this.paginator.getFirst(), 3598 rows: this.paginator.getRows(), 3599 page: this.paginator.getCurrentPage() 3600 }; 3601 this.clearCacheMap(); 3602 this.fetchNextPage(newState); 3603 } 3604 }, 3605 3606 /** 3607 * Applies events related to sorting in a non-obstrusive way 3608 */ 3609 bindSortEvents: function() { 3610 var $this = this, 3611 hasAriaSort = false; 3612 this.cfg.tabindex = this.cfg.tabindex||'0'; 3613 this.headers = this.thead.find('> tr > th'); 3614 this.sortableColumns = this.headers.filter('.ui-sortable-column'); 3615 this.sortableColumns.attr('tabindex', this.cfg.tabindex); 3616 3617 //aria messages 3618 this.ascMessage = PrimeFaces.getAriaLabel('datatable.sort.ASC'); 3619 this.descMessage = PrimeFaces.getAriaLabel('datatable.sort.DESC'); 3620 3621 //reflow dropdown 3622 this.reflowDD = $(this.jqId + '_reflowDD'); 3623 3624 if(this.cfg.multiSort) { 3625 this.sortMeta = []; 3626 } 3627 3628 for(var i = 0; i < this.sortableColumns.length; i++) { 3629 var columnHeader = this.sortableColumns.eq(i), 3630 columnHeaderId = columnHeader.attr('id'), 3631 sortIcon = columnHeader.children('span.ui-sortable-column-icon'), 3632 sortOrder = null, 3633 resolvedSortMetaIndex = null, 3634 ariaLabel = columnHeader.attr('aria-label'); 3635 3636 if(columnHeader.hasClass('ui-state-active')) { 3637 if(sortIcon.hasClass('ui-icon-triangle-1-n')) { 3638 sortOrder = this.SORT_ORDER.ASCENDING; 3639 columnHeader.attr('aria-label', this.getSortMessage(ariaLabel, this.descMessage)); 3640 if(!hasAriaSort) { 3641 columnHeader.attr('aria-sort', 'ascending'); 3642 hasAriaSort = true; 3643 } 3644 } 3645 else { 3646 sortOrder = this.SORT_ORDER.DESCENDING; 3647 columnHeader.attr('aria-label', this.getSortMessage(ariaLabel, this.ascMessage)); 3648 if(!hasAriaSort) { 3649 columnHeader.attr('aria-sort', 'descending'); 3650 hasAriaSort = true; 3651 } 3652 } 3653 3654 if (this.cfg.multiSort && this.cfg.sortMetaOrder) { 3655 resolvedSortMetaIndex = $.inArray(columnHeaderId, this.cfg.sortMetaOrder); 3656 3657 this.sortMeta[resolvedSortMetaIndex] = { 3658 col: columnHeaderId, 3659 order: sortOrder 3660 }; 3661 } 3662 3663 $this.updateReflowDD(columnHeader, sortOrder); 3664 } 3665 else { 3666 sortOrder = this.SORT_ORDER.UNSORTED; 3667 columnHeader.attr('aria-label', this.getSortMessage(ariaLabel, this.ascMessage)); 3668 if(!hasAriaSort && i == (this.sortableColumns.length - 1)) { 3669 this.sortableColumns.eq(0).attr('aria-sort', 'other'); 3670 hasAriaSort = true; 3671 } 3672 } 3673 3674 columnHeader.data('sortorder', sortOrder); 3675 } 3676 3677 this.sortableColumns.on('mouseenter.dataTable', function() { 3678 var column = $(this); 3679 3680 if(!column.hasClass('ui-state-active')) 3681 column.addClass('ui-state-hover'); 3682 }) 3683 .on('mouseleave.dataTable', function() { 3684 var column = $(this); 3685 3686 if(!column.hasClass('ui-state-active')) 3687 column.removeClass('ui-state-hover'); 3688 }) 3689 .on('blur.dataTable', function() { 3690 $(this).removeClass('ui-state-focus'); 3691 }) 3692 .on('focus.dataTable', function() { 3693 $(this).addClass('ui-state-focus'); 3694 }) 3695 .on('keydown.dataTable', function(e) { 3696 var key = e.which, 3697 keyCode = $.ui.keyCode; 3698 3699 if((key === keyCode.ENTER) && $(e.target).is(':not(:input)')) { 3700 $(this).trigger('click.dataTable', (e.metaKey||e.ctrlKey)); 3701 e.preventDefault(); 3702 } 3703 }) 3704 .on('click.dataTable', function(e, metaKeyOn) { 3705 if(!$this.shouldSort(e, this)) { 3706 return; 3707 } 3708 3709 PrimeFaces.clearSelection(); 3710 3711 var columnHeader = $(this), 3712 sortOrderData = columnHeader.data('sortorder'), 3713 sortOrder = (sortOrderData === $this.SORT_ORDER.UNSORTED) ? $this.SORT_ORDER.ASCENDING : -1 * sortOrderData, 3714 metaKey = e.metaKey||e.ctrlKey||metaKeyOn; 3715 3716 if($this.cfg.multiSort) { 3717 if(metaKey) { 3718 $this.addSortMeta({ 3719 col: columnHeader.attr('id'), 3720 order: sortOrder 3721 }); 3722 $this.sort(columnHeader, sortOrder, true); 3723 } 3724 else { 3725 $this.sortMeta = []; 3726 $this.addSortMeta({ 3727 col: columnHeader.attr('id'), 3728 order: sortOrder 3729 }); 3730 $this.sort(columnHeader, sortOrder); 3731 } 3732 } 3733 else { 3734 $this.sort(columnHeader, sortOrder); 3735 } 3736 3737 if($this.cfg.scrollable) { 3738 $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).trigger('focus'); 3739 } 3740 3741 $this.updateReflowDD(columnHeader, sortOrder); 3742 }); 3743 3744 if(this.reflowDD && this.cfg.reflow) { 3745 PrimeFaces.skinSelect(this.reflowDD); 3746 this.reflowDD.change(function(e) { 3747 var arrVal = $(this).val().split('_'), 3748 columnHeader = $this.sortableColumns.eq(parseInt(arrVal[0])), 3749 sortOrder = parseInt(arrVal[1]); 3750 3751 columnHeader.data('sortorder', sortOrder); 3752 columnHeader.trigger('click.dataTable'); 3753 }); 3754 } 3755 }, 3756 3757 getSortMessage: function(ariaLabel, sortOrderMessage) { 3758 var headerName = ariaLabel ? ariaLabel.split(':')[0] : ''; 3759 return headerName + ': ' + sortOrderMessage; 3760 }, 3761 3762 shouldSort: function(event, column) { 3763 if(this.isEmpty()) { 3764 return false;
3765 } 3766 3767 var target = $(event.target); 3768 if(target.closest('.ui-column-customfilter', column).length) { 3769 return false; 3770 } 3771 3772 return target.is('th,span'); 3773 }, 3774 3775 addSortMeta: function(meta) { 3776 this.sortMeta = $.grep(this.sortMeta, function(value) { 3777 return value.col !== meta.col; 3778 }); 3779 3780 this.sortMeta.push(meta); 3781 }, 3782 3783 /** 3784 * Binds filter events to standard filters 3785 */ 3786 setupFiltering: function() { 3787 var $this = this, 3788 filterColumns = this.thead.find('> tr > th.ui-filter-column'); 3789 this.cfg.filterEvent = this.cfg.filterEvent||'keyup'; 3790 this.cfg.filterDelay = this.cfg.filterDelay||300; 3791 3792 filterColumns.children('.ui-column-filter').each(function() { 3793 var filter = $(this); 3794 3795 if(filter.is('input:text')) { 3796 PrimeFaces.skinInput(filter); 3797 $this.bindTextFilter(filter); 3798 } 3799 else { 3800 PrimeFaces.skinSelect(filter); 3801 $this.bindChangeFilter(filter); 3802 } 3803 }); 3804 }, 3805 3806 bindTextFilter: function(filter) { 3807 if(this.cfg.filterEvent === 'enter') 3808 this.bindEnterKeyFilter(filter); 3809 else 3810 this.bindFilterEvent(filter); 3811 }, 3812 3813 bindChangeFilter: function(filter) { 3814 var $this = this; 3815 3816 filter.off('change') 3817 .on('change', function() { 3818 $this.filter(); 3819 }); 3820 }, 3821 3822 bindEnterKeyFilter: function(filter) { 3823 var $this = this; 3824 3825 filter.off('keydown keyup') 3826 .on('keydown', PrimeFaces.utils.blockEnterKey) 3827 .on('keyup', function(e) { 3828 var key = e.which, 3829 keyCode = $.ui.keyCode; 3830 3831 if((key === keyCode.ENTER)) { 3832 $this.filter(); 3833 3834 e.preventDefault(); 3835 } 3836 }); 3837 }, 3838 3839 bindFilterEvent: function(filter) { 3840 var $this = this; 3841 var filterEventName = this.cfg.filterEvent + '.dataTable'; 3842 3843 //prevent form submit on enter key 3844 filter.off('keydown.dataTable-blockenter ' + filterEventName) 3845 .on('keydown.dataTable-blockenter', PrimeFaces.utils.blockEnterKey) 3846 .on(filterEventName, function(e) { 3847 if (PrimeFaces.utils.ignoreFilterKey(e)) { 3848 return; 3849 } 3850 3851 if($this.filterTimeout) { 3852 clearTimeout($this.filterTimeout); 3853 } 3854 3855 $this.filterTimeout = setTimeout(function() { 3856 $this.filter(); 3857 $this.filterTimeout = null; 3858 }, 3859 $this.cfg.filterDelay); 3860 }); 3861 3862 // #89 IE clear "x" button 3863 if (PrimeFaces.env.isIE()) { 3864 filter.off('mouseup.dataTable').on('mouseup.dataTable', function(e) { 3865 var input = $(this), 3866 oldValue = input.val(); 3867 3868 if(oldValue == "") { 3869 return; 3870 } 3871 3872 setTimeout(function() { 3873 var newValue = input.val(); 3874 if(newValue == "") { 3875 $this.filter(); 3876 } 3877 }, 1); 3878 }); 3879 } 3880 }, 3881 3882 setupRowHover: function() { 3883 var selector = '> tr.ui-widget-content'; 3884 if(!this.cfg.selectionMode || this.cfg.selectionMode === 'checkbox') { 3885 this.bindRowHover(selector); 3886 } 3887 }, 3888 3889 setupSelection: function() { 3890 this.selectionHolder = this.jqId + '_selection'; 3891 this.cfg.rowSelectMode = this.cfg.rowSelectMode||'new'; 3892 this.rowSelector = '> tr.ui-widget-content.ui-datatable-selectable'; 3893 this.cfg.disabledTextSelection = this.cfg.disabledTextSelection === false ? false : true; 3894 this.cfg.selectionPageOnly = this.cfg.selectionPageOnly !== false; 3895 this.rowSelectorForRowClick = this.cfg.rowSelector||'td:not(.ui-column-unselectable):not(.ui-grouped-column),span:not(.ui-c)'; 3896 3897 var preselection = $(this.selectionHolder).val(); 3898 this.selection = (preselection === "") ? [] : preselection.split(','); 3899 3900 //shift key based range selection 3901 this.originRowIndex = null; 3902 this.cursorIndex = null; 3903 3904 this.bindSelectionEvents(); 3905 }, 3906 3907 /** 3908 * Applies events related to selection in a non-obstrusive way 3909 */ 3910 bindSelectionEvents: function() { 3911 if(this.cfg.selectionMode === 'radio') { 3912 this.bindRadioEvents(); 3913 } 3914 else if(this.cfg.selectionMode === 'checkbox') { 3915 this.bindCheckboxEvents(); 3916 this.updateHeaderCheckbox(); 3917 3918 if(this.cfg.rowSelectMode !== 'checkbox') { 3919 this.bindRowEvents(); 3920 } 3921 } 3922 else { 3923 this.bindRowEvents(); 3924 } 3925 }, 3926 3927 bindRowEvents: function() { 3928 var $this = this; 3929 3930 this.bindRowHover(this.rowSelector); 3931 3932 this.tbody.off('click.dataTable mousedown.dataTable', this.rowSelector).on('mousedown.dataTable', this.rowSelector, null, function(e) { 3933 $this.mousedownOnRow = true; 3934 }) 3935 .on('click.dataTable', this.rowSelector, null, function(e) { 3936 $this.onRowClick(e, this); 3937 $this.mousedownOnRow = false;
3938 }); 3939 3940 //double click 3941 if(this.hasBehavior('rowDblselect')) { 3942 this.tbody.off('dblclick.dataTable', this.rowSelector).on('dblclick.dataTable', this.rowSelector, null, function(e) { 3943 $this.onRowDblclick(e, $(this)); 3944 }); 3945 }; 3946 3947 this.bindSelectionKeyEvents(); 3948 }, 3949 3950 bindSelectionKeyEvents: function() { 3951 var $this = this; 3952 3953 this.getFocusableTbody().on('focus', function(e) { 3954 //ignore mouse click on row 3955 if(!$this.mousedownOnRow) { 3956 $this.focusedRow = $this.tbody.children('tr.ui-widget-content.ui-datatable-selectable.ui-state-highlight').eq(0); 3957 if ($this.focusedRow.length == 0) { 3958 $this.focusedRow = $this.tbody.children('tr.ui-widget-content.ui-datatable-selectable').eq(0); 3959 } 3960 3961 $this.highlightFocusedRow(); 3962 3963 if($this.cfg.scrollable) { 3964 PrimeFaces.scrollInView($this.scrollBody, $this.focusedRow); 3965 } 3966 } 3967 }) 3968 .on('blur', function() { 3969 if($this.focusedRow) { 3970 $this.unhighlightFocusedRow(); 3971 $this.focusedRow = null; 3972 } 3973 }) 3974 .on('keydown', function(e) { 3975 var keyCode = $.ui.keyCode, 3976 key = e.which; 3977 3978 if($(e.target).is(':input')) { 3979 return; 3980 } 3981 3982 if($this.focusedRow) { 3983 switch(key) { 3984 case keyCode.UP: 3985 case keyCode.DOWN: 3986 var rowSelector = 'tr.ui-widget-content.ui-datatable-selectable', 3987 row = key === keyCode.UP ? $this.focusedRow.prev(rowSelector) : $this.focusedRow.next(rowSelector); 3988 3989 if(row.length) { 3990 $this.unhighlightFocusedRow(); 3991 3992 if($this.isCheckboxSelectionEnabled()) { 3993 row.find('> td.ui-selection-column .ui-chkbox input').focus(); 3994 } 3995 else { 3996 $this.focusedRow = row; 3997 } 3998 3999 $this.highlightFocusedRow(); 4000 4001 if($this.cfg.scrollable) { 4002 PrimeFaces.scrollInView($this.scrollBody, $this.focusedRow); 4003 } 4004 } 4005 e.preventDefault(); 4006 break; 4007 4008 case keyCode.ENTER: 4009 case keyCode.SPACE: 4010 if($this.focusedRowWithCheckbox) { 4011 $this.focusedRow.find('> td.ui-selection-column .ui-chkbox .ui-chkbox-box').trigger('click.dataTable'); 4012 } 4013 else { 4014 e.target = $this.focusedRow.children().eq(0).get(0); 4015 $this.onRowClick(e,$this.focusedRow.get(0)); 4016 } 4017 4018 e.preventDefault(); 4019 break; 4020 4021 default: 4022 break; 4023 }; 4024 } 4025 }); 4026 4027 }, 4028 4029 highlightFocusedRow: function() { 4030 this.focusedRow.addClass('ui-state-hover'); 4031 }, 4032 4033 unhighlightFocusedRow: function() { 4034 this.focusedRow.removeClass('ui-state-hover'); 4035 }, 4036 4037 assignFocusedRow: function(row) { 4038 this.focusedRow = row; 4039 }, 4040 4041 bindRowHover: function(rowSelector) { 4042 var $this = this; 4043 this.tbody.off('mouseenter.dataTable mouseleave.dataTable', rowSelector) 4044 .on('mouseenter.dataTable', rowSelector, null, function() { 4045 var element = $(this); 4046 if (!$this.ignoreRowHoverEvent && !element.hasClass('ui-state-highlight')) { 4047 $(this).addClass('ui-state-hover'); 4048 } 4049 }) 4050 .on('mouseleave.dataTable', rowSelector, null, function() { 4051 var element = $(this); 4052 if (!$this.ignoreRowHoverEvent && !element.hasClass('ui-state-highlight')) { 4053 $(this).removeClass('ui-state-hover'); 4054 } 4055 }); 4056 4057 if (this.cfg.groupColumnIndexes) { 4058 var columnSelector = rowSelector + ' > td'; 4059 this.tbody.off('mouseenter.dataTable mouseleave.dataTable', columnSelector) 4060 .on('mouseenter.dataTable', columnSelector, null, function() { 4061 var row = $(this).parent(); 4062 if ($(this).hasClass('ui-grouped-column')) { 4063 row.removeClass('ui-state-hover'); 4064 $this.ignoreRowHoverEvent = true; 4065 } 4066 else if (!row.hasClass('ui-state-highlight')) { 4067 row.addClass('ui-state-hover'); 4068 } 4069 }) 4070 .on('mouseleave.dataTable', columnSelector, null, function() { 4071 if (!$(this).hasClass('ui-grouped-column')) { 4072 $this.ignoreRowHoverEvent = false;
4073 } 4074 }); 4075 } 4076 }, 4077 4078 bindRadioEvents: function() { 4079 var $this = this, 4080 radioInputSelector = '> tr.ui-widget-content:not(.ui-datatable-empty-message) > td.ui-selection-column :radio'; 4081 4082 if(this.cfg.nativeElements) { 4083 this.tbody.off('click.dataTable', radioInputSelector).on('click.dataTable', radioInputSelector, null, function(e) { 4084 var radioButton = $(this); 4085 4086 if(!radioButton.prop('checked')) 4087 $this.selectRowWithRadio(radioButton); 4088 }); 4089 } 4090 else { 4091 var radioSelector = '> tr.ui-widget-content:not(.ui-datatable-empty-message) > td.ui-selection-column .ui-radiobutton .ui-radiobutton-box'; 4092 this.tbody.off('click.dataTable mouseover.dataTable mouseout.dataTable', radioSelector) 4093 .on('mouseover.dataTable', radioSelector, null, function() { 4094 var radio = $(this); 4095 if(!radio.hasClass('ui-state-disabled')&&!radio.hasClass('ui-state-active')) { 4096 radio.addClass('ui-state-hover'); 4097 } 4098 }) 4099 .on('mouseout.dataTable', radioSelector, null, function() { 4100 var radio = $(this); 4101 radio.removeClass('ui-state-hover'); 4102 }) 4103 .on('click.dataTable', radioSelector, null, function() { 4104 var radio = $(this), 4105 checked = radio.hasClass('ui-state-active'), 4106 disabled = radio.hasClass('ui-state-disabled'); 4107 4108 if(!disabled && !checked) { 4109 $this.selectRowWithRadio(radio); 4110 } 4111 }); 4112 } 4113 4114 //keyboard support 4115 this.tbody.off('focus.dataTable blur.dataTable change.dataTable', radioInputSelector) 4116 .on('focus.dataTable', radioInputSelector, null, function() { 4117 var input = $(this), 4118 box = input.parent().next(); 4119 4120 if(input.prop('checked')) { 4121 box.removeClass('ui-state-active'); 4122 } 4123 4124 box.addClass('ui-state-focus'); 4125 }) 4126 .on('blur.dataTable', radioInputSelector, null, function() { 4127 var input = $(this), 4128 box = input.parent().next(); 4129 4130 if(input.prop('checked')) { 4131 box.addClass('ui-state-active'); 4132 } 4133 4134 box.removeClass('ui-state-focus'); 4135 }) 4136 .on('change.dataTable', radioInputSelector, null, function() { 4137 var currentInput = $this.tbody.find(radioInputSelector).filter(':checked'), 4138 currentRadio = currentInput.parent().next(); 4139 4140 $this.selectRowWithRadio(currentRadio); 4141 }); 4142 4143 }, 4144 4145 bindCheckboxEvents: function() { 4146 var $this = this, 4147 checkboxInputSelector = '> tr.ui-widget-content.ui-datatable-selectable > td.ui-selection-column :checkbox'; 4148 4149 if(this.cfg.nativeElements) { 4150 this.checkAllToggler = this.thead.find('> tr > th.ui-selection-column > :checkbox'); 4151 this.checkAllTogglerInput = this.checkAllToggler; 4152 4153 this.checkAllToggler.on('click', function() { 4154 $this.toggleCheckAll(); 4155 }); 4156 4157 this.tbody.off('click.dataTable', checkboxInputSelector).on('click.dataTable', checkboxInputSelector, null, function(e) { 4158 var checkbox = $(this); 4159 4160 if(checkbox.prop('checked')) 4161 $this.selectRowWithCheckbox(checkbox); 4162 else 4163 $this.unselectRowWithCheckbox(checkbox); 4164 }); 4165 } 4166 else { 4167 this.checkAllToggler = this.thead.find('> tr > th.ui-selection-column > .ui-chkbox.ui-chkbox-all > .ui-chkbox-box'); 4168 this.checkAllTogglerInput = this.checkAllToggler.prev().children(':checkbox'); 4169 4170 this.checkAllToggler.on('mouseover', function() { 4171 var box = $(this); 4172 if(!box.hasClass('ui-state-disabled')&&!box.hasClass('ui-state-active')) { 4173 box.addClass('ui-state-hover'); 4174 } 4175 }) 4176 .on('mouseout', function() { 4177 $(this).removeClass('ui-state-hover'); 4178 }) 4179 .on('click', function() { 4180 var box = $(this); 4181 if(!box.hasClass('ui-state-disabled')) { 4182 $this.toggleCheckAll(); 4183 } 4184 }); 4185 4186 var checkboxSelector = '> tr.ui-widget-content.ui-datatable-selectable > td.ui-selection-column .ui-chkbox .ui-chkbox-box'; 4187 this.tbody.off('mouseover.dataTable mouseover.dataTable click.dataTable', checkboxSelector) 4188 .on('mouseover.dataTable', checkboxSelector, null, function() { 4189 var box = $(this); 4190 if(!box.hasClass('ui-state-active')) { 4191 box.addClass('ui-state-hover'); 4192 } 4193 }) 4194 .on('mouseout.dataTable', checkboxSelector, null, function() { 4195 $(this).removeClass('ui-state-hover'); 4196 }) 4197 .on('click.dataTable', checkboxSelector, null, function() { 4198 var checkbox = $(this), 4199 input = checkbox.prev().children('input'); 4200 4201 if(input.prop('checked')) 4202 $this.unselectRowWithCheckbox(checkbox); 4203 else 4204 $this.selectRowWithCheckbox(checkbox); 4205 }); 4206 } 4207 4208 //keyboard support 4209 this.tbody.off('focus.dataTable blur.dataTable change.dataTable', checkboxInputSelector) 4210 .on('focus.dataTable', checkboxInputSelector, null, function() { 4211 var input = $(this), 4212 box = input.parent().next(); 4213 4214 if(input.prop('checked')) { 4215 box.removeClass('ui-state-active'); 4216 } 4217 4218 box.addClass('ui-state-focus'); 4219 4220 $this.focusedRow = input.closest('.ui-datatable-selectable'); 4221 $this.focusedRowWithCheckbox = true; 4222 }) 4223 .on('blur.dataTable', checkboxInputSelector, null, function() { 4224 var input = $(this), 4225 box = input.parent().next(); 4226 4227 if(input.prop('checked')) { 4228 box.addClass('ui-state-active'); 4229 } 4230 4231 box.removeClass('ui-state-focus'); 4232 4233 $this.unhighlightFocusedRow(); 4234 $this.focusedRow = null; 4235 $this.focusedRowWithCheckbox = false;
4236 }) 4237 .on('change.dataTable', checkboxInputSelector, null, function(e) { 4238 var input = $(this), 4239 box = input.parent().next(); 4240 4241 if(input.prop('checked')) { 4242 $this.selectRowWithCheckbox(box); 4243 } 4244 else { 4245 $this.unselectRowWithCheckbox(box); 4246 } 4247 }); 4248 4249 this.checkAllTogglerInput.on('focus.dataTable', function(e) { 4250 var input = $(this), 4251 box = input.parent().next(); 4252 4253 if(!box.hasClass('ui-state-disabled')) { 4254 if(input.prop('checked')) { 4255 box.removeClass('ui-state-active'); 4256 } 4257 4258 box.addClass('ui-state-focus'); 4259 } 4260 }) 4261 .on('blur.dataTable', function(e) { 4262 var input = $(this), 4263 box = input.parent().next(); 4264 4265 if(input.prop('checked')) { 4266 box.addClass('ui-state-active'); 4267 } 4268 4269 box.removeClass('ui-state-focus'); 4270 }) 4271 .on('change.dataTable', function(e) { 4272 var input = $(this), 4273 box = input.parent().next(); 4274 4275 if(!box.hasClass('ui-state-disabled')) { 4276 if(!input.prop('checked')) { 4277 box.addClass('ui-state-active'); 4278 } 4279 4280 $this.toggleCheckAll(); 4281 4282 if(input.prop('checked')) { 4283 box.removeClass('ui-state-active').addClass('ui-state-focus'); 4284 } 4285 } 4286 }); 4287 }, 4288 4289 toggleRow: function(row) { 4290 if(row && !this.isRowTogglerClicked) { 4291 var toggler = row.find('> td > div.ui-row-toggler'); 4292 this.toggleExpansion(toggler); 4293 } 4294 this.isRowTogglerClicked = false; 4295 }, 4296 4297 /** 4298 * Applies events related to row expansion in a non-obstrusive way 4299 */ 4300 bindExpansionEvents: function() { 4301 var $this = this, 4302 togglerSelector = '> tr > td > div.ui-row-toggler'; 4303 4304 this.tbody.off('click.datatable-expansion', togglerSelector) 4305 .on('click.datatable-expansion', togglerSelector, null, function() { 4306 $this.isRowTogglerClicked = true; 4307 $this.toggleExpansion($(this)); 4308 }) 4309 .on('keydown.datatable-expansion', togglerSelector, null, function(e) { 4310 var key = e.which, 4311 keyCode = $.ui.keyCode; 4312 4313 if((key === keyCode.ENTER)) { 4314 $this.toggleExpansion($(this)); 4315 e.preventDefault(); 4316 } 4317 }); 4318 }, 4319 4320 bindContextMenu : function(menuWidget, targetWidget, targetId, cfg) { 4321 var $this = this; 4322 var targetSelector = targetId + ' tbody.ui-datatable-data > tr.ui-widget-content'; 4323 var targetEvent = cfg.event + '.datatable'; 4324 this.contextMenuWidget = menuWidget; 4325 4326 $(document).off(targetEvent, targetSelector).on(targetEvent, targetSelector, null, function(e) { 4327 var row = $(this); 4328 4329 if(targetWidget.cfg.selectionMode && row.hasClass('ui-datatable-selectable')) { 4330 targetWidget.onRowRightClick(e, this, cfg.selectionMode); 4331 4332 menuWidget.show(e); 4333 } 4334 else if(targetWidget.cfg.editMode === 'cell') { 4335 var target = $(e.target), 4336 cell = target.is('td.ui-editable-column') ? target : target.parents('td.ui-editable-column:first'); 4337 4338 if(targetWidget.contextMenuCell) { 4339 targetWidget.contextMenuCell.removeClass('ui-state-highlight'); 4340 } 4341 4342 targetWidget.contextMenuClick = true; 4343 targetWidget.contextMenuCell = cell; 4344 targetWidget.contextMenuCell.addClass('ui-state-highlight'); 4345 4346 menuWidget.show(e); 4347 } 4348 else if(row.hasClass('ui-datatable-empty-message') && !$this.cfg.disableContextMenuIfEmpty) { 4349 menuWidget.show(e); 4350 } 4351 }); 4352 4353 if(this.cfg.scrollable && this.scrollBody) { 4354 this.scrollBody.off('scroll.dataTable-contextmenu').on('scroll.dataTable-contextmenu', function() { 4355 if($this.contextMenuWidget.jq.is(':visible')) { 4356 $this.contextMenuWidget.hide(); 4357 } 4358 }); 4359 } 4360 }, 4361 4362 bindRowClick: function() { 4363 var $this = this, 4364 rowSelector = '> tr.ui-widget-content:not(.ui-expanded-row-content)'; 4365 this.tbody.off('click.dataTable-rowclick', rowSelector).on('click.dataTable-rowclick', rowSelector, null, function(e) { 4366 var target = $(e.target), 4367 row = target.is('tr.ui-widget-content') ? target : target.closest('tr.ui-widget-content'); 4368 4369 $this.cfg.onRowClick.call(this, row); 4370 }); 4371 }, 4372 4373 initReflow: function() { 4374 var headerColumns = this.thead.find('> tr > th'); 4375 4376 for(var i = 0; i < headerColumns.length; i++) { 4377 var headerColumn = headerColumns.eq(i), 4378 reflowHeaderText = headerColumn.find('.ui-reflow-headertext:first').text(), 4379 colTitleEl = headerColumn.children('.ui-column-title'), 4380 title = (reflowHeaderText && reflowHeaderText.length) ? reflowHeaderText : colTitleEl.text(); 4381 this.tbody.find('> tr:not(.ui-datatable-empty-message) > td:nth-child(' + (i + 1) + ')').prepend('<span class="ui-column-title">' + PrimeFaces.escapeHTML(title) + '</span>'); 4382 } 4383 }, 4384 4385 setupScrolling: function() { 4386 this.scrollHeader = this.jq.children('.ui-datatable-scrollable-header'); 4387 this.scrollBody = this.jq.children('.ui-datatable-scrollable-body'); 4388 this.scrollFooter = this.jq.children('.ui-datatable-scrollable-footer'); 4389 this.scrollStateHolder = $(this.jqId + '_scrollState'); 4390 this.scrollHeaderBox = this.scrollHeader.children('div.ui-datatable-scrollable-header-box'); 4391 this.scrollFooterBox = this.scrollFooter.children('div.ui-datatable-scrollable-footer-box'); 4392 this.headerTable = this.scrollHeaderBox.children('table'); 4393 this.bodyTable = this.cfg.virtualScroll ? this.scrollBody.children('div').children('table') : this.scrollBody.children('table'); 4394 this.footerTable = this.scrollFooter.children('table'); 4395 this.footerCols = this.scrollFooter.find('> .ui-datatable-scrollable-footer-box > table > tfoot > tr > td'); 4396 this.percentageScrollHeight = this.cfg.scrollHeight && (this.cfg.scrollHeight.indexOf('%') !== -1); 4397 this.percentageScrollWidth = this.cfg.scrollWidth && (this.cfg.scrollWidth.indexOf('%') !== -1); 4398 var $this = this,
4399 scrollBarWidth = this.getScrollbarWidth() + 'px', 4400 hScrollWidth = this.scrollBody[0].scrollWidth; 4401 4402 if(this.cfg.scrollHeight) { 4403 if(this.percentageScrollHeight) { 4404 this.adjustScrollHeight(); 4405 } 4406 4407 if(this.hasVerticalOverflow()) { 4408 this.scrollHeaderBox.css('margin-right', scrollBarWidth); 4409 this.scrollFooterBox.css('margin-right', scrollBarWidth); 4410 } 4411 } 4412 4413 this.fixColumnWidths(); 4414 4415 if(this.cfg.scrollWidth) { 4416 if(this.percentageScrollWidth) 4417 this.adjustScrollWidth(); 4418 else 4419 this.setScrollWidth(parseInt(this.cfg.scrollWidth)); 4420 } 4421 4422 this.cloneHead(); 4423 4424 this.restoreScrollState(); 4425 4426 if(this.cfg.liveScroll) { 4427 this.scrollOffset = 0; 4428 this.cfg.liveScrollBuffer = (100 - this.cfg.liveScrollBuffer) / 100; 4429 this.shouldLiveScroll = true; 4430 this.loadingLiveScroll = false; 4431 this.allLoadedLiveScroll = $this.cfg.scrollStep >= $this.cfg.scrollLimit; 4432 } 4433 4434 if(this.cfg.virtualScroll) { 4435 var row = this.bodyTable.children('tbody').children('tr.ui-widget-content'); 4436 if(row) { 4437 var hasEmptyMessage = row.eq(0).hasClass('ui-datatable-empty-message'), 4438 scrollLimit = $this.cfg.scrollLimit; 4439 4440 if(hasEmptyMessage) { 4441 scrollLimit = 1; 4442 $this.bodyTable.css('top', '0px'); 4443 } 4444 4445 this.rowHeight = row.outerHeight(); 4446 this.scrollBody.children('div').css('height', parseFloat((scrollLimit * this.rowHeight + 1) + 'px')); 4447 4448 if(hasEmptyMessage && this.cfg.scrollHeight && this.percentageScrollHeight) { 4449 setTimeout(function() { 4450 $this.adjustScrollHeight(); 4451 }, 10); 4452 } 4453 } 4454 } 4455 4456 this.scrollBody.on('scroll.dataTable', function() { 4457 var scrollLeft = $this.scrollBody.scrollLeft(); 4458 4459 if ($this.isRTL) { 4460 $this.scrollHeaderBox.css('margin-right', (scrollLeft - hScrollWidth + this.clientWidth)); 4461 $this.scrollFooterBox.css('margin-right', (scrollLeft - hScrollWidth + this.clientWidth)); 4462 } 4463 else { 4464 $this.scrollHeaderBox.css('margin-left', -scrollLeft); 4465 $this.scrollFooterBox.css('margin-left', -scrollLeft); 4466 } 4467 4468 if($this.isEmpty()) { 4469 return; 4470 } 4471 4472 if($this.cfg.virtualScroll) { 4473 var virtualScrollBody = this; 4474 4475 clearTimeout($this.scrollTimeout); 4476 $this.scrollTimeout = setTimeout(function() { 4477 var viewportHeight = $this.scrollBody.outerHeight(), 4478 tableHeight = $this.bodyTable.outerHeight(), 4479 pageHeight = $this.rowHeight * $this.cfg.scrollStep, 4480 virtualTableHeight = parseFloat(($this.cfg.scrollLimit * $this.rowHeight) + 'px'), 4481 pageCount = (virtualTableHeight / pageHeight)||1; 4482 4483 if(virtualScrollBody.scrollTop + viewportHeight > parseFloat($this.bodyTable.css('top')) + tableHeight || virtualScrollBody.scrollTop < parseFloat($this.bodyTable.css('top'))) { 4484 var page = Math.floor((virtualScrollBody.scrollTop * pageCount) / (virtualScrollBody.scrollHeight)) + 1; 4485 $this.loadRowsWithVirtualScroll(page, function () { 4486 $this.bodyTable.css('top', ((page - 1) * pageHeight) + 'px'); 4487 }); 4488 } 4489 }, 200); 4490 } 4491 else if($this.shouldLiveScroll) { 4492 var scrollTop = Math.ceil(this.scrollTop), 4493 scrollHeight = this.scrollHeight, 4494 viewportHeight = this.clientHeight; 4495 4496 if((scrollTop >
4496= ((scrollHeight * $this.cfg.liveScrollBuffer) - (viewportHeight))) && $this.shouldLoadLiveScroll()) { 4497 $this.loadLiveRows(); 4498 } 4499 } 4500 4501 $this.saveScrollState(); 4502 }); 4503 4504 this.scrollHeader.on('scroll.dataTable', function() { 4505 $this.scrollHeader.scrollLeft(0); 4506 }); 4507 4508 this.scrollFooter.on('scroll.dataTable', function() { 4509 $this.scrollFooter.scrollLeft(0); 4510 }); 4511 4512 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 4513 if ($this.percentageScrollHeight) { 4514 $this.adjustScrollHeight(); 4515 } 4516 if ($this.percentageScrollWidth) { 4517 $this.adjustScrollWidth(); 4518 } 4519 }); 4520 }, 4521 4522 shouldLoadLiveScroll: function() { 4523 return (!this.loadingLiveScroll && !this.allLoadedLiveScroll); 4524 }, 4525 4526 /** 4527 * Clones a table header and removes duplicate ids. 4528 */ 4529 cloneTableHeader: function(thead, table) { 4530 var clone = thead.clone(); 4531 clone.find('th').each(function() { 4532 var header = $(this); 4533 header.attr('id', header.attr('id') + '_clone'); 4534 $(this).children().not('.ui-column-title').remove(); 4535 $(this).children('.ui-column-title').children().remove(); 4536 }); 4537 clone.removeAttr('id').addClass('ui-datatable-scrollable-theadclone').height(0).prependTo(table); 4538 4539 return clone; 4540 }, 4541 4542 cloneHead: function() { 4543 var $this = this; 4544 4545 if (this.theadClone) { 4546 this.theadClone.remove(); 4547 } 4548 this.theadClone = this.cloneTableHeader(this.thead, this.bodyTable); 4549 4550 //reflect events from clone to original 4551 if(this.sortableColumns.length) { 4552 this.sortableColumns.removeAttr('tabindex').off('blur.dataTable focus.dataTable keydown.dataTable'); 4553 4554 var clonedColumns = this.theadClone.find('> tr > th'), 4555 clonedSortableColumns = clonedColumns.filter('.ui-sortable-column'); 4556 clonedColumns.each(function() { 4557 var col = $(this), 4558 originalId = col.attr('id').split('_clone')[0]; 4559 if(col.hasClass('ui-sortable-column')) { 4560 col.data('original', originalId); 4561 } 4562 4563 $this.setOuterWidth($(PrimeFaces.escapeClientId(originalId)), col[0].style.width); 4564 }); 4565 4566 clonedSortableColumns.on('blur.dataTable', function() { 4567 $(PrimeFaces.escapeClientId($(this).data('original'))).removeClass('ui-state-focus'); 4568 }) 4569 .on('focus.dataTable', function() { 4570 $(PrimeFaces.escapeClientId($(this).data('original'))).addClass('ui-state-focus'); 4571 }) 4572 .on('keydown.dataTable', function(e) { 4573 var key = e.which, 4574 keyCode = $.ui.keyCode; 4575 4576 if((key === keyCode.ENTER) && $(e.target).is(':not(:input)')) { 4577 $(PrimeFaces.escapeClientId($(this).data('original'))).trigger('click.dataTable', (e.metaKey||e.ctrlKey)); 4578 e.preventDefault(); 4579 } 4580 }); 4581 } 4582 }, 4583 4584 adjustScrollHeight: function() { 4585 var relativeHeight = this.jq.parent().innerHeight() * (parseInt(this.cfg.scrollHeight) / 100), 4586 headerChilden = this.jq.children('.ui-datatable-header'), 4587 footerChilden = this.jq.children('.ui-datatable-footer'), 4588 tableHeaderHeight = (headerChilden.length > 0) ? headerChilden.outerHeight(true) : 0, 4589 tableFooterHeight = (footerChilden.length > 0) ? footerChilden.outerHeight(true) : 0, 4590 scrollersHeight = (this.scrollHeader.outerHeight(true) + this.scrollFooter.outerHeight(true)), 4591 paginatorsHeight = this.paginator ? this.paginator.getContainerHeight(true) : 0, 4592 height = (relativeHeight - (scrollersHeight + paginatorsHeight + tableHeaderHeight + tableFooterHeight)); 4593 4594 if(this.cfg.virtualScroll) { 4595 this.scrollBody.css('max-height', height); 4596 } 4597 else { 4598 this.scrollBody.height(height); 4599 } 4600 }, 4601 4602 adjustScrollWidth: function() { 4603 var width = parseInt((this.jq.parent().innerWidth() * (parseInt(this.cfg.scrollWidth) / 100))); 4604 this.setScrollWidth(width); 4605 }, 4606 4607 setOuterWidth: function(element, width) { 4608 if (element.css('box-sizing') === 'border-box') { // Github issue: #5014 4609 var diff = element.outerWidth() - element.width(); 4610 element.width(parseFloat(width) - diff); 4611 } 4612 else { 4613 element.width(width); 4614 } 4615 }, 4616 4617 setScrollWidth: function(width) { 4618 var $this = this; 4619 this.jq.children('.ui-widget-header').each(function() { 4620 $this.setOuterWidth($(this), width); 4621 }); 4622 this.scrollHeader.width(width); 4623 this.scrollBody.css('margin-right', 0).width(width); 4624 this.scrollFooter.width(width); 4625 }, 4626 4627 alignScrollBody: function() {
4628 var marginRight = this.hasVerticalOverflow() ? this.getScrollbarWidth() + 'px' : '0px'; 4629 4630 this.scrollHeaderBox.css('margin-right', marginRight); 4631 this.scrollFooterBox.css('margin-right', marginRight); 4632 }, 4633 4634 getScrollbarWidth: function() { 4635 if(!this.scrollbarWidth) { 4636 this.scrollbarWidth = PrimeFaces.env.browser.webkit ? '15' : PrimeFaces.calculateScrollbarWidth(); 4637 } 4638 4639 return this.scrollbarWidth; 4640 }, 4641 4642 hasVerticalOverflow: function() { 4643 return (this.cfg.scrollHeight && this.bodyTable.outerHeight() > this.scrollBody.outerHeight()); 4644 }, 4645 4646 restoreScrollState: function() { 4647 var scrollState = this.scrollStateHolder.val(), 4648 scrollValues = scrollState.split(','); 4649 4650 if (scrollValues[0] == '-1') { 4651 scrollValues[0] = this.scrollBody[0].scrollWidth; 4652 } 4653 4654 this.scrollBody.scrollLeft(scrollValues[0]); 4655 this.scrollBody.scrollTop(scrollValues[1]); 4656 }, 4657 4658 saveScrollState: function() { 4659 var scrollState = this.scrollBody.scrollLeft() + ',' + this.scrollBody.scrollTop(); 4660 4661 this.scrollStateHolder.val(scrollState); 4662 }, 4663 4664 clearScrollState: function() { 4665 this.scrollStateHolder.val('0,0'); 4666 }, 4667 4668 fixColumnWidths: function() { 4669 var $this = this; 4670 4671 if(!this.columnWidthsFixed) { 4672 if(this.cfg.scrollable) { 4673 this.scrollHeader.find('> .ui-datatable-scrollable-header-box > table > thead > tr > th').each(function() { 4674 var headerCol = $(this), 4675 colIndex = headerCol.index(), 4676 headerStyle = headerCol[0].style, 4677 width = headerStyle.width||headerCol.width(); 4678 4679 if($this.cfg.multiViewState && $this.resizableStateHolder && $this.resizableStateHolder.attr('value')) { 4680 width = ($this.findColWidthInResizableState(headerCol.attr('id')) || width); 4681 } 4682 4683 $this.setOuterWidth(headerCol, width); 4684 4685 if($this.footerCols.length > 0) { 4686 var footerCol = $this.footerCols.eq(colIndex); 4687 $this.setOuterWidth(footerCol, width); 4688 } 4689 }); 4690 } 4691 else { 4692 var columns = this.jq.find('> .ui-datatable-tablewrapper > table > thead > tr > th'), 4693 visibleColumns = columns.filter(':visible'), 4694 hiddenColumns = columns.filter(':hidden'); 4695 4696 this.setColumnsWidth(visibleColumns); 4697 /* IE fixes */ 4698 this.setColumnsWidth(hiddenColumns); 4699 } 4700 4701 this.columnWidthsFixed = true; 4702 } 4703 }, 4704 4705 setColumnsWidth: function(columns) { 4706 if(columns.length) { 4707 var $this = this; 4708 4709 columns.each(function() { 4710 var col = $(this), 4711 colStyle = col[0].style, 4712 width = colStyle.width||col.width(); 4713 4714 if($this.cfg.multiViewState && $this.resizableStateHolder && $this.resizableStateHolder.attr('value')) { 4715 width = ($this.findColWidthInResizableState(col.attr('id')) || width); 4716 } 4717 4718 col.width(width); 4719 }); 4720 } 4721 }, 4722 4723 /** 4724 * Loads rows on-the-fly when scrolling live 4725 */ 4726 loadLiveRows: function() { 4727 if(this.liveScrollActive||(this.scrollOffset + this.cfg.scrollStep > this.cfg.scrollLimit)) { 4728 return; 4729 } 4730 4731 this.liveScrollActive = true; 4732 this.scrollOffset += this.cfg.scrollStep; 4733 4734 //Disable scroll if there is no more data left 4735 if(this.scrollOffset === this.cfg.scrollLimit) { 4736 this.shouldLiveScroll = false; 4737 } 4738 4739 var $this = this, 4740 options = { 4741 source: this.id, 4742 process: this.id, 4743 update: this.id, 4744 formId: this.cfg.formId, 4745 params: [{name: this.id + '_scrolling', value: true}, 4746 {name: this.id + '_skipChildren', value: true}, 4747 {name: this.id + '_scrollOffset', value: this.scrollOffset},
4748 {name: this.id + '_encodeFeature', value: true}], 4749 onsuccess: function(responseXML, status, xhr) { 4750 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4751 widget: $this, 4752 handle: function(content) { 4753 //insert new rows 4754 this.updateData(content, false); 4755 4756 this.liveScrollActive = false; 4757 } 4758 }); 4759 4760 return true; 4761 }, 4762 oncomplete: function(xhr, status, args, data) { 4763 if(typeof args.totalRecords !== 'undefined') { 4764 $this.cfg.scrollLimit = args.totalRecords; 4765 } 4766 4767 $this.loadingLiveScroll = false; 4768 $this.allLoadedLiveScroll = ($this.scrollOffset + $this.cfg.scrollStep) >= $this.cfg.scrollLimit; 4769 4770 // reset index of shift selection on multiple mode 4771 $this.originRowIndex = null; 4772 } 4773 }; 4774 4775 PrimeFaces.ajax.Request.handle(options); 4776 }, 4777 4778 loadRowsWithVirtualScroll: function(page, callback) { 4779 if(this.virtualScrollActive) { 4780 return; 4781 } 4782 4783 this.virtualScrollActive = true; 4784 4785 var $this = this, 4786 first = (page - 1) * this.cfg.scrollStep, 4787 options = { 4788 source: this.id, 4789 process: this.id, 4790 update: this.id, 4791 formId: this.cfg.formId, 4792 params: [{name: this.id + '_scrolling', value: true}, 4793 {name: this.id + '_skipChildren', value: true}, 4794 {name: this.id + '_first', value: first}, 4795 {name: this.id + '_encodeFeature', value: true}], 4796 onsuccess: function(responseXML, status, xhr) { 4797 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4798 widget: $this, 4799 handle: function(content) { 4800 //insert new rows 4801 this.updateData(content); 4802 callback(); 4803 this.virtualScrollActive = false; 4804 } 4805 }); 4806 4807 return true; 4808 }, 4809 oncomplete: function(xhr, status, args, data) { 4810 if(typeof args.totalRecords !== 'undefined') { 4811 $this.cfg.scrollLimit = args.totalRecords; 4812 } 4813 4814 // reset index of shift selection on multiple mode 4815 $this.originRowIndex = null; 4816 } 4817 }; 4818 if (this.hasBehavior('virtualScroll')) { 4819 this.callBehavior('virtualScroll', options); 4820 } else { 4821 PrimeFaces.ajax.Request.handle(options); 4822 } 4823 }, 4824 4825 /** 4826 * Ajax pagination 4827 */ 4828 paginate: function(newState) { 4829 var $this = this, 4830 options = { 4831 source: this.id, 4832 update: this.id, 4833 process: this.id, 4834 formId: this.cfg.formId, 4835 params: [{name: this.id + '_pagination', value: true}, 4836 {name: this.id + '_first', value: newState.first}, 4837 {name: this.id + '_rows', value: newState.rows}, 4838 {name: this.id + '_skipChildren', value: true}, 4839 {name: this.id + '_encodeFeature', value: true}] 4840 }; 4841 4842 if (!this.cfg.partialUpdate) { 4843 options.params.push({name: this.id + '_fullUpdate', value: true}); 4844 4845 options.onsuccess = function(responseXML, status, xhr) { 4846 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4847 widget: $this, 4848 handle: function(content) { 4849 this.jq.replaceWith(content); 4850 } 4851 }); 4852 4853 return true; 4854 }; 4855 } 4856 else { 4857 options.onsuccess = function(responseXML, status, xhr) { 4858 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4859 widget: $this, 4860 handle: function(content) { 4861 this.updateData(content); 4862 4863 if(this.checkAllToggler) { 4864 this.updateHeaderCheckbox(); 4865 } 4866 4867 if(this.cfg.scrollable) { 4868 this.alignScrollBody(); 4869 } 4870 4871 if(this.cfg.clientCache) { 4872 this.cacheMap[newState.first] = content; 4873 } 4874 } 4875 }); 4876 4877 return true; 4878 }; 4879 4880 options.oncomplete = function(xhr, status, args, data) { 4881 $this.paginator.cfg.page = newState.page; 4882 if(args && typeof args.totalRecords !== 'undefined') { 4883 $this.paginator.updateTotalRecords(args.totalRecords); 4884 } 4885 else { 4886 $this.paginator.updateUI(); 4887 } 4888 $this.updateColumnsView(); 4889 // reset index of shift selection on multiple mode 4890 $this.originRowIndex = null; 4891 }; 4892 } 4893 4894 if(this.hasBehavior('page')) { 4895 this.callBehavior('page', options); 4896 } 4897 else { 4898 PrimeFaces.ajax.Request.handle(options); 4899 } 4900 }, 4901 4902 /** 4903 * Loads next page asynchronously to keep it at viewstate and Upd
4903ates viewstate 4904 */ 4905 fetchNextPage: function(newState) { 4906 var rows = newState.rows, 4907 first = newState.first, 4908 $this = this, 4909 options = { 4910 source: this.id, 4911 process: this.id, 4912 update: this.id, 4913 global: false, 4914 params: [{name: this.id + '_skipChildren', value: true}, 4915 {name: this.id + '_encodeFeature', value: true}, 4916 {name: this.id + '_first', value: first}, 4917 {name: this.id + '_rows', value: rows}, 4918 {name: this.id + '_pagination', value: true}, 4919 {name: this.id + '_clientCache', value: true}], 4920 onsuccess: function(responseXML, status, xhr) { 4921 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4922 widget: $this, 4923 handle: function(content) { 4924 if(content.length) { 4925 var nextFirstValue = first + rows; 4926 $this.cacheMap[nextFirstValue] = content; 4927 } 4928 } 4929 }); 4930 4931 return true; 4932 } 4933 }; 4934 4935 PrimeFaces.ajax.Request.handle(options); 4936 }, 4937 4938 updatePageState: function(newState) { 4939 var $this = this, 4940 options = { 4941 source: this.id, 4942 process: this.id, 4943 update: this.id, 4944 global: false, 4945 params: [{name: this.id + '_pagination', value: true}, 4946 {name: this.id + '_encodeFeature', value: true}, 4947 {name: this.id + '_pageState', value: true}, 4948 {name: this.id + '_first', value: newState.first}, 4949 {name: this.id + '_rows', value: newState.rows}], 4950 onsuccess: function(responseXML, status, xhr) { 4951 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4952 widget: $this, 4953 handle: function(content) { 4954 // do nothing 4955 } 4956 }); 4957 4958 return true; 4959 } 4960 }; 4961 4962 PrimeFaces.ajax.Request.handle(options); 4963 }, 4964 4965 /** 4966 * Ajax sort 4967 */ 4968 sort: function(columnHeader, order, multi) { 4969 var $this = this, 4970 options = { 4971 source: this.id, 4972 update: this.id, 4973 process: this.id, 4974 params: [{name: this.id + '_sorting', value: true}, 4975 {name: this.id + '_skipChildren', value: true}, 4976 {name: this.id + '_encodeFeature', value: true}] 4977 }; 4978 4979 if (!this.cfg.partialUpdate) { 4980 options.params.push({name: this.id + '_fullUpdate', value: true}); 4981 4982 options.onsuccess = function(responseXML, status, xhr) { 4983 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4984 widget: $this, 4985 handle: function(content) { 4986 this.jq.replaceWith(content); 4987 } 4988 }); 4989 4990 return true; 4991 }; 4992 } 4993 else { 4994 options.onsuccess = function(responseXML, status, xhr) { 4995 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 4996 widget: $this, 4997 handle: function(content) { 4998 this.updateData(content); 4999 5000 if(this.checkAllToggler) { 5001 this.updateHeaderCheckbox(); 5002 } 5003 } 5004 }); 5005 5006 return true; 5007 }; 5008 5009 options.oncomplete = function(xhr, status, args, data) { 5010 var paginator = $this.getPaginator(); 5011 if(args && args.totalRecords) { 5012 $this.cfg.scrollLimit = args.totalRecords; 5013 5014 if(paginator && paginator.cfg.rowCount !== args.totalRecords) { 5015 paginator.setTotalRecords(args.totalRecords); 5016 } 5017 } 5018 5019 if(!args.validationFailed) { 5020 if(paginator) { 5021 paginator.setPage(0, true); 5022 } 5023 5024 // remove aria-sort 5025 var activeColumns = $this.sortableColumns.filter('.ui-state-active'); 5026 if(activeColumns.length) { 5027 activeColumns.removeAttr('aria-sort'); 5028 } 5029 else { 5030 $this.sortableColumns.eq(0).removeAttr('aria-sort'); 5031 } 5032 5033 if(!multi) { 5034 //aria reset 5035 for(var i = 0; i < activeColumns.length; i++) { 5036 var activeColumn = $(activeColumns.get(i)), 5037 ariaLabelOfActive = activeColumn.attr('aria-label'); 5038 5039 activeColumn.attr('aria-label', $this.get
5039SortMessage(ariaLabelOfActive, $this.ascMessage)); 5040 $(PrimeFaces.escapeClientId(activeColumn.attr('id') + '_clone')).removeAttr('aria-sort').attr('aria-label', $this.getSortMessage(ariaLabelOfActive, $this.ascMessage)); 5041 } 5042 5043 activeColumns.data('sortorder', $this.SORT_ORDER.UNSORTED).removeClass('ui-state-active') 5044 .find('.ui-sortable-column-icon').removeClass('ui-icon-triangle-1-n ui-icon-triangle-1-s'); 5045 } 5046 5047 columnHeader.data('sortorder', order).removeClass('ui-state-hover').addClass('ui-state-active'); 5048 var sortIcon = columnHeader.find('.ui-sortable-column-icon'), 5049 ariaLabel = columnHeader.attr('aria-label'); 5050 5051 if(order === $this.SORT_ORDER.DESCENDING) { 5052 sortIcon.removeClass('ui-icon-triangle-1-n').addClass('ui-icon-triangle-1-s'); 5053 columnHeader.attr('aria-sort', 'descending').attr('aria-label', $this.getSortMessage(ariaLabel, $this.ascMessage)); 5054 $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).attr('aria-sort', 'descending').attr('aria-label', $this.getSortMessage(ariaLabel, $this.ascMessage)); 5055 } else if(order === $this.SORT_ORDER.ASCENDING) { 5056 sortIcon.removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-n'); 5057 columnHeader.attr('aria-sort', 'ascending').attr('aria-label', $this.getSortMessage(ariaLabel, $this.descMessage)); 5058 $(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).attr('aria-sort', 'ascending').attr('aria-label', $this.getSortMessage(ariaLabel, $this.descMessage)); 5059 } 5060 } 5061 5062 if($this.cfg.virtualScroll) { 5063 $this.resetVirtualScrollBody(); 5064 } 5065 else if($this.cfg.liveScroll) { 5066 $this.scrollOffset = 0; 5067 $this.liveScrollActive = false; 5068 $this.shouldLiveScroll = true; 5069 $this.loadingLiveScroll = false; 5070 $this.allLoadedLiveScroll = $this.cfg.scrollStep >= $this.cfg.scrollLimit; 5071 } 5072 5073 if($this.cfg.clientCache) { 5074 $this.clearCacheMap(); 5075 } 5076 5077 $this.updateColumnsView(); 5078 5079 // reset index of shift selection on multiple mode 5080 $this.originRowIndex = null; 5081 }; 5082 } 5083 5084 if(multi) { 5085 options.params.push({name: this.id + '_multiSorting', value: true}); 5086 options.params.push({name: this.id + '_sortKey', value: $this.joinSortMetaOption('col')}); 5087 options.params.push({name: this.id + '_sortDir', value: $this.joinSortMetaOption('order')}); 5088 } 5089 else { 5090 options.params.push({name: this.id + '_sortKey', value: columnHeader.attr('id')}); 5091 options.params.push({name: this.id + '_sortDir', value: order}); 5092 } 5093 5094 if(this.hasBehavior('sort')) { 5095 this.callBehavior('sort', options); 5096 } 5097 else { 5098 PrimeFaces.ajax.Request.handle(options); 5099 } 5100 }, 5101 5102 joinSortMetaOption: function(option) { 5103 var value = ''; 5104 5105 for(var i = 0; i < this.sortMeta.length; i++) { 5106 value += this.sortMeta[i][option]; 5107 5108 if(i !== (this.sortMeta.length - 1)) { 5109 value += ','; 5110 } 5111 } 5112 5113 return value; 5114 }, 5115 5116 /** 5117 * Ajax filter 5118 */ 5119 filter: function() { 5120 var $this = this, 5121 options = { 5122 source: this.id, 5123 update: this.id, 5124 process: this.id, 5125 formId: this.cfg.formId, 5126 params: [{name: this.id + '_filtering', value: true}, 5127 {name: this.id + '_encodeFeature', value: true}] 5128 }; 5129 5130 if (!this.cfg.partialUpdate){ 5131 options.params.push({name: this.id + '_fullUpdate', value: true}); 5132 5133 options.onsuccess = function(responseXML, status, xhr) { 5134 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 5135 widget: $this, 5136 handle: function(content) { 5137 this.jq.replaceWith(content); 5138 } 5139 }); 5140 5141 return true; 5142 }; 5143 } 5144 else { 5145 options.onsuccess = function(responseXML, status, xhr) { 5146 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 5147 widget: $this, 5148 handle: function(content) { 5149 this.updateData(content); 5150 5151 if(this.cfg.scrollable) { 5152 this.alignScrollBody(); 5153 } 5154 5155 if(this.isCheckboxSelectionEnabled()) { 5156 this.updateHeaderCheckbox(); 5157 } 5158 } 5159 }); 5160 5161 return true; 5162 }; 5163 5164 options.oncomplete = function(xhr, status, args, data) { 5165 var paginator = $this.getPaginator(); 5166 if(args && typeof args.totalRecords !== 'undefined') { 5167 $this.cfg.scrollLimit = args.totalRecords; 5168 5169 if(paginator) { 5170 paginator.setTotalRecords(args.totalRecords); 5171 } 5172 } 5173 5174 if($this.cfg.clientCache) { 5175 $this.clearCacheMap(); 5176 } 5177 5178 if($this.cfg.virtualScroll) { 5179 var row = $this.bodyTable.children('tbody').children('tr.ui-widget-content'); 5180 if(row) { 5181 var hasEmptyMessage = row.eq(0).hasClass('ui-datatable-empty-message'), 5182 scrollLimit = $this.cfg.scrollLimit; 5183 5184 if(hasEmptyMessage) { 5185 scrollLimit = 1; 5186 } 5187 5188 $this.resetVirtualScrollBody(); 5189 5190 $this.rowHeight = row.outerHeight(); 5191 $this.scrollBody.children('div').css({'height': parseFloat((scrollLimit * $this.rowHeight + 1) + 'px')}); 5192 5193 if(hasEmptyMessage && $this.cfg.scrollHeight && $this.percentageScrollHeight) { 5194 setTimeout(function() { 5195 $this.adjustScrollHeight(); 5196 }, 10); 5197 } 5198 } 5199 } 5200 else if($this.cfg.liveScroll) { 5201 $this.scrollOffset = 0; 5202 $this.liveScrollActive = false;
5203 $this.shouldLiveScroll = true; 5204 $this.loadingLiveScroll = false; 5205 $this.allLoadedLiveScroll = $this.cfg.scrollStep >= $this.cfg.scrollLimit; 5206 } 5207 5208 $this.updateColumnsView(); 5209 $this.updateEmptyColspan(); 5210 5211 // reset index of shift selection on multiple mode 5212 $this.originRowIndex = null; 5213 }; 5214 } 5215 5216 if(this.hasBehavior('filter')) { 5217 this.callBehavior('filter', options); 5218 } 5219 else { 5220 PrimeFaces.ajax.Request.handle(options); 5221 } 5222 }, 5223 5224 onRowClick: function(event, rowElement, silent) { 5225 //Check if rowclick triggered this event not a clickable element in row content 5226 if($(event.target).is(this.rowSelectorForRowClick)) { 5227 var row = $(rowElement), 5228 selected = row.hasClass('ui-state-highlight'), 5229 metaKey = event.metaKey||event.ctrlKey, 5230 shiftKey = event.shiftKey; 5231 5232 this.assignFocusedRow(row); 5233 5234 //unselect a selected row if metakey is on 5235 if(selected && metaKey) { 5236 this.unselectRow(row, silent); 5237 } 5238 else { 5239 //unselect previous selection if this is single selection or multiple one with no keys 5240 if(this.isSingleSelection() || (this.isMultipleSelection() && event && !metaKey && !shiftKey && this.cfg.rowSelectMode === 'new' )) { 5241 this.unselectAllRows(); 5242 } 5243 5244 //range selection with shift key 5245 if(this.isMultipleSelection() && event && event.shiftKey && this.originRowIndex !== null) { 5246 this.selectRowsInRange(row); 5247 } 5248 else if(this.cfg.rowSelectMode === 'add' && selected) { 5249 this.unselectRow(row, silent); 5250 } 5251 //select current row 5252 else { 5253 this.originRowIndex = row.index(); 5254 this.cursorIndex = null; 5255 this.selectRow(row, silent); 5256 } 5257 } 5258 5259 if(this.cfg.disabledTextSelection) { 5260 PrimeFaces.clearSelection(); 5261 } 5262 } 5263 }, 5264 5265 onRowDblclick: function(event, row) { 5266 if(this.cfg.disabledTextSelection) { 5267 PrimeFaces.clearSelection(); 5268 } 5269 5270 //Check if rowclick triggered this event not a clickable element in row content 5271 if($(event.target).is(this.rowSelectorForRowClick)) { 5272 var rowMeta = this.getRowMeta(row); 5273 5274 this.fireRowSelectEvent(rowMeta.key, 'rowDblselect'); 5275 } 5276 }, 5277 5278 onRowRightClick: function(event, rowElement, cmSelMode) { 5279 var row = $(rowElement), 5280 rowMeta = this.getRowMeta(row), 5281 selected = row.hasClass('ui-state-highlight'); 5282 5283 this.assignFocusedRow(row); 5284 5285 if(cmSelMode === 'single' || !selected) { 5286 this.unselectAllRows(); 5287 } 5288 5289 this.selectRow(row, true); 5290 5291 this.fireRowSelectEvent(rowMeta.key, 'contextMenu'); 5292 5293 if(this.cfg.disabledTextSelection) { 5294 PrimeFaces.clearSelection(); 5295 } 5296 }, 5297 5298 /** 5299 * @param r {Row Index || Row Element} 5300 */ 5301 findRow: function(r) { 5302 var row = r; 5303 5304 if(PrimeFaces.isNumber(r)) { 5305 row = this.tbody.children('tr:eq(' + r + ')'); 5306 } 5307 5308 return row; 5309 }, 5310 5311 selectRowsInRange: function(row) { 5312 var rows = this.tbody.children(), 5313 rowMeta = this.getRowMeta(row), 5314 $this = this; 5315 5316 //unselect previously selected rows with shift 5317 if(this.cursorIndex !== null) { 5318 var oldCursorIndex = this.cursorIndex, 5319 rowsToUnselect = oldCursorIndex > this.originRowIndex ? rows.slice(this.originRowIndex, oldCursorIndex + 1) : rows.slice(oldCursorIndex, this.originRowIndex + 1); 5320 5321 rowsToUnselect.each(function(i, item) { 5322 $this.unselectRow($(item), true); 5323 }); 5324 } 5325 5326 //select rows between cursor and origin 5327 this.cursorIndex = row.index(); 5328 5329 var rowsToSelect = this.cursorIndex > this.originRowIndex ? rows.slice(this.originRowIndex, this.cursorIndex + 1) : rows.slice(this.cursorIndex, this.originRowIndex + 1); 5330 5331 rowsToSelect.each(function(i, item) { 5332 $this.selectRow($(item), true); 5333 }); 5334 5335 this.fireRowSelectEvent(rowMeta.key, 'rowSelect'); 5336 }, 5337 5338 selectRow: function(r, silent) { 5339 var row = this.findRow(r); 5340 if(!row.hasClass('ui-datatable-selectable')) { 5341 return; 5342 } 5343 5344 var rowMeta = this.getRowMeta(row); 5345 5346 this.highlightRow(row); 5347 5348 if(this.isCheckboxSelectionEnabled()) { 5349 if(this.cfg.nativeElements) 5350 row.children('td.ui-selection-column').find(':checkbox').prop('checked', true); 5351 else 5352 this.selectCheckbox(row.children('td.ui-selection-column').find('> div.ui-chkbox > div.ui-chkbox-box')); 5353 5354 this.updateHeaderCheckbox(); 5355 } 5356 5357 this.addSelection(rowMeta.key); 5358 5359 this.writeSelections(); 5360 5361 if(!silent) { 5362 this.fireRowSelectEvent(rowMeta.key, 'rowSelect'); 5363 } 5364 }, 5365 5366 unselectRow: function(r, silent) { 5367 var row = this.findRow(r); 5368 if(!row.hasClass('ui-datatable-selectable')) { 5369 return; 5370 } 5371 5372 var rowMeta = this.getRowMeta(row); 5373 5374 this.unhighlightRow(row); 5375 5376 if(this.isCheckboxSelectionEnabled()) { 5377 if(this.cfg.nativeElements) 5378 row.children('td.ui-selection-column').find(':checkbox').prop('checked', false); 5379 else 5380 this.unselectCheckbox(row.children('td.ui-selection-column').find('> div.ui-chkbox > div.ui-chkbox-box')); 5381 5382 this.updateHeaderCheckbox(); 5383 } 5384 5385 this.removeSelection(rowMeta.key); 5386 5387 this.writeSelections(); 5388 5389 if(!silent) { 5390 this.fireRowUnselectEvent(rowMeta.key, "rowUnselect"); 5391 } 5392 }, 5393 5394 /* 5395 * Highlights row as selected 5396 */ 5397 highlightRow: function(row) { 5398 row.removeClass('ui-state-hover').addClass('ui-state-highlight').attr('aria-selected', true); 5399 }, 5400 5401 /* 5402 * Clears selected visuals 5403 */ 5404 unhighlightRow: function(row) { 5405 row.removeClass('ui-state-highlight').attr('aria-selected', false); 5406 }, 5407 5408 /** 5409 * Sends a rowSelectEvent on server side to invoke a rowSelectListener if defined 5410 */ 5411 fireRowSelectEvent: function(rowKey, behaviorEvent) { 5412 if(this.hasBehavior(behaviorEvent)) { 5413 var ext = { 5414 params: [{name: this.id + '_instantSelectedRowKey', value: rowKey} 5415 ] 5416 }; 5417 5418 this.callBehavior(behaviorEvent, ext); 5419 } 5420 }, 5421 5422 /** 5423 * Sends a rowUnselectEvent on server side to invoke a rowUnselectListener if defined 5424 */ 5425 fireRowUnselectEvent: function(rowKey, behaviorEvent) { 5426 if(this.hasBehavior(behaviorEvent)) { 5427 var ext = { 5428 params: [ 5429 { 5430 name: this.id + '_instantUnselectedRowKey', 5431 value: rowKey 5432 } 5433 ] 5434 }; 5435 5436 this.callBehavior(behaviorEvent, ext); 5437 } 5438 }, 5439 5440 /** 5441 * Selects the corresping row of a radio based column selection 5442 */ 5443 selectRowWithRadio: function(radio) { 5444 var row = radio.closest('tr'), 5445 rowMeta = this.getRowMeta(row); 5446 5447 //clean selection 5448 this.unselectAllRows(); 5449 5450 //select current 5451 if(!this.cfg.nativeElements) { 5452 this.selectRadio(radio); 5453 } 5454 5455 this.highlightRow(row); 5456 this.addSelection(rowMeta.key); 5457 this.writeSelections(); 5458 this.fireRowSelectEvent(rowMeta.key, 'rowSelectRadio'); 5459 }, 5460 5461 /** 5462 * Selects the corresponding row of a checkbox based column selection 5463 */ 5464 selectRowWithCheckbox: function(checkbox, silent) { 5465 var row = checkbox.closest('tr'); 5466 if(!row.hasClass('ui-datatable-selectable')) { 5467 return; 5468 } 5469 5470 var rowMeta = this.getRowMeta(row); 5471 5472 this.highlightRow(row); 5473 5474 if(!this.cfg.nativeElements) { 5475 this.selectCheckbox(checkbox); 5476 } 5477 5478 this.addSelection(rowMeta.key); 5479 5480 this.writeSelections(); 5481 5482 if(!silent) { 5483 this.updateHeaderCheckbox(); 5484 this.fireRowSelectEvent(rowMeta.key, "rowSelectCheckbox"); 5485 } 5486 }, 5487 5488 /** 5489 * Unselects the corresponding row of a checkbox based column selection 5490 */ 5491 unselectRowWithCheckbox: function(checkbox, silent) { 5492 var row = checkbox.closest('tr'); 5493 if(!row.hasClass('ui-datatable-selectable')) { 5494 return; 5495 } 5496 5497 var rowMeta = this.getRowMeta(row); 5498 5499 this.unhighlightRow(row); 5500 5501 if(!this.cfg.nativeElements) { 5502 this.unselectCheckbox(checkbox); 5503 } 5504 5505 this.removeSelection(rowMeta.key); 5506 5507 this.uncheckHeaderCheckbox(); 5508 5509 this.writeSelections(); 5510 5511 if(!silent) { 5512 this.fireRowUnselectEvent(rowMeta.key, "rowUnselectCheckbox"); 5513 } 5514 }, 5515 5516 unselectAllRows: function() { 5517 var selectedRows = this.tbody.children('tr.ui-state-highlight'), 5518 checkboxSelectionEnabled = this.isCheckboxSelectionEnabled(), 5519 radioSelectionEnabled = this.isRadioSelectionEnabled(); 5520 5521 for(var i = 0; i < selectedRows.length; i++) { 5522 var row = selectedRows.eq(i); 5523 if(!row.hasClass('ui-datatable-selectable')) { 5524 continue; 5525 } 5526 5527 this.unhighlightRow(row); 5528 5529 if(checkboxSelectionEnabled) { 5530 if(this.cfg.nativeElements) 5531 row.children('td.ui-selection-column').find(':checkbox').prop('checked', false); 5532 else 5533 this.unselectCheckbox(row.children('td.ui-selection-column').find('> div.ui-chkbox > div.ui-chkbox-box')); 5534 } 5535 else if(radioSelectionEnabled) { 5536 if(this.cfg.nativeElements) 5537 row.children('td.ui-selection-column').find(':radio').prop('checked', false); 5538 else 5539 this.unselectRadio(row.children('td.ui-selection-column').find('> div.ui-radiobutton > div.ui-radiobutton-box')); 5540 } 5541 } 5542 5543 if(checkboxSelectionEnabled) { 5544 this.uncheckHeaderCheckbox(); 5545 } 5546 5547 this.selection = []; 5548 this.writeSelections(); 5549 }, 5550 5551 selectAllRowsOnPage: function() { 5552 var rows = this.tbody.children('tr'); 5553 for(var i = 0; i < rows.length; i++) { 5554 var row = rows.eq(i); 5555 this.selectRow(row, true); 5556 } 5557 }, 5558 5559 unselectAllRowsOnPage: function() { 5560 var rows = this.tbody.children('tr'); 5561 for(var i = 0; i < rows.length; i++) { 5562 var row = rows.eq(i); 5563 this.unselectRow(row, true); 5564 } 5565 }, 5566 5567 selectAllRows: function() { 5568 this.selectAllRowsOnPage(); 5569 this.selection = new Array('@all'); 5570 this.writeSelections(); 5571 }, 5572 5573 /** 5574 * Toggles all rows with checkbox 5575 */ 5576 toggleCheckAll: function() { 5577 var shouldCheckAll = true; 5578 if(this.cfg.nativeElements) { 5579 var checkboxes = this.tbody.find('> tr.ui-datatable-selectable > td.ui-selection-column > :checkbox:visible'), 5580 checked = this.checkAllToggler.prop('checked'), 5581 $this = this; 5582 5583 checkboxes.each(function() { 5584 if(checked) { 5585 var checkbox = $(this); 5586 checkbox.prop('checked', true); 5587 $this.selectRowWithCheckbox(checkbox, true); 5588 } 5589 else { 5590 var checkbox = $(this); 5591 checkbox.prop('checked', false); 5592 $this.unselectRowWithCheckbox(checkbox, true); 5593 shouldCheckAll = false;
5594 } 5595 }); 5596 } 5597 else { 5598 var checkboxes = this.tbody.find('> tr.ui-datatable-selectable > td.ui-selection-column .ui-chkbox-box:visible'), 5599 checked = this.checkAllToggler.hasClass('ui-state-active'), 5600 $this = this; 5601 5602 if(checked) { 5603 this.checkAllToggler.removeClass('ui-state-active').children('span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 5604 this.checkAllTogglerInput.prop('checked', false).attr('aria-checked', false); 5605 shouldCheckAll = false; 5606 5607 checkboxes.each(function() { 5608 $this.unselectRowWithCheckbox($(this), true); 5609 }); 5610 } 5611 else { 5612 this.checkAllToggler.addClass('ui-state-active').children('span.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 5613 this.checkAllTogglerInput.prop('checked', true).attr('aria-checked', true); 5614 5615 checkboxes.each(function() { 5616 $this.selectRowWithCheckbox($(this), true); 5617 }); 5618 } 5619 } 5620 5621 // GitHub #6730 user wants all rows not just displayed rows 5622 if(!this.cfg.selectionPageOnly && shouldCheckAll) { 5623 this.selectAllRows(); 5624 } 5625 5626 //save state 5627 this.writeSelections(); 5628 5629 //fire toggleSelect event 5630 if(this.hasBehavior('toggleSelect')) { 5631 var ext = { 5632 params: [{name: this.id + '_checked', value: !checked}] 5633 }; 5634 5635 this.callBehavior('toggleSelect', ext); 5636 } 5637 }, 5638 5639 selectCheckbox: function(checkbox) { 5640 if(!checkbox.hasClass('ui-state-focus')) { 5641 checkbox.addClass('ui-state-active'); 5642 } 5643 checkbox.children('span.ui-chkbox-icon:first').removeClass('ui-icon-blank').addClass(' ui-icon-check'); 5644 checkbox.prev().children('input').prop('checked', true).attr('aria-checked', true); 5645 }, 5646 5647 unselectCheckbox: function(checkbox) { 5648 checkbox.removeClass('ui-state-active'); 5649 checkbox.children('span.ui-chkbox-icon:first').addClass('ui-icon-blank').removeClass('ui-icon-check'); 5650 checkbox.prev().children('input').prop('checked', false).attr('aria-checked', false); 5651 }, 5652 5653 selectRadio: function(radio){ 5654 radio.removeClass('ui-state-hover'); 5655 if(!radio.hasClass('ui-state-focus')) { 5656 radio.addClass('ui-state-active'); 5657 } 5658 radio.children('.ui-radiobutton-icon').addClass('ui-icon-bullet').removeClass('ui-icon-blank'); 5659 radio.prev().children('input').prop('checked', true); 5660 }, 5661 5662 unselectRadio: function(radio){ 5663 radio.removeClass('ui-state-active').children('.ui-radiobutton-icon').addClass('ui-icon-blank').removeClass('ui-icon-bullet'); 5664 radio.prev().children('input').prop('checked', false); 5665 }, 5666 5667 /** 5668 * Expands a row to display detail content 5669 */ 5670 toggleExpansion: function(toggler) { 5671 var row = toggler.closest('tr'), 5672 rowIndex = this.getRowMeta(row).index, 5673 iconOnly = toggler.hasClass('ui-icon'), 5674 labels = toggler.children('span'), 5675 expanded = iconOnly ? toggler.hasClass('ui-icon-circle-triangle-s'): toggler.children('span').eq(0).hasClass('ui-helper-hidden'), 5676 $this = this; 5677 5678 //Run toggle expansion if row is not being toggled already to prevent conflicts 5679 if($.inArray(rowIndex, this.expansionProcess) === -1) { 5680 this.expansionProcess.push(rowIndex); 5681 5682 if(expanded) { 5683 if(iconOnly) { 5684 toggler.addClass('ui-icon-circle-triangle-e').removeClass('ui-icon-circle-triangle-s').attr('aria-expanded', false); 5685 } 5686 else { 5687 labels.eq(0).removeClass('ui-helper-hidden'); 5688 labels.eq(1).addClass('ui-helper-hidden'); 5689 } 5690 5691 this.collapseRow(row); 5692 $this.expansionProcess = $.grep($this.expansionProcess, function(r) { 5693 return (r !== rowIndex); 5694 }); 5695 this.fireRowCollapseEvent(row); 5696 } 5697 else { 5698 if(this.cfg.rowExpandMode === 'single') { 5699 this.collapseAllRows(); 5700 } 5701 5702 if(iconOnly) { 5703 toggler.addClass('ui-icon-circle-triangle-s').removeClass('ui-icon-circle-triangle-e').attr('aria-expanded', true); 5704 } 5705 else { 5706 labels.eq(0).addClass('ui-helper-hidden'); 5707 labels.eq(1).removeClass('ui-helper-hidden'); 5708 } 5709 5710 this.loadExpandedRowContent(row); 5711 } 5712 } 5713 }, 5714 5715 loadExpandedRowContent: function(row) { 5716 // To check whether or not any hidden expansion content exists to avoid reloading multiple duplicate nodes in DOM 5717 var expansionContent = row.next('.ui-expanded-row-content'); 5718 if(expansionContent.length > 0) { 5719 expansionContent.remove(); 5720 } 5721 5722 var $this = this, 5723 rowIndex = this.getRowMeta(row).index, 5724 options = { 5725 source: this.id, 5726 process: this.id, 5727 update: this.id, 5728 formId: this.cfg.formId, 5729 params: [{name: this.id + '_rowExpansion', value: true}, 5730 {name: this.id + '_expandedRowIndex', value: rowIndex}, 5731 {name: this.id + '_encodeFeature', value: true}, 5732 {name: this.id + '_skipChildren', value: true}], 5733 onsuccess: function(responseXML, status, xhr) { 5734 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 5735 widget: $this, 5736 handle: function(content) { 5737 if(content && $.trim(content).length) { 5738 row.addClass('ui-expanded-row'); 5739 this.displayExpandedRow(row, content); 5740 } 5741 } 5742 }); 5743 5744 return true; 5745 }, 5746 oncomplete: function() { 5747 $this.expansionProcess = $.grep($this.expansionProcess, function(r) { 5748 return r !== rowIndex; 5749 }); 5750 } 5751 }; 5752 5753 if(this.hasBehavior('rowToggle')) { 5754 this.callBehavior('rowToggle', options); 5755 } 5756 else { 5757 PrimeFaces.ajax.Request.handle(options); 5758 } 5759 }, 5760 5761 displayExpandedRow: function(row, content) { 5762 row.after(content); 5763 this.updateRowspan(row); 5764 this.updateColspan(row.next()); 5765 }, 5766 5767 fireRowCollapseEvent: function(row) { 5768 var rowIndex = this.getRowMeta(row).index; 5769 5770 if(this.hasBehavior('rowToggle')) { 5771 var ext = { 5772 params: [ 5773 { 5774 name: this.id + '_collapsedRowIndex', 5775 value: rowIndex 5776 } 5777 ] 5778 }; 5779 5780 this.callBehavior('rowToggle', ext); 5781 } 5782 }, 5783 5784 collapseRow: function(row) { 5785 // #942: need to use "hide" instead of "remove" to avoid incorrect form mapping when a row is collapsed 5786 row.removeClass('ui-expanded-row').next('.ui-expanded-row-content').hide(); 5787 this.updateRowspan(row); 5788 }, 5789 5790 collapseAllRows: function() { 5791 var $this = this; 5792 5793 this.getExpandedRows().each(function() { 5794 var expandedRow = $(this); 5795 $this.collapseRow(expandedRow); 5796 5797 var columns = expandedRow.children('td'); 5798 for(var i = 0; i < columns.length; i++) { 5799 var column = columns.eq(i), 5800 toggler = column.children('.ui-row-toggler'); 5801 5802 if(toggler.length > 0) { 5803 if(toggler.hasClass('ui-icon')) { 5804 toggler.addClass('ui-icon-circle-triangle-e').removeClass('ui-icon-circle-triangle-s'); 5805 } 5806 else { 5807 var labels = toggler.children('span'); 5808 labels.eq(0).removeClass('ui-helper-hidden'); 5809 labels.eq(1).addClass('ui-helper-hidden'); 5810 } 5811 break; 5812 } 5813 } 5814 }); 5815 }, 5816 5817 getExpandedRows: function() { 5818 return this.tbody.children('.ui-expanded-row'); 5819 }, 5820 5821 /** 5822 * Binds editor events non-obstrusively 5823 */ 5824 bindEditEvents: function() { 5825 var $this = this; 5826 this.cfg.saveOnCellBlur = (this.cfg.saveOnCellBlur === false) ? false : true; 5827 5828 if(this.cfg.editMode === 'row') { 5829 var rowEditorSelector = '> tr > td > div.ui-row-editor > a'; 5830 5831 this.tbody.off('click.datatable focus.datatable blur.datatable', rowEditorSelector) 5832 .on('click.datatable', rowEditorSelector, null, function(e) { 5833 var element = $(this), 5834 row = element.closest('tr'); 5835 5836 if(element.hasClass('ui-row-editor-pencil')) { 5837 $this.switchToRowEdit(row); 5838 element.hide().siblings().show(); 5839 } 5840 else if(element.hasClass('ui-row-editor-check')) { 5841 $this.saveRowEdit(row); 5842 } 5843 else if(element.hasClass('ui-row-editor-close')) { 5844 $this.cancelRowEdit(row); 5845 } 5846 5847 e.preventDefault(); 5848 }) 5849 .on('focus.datatable', rowEditorSelector, null, function(e) { 5850 $(this).addClass('ui-row-editor-outline'); 5851 }) 5852 .on('blur.datatable', rowEditorSelector, null, function(e) { 5853 $(this).removeClass('ui-row-editor-outline'); 5854 }); 5855 5856 // GitHub #433 Allow ENTER to submit ESC to cancel row editor 5857 $(document).off("keydown", "tr.ui-row-editing")
5858 .on("keydown", "tr.ui-row-editing", function(e) { 5859 var keyCode = $.ui.keyCode; 5860 switch (e.which) { 5861 case keyCode.ENTER: 5862 $(this).closest("tr").find(".ui-row-editor-check").click(); 5863 return false; // prevents executing other event handlers (adding new row to the table) 5864 case keyCode.ESCAPE: 5865 $(this).closest("tr").find(".ui-row-editor-close").click(); 5866 return false; 5867 default: 5868 break; 5869 } 5870 }); 5871 } 5872 else if(this.cfg.editMode === 'cell') { 5873 var originalCellSelector = '> tr > td.ui-editable-column' 5874 cellSelector = this.cfg.cellSeparator || originalCellSelector, 5875 editEvent = (this.cfg.editInitEvent !== 'click') ? this.cfg.editInitEvent + '.datatable-cell click.datatable-cell' : 'click.datatable-cell'; 5876 5877 if (this.cfg.cellSeparator) { 5878 this.tbody.off(editEvent, originalCellSelector) 5879 .on(editEvent, originalCellSelector, null, function (e) { 5880 $this.incellClick = true; 5881 5882 if (!$(this).hasClass('ui-cell-editing') && e.type === $this.cfg.editInitEvent && $this.cfg.editInitEvent === "dblclick") { 5883 $this.incellClick = false; 5884 } 5885 }); 5886 } 5887 5888 this.tbody.off(editEvent, cellSelector) 5889 .on(editEvent, cellSelector, null, function(e) { 5890 $this.incellClick = true; 5891 5892 var item = $(this), 5893 cell = item.hasClass('ui-editable-column') ? item : item.closest('.ui-editable-column'); 5894 5895 if(!cell.hasClass('ui-cell-editing') && e.type === $this.cfg.editInitEvent) { 5896 $this.showCellEditor(cell); 5897 5898 if($this.cfg.editInitEvent === "dblclick") { 5899 $this.incellClick = false; 5900 } 5901 } 5902 }); 5903 5904 $(document).off('click.datatable-cell-blur' + this.id) 5905 .on('click.datatable-cell-blur' + this.id, function(e) { 5906 var target = $(e.target); 5907 if(!$this.incellClick && (target.is('.ui-input-overlay') || target.closest('.ui-input-overlay').length || target.closest('.ui-datepicker-buttonpane').length)) { 5908 $this.incellClick = true; 5909 } 5910 5911 if(!$this.incellClick && $this.currentCell && !$this.contextMenuClick && !$.datepicker._datepickerShowing) { 5912 if($this.cfg.saveOnCellBlur) 5913 $this.saveCell($this.currentCell); 5914 else 5915 $this.doCellEditCancelRequest($this.currentCell); 5916 } 5917 5918 $this.incellClick = false; 5919 $this.contextMenuClick = false; 5920 }); 5921 } 5922 }, 5923 5924 switchToRowEdit: function(row) { 5925 if(this.cfg.rowEditMode === "lazy") { 5926 this.lazyRowEditInit(row); 5927 } 5928 else { 5929 this.showRowEditors(row); 5930 5931 if(this.hasBehavior('rowEditInit')) { 5932 var rowIndex = this.getRowMeta(row).index; 5933 5934 var ext = { 5935 params: [{name: this.id + '_rowEditIndex', value: rowIndex}] 5936 }; 5937 5938 this.callBehavior('rowEditInit', ext); 5939 } 5940 } 5941 }, 5942 5943 showRowEditors: function(row) { 5944 row.addClass('ui-state-highlight ui-row-editing').children('td.ui-editable-column').each(function() { 5945 var column = $(this); 5946 5947 column.find('.ui-cell-editor-output').hide(); 5948 column.find('.ui-cell-editor-input').show(); 5949 }); 5950 5951 var inputs=row.find(':input:enabled'); 5952 if (inputs.length > 0) { 5953 inputs.first().focus(); 5954 } 5955 }, 5956 5957 getCellMeta: function(cell) { 5958 var rowMeta = this.getRowMeta(cell.closest('tr')), 5959 cellIndex = cell.index(); 5960 5961 if(this.cfg.scrollable && this.cfg.frozenColumns) { 5962 cellIndex = (this.scrollTbody.is(cell.closest('tbody'))) ? (cellIndex + $this.cfg.frozenColumns) : cellIndex; 5963 } 5964 5965 var cellInfo = rowMeta.index + ',' + cellIndex; 5966 if(rowMeta.key) { 5967 cellInfo = cellInfo + ',' + rowMeta.key; 5968 } 5969 5970 return cellInfo; 5971 }, 5972 5973 cellEditInit: function(cell) { 5974 var cellInfo = this.getCellMeta(cell), 5975 cellEditor = cell.children('.ui-cell-editor'), 5976 $this = this; 5977 5978 var options = { 5979 source: this.id, 5980 process: this.id, 5981 update: this.id, 5982 global: false, 5983 params: [{name: this.id + '_encodeFeature', value: true}, 5984 {name: this.id + '_cellEditInit', value: true}, 5985 {name: this.id + '_cellInfo', value: cellInfo}], 5986 onsuccess: function(responseXML, status, xhr) { 5987 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 5988 widget: $this, 5989 handle: function(content) { 5990 cellEditor.children('.ui-cell-editor-input').html(content); 5991 } 5992 }); 5993 5994 return true; 5995 }, 5996 oncomplete: function(xhr, status, args, data) {
5997 cell.data('edit-events-bound', false); 5998 $this.showCurrentCell(cell); 5999 } 6000 }; 6001 6002 if(this.hasBehavior('cellEditInit')) { 6003 this.callBehavior('cellEditInit', options); 6004 } 6005 else { 6006 PrimeFaces.ajax.Request.handle(options); 6007 } 6008 }, 6009 6010 showCellEditor: function(c) { 6011 this.incellClick = true; 6012 6013 var cell = null; 6014 6015 if(c) { 6016 cell = c; 6017 6018 //remove contextmenu selection highlight 6019 if(this.contextMenuCell) { 6020 this.contextMenuCell.parent().removeClass('ui-state-highlight'); 6021 } 6022 } 6023 else { 6024 cell = this.contextMenuCell; 6025 } 6026 6027 var editorInput = cell.find('> .ui-cell-editor > .ui-cell-editor-input'); 6028 if(editorInput.length !== 0 && editorInput.children().length === 0 && this.cfg.editMode === 'cell') { 6029 // for lazy cellEditMode 6030 this.cellEditInit(cell); 6031 } 6032 else { 6033 this.showCurrentCell(cell); 6034 6035 if(this.hasBehavior('cellEditInit')) { 6036 var cellInfo = this.getCellMeta(cell); 6037 var ext = { 6038 params: [{name: this.id + '_cellInfo', value: cellInfo}] 6039 }; 6040 this.callBehavior('cellEditInit', ext); 6041 } 6042 } 6043 }, 6044 6045 showCurrentCell: function(cell) { 6046 var $this = this; 6047 6048 if(this.currentCell) { 6049 if(this.cfg.saveOnCellBlur) 6050 this.saveCell(this.currentCell); 6051 else if(!this.currentCell.is(cell)) 6052 this.doCellEditCancelRequest(this.currentCell); 6053 } 6054 6055 if(cell && cell.length) { 6056 this.currentCell = cell; 6057 6058 var cellEditor = cell.children('div.ui-cell-editor'), 6059 displayContainer = cellEditor.children('div.ui-cell-editor-output'), 6060 inputContainer = cellEditor.children('div.ui-cell-editor-input'), 6061 inputs = inputContainer.find(':input:enabled'), 6062 multi = inputs.length > 1; 6063 6064 cell.addClass('ui-state-highlight ui-cell-editing'); 6065 displayContainer.hide(); 6066 inputContainer.show(); 6067 inputs.eq(0).focus().select(); 6068 6069 //metadata 6070 if(multi) { 6071 var oldValues = []; 6072 for(var i = 0; i < inputs.length; i++) { 6073 var input = inputs.eq(i); 6074 6075 if(input.is(':checkbox')) { 6076 oldValues.push(input.val() + "_" + input.is(':checked')); 6077 } 6078 else { 6079 oldValues.push(input.val()); 6080 } 6081 } 6082 6083 cell.data('multi-edit', true); 6084 cell.data('old-value', oldValues); 6085 } 6086 else { 6087 cell.data('multi-edit', false); 6088 cell.data('old-value', inputs.eq(0).val()); 6089 } 6090 6091 //bind events on demand 6092 if(!cell.data('edit-events-bound')) { 6093 cell.data('edit-events-bound', true); 6094 6095 inputs.on('keydown.datatable-cell', function(e) { 6096 var keyCode = $.ui.keyCode, 6097 shiftKey = e.shiftKey, 6098 key = e.which, 6099 input = $(this); 6100 6101 if(key === keyCode.ENTER) { 6102 $this.saveCell(cell); 6103 $this.currentCell = null; 6104 6105 e.preventDefault(); 6106 } 6107 else if(key === keyCode.TAB) { 6108 if(multi) { 6109 var focusIndex = shiftKey ? input.index() - 1 : input.index() + 1; 6110 6111 if(focusIndex < 0 || (focusIndex === inputs.length) || input.parent().hasClass('ui-inputnumber') || input.parent().hasClass('ui-helper-hidden-accessible')) { 6112 $this.tabCell(cell, !shiftKey); 6113 } else { 6114 inputs.eq(focusIndex).focus(); 6115 } 6116 } 6117 else { 6118 $this.tabCell(cell, !shiftKey); 6119 } 6120 6121 e.preventDefault(); 6122 } 6123 else if(key === keyCode.ESCAPE) { 6124 $this.doCellEditCancelRequest(cell); 6125 e.preventDefault(); 6126 } 6127 }) 6128 .on('focus.datatable-cell click.datatable-cell', function(e) { 6129 $this.currentCell = cell; 6130 }); 6131 } 6132 } 6133 else { 6134 this.currentCell = null; 6135 } 6136 }, 6137 6138 tabCell: function(cell, forward) { 6139 var targetCell = forward ? cell.nextAll('td.ui-editable-column:first') : cell.prevAll('td.ui-editable-column:first'); 6140 if(targetCell.length == 0) { 6141 var tabRow = forward ? cell.parent().next() : cell.parent().prev(); 6142 targetCell = forward ? tabRow.children('td.ui-editable-column:first') : tabRow.children('td.ui-editable-column:last'); 6143 } 6144 6145 var cellEditor = targetCell.children('div.ui-cell-editor'), 6146 inputContainer = cellEditor.children('div.ui-cell-editor-input'); 6147 6148 if(inputContainer.length) { 6149 var inputs = inputContainer.find(':input'),
6150 disabledInputs = inputs.filter(':disabled'); 6151 6152 if(inputs.length === disabledInputs.length) { 6153 this.tabCell(targetCell, forward); 6154 return; 6155 } 6156 } 6157 6158 this.showCellEditor(targetCell); 6159 }, 6160 6161 saveCell: function(cell) { 6162 var inputs = cell.find('div.ui-cell-editor-input :input:enabled'), 6163 changed = false, 6164 valid = cell.data('valid'), 6165 $this = this; 6166 6167 if(cell.data('multi-edit')) { 6168 var oldValues = cell.data('old-value'); 6169 for(var i = 0; i < inputs.length; i++) { 6170 var input = inputs.eq(i), 6171 inputVal = input.val(), 6172 oldValue = oldValues[i]; 6173 6174 if(input.is(':checkbox') || input.is(':radio')) { 6175 inputVal = inputVal + "_" + input.is(':checked'); 6176 } 6177 6178 if(inputVal != oldValue) { 6179 changed = true; 6180 break; 6181 } 6182 } 6183 } 6184 else { 6185 var input = inputs.eq(0), 6186 inputVal = input.val(), 6187 oldValue = cell.data('old-value'); 6188 6189 if(input.is(':checkbox') || input.is(':radio')) { 6190 inputVal = inputVal + "_" + input.is(':checked'); 6191 } 6192 changed = (inputVal != oldValue); 6193 } 6194 6195 if(changed || valid == false) 6196 $this.doCellEditRequest(cell); 6197 else 6198 $this.viewMode(cell); 6199 6200 if(this.cfg.saveOnCellBlur) { 6201 this.currentCell = null; 6202 } 6203 }, 6204 6205 viewMode: function(cell) { 6206 var cellEditor = cell.children('div.ui-cell-editor'), 6207 editableContainer = cellEditor.children('div.ui-cell-editor-input'), 6208 displayContainer = cellEditor.children('div.ui-cell-editor-output'); 6209 6210 cell.removeClass('ui-cell-editing ui-state-error ui-state-highlight'); 6211 displayContainer.show(); 6212 editableContainer.hide(); 6213 cell.removeData('old-value').removeData('multi-edit'); 6214 6215 if(this.cfg.cellEditMode === "lazy") { 6216 editableContainer.children().remove(); 6217 } 6218 }, 6219 6220 doCellEditRequest: function(cell) { 6221 var rowMeta = this.getRowMeta(cell.closest('tr')), 6222 cellEditor = cell.children('.ui-cell-editor'), 6223 cellEditorId = cellEditor.attr('id'), 6224 cellIndex = cell.index(), 6225 $this = this; 6226 6227 if(this.cfg.scrollable && this.cfg.frozenColumns) { 6228 cellIndex = (this.scrollTbody.is(cell.closest('tbody'))) ? (cellIndex + $this.cfg.frozenColumns) : cellIndex; 6229 } 6230 6231 var cellInfo = rowMeta.index + ',' + cellIndex; 6232 if(rowMeta.key) { 6233 cellInfo = cellInfo + ',' + rowMeta.key; 6234 } 6235 6236 var options = { 6237 source: this.id, 6238 process: this.id, 6239 update: this.id, 6240 params: [{name: this.id + '_encodeFeature', value: true}, 6241 {name: this.id + '_cellInfo', value: cellInfo}, 6242 {name: cellEditorId, value: cellEditorId}], 6243 onsuccess: function(responseXML, status, xhr) { 6244 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 6245 widget: $this, 6246 handle: function(content) { 6247 cellEditor.children('.ui-cell-editor-output').html(content); 6248 } 6249 }); 6250 6251 return true; 6252 }, 6253 oncomplete: function(xhr, status, args, data) { 6254 if(args.validationFailed){ 6255 cell.data('valid', false); 6256 cell.addClass('ui-state-error'); 6257 } 6258 else{ 6259 cell.data('valid', true); 6260 $this.viewMode(cell); 6261 } 6262 6263 if($this.cfg.clientCache) { 6264 $this.clearCacheMap(); 6265 } 6266 } 6267 }; 6268 6269 if(this.hasBehavior('cellEdit')) { 6270 this.callBehavior('cellEdit', options); 6271 } 6272 else { 6273 PrimeFaces.ajax.Request.handle(options); 6274 } 6275 }, 6276 6277 doCellEditCancelRequest: function(cell) { 6278 var rowMeta = this.getRowMeta(cell.closest('tr')), 6279 cellEditor = cell.children('.ui-cell-editor'), 6280 cellIndex = cell.index(), 6281 $this = this; 6282 6283 if(this.cfg.scrollable && this.cfg.frozenColumns) { 6284 cellIndex = (this.scrollTbody.is(cell.closest('tbody'))) ? (cellIndex + $this.cfg.frozenColumns) : cellIndex; 6285 } 6286 6287 var cellInfo = rowMeta.index + ',' + cellIndex; 6288 if(rowMeta.key) { 6289 cellInfo = cellInfo + ',' + rowMeta.key; 6290 } 6291 6292 this.currentCell = null; 6293 6294 var options = { 6295 source: this.id, 6296 process: this.id, 6297 update: this.id, 6298 params: [{name: this.id + '_encodeFeature', value: true}, 6299 {name: this.id + '_cellEditCancel', value: true}, 6300 {name: this.id + '_cellInfo', value: cellInfo}], 6301 onsuccess: function(responseXML, status, xhr) { 6302 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 6303 widget: $this, 6304 handle: function(content) { 6305 cellEditor.children('.ui-cell-editor-input').html(content); 6306 } 6307 }); 6308 6309 return true; 6310 }, 6311 oncomplete: function(xhr, status, args, data) { 6312 $this.viewMode(cell);
6313 cell.data('edit-events-bound', false); 6314 6315 if($this.cfg.clientCache) { 6316 $this.clearCacheMap(); 6317 } 6318 } 6319 }; 6320 6321 if(this.hasBehavior('cellEditCancel')) { 6322 this.callBehavior('cellEditCancel', options); 6323 } 6324 else { 6325 PrimeFaces.ajax.Request.handle(options); 6326 } 6327 }, 6328 6329 /** 6330 * Saves the edited row 6331 */ 6332 saveRowEdit: function(rowEditor) { 6333 this.doRowEditRequest(rowEditor, 'save'); 6334 }, 6335 6336 /** 6337 * Cancels row editing 6338 */ 6339 cancelRowEdit: function(rowEditor) { 6340 this.doRowEditRequest(rowEditor, 'cancel'); 6341 }, 6342 6343 /** 6344 * Sends an ajax request to handle row save or cancel 6345 */ 6346 doRowEditRequest: function(rowEditor, action) { 6347 var row = rowEditor.closest('tr'), 6348 rowIndex = this.getRowMeta(row).index, 6349 expanded = row.hasClass('ui-expanded-row'), 6350 $this = this, 6351 options = { 6352 source: this.id, 6353 process: this.id, 6354 update: this.id, 6355 formId: this.cfg.formId, 6356 params: [{name: this.id + '_rowEditIndex', value: this.getRowMeta(row).index}, 6357 {name: this.id + '_rowEditAction', value: action}, 6358 {name: this.id + '_encodeFeature', value: true}], 6359 onsuccess: function(responseXML, status, xhr) { 6360 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 6361 widget: $this, 6362 handle: function(content) { 6363 if(expanded) { 6364 this.collapseRow(row); 6365 } 6366 6367 this.updateRow(row, content); 6368 } 6369 }); 6370 6371 return true; 6372 }, 6373 oncomplete: function(xhr, status, args, data) { 6374 if(args && args.validationFailed) { 6375 $this.invalidateRow(rowIndex); 6376 } 6377 else { 6378 if($this.cfg.rowEditMode === "lazy") { 6379 var index = ($this.paginator) ? (rowIndex % $this.paginator.getRows()) : rowIndex, 6380 newRow = $this.tbody.children('tr').eq(index); 6381 $this.getRowEditors(newRow).children('.ui-cell-editor-input').children().remove(); 6382 } 6383 } 6384 6385 if($this.cfg.clientCache) { 6386 $this.clearCacheMap(); 6387 } 6388 } 6389 }; 6390 6391 if(action === 'save') { 6392 this.getRowEditors(row).each(function() { 6393 options.params.push({name: this.id, value: this.id}); 6394 }); 6395 } 6396 6397 if(action === 'save' && this.hasBehavior('rowEdit')) { 6398 this.callBehavior('rowEdit', options); 6399 } 6400 else if(action === 'cancel' && this.hasBehavior('rowEditCancel')) { 6401 this.callBehavior('rowEditCancel', options); 6402 } 6403 else { 6404 PrimeFaces.ajax.Request.handle(options); 6405 } 6406 }, 6407 6408 lazyRowEditInit: function(row) { 6409 var rowIndex = this.getRowMeta(row).index, 6410 $this = this; 6411 6412 var options = { 6413 source: this.id, 6414 process: this.id, 6415 update: this.id, 6416 global: false, 6417 params: [{name: this.id + '_encodeFeature', value: true}, 6418 {name: this.id + '_rowEditInit', value: true}, 6419 {name: this.id + '_rowEditIndex', value: rowIndex}], 6420 onsuccess: function(responseXML, status, xhr) { 6421 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 6422 widget: $this, 6423 handle: function(content) { 6424 $this.updateRow(row, content); 6425 } 6426 }); 6427 6428 return true; 6429 }, 6430 oncomplete: function(xhr, status, args, data) { 6431 var index = ($this.paginator) ? (rowIndex % $this.paginator.getRows()) : rowIndex, 6432 newRow = $this.tbody.children('tr').eq(index); 6433 $this.showRowEditors(newRow); 6434 } 6435 }; 6436 6437 if(this.hasBehavior('rowEditInit')) { 6438 this.cfg.behaviors['rowEditInit'].call(this, options); 6439 } 6440 else { 6441 PrimeFaces.ajax.Request.handle(options); 6442 } 6443 }, 6444 6445 /* 6446 * Updates row with given content 6447 */ 6448 updateRow: function(row, content) { 6449 row.replaceWith(content); 6450 }, 6451 6452 /**
6453 * Displays row editors in invalid format 6454 */ 6455 invalidateRow: function(index) { 6456 var i = (this.paginator) ? (index % this.paginator.getRows()) : index; 6457 this.tbody.children('tr[data-ri]').eq(i).addClass('ui-widget-content ui-row-editing ui-state-error'); 6458 }, 6459 6460 /** 6461 * Finds all editors of a row 6462 */ 6463 getRowEditors: function(row) { 6464 return row.find('div.ui-cell-editor'); 6465 }, 6466 6467 /** 6468 * Returns the paginator instance if any defined 6469 */ 6470 getPaginator: function() { 6471 return this.paginator; 6472 }, 6473 6474 /** 6475 * Writes selected row ids to state holder 6476 */ 6477 writeSelections: function() { 6478 $(this.selectionHolder).val(this.selection.join(',')); 6479 }, 6480 6481 isSingleSelection: function() { 6482 return this.cfg.selectionMode == 'single'; 6483 }, 6484 6485 isMultipleSelection: function() { 6486 return this.cfg.selectionMode == 'multiple' || this.isCheckboxSelectionEnabled(); 6487 }, 6488 6489 /** 6490 * Clears the selection state 6491 */ 6492 clearSelection: function() { 6493 this.selection = []; 6494 6495 $(this.selectionHolder).val(''); 6496 }, 6497 6498 /** 6499 * Returns true|false if selection is enabled|disabled 6500 */ 6501 isSelectionEnabled: function() { 6502 return this.cfg.selectionMode != undefined || this.cfg.columnSelectionMode != undefined; 6503 }, 6504 6505 /** 6506 * Returns true|false if checkbox selection is enabled|disabled 6507 */ 6508 isCheckboxSelectionEnabled: function() { 6509 return this.cfg.selectionMode === 'checkbox'; 6510 }, 6511 6512 /** 6513 * Returns true|false if radio selection is enabled|disabled 6514 */ 6515 isRadioSelectionEnabled: function() { 6516 return this.cfg.selectionMode === 'radio'; 6517 }, 6518 6519 /** 6520 * Clears table filters 6521 */ 6522 clearFilters: function() { 6523 this.thead.find('> tr > th.ui-filter-column > .ui-column-filter').val(''); 6524 $(this.jqId + '\\:globalFilter').val(''); 6525 6526 this.filter(); 6527 }, 6528 6529 setupResizableColumns: function() { 6530 this.cfg.resizeMode = this.cfg.resizeMode||'fit'; 6531 6532 this.fixColumnWidths(); 6533 6534 this.hasColumnGroup = this.hasColGroup(); 6535 if(this.hasColumnGroup) { 6536 this.addGhostRow(); 6537 } 6538 6539 if(!this.cfg.liveResize) { 6540 this.resizerHelper = $('<div class="ui-column-resizer-helper ui-state-highlight"></div>').appendTo(this.jq); 6541 } 6542 6543 this.addResizers(); 6544 6545 var resizers = this.thead.find('> tr > th > span.ui-column-resizer'), 6546 $this = this; 6547 6548 resizers.draggable({ 6549 axis: 'x', 6550 start: function(event, ui) { 6551 ui.helper.data('originalposition', ui.helper.offset()); 6552 6553 if($this.cfg.liveResize) { 6554 $this.jq.css('cursor', 'col-resize'); 6555 } 6556 else { 6557 var header = $this.cfg.stickyHeader ? $this.clone : $this.thead, 6558 height = $this.cfg.scrollable ? $this.scrollBody.height() : header.parent().height() - header.height() - 1; 6559 6560 if($this.cfg.stickyHeader) { 6561 height = height - $this.relativeHeight; 6562 } 6563 6564 $this.resizerHelper.height(height); 6565 $this.resizerHelper.show(); 6566 } 6567 }, 6568 drag: function(event, ui) { 6569 if($this.cfg.liveResize) { 6570 $this.resize(event, ui); 6571 } 6572 else { 6573 $this.resizerHelper.offset({ 6574 left: ui.helper.offset().left + ui.helper.width() / 2, 6575 top: $this.thead.offset().top + $this.thead.height() 6576 }); 6577 } 6578 }, 6579 stop: function(event, ui) { 6580 ui.helper.css({ 6581 'left': '', 6582 'top': '0px' 6583 }); 6584 6585 if($this.cfg.liveResize) { 6586 $this.jq.css('cursor', 'default'); 6587 } else { 6588 $this.resize(event, ui); 6589 $this.resizerHelper.hide(); 6590 } 6591 6592 if($this.cfg.resizeMode === 'expand') { 6593 setTimeout(function() { 6594 $this.fireColumnResizeEvent(ui.helper.parent()); 6595 }, 5); 6596 } 6597 else { 6598 $this.fireColumnResizeEvent(ui.helper.parent()); 6599 } 6600 6601 if($this.cfg.stickyHeader) { 6602 $this.reclone(); 6603 } 6604 }, 6605 containment: this.cfg.resizeMode === "expand" ? "document" : this.jq 6606 }); 6607 }, 6608 6609 fireColumnResizeEvent: function(columnHeader) { 6610 if(this.hasBehavior('colResize')) { 6611 var options = { 6612 source: this.id, 6613 process: this.id, 6614 params: [ 6615 {name: this.id + '_colResize', value: true}, 6616 {name: this.id + '_columnId', value: columnHeader.attr('id')}, 6617 {name: this.id + '_width', value: parseInt(columnHeader.width())}, 6618 {name: this.id + '_height', value: parseInt(columnHeader.height())} 6619 ] 6620 }; 6621 6622 this.callBehavior('colResize', options); 6623 } 6624 }, 6625 6626 hasColGroup: function() { 6627 return this.thead.children('tr').length > 1; 6628 }, 6629 6630 addGhostRow: function() { 6631 var firstRow = this.tbody.find('tr:first'); 6632 if(firstRow.hasClass('ui-datatable-empty-message')) { 6633 return; 6634 } 6635 6636 var columnsOfFirstRow = firstRow.children('td'), 6637 dataColumnsCount = columnsOfFirstRow.length, 6638 columnMarkup = ''; 6639 6640 for(var i = 0; i < dataColumnsCount; i++) { 6641 var colWidth = columnsOfFirstRow.eq(i).width() + 1, 6642 id = this.id + '_ghost_' + i; 6643 6644 if(this.cfg.multiViewState && this.resizableStateHolder.attr('value')) { 6645 colWidth = (this.findColWidthInResizableState(id) || colWidth); 6646 } 6647 6648 columnMarkup += '<th id="' + id + '" style="height:0px;border-bottom-width: 0px;border-top-width: 0px;padding-top: 0px;padding-bottom: 0px;outline: 0 none; width:' + colWidth + 'px" class="ui-resizable-column"></th>'; 6649 } 6650 6651 this.thead.prepend('<tr>' + columnMarkup + '</tr>'); 6652 6653 if(this.cfg.scrollable) { 6654 this.theadClone.prepend('<tr>' + columnMarkup + '</tr>'); 6655 this.footerTable.children('tfoot').prepend('<tr>' + columnMarkup + '</tr>'); 6656 } 6657 }, 6658 6659 findGroupResizer: function(ui) { 6660 for(var i = 0; i < this.groupResizers.length; i++) { 6661 var groupResizer = this.groupResizers.eq(i); 6662 if(groupResizer.offset().left === ui.helper.data('originalposition').left) { 6663 return groupResizer; 6664 } 6665 } 6666 6667 return null; 6668 }, 6669 6670 addResizers: function() { 6671 var resizableColumns = this.thead.find('> tr > th.ui-resizable-column'); 6672 resizableColumns.prepend('<span class="ui-column-resizer"> </span>'); 6673 6674 if(this.cfg.resizeMode === 'fit') { 6675 resizableColumns.filter(':last-child').children('span.ui-column-resizer').hide(); 6676 } 6677 6678 if(this.hasColumnGroup) { 6679 this.groupResizers = this.thead.find('> tr:first > th > .ui-column-resizer'); 6680 } 6681 }, 6682 6683 resize: function(event, ui) { 6684 var columnHeader, nextColumnHeader, change = null, newWidth = null, nextColumnWidth = null, 6685 expandMode = (this.cfg.resizeMode === 'expand'), 6686 table = this.thead.parent(), 6687 $this = this; 6688 6689 if(this.hasColumnGroup) { 6690 var groupResizer = this.findGroupResizer(ui); 6691 if(!groupResizer) { 6692 return; 6693 } 6694 6695 columnHeader = groupResizer.parent(); 6696 } 6697 else { 6698 columnHeader = ui.helper.parent(); 6699 } 6700 6701 var title = columnHeader.children('.ui-column-title'); 6702 if(PrimeFaces.env.isIE()) { 6703 title.css('display', 'none'); 6704 } 6705 6706 var nextColumnHeader = columnHeader.nextAll(':visible:first'); 6707 6708 if(this.cfg.liveResize) { 6709 change = columnHeader.outerWidth() - (event.pageX - columnHeader.offset().left), 6710 newWidth = (columnHeader.width() - change), 6711 nextColumnWidth = (nextColumnHeader.width() + change); 6712 } 6713 else { 6714 change = (ui.position.left - ui.originalPosition.left), 6715 newWidth = (columnHeader.width() + change), 6716 nextColumnWidth = (nextColumnHeader.width() - change); 6717 } 6718 6719 var minWidth = parseInt(columnHeader.css('min-width')); 6720 minWidth = (minWidth == 0) ? 15 : minWidth; 6721 6722 if(PrimeFaces.env.isIE()) { 6723 title.css('display', ''); 6724 } 6725 6726 if((newWidth > minWidth && nextColumnWidth > minWidth) || (expandMode && newWidth > minWidth)) { 6727 if(expandMode) { 6728 table.width(table.width() + change); 6729 setTimeout(function() { 6730 columnHeader.width(newWidth); 6731 $this.updateResizableState(columnHeader, nextColumnHeader, table, newWidth, null); 6732 }, 1); 6733 } 6734 else { 6735 columnHeader.width(newWidth); 6736 nextColumnHeader.width(nextColumnWidth); 6737 this.updateResizableState(columnHeader, nextColumnHeader, table, newWidth, nextColumnWidth); 6738 } 6739 6740 if(this.cfg.scrollable) { 6741 var cloneTable = this.theadClone.parent(), 6742 colIndex = columnHeader.index(); 6743 6744 if(expandMode) { 6745 //body 6746 cloneTable.width(cloneTable.width() + change); 6747 6748 //footer 6749 this.footerTable.width(this.footerTable.width() + change); 6750 6751 setTimeout(function() { 6752 if($this.hasColumnGroup) { 6753 $this.theadClone.find('> tr:first').children('th').eq(colIndex).width(newWidth); //body 6754 $this.footerTable.find('> tfoot > tr:first').children('th').eq(colIndex).width(newWidth); //footer 6755 } 6756 else { 6757 $this.theadClone.find(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); //body 6758 $this.footerCols.eq(colIndex).width(newWidth); //footer 6759 } 6760 }, 1); 6761 } 6762 else { 6763 if(this.hasColumnGroup) { 6764 //body 6765 this.theadClone.find('> tr:first').children('th').eq(colIndex).width(newWidth); 6766 this.theadClone.find('> tr:first').children('th').eq(colIndex + 1).width(nextColumnWidth); 6767 6768 //footer 6769 this.footerTable.find('> tfoot > tr:first').children('th').eq(colIndex).width(newWidth); 6770 this.footerTable.find('> tfoot > tr:first').children('th').eq(colIndex + 1).width(nextColumnWidth); 6771 } 6772 else { 6773 //body 6774 this.theadClone.find(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); 6775 this.theadClone.find(PrimeFaces.escapeClientId(nextColumnHeader.attr('id') + '_clone')).width(nextColumnWidth); 6776 6777 //footer 6778 if(this.footerCols.length > 0) { 6779 var footerCol = this.footerCols.eq(colIndex), 6780 nextFooterCol = footerCol.next(); 6781 6782 footerCol.width(newWidth); 6783 nextFooterCol.width(nextColumnWidth); 6784 } 6785 } 6786 } 6787 } 6788 } 6789 }, 6790 6791 /** 6792 * Remove given rowIndex from selection 6793 */ 6794 removeSelection: function(rowIndex) { 6795 this.selection = $.grep(this.selection, function(value) { 6796 return value != rowIndex; 6797 }); 6798 }, 6799 6800 /** 6801 * Adds given rowKey to selection if it doesn't exist already 6802 */ 6803 addSelection: function(rowKey) { 6804 if(!this.isSelected(rowKey)) { 6805 this.selection.push(rowKey); 6806 } 6807 }, 6808 6809 /** 6810 * Finds if given rowKey is in selection 6811 */ 6812 isSelected: function(rowKey) { 6813 return PrimeFaces.inArray(this.selection, rowKey); 6814 }, 6815 6816 getRowMeta: function(row) { 6817 var meta = { 6818 index: row.data('ri'), 6819 key: row.attr('data-rk') 6820 }; 6821 6822 return meta; 6823 }, 6824 6825 setupDraggableColumns: function() { 6826 this.orderStateHolder = $(this.jqId + '_columnOrder'); 6827 this.saveColumnOrder(); 6828 6829 this.dragIndicatorTop = $('<span class="ui-icon ui-icon-arrowthick-1-s" style="position:absolute"></span>').hide().appendTo(this.jq); 6830 this.dragIndicatorBottom = $('<span class="ui-icon ui-icon-arrowthick-1-n" style="position:absolute"></span>').hide().appendTo(this.jq); 6831 6832 var $this = this; 6833 6834 $(this.jqId + ' thead th').draggable({ 6835 appendTo: 'body', 6836 opacity: 0.75, 6837 cursor: 'move', 6838 scope: this.id, 6839 cancel: ':input,.ui-column-resizer', 6840 start: function(event, ui) { 6841 ui.helper.css('z-index', ++PrimeFaces.zindex); 6842 }, 6843 drag: function(event, ui) { 6844 var droppable = ui.helper.data('droppable-column'); 6845 6846 if(droppable) { 6847 var droppableOffset = droppable.offset(), 6848 topArrowY = droppableOffset.top - 10, 6849 bottomArrowY = droppableOffset.top + droppable.height() + 8, 6850 arrowX = null; 6851 6852 //calculate coordinates of arrow depending on mouse location 6853 if(event.originalEvent.pageX >= droppableOffset.left + (droppable.width() / 2)) { 6854 var nextDroppable = droppable.next(); 6855 if(nextDroppable.length == 1) 6856 arrowX = nextDroppable.offset().left - 9; 6857 else 6858 arrowX = droppable.offset().left + droppable.
6858innerWidth() - 9; 6859 6860 ui.helper.data('drop-location', 1); //right 6861 } 6862 else { 6863 arrowX = droppableOffset.left - 9; 6864 ui.helper.data('drop-location', -1); //left 6865 } 6866 6867 $this.dragIndicatorTop.offset({ 6868 'left': arrowX, 6869 'top': topArrowY - 3 6870 }).show(); 6871 6872 $this.dragIndicatorBottom.offset({ 6873 'left': arrowX, 6874 'top': bottomArrowY - 3 6875 }).show(); 6876 } 6877 }, 6878 stop: function(event, ui) { 6879 //hide dnd arrows 6880 $this.dragIndicatorTop.css({ 6881 'left':0, 6882 'top':0 6883 }).hide(); 6884 6885 $this.dragIndicatorBottom.css({ 6886 'left':0, 6887 'top':0 6888 }).hide(); 6889 }, 6890 helper: function() { 6891 var header = $(this), 6892 helper = $('<div class="ui-widget ui-state-default" style="padding:4px 10px;text-align:center;"></div>'); 6893 6894 helper.width(header.width()); 6895 helper.height(header.height()); 6896 6897 helper.html(header.html()); 6898 6899 return helper.get(0); 6900 } 6901 }).droppable({ 6902 hoverClass:'ui-state-highlight', 6903 tolerance:'pointer', 6904 scope: this.id, 6905 over: function(event, ui) { 6906 ui.helper.data('droppable-column', $(this)); 6907 }, 6908 drop: function(event, ui) { 6909 var draggedColumnHeader = ui.draggable, 6910 dropLocation = ui.helper.data('drop-location'), 6911 droppedColumnHeader = $(this), 6912 draggedColumnFooter = null, 6913 droppedColumnFooter = null; 6914 6915 var draggedCells = $this.tbody.find('> tr:not(.ui-expanded-row-content) > td:nth-child(' + (draggedColumnHeader.index() + 1) + ')'), 6916 droppedCells = $this.tbody.find('> tr:not(.ui-expanded-row-content) > td:nth-child(' + (droppedColumnHeader.index() + 1) + ')'); 6917 6918 if($this.tfoot.length) { 6919 var footerColumns = $this.tfoot.find('> tr > td'), 6920 draggedColumnFooter = footerColumns.eq(draggedColumnHeader.index()), 6921 droppedColumnFooter = footerColumns.eq(droppedColumnHeader.index()); 6922 } 6923 6924 //drop right 6925 if(dropLocation > 0) { 6926 if($this.cfg.resizableColumns) { 6927 if(droppedColumnHeader.next().length) { 6928 droppedColumnHeader.children('span.ui-column-resizer').show(); 6929 draggedColumnHeader.children('span.ui-column-resizer').hide(); 6930 } 6931 } 6932 6933 draggedColumnHeader.insertAfter(droppedColumnHeader); 6934 6935 draggedCells.each(function(i, item) { 6936 $(this).insertAfter(droppedCells.eq(i)); 6937 }); 6938 6939 if(draggedColumnFooter && droppedColumnFooter) { 6940 draggedColumnFooter.insertAfter(droppedColumnFooter); 6941 } 6942 6943 //sync clone 6944 if($this.cfg.scrollable) { 6945 var draggedColumnClone = $(document.getElementById(draggedColumnHeader.attr('id') + '_clone')), 6946 droppedColumnClone = $(document.getElementById(droppedColumnHeader.attr('id') + '_clone')); 6947 draggedColumnClone.insertAfter(droppedColumnClone); 6948 } 6949 } 6950 //drop left 6951 else { 6952 draggedColumnHeader.insertBefore(droppedColumnHeader); 6953 6954 draggedCells.each(function(i, item) { 6955 $(this).insertBefore(droppedCells.eq(i)); 6956 }); 6957 6958 if(draggedColumnFooter && droppedColumnFooter) { 6959 draggedColumnFooter.insertBefore(droppedColumnFooter); 6960 } 6961 6962 //sync clone 6963 if($this.cfg.scrollable) { 6964 var draggedColumnClone = $(document.getElementById(draggedColumnHeader.attr('id') + '_clone')), 6965 droppedColumnClone = $(document.getElementById(droppedColumnHeader.attr('id') + '_clone')); 6966 draggedColumnClone.insertBefore(droppedColumnClone); 6967 } 6968 } 6969 6970 //save order 6971 $this.saveColumnOrder(); 6972 6973 //fire colReorder event 6974 if($this.hasBehavior('colReorder')) { 6975 var ext = null; 6976 6977 if($this.cfg.multiViewState) { 6978 ext = { 6979 params: [{name: this.id + '_encodeFeature', value: true}] 6980 }; 6981 } 6982 6983 $this.callBehavior('colReorder', ext); 6984 } 6985 } 6986 }); 6987 }, 6988 6989 saveColumnOrder: function() { 6990 var columnIds = [], 6991 columns = $(this.jqId + ' thead:first th'); 6992 6993 columns.each(function(i, item) { 6994 columnIds.push($(item).attr('id')); 6995 }); 6996 6997 this.orderStateHolder.val(columnIds.join(',')); 6998 }, 6999 7000 makeRowsDraggable: function() { 7001 var $this = this, 7002 draggableHandle = this.cfg.rowDragSelector||'td,span:not(.ui-c)'; 7003 7004 this.tbody.sortable({ 7005 placeholder: 'ui-datatable-rowordering ui-state-active', 7006 cursor: 'move', 7007 handle: draggableHandle, 7008 appendTo: document.body, 7009 start: function(event, ui) { 7010 ui.helper.css('z-index', ++PrimeFaces.zindex); 7011 }, 7012 helper: function(event, ui) { 7013 var cells = ui.children(),
7014 helper = $('<div class="ui-datatable ui-widget"><table><tbody class="ui-datatable-data"></tbody></table></div>'), 7015 helperRow = ui.clone(), 7016 helperCells = helperRow.children(); 7017 7018 for(var i = 0; i < helperCells.length; i++) { 7019 helperCells.eq(i).width(cells.eq(i).width()); 7020 } 7021 7022 helperRow.appendTo(helper.find('tbody')); 7023 7024 return helper; 7025 }, 7026 update: function(event, ui) { 7027 var fromIndex = ui.item.data('ri'), 7028 toIndex = $this.paginator ? $this.paginator.getFirst() + ui.item.index(): ui.item.index(); 7029 7030 $this.syncRowParity(); 7031 7032 var options = { 7033 source: $this.id, 7034 process: $this.id, 7035 params: [ 7036 {name: $this.id + '_rowreorder', value: true}, 7037 {name: $this.id + '_fromIndex', value: fromIndex}, 7038 {name: $this.id + '_toIndex', value: toIndex}, 7039 {name: this.id + '_skipChildren', value: true} 7040 ] 7041 } 7042 7043 if($this.hasBehavior('rowReorder')) { 7044 $this.callBehavior('rowReorder', options); 7045 } 7046 else { 7047 PrimeFaces.ajax.Request.handle(options); 7048 } 7049 }, 7050 change: function(event, ui) { 7051 if($this.cfg.scrollable) { 7052 PrimeFaces.scrollInView($this.scrollBody, ui.placeholder); 7053 } 7054 } 7055 }); 7056 }, 7057 7058 syncRowParity: function() { 7059 var rows = this.tbody.children('tr.ui-widget-content'), 7060 first = this.paginator ? this.paginator.getFirst(): 0; 7061 7062 for(var i = first; i < rows.length; i++) { 7063 var row = rows.eq(i); 7064 7065 row.data('ri', i).removeClass('ui-datatable-even ui-datatable-odd'); 7066 7067 if(i % 2 === 0) 7068 row.addClass('ui-datatable-even'); 7069 else 7070 row.addClass('ui-datatable-odd'); 7071 7072 } 7073 }, 7074 7075 /** 7076 * Returns if there is any data displayed 7077 */ 7078 isEmpty: function() { 7079 return this.tbody.children('tr.ui-datatable-empty-message').length === 1; 7080 }, 7081 7082 getSelectedRowsCount: function() { 7083 return this.isSelectionEnabled() ? this.selection.length : 0; 7084 }, 7085 7086 updateHeaderCheckbox: function() { 7087 if(this.isEmpty()) { 7088 this.uncheckHeaderCheckbox(); 7089 this.disableHeaderCheckbox(); 7090 } 7091 else if(!this.cfg.selectionPageOnly) { 7092 if(this.selection.includes('@all')) { 7093 this.enableHeaderCheckbox(); 7094 this.checkHeaderCheckbox(); 7095 } 7096 } 7097 else { 7098 var checkboxes, selectedCheckboxes, enabledCheckboxes, disabledCheckboxes; 7099 7100 if(this.cfg.nativeElements) { 7101 checkboxes = this.tbody.find('> tr > td.ui-selection-column > :checkbox'); 7102 enabledCheckboxes = checkboxes.filter(':enabled'); 7103 disabledCheckboxes = checkboxes.filter(':disabled'); 7104 selectedCheckboxes = enabledCheckboxes.filter(':checked'); 7105 } 7106 else { 7107 checkboxes = this.tbody.find('> tr > td.ui-selection-column .ui-chkbox-box'); 7108 enabledCheckboxes = checkboxes.filter(':not(.ui-state-disabled)'); 7109 disabledCheckboxes = checkboxes.filter('.ui-state-disabled'); 7110 selectedCheckboxes = enabledCheckboxes.prev().children(':checked'); 7111 } 7112 7113 if(enabledCheckboxes.length && enabledCheckboxes.length === selectedCheckboxes.length) 7114 this.checkHeaderCheckbox(); 7115 else 7116 this.uncheckHeaderCheckbox(); 7117 7118 if(checkboxes.length === disabledCheckboxes.length) 7119 this.disableHeaderCheckbox(); 7120 else 7121 this.enableHeaderCheckbox(); 7122 } 7123 }, 7124 7125 checkHeaderCheckbox: function() { 7126 if(this.cfg.nativeElements) { 7127 this.checkAllToggler.prop('checked', true); 7128 } 7129 else { 7130 this.checkAllToggler.addClass('ui-state-active').children('span.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 7131 this.checkAllTogglerInput.prop('checked', true).attr('aria-checked', true); 7132 } 7133 }, 7134 7135 uncheckHeaderCheckbox: function() { 7136 if(this.cfg.nativeElements) { 7137 this.checkAllToggler.prop('checked', false); 7138 } 7139 else { 7140 this.checkAllToggler.removeClass('ui-state-active').children('span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 7141 this.checkAllTogglerInput.prop('checked', false).attr('aria-checked', false); 7142 } 7143 }, 7144 7145 disableHeaderCheckbox: function() { 7146 if(this.cfg.nativeElements) 7147 this.checkAllToggler.prop('disabled', true); 7148 else 7149 this.checkAllToggler.addClass('ui-state-disabled'); 7150 }, 7151 7152 enableHeaderCheckbox: function() { 7153 if(this.cfg.nativeElements) 7154 this.checkAllToggler.prop('disabled', false); 7155 else 7156 this.checkAllToggler.removeClass('ui-state-disabled'); 7157 }, 7158 7159 setupStickyHeader: function() { 7160 var table = this.thead.parent(), 7161 offset = table.offset(), 7162 win = $(window), 7163 $this = this, 7164 orginTableContent = this.jq.find('> .ui-datatable-tablewrapper > table'), 7165 fixedElementsOnTop = this.cfg.stickyTopAt ? $(this.cfg.stickyTopAt) : null, 7166 fixedElementsHeight = 0; 7167 7168 if (fixedElementsOnTop && fixedElementsOnTop.length) { 7169 for (var i = 0; i < fixedElementsOnTop.length; i++) { 7170 fixedElementsHeight += fixedElementsOnTop.eq(i).outerHeight(); 7171 } 7172 } 7173
7174 this.stickyContainer = $('<div class="ui-datatable ui-datatable-sticky ui-widget"><table></table></div>'); 7175 this.clone = this.thead.clone(false); 7176 this.stickyContainer.children('table').append(this.thead); 7177 table.prepend(this.clone); 7178 7179 this.stickyContainer.css({ 7180 position: 'absolute', 7181 width: table.outerWidth(), 7182 top: offset.top, 7183 left: offset.left, 7184 'z-index': ++PrimeFaces.zindex 7185 }); 7186 7187 this.jq.prepend(this.stickyContainer); 7188 7189 if(this.cfg.resizableColumns) { 7190 this.relativeHeight = 0; 7191 } 7192 7193 PrimeFaces.utils.registerScrollHandler(this, 'scroll.' + this.id, function() { 7194 var scrollTop = win.scrollTop(), 7195 tableOffset = table.offset(); 7196 7197 if(scrollTop + fixedElementsHeight > tableOffset.top) { 7198 $this.stickyContainer.css({ 7199 'position': 'fixed', 7200 'top': fixedElementsHeight 7201 }) 7202 .addClass('ui-shadow ui-sticky'); 7203 7204 if($this.cfg.resizableColumns) { 7205 $this.relativeHeight = (scrollTop + fixedElementsHeight) - tableOffset.top; 7206 } 7207 7208 if(scrollTop + fixedElementsHeight >= (tableOffset.top + $this.tbody.height())) 7209 $this.stickyContainer.hide(); 7210 else 7211 $this.stickyContainer.show(); 7212 } 7213 else { 7214 $this.stickyContainer.css({ 7215 'position': 'absolute', 7216 'top': tableOffset.top 7217 }) 7218 .removeClass('ui-shadow ui-sticky'); 7219 7220 if($this.stickyContainer.is(':hidden')) { 7221 $this.stickyContainer.show(); 7222 } 7223 7224 if($this.cfg.resizableColumns) { 7225 $this.relativeHeight = 0; 7226 } 7227 } 7228 }); 7229 7230 PrimeFaces.utils.registerResizeHandler(this, 'resize.sticky-' + this.id, null, function(e) { 7231 var _delay = e.data.delay; 7232 7233 if (_delay !== null && typeof _delay === 'number' && _delay > -1) { 7234 if ($this.resizeTimeout) { 7235 clearTimeout($this.resizeTimeout); 7236 } 7237 7238 $this.stickyContainer.hide(); 7239 $this.resizeTimeout = setTimeout(function() { 7240 $this.stickyContainer.css('left', orginTableContent.offset().left); 7241 $this.stickyContainer.width(table.outerWidth()); 7242 $this.stickyContainer.show(); 7243 }, _delay); 7244 } 7245 else { 7246 $this.stickyContainer.width(table.outerWidth()); 7247 } 7248 }, { delay: null }); 7249 7250 //filter support 7251 this.clone.find('.ui-column-filter').prop('disabled', true); 7252 }, 7253 7254 getFocusableTbody: function() { 7255 return this.tbody; 7256 }, 7257 7258 reclone: function() { 7259 this.clone.remove(); 7260 this.clone = this.thead.clone(false); 7261 this.jq.find('.ui-datatable-tablewrapper > table').prepend(this.clone); 7262 }, 7263 7264 addRow: function() { 7265 var $this = this, 7266 options = { 7267 source: this.id, 7268 process: this.id, 7269 update: this.id, 7270 params: [{name: this.id + '_addrow', value: true}, 7271 {name: this.id + '_skipChildren', value: true}, 7272 {name: this.id + '_encodeFeature', value: true}], 7273 onsuccess: function(responseXML, status, xhr) { 7274 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 7275 widget: $this, 7276 handle: function(content) { 7277 this.tbody.append(content); 7278 } 7279 }); 7280 7281 return true; 7282 } 7283 }; 7284 7285 PrimeFaces.ajax.Request.handle(options); 7286 }, 7287 7288 clearCacheMap: function() { 7289 this.cacheMap = {}; 7290 }, 7291
7292 loadDataWithCache: function(newState) { 7293 var isRppChanged = false; 7294 if(this.cacheRows != newState.rows) { 7295 this.clearCacheMap(); 7296 this.cacheRows = newState.rows; 7297 isRppChanged = true; 7298 } 7299 7300 var pageFirst = newState.first, 7301 nextPageFirst = newState.rows + pageFirst, 7302 lastPageFirst = this.cfg.paginator.pageCount * newState.rows, 7303 hasNextPage = (!this.cacheMap[nextPageFirst]) && nextPageFirst < lastPageFirst; 7304 7305 if(this.cacheMap[pageFirst] && !isRppChanged) { 7306 this.updateData(this.cacheMap[pageFirst]); 7307 this.paginator.cfg.page = newState.page; 7308 this.paginator.updateUI(); 7309 7310 if(!hasNextPage) { 7311 this.updatePageState(newState); 7312 } 7313 } 7314 else { 7315 this.paginate(newState); 7316 } 7317 7318 if(hasNextPage) { 7319 this.fetchNextPage(newState); 7320 } 7321 }, 7322 7323 updateReflowDD: function(columnHeader, sortOrder) { 7324 if(this.reflowDD && this.cfg.reflow) { 7325 var options = this.reflowDD.children('option'), 7326 orderIndex = sortOrder > 0 ? 0 : 1; 7327 7328 options.filter(':selected').prop('selected', false); 7329 options.filter('[value="' + $.escapeSelector(columnHeader.index() + '_' + orderIndex) + '"]').prop('selected', true); 7330 } 7331 }, 7332 7333 groupRows: function() { 7334 var rows = this.tbody.children('tr'); 7335 for(var i = 0; i < this.cfg.groupColumnIndexes.length; i++) { 7336 this.groupRow(this.cfg.groupColumnIndexes[i], rows); 7337 } 7338 7339 rows.children('td.ui-duplicated-column').remove(); 7340 }, 7341 7342 groupRow: function(colIndex, rows) { 7343 var groupStartIndex = null, rowGroupCellData = null, rowGroupCount = null; 7344 7345 for(var i = 0; i < rows.length; i++) { 7346 var row = rows.eq(i); 7347 var column = row.children('td').eq(colIndex); 7348 var columnData = column.text(); 7349 if(rowGroupCellData != columnData) { 7350 groupStartIndex = i; 7351 rowGroupCellData = columnData; 7352 rowGroupCount = 1; 7353 7354 if (this.cfg.liveScroll && column[0].hasAttribute('rowspan')) { 7355 rowGroupCount = parseInt(column.attr('rowspan')); 7356 i += rowGroupCount - 1; 7357 } 7358 7359 row.addClass('ui-datatable-grouped-row'); 7360 } 7361 else { 7362 column.addClass('ui-duplicated-column'); 7363 rowGroupCount++; 7364 } 7365 7366 if(groupStartIndex != null && rowGroupCount > 1) { 7367 rows.eq(groupStartIndex).children('td').eq(colIndex).attr('rowspan', rowGroupCount); 7368 } 7369 } 7370 }, 7371 7372 bindToggleRowGroupEvents: function() { 7373 var expandableRows = this.tbody.children('tr.ui-rowgroup-header'), 7374 toggler = expandableRows.find('> td:first > a.ui-rowgroup-toggler'); 7375 7376 toggler.off('click.dataTable-rowgrouptoggler').on('click.dataTable-rowgrouptoggler', function(e) { 7377 var link = $(this), 7378 togglerIcon = link.children('.ui-rowgroup-toggler-icon'), 7379 parentRow = link.closest('tr.ui-rowgroup-header'); 7380 7381 if(togglerIcon.hasClass('ui-icon-circle-triangle-s')) { 7382 link.attr('aria-expanded', false); 7383 togglerIcon.addClass('ui-icon-circle-triangle-e').removeClass('ui-icon-circle-triangle-s'); 7384 parentRow.nextUntil('tr.ui-rowgroup-header').hide(); 7385 } 7386 else { 7387 link.attr('aria-expanded', true); 7388 togglerIcon.addClass('ui-icon-circle-triangle-s').removeClass('ui-icon-circle-triangle-e'); 7389 parentRow.nextUntil('tr.ui-rowgroup-header').show(); 7390 } 7391 7392 e.preventDefault(); 7393 }); 7394 }, 7395 7396 calculateColspan: function() { 7397 var visibleHeaderColumns = this.thead.find('> tr:first th:not(.ui-helper-hidden):not(.ui-grouped-column)'), 7398 colSpanValue = 0; 7399 7400 for(var i = 0; i < visibleHeaderColumns.length; i++) { 7401 var column = visibleHeaderColumns.eq(i); 7402 if(column.is('[colspan]')) { 7403 colSpanValue += parseInt(column.attr('colspan')); 7404 } 7405 else { 7406 colSpanValue++; 7407 } 7408 } 7409 7410 return colSpanValue; 7411 }, 7412 7413 updateColspan: function(row, colspanValue) { 7414 row.children('td').attr('colspan', colspanValue || this.calculateColspan()); 7415 }, 7416 7417 updateEmptyColspan: function() { 7418 var emptyRow = this.tbody.children('tr:first'); 7419 if(emptyRow && emptyRow.hasClass('ui-datatable-empty-message')) { 7420 this.updateColspan(emptyRow); 7421 } 7422 }, 7423 7424 updateRowspan: function(row) { 7425 if (this.cfg.groupColumnIndexes) { 7426 var isGroupedRow = row.hasClass('ui-datatable-grouped-row'); 7427 var groupedRow = isGroupedRow ? row : row.prevAll('.ui-datatable-grouped-row:first'); 7428 var groupedColumn = groupedRow.children('.ui-grouped-column:first'); 7429 var rowSpan = groupedRow.nextUntil('.ui-datatable-grouped-row').not(':hidden').length + 1; 7430 var diff = rowSpan - parseInt(groupedColumn.attr('rowspan') || 1); 7431 groupedColumn.attr('rowspan', rowSpan); 7432 7433 var groupedColumnIndex = groupedColumn.index(); 7434 if (groupedColumnIndex > 0) { 7435 var columns = row.children('td:visible'); 7436 for (var i = 0; i < groupedColumnIndex; i++) { 7437 var column = columns.eq(i); 7438 if (column) { 7439 column.attr('rowspan', parseInt(column.attr('rowspan') || 1) + diff); 7440 } 7441 } 7442 } 7443 } 7444 }, 7445 7446 updateExpandedRowsColspan: function() { 7447 var colspanValue = this.calculateColspan(), 7448 $this = this; 7449 this.getExpandedRows().each(function() { 7450 $this.updateColspan($(this).next('.ui-expanded-row-content'), colspanValue); 7451 }); 7452 }, 7453 7454 updateResizableState: function(columnHeader, nextColumnHeader, table, newWidth, nextColumnWidth) { 7455 if(this.cfg.multiViewState) { 7456 var expandMode = (this.cfg.resizeMode === 'expand'), 7457 currentColumnId = columnHeader.attr('id'), 7458 nextColumnId = nextColumnHeader.attr('id'), 7459 tableId = this.id + "_tableWidthState", 7460 currentColumnState = currentColumnId + '_' + newWidth, 7461 nextColumnState = nextColumnId + '_' + nextColumnWidth, 7462 tableState = tableId + '_' + parseInt(table.css('width')), 7463 currentColumnMatch = false, 7464 nextColumnMatch = false, 7465 tableMatch = false;
7466 7467 for(var i = 0; i < this.resizableState.length; i++) { 7468 var state = this.resizableState[i]; 7469 if(state.indexOf(currentColumnId) === 0) { 7470 this.resizableState[i] = currentColumnState; 7471 currentColumnMatch = true; 7472 } 7473 else if(!expandMode && state.indexOf(nextColumnId) === 0) { 7474 this.resizableState[i] = nextColumnState; 7475 nextColumnMatch = true; 7476 } 7477 else if(expandMode && state.indexOf(tableId) === 0) { 7478 this.resizableState[i] = tableState; 7479 tableMatch = true; 7480 } 7481 } 7482 7483 if(!currentColumnMatch) { 7484 this.resizableState.push(currentColumnState); 7485 } 7486 7487 if(!expandMode && !nextColumnMatch) { 7488 this.resizableState.push(nextColumnState); 7489 } 7490 7491 if(expandMode && !tableMatch) { 7492 this.resizableState.push(tableState); 7493 } 7494 7495 this.resizableStateHolder.val(this.resizableState.join(',')); 7496 } 7497 }, 7498 7499 findColWidthInResizableState: function(id) { 7500 for(var i = 0; i < this.resizableState.length; i++) { 7501 var state = this.resizableState[i]; 7502 if(state.indexOf(id) === 0) { 7503 return state.substring(state.lastIndexOf('_') + 1, state.length); 7504 } 7505 } 7506 }, 7507 7508 updateColumnsView: function() { 7509 if(this.isEmpty()) { 7510 return; 7511 } 7512 7513 // update the visibility of columns but ignore expanded rows 7514 for(var i = 0; i < this.headers.length; i++) { 7515 var header = this.headers.eq(i), 7516 col = this.tbody.find('> tr:not(.ui-expanded-row-content) > td:nth-child(' + (header.index() + 1) + ')'); 7517 7518 if(header.hasClass('ui-helper-hidden')) { 7519 col.addClass('ui-helper-hidden'); 7520 } 7521 else { 7522 col.removeClass('ui-helper-hidden'); 7523 } 7524 } 7525 7526 // update the colspan of the expanded rows 7527 if(this.cfg.expansion) { 7528 this.updateExpandedRowsColspan(); 7529 } 7530 }, 7531 7532 resetVirtualScrollBody: function() { 7533 this.bodyTable.css('top', '0px'); 7534 this.scrollBody.scrollTop(0); 7535 this.clearScrollState(); 7536 } 7537 7538}); 7539 7540/** 7541 * PrimeFaces DataTable with Frozen Columns Widget 7542 */ 7543PrimeFaces.widget.FrozenDataTable = PrimeFaces.widget.DataTable.extend({ 7544 7545 setupScrolling: function() { 7546 this.scrollLayout = this.jq.find('> table > tbody > tr > td.ui-datatable-frozenlayout-right'); 7547 this.frozenLayout = this.jq.find('> table > tbody > tr > td.ui-datatable-frozenlayout-left'); 7548 this.scrollContainer = this.jq.find('> table > tbody > tr > td.ui-datatable-frozenlayout-right > .ui-datatable-scrollable-container'); 7549 this.frozenContainer = this.jq.find('> table > tbody > tr > td.ui-datatable-frozenlayout-left > .ui-datatable-frozen-container'); 7550 this.scrollHeader = this.scrollContainer.children('.ui-datatable-scrollable-header'); 7551 this.scrollHeaderBox = this.scrollHeader.children('div.ui-datatable-scrollable-header-box'); 7552 this.scrollBody = this.scrollContainer.children('.ui-datatable-scrollable-body'); 7553 this.scrollFooter = this.scrollContainer.children('.ui-datatable-scrollable-footer'); 7554 this.scrollFooterBox = this.scrollFooter.children('div.ui-datatable-scrollable-footer-box'); 7555 this.scrollStateHolder = $(this.jqId + '_scrollState'); 7556 this.scrollHeaderTable = this.scrollHeaderBox.children('table'); 7557 this.scrollBodyTable = this.cfg.virtualScroll ? this.scrollBody.children('div').children('table') : this.scrollBody.children('table'); 7558 this.scrollThead = this.thead.eq(1); 7559 this.scrollTbody = this.tbody.eq(1); 7560 this.scrollFooterTable = this.scrollFooterBox.children('table'); 7561 this.scrollFooterCols = this.scrollFooter.find('> .ui-datatable-scrollable-footer-box > table > tfoot > tr > td'); 7562 this.frozenHeader = this.frozenContainer.children('.ui-datatable-scrollable-header'); 7563 this.frozenBody = this.frozenContainer.children('.ui-datatable-scrollable-body'); 7564 this.frozenBodyTable = this.cfg.virtualScroll ? this.frozenBody.children('div').children('table') : this.frozenBody.children('table'); 7565 this.frozenThead = this.thead.eq(0); 7566 this.frozenTbody = this.tbody.eq(0); 7567 this.frozenFooter = this.frozenContainer.children('.ui-datatable-scrollable-footer'); 7568 this.frozenFooterTable = this.frozenFooter.find('> .ui-datatable-scrollable-footer-box > table'); 7569 this.frozenFooterCols = this.frozenFooter.find('> .ui-datatable-scrollable-footer-box > table > tfoot > tr > td'); 7570 this.percentageScrollHeight = this.cfg.scrollHeight && (this.cfg.scrollHeight.indexOf('%') !== -1); 7571 this.percentageScrollWidth = this.cfg.scrollWidth && (this.cfg.scrollWidth.indexOf('%') !== -1); 7572 7573 this.frozenThead.find('> tr > th').addClass('ui-frozen-column'); 7574 7575 var $this = this,
7576 scrollBarWidth = this.getScrollbarWidth() + 'px', 7577 hScrollWidth = this.scrollBody[0].scrollWidth; 7578 7579 if(this.cfg.scrollHeight) { 7580 if(this.percentageScrollHeight) { 7581 this.adjustScrollHeight(); 7582 } 7583 7584 if(this.hasVerticalOverflow()) { 7585 this.scrollHeaderBox.css('margin-right', scrollBarWidth); 7586 this.scrollFooterBox.css('margin-right', scrollBarWidth); 7587 } 7588 } 7589 7590 if(this.cfg.selectionMode) { 7591 this.scrollTbody.removeAttr('tabindex'); 7592 } 7593 7594 this.fixColumnWidths(); 7595 7596 if(this.cfg.scrollWidth) { 7597 if(this.percentageScrollWidth) 7598 this.adjustScrollWidth(); 7599 else 7600 this.setScrollWidth(parseInt(this.cfg.scrollWidth)); 7601 7602 if(this.hasVerticalOverflow()) { 7603 var browser = PrimeFaces.env.browser; 7604 if(browser.webkit === true || browser.mozilla === true) 7605 this.frozenBody.append('<div style="height:' + scrollBarWidth + ';border:1px solid transparent"></div>'); 7606 else 7607 this.frozenBodyTable.css('margin-bottom', scrollBarWidth); 7608 } 7609 } 7610 7611 this.cloneHead(); 7612 7613 this.restoreScrollState(); 7614 7615 if(this.cfg.liveScroll) { 7616 this.scrollOffset = 0; 7617 this.cfg.liveScrollBuffer = (100 - this.cfg.liveScrollBuffer) / 100; 7618 this.shouldLiveScroll = true; 7619 this.loadingLiveScroll = false; 7620 this.allLoadedLiveScroll = $this.cfg.scrollStep >= $this.cfg.scrollLimit; 7621 } 7622 7623 if(this.cfg.virtualScroll) { 7624 var row = this.scrollTbody.children('tr.ui-widget-content'); 7625 if(row) { 7626 this.rowHeight = row.outerHeight(); 7627 this.scrollBody.children('div').css('height', parseFloat((this.cfg.scrollLimit * this.rowHeight) + 'px')); 7628 this.frozenBody.children('div').css('height', parseFloat((this.cfg.scrollLimit * this.rowHeight) + 'px')); 7629 } 7630 7631 if(!this.cfg.scrollHeight) { 7632 this.frozenBody.css('height', this.scrollBody.height()); 7633 } 7634 } 7635 7636 this.scrollBody.scroll(function() { 7637 var scrollLeft = $this.scrollBody.scrollLeft(), 7638 scrollTop = $this.scrollBody.scrollTop(); 7639 7640 if ($this.isRTL) { 7641 $this.scrollHeaderBox.css('margin-right', (scrollLeft - hScrollWidth + this.clientWidth)); 7642 $this.scrollFooterBox.css('margin-right', (scrollLeft - hScrollWidth + this.clientWidth)); 7643 } 7644 else { 7645 $this.scrollHeaderBox.css('margin-left', -scrollLeft); 7646 $this.scrollFooterBox.css('margin-left', -scrollLeft); 7647 } 7648 7649 $this.frozenBody.scrollTop(scrollTop); 7650 7651 if($this.cfg.virtualScroll) { 7652 var virtualScrollBody = this; 7653 7654 clearTimeout($this.scrollTimeout); 7655 $this.scrollTimeout = setTimeout(function() { 7656 var viewportHeight = $this.scrollBody.outerHeight(), 7657 tableHeight = $this.scrollBodyTable.outerHeight(), 7658 pageHeight = $this.rowHeight * $this.cfg.scrollStep, 7659 virtualTableHeight = parseFloat(($this.cfg.scrollLimit * $this.rowHeight) + 'px'), 7660 pageCount = (virtualTableHeight / pageHeight)||1; 7661 7662 if(virtualScrollBody.scrollTop + viewportHeight > parseFloat($this.scrollBodyTable.css('top')) + tableHeight || virtualScrollBody.scrollTop < parseFloat($this.scrollBodyTable.css('top'))) { 7663 var page = Math.floor((virtualScrollBody.scrollTop * pageCount) / (virtualScrollBody.scrollHeight)) + 1; 7664 $this.loadRowsWithVirtualScroll(page, function () { 7665 $this.scrollBodyTable.css('top', ((page - 1) * pageHeight) + 'px'); 7666 $this.frozenBodyTable.css('top', ((page - 1) * pageHeight) + 'px'); 7667 }); 7668 } 7669 }, 200); 7670 } 7671 else if($this.shouldLiveScroll) { 7672 var scrollTop = Math.ceil(this.scrollTop), 7673 scrollHeight = this.scrollHeight,
7674 viewportHeight = this.clientHeight; 7675 7676 if((scrollTop >= ((scrollHeight * $this.cfg.liveScrollBuffer) - (viewportHeight))) && $this.shouldLoadLiveScroll()) { 7677 $this.loadLiveRows(); 7678 } 7679 } 7680 7681 $this.saveScrollState(); 7682 }); 7683 7684 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 7685 if ($this.percentageScrollHeight) { 7686 $this.adjustScrollHeight(); 7687 } 7688 if ($this.percentageScrollWidth) { 7689 $this.adjustScrollWidth(); 7690 } 7691 }); 7692 }, 7693 7694 cloneHead: function() { 7695 if (this.frozenTheadClone) { 7696 this.frozenTheadClone.remove(); 7697 } 7698 this.frozenTheadClone = this.cloneTableHeader(this.frozenThead, this.frozenBodyTable); 7699 7700 if (this.scrollTheadClone) { 7701 this.scrollTheadClone.remove(); 7702 } 7703 this.scrollTheadClone = this.cloneTableHeader(this.scrollThead, this.scrollBodyTable); 7704 }, 7705 7706 hasVerticalOverflow: function() { 7707 return this.scrollBodyTable.outerHeight() > this.scrollBody.outerHeight(); 7708 }, 7709 7710 adjustScrollHeight: function() { 7711 var relativeHeight = this.jq.parent().innerHeight() * (parseInt(this.cfg.scrollHeight) / 100), 7712 headerChilden = this.jq.children('.ui-datatable-header'), 7713 footerChilden = this.jq.children('.ui-datatable-footer'), 7714 tableHeaderHeight = (headerChilden.length > 0) ? headerChilden.outerHeight(true) : 0, 7715 tableFooterHeight = (footerChilden.length > 0) ? footerChilden.outerHeight(true) : 0, 7716 scrollersHeight = (this.scrollHeader.innerHeight() + this.scrollFooter.innerHeight()), 7717 paginatorsHeight = this.paginator ? this.paginator.getContainerHeight(true) : 0, 7718 height = (relativeHeight - (scrollersHeight + paginatorsHeight + tableHeaderHeight + tableFooterHeight)); 7719 7720 if(this.cfg.virtualScroll) { 7721 this.scrollBody.css('max-height', height); 7722 this.frozenBody.css('max-height', height); 7723 } 7724 else { 7725 this.scrollBody.height(height); 7726 this.frozenBody.height(height); 7727 } 7728 }, 7729 7730 //@Override 7731 adjustScrollWidth: function() { 7732 var scrollLayoutWidth = this.jq.parent().innerWidth() - this.frozenLayout.innerWidth(), 7733 width = parseInt((scrollLayoutWidth * (parseInt(this.cfg.scrollWidth) / 100))); 7734 7735 this.setScrollWidth(width); 7736 }, 7737 7738 setScrollWidth: function(width) { 7739 this.scrollHeader.width(width); 7740 this.scrollBody.css('margin-right', 0).width(width); 7741 this.scrollFooter.width(width); 7742 7743 var $this = this, 7744 headerWidth = width + this.frozenLayout.width(); 7745 7746 this.jq.children('.ui-widget-header').each(function() { 7747 $this.setOuterWidth($(this), headerWidth); 7748 }); 7749 }, 7750 7751 fixColumnWidths: function() { 7752 if(!this.columnWidthsFixed) { 7753 7754 if(this.cfg.scrollable) { 7755 this._fixColumnWidths(this.scrollHeader, this.scrollFooterCols, this.scrollColgroup); 7756 this._fixColumnWidths(this.frozenHeader, this.frozenFooterCols, this.frozenColgroup); 7757 } 7758 else { 7759 this.jq.find('> .ui-datatable-tablewrapper > table > thead > tr > th').each(function() { 7760 var col = $(this), 7761 colStyle = col[0].style, 7762 width = colStyle.width||col.width(); 7763 col.width(width); 7764 }); 7765 } 7766 7767 this.columnWidthsFixed = true; 7768 } 7769 }, 7770 7771 _fixColumnWidths: function(header, footerCols) { 7772 var $this = this; 7773 7774 header.find('> .ui-datatable-scrollable-header-box > table > thead > tr > th').each(function() { 7775 var headerCol = $(this), 7776 colIndex = headerCol.index(), 7777 headerStyle = headerCol[0].style, 7778 width = headerStyle.width||headerCol.width(); 7779 7780 $this.setOuterWidth(headerCol, width); 7781 7782 if(footerCols.length > 0) { 7783 var footerCol = footerCols.eq(colIndex); 7784 $this.setOuterWidth(footerCol, width); 7785 } 7786 }); 7787 }, 7788 7789 //@Override 7790 updateData: function(data, clear) { 7791 var table = $('<table><tbody>' + data + '</tbody></table>'),
7792 rows = table.find('> tbody > tr'), 7793 empty = (clear === undefined) ? true: clear; 7794 7795 if(empty) { 7796 this.frozenTbody.children().remove(); 7797 this.scrollTbody.children().remove(); 7798 } 7799 7800 //find slice index by checking how many rendered columns there are in frozen part 7801 var firstRow = this.frozenTbody.children('tr:first'), 7802 frozenColumnCount = firstRow.length ? firstRow.children('td').length: this.cfg.frozenColumns; 7803 7804 for(var i = 0; i < rows.length; i++) { 7805 var row = rows.eq(i), 7806 columns = row.children('td'), 7807 frozenRow = this.copyRow(row), 7808 scrollableRow = this.copyRow(row); 7809 7810 if(row.hasClass('ui-datatable-empty-message')) { 7811 var colspan = columns.attr('colspan'), 7812 cloneColumns = columns.clone(); 7813 7814 frozenRow.append(columns.attr('colspan', this.cfg.frozenColumns)); 7815 scrollableRow.append(cloneColumns.attr('colspan', (colspan - this.cfg.frozenColumns))); 7816 } 7817 else { 7818 frozenRow.append(columns.slice(0, frozenColumnCount)); 7819 scrollableRow.append(columns.slice(frozenColumnCount)); 7820 } 7821 7822 this.frozenTbody.append(frozenRow); 7823 this.scrollTbody.append(scrollableRow); 7824 } 7825 7826 this.postUpdateData(); 7827 }, 7828 7829 copyRow: function(original) { 7830 return $('<tr></tr>').attr('data-ri', original.data('ri')).attr('data-rk', original.data('rk')).addClass(original.attr('class')). 7831 attr('role', 'row').attr('aria-selected', original.attr('aria-selected')); 7832 }, 7833 7834 getThead: function() { 7835 return $(this.jqId + '_frozenThead,' + this.jqId + '_scrollableThead'); 7836 }, 7837 7838 getTbody: function() { 7839 return $(this.jqId + '_frozenTbody,' + this.jqId + '_scrollableTbody'); 7840 }, 7841 7842 getTfoot: function() { 7843 return $(this.jqId + '_frozenTfoot,' + this.jqId + '_scrollableTfoot'); 7844 }, 7845 7846 bindRowHover: function(selector) { 7847 var $this = this; 7848 7849 this.tbody.off('mouseover.datatable mouseout.datatable', selector) 7850 .on('mouseover.datatable', selector, null, function() { 7851 var row = $(this), 7852 twinRow = $this.getTwinRow(row); 7853 7854 if(!row.hasClass('ui-state-highlight')) { 7855 row.addClass('ui-state-hover'); 7856 twinRow.addClass('ui-state-hover'); 7857 } 7858 }) 7859 .on('mouseout.datatable', selector, null, function() { 7860 var row = $(this), 7861 twinRow = $this.getTwinRow(row); 7862 7863 if(!row.hasClass('ui-state-highlight')) { 7864 row.removeClass('ui-state-hover'); 7865 twinRow.removeClass('ui-state-hover'); 7866 } 7867 }); 7868 }, 7869 7870 getTwinRow: function(row) { 7871 var twinTbody = (this.tbody.index(row.parent()) === 0) ? this.tbody.eq(1) : this.tbody.eq(0); 7872 7873 return twinTbody.children().eq(row.index()); 7874 }, 7875 7876 //@Override 7877 highlightRow: function(row) { 7878 this._super(row); 7879 this._super(this.getTwinRow(row)); 7880 }, 7881 7882 //@Override 7883 unhighlightRow: function(row) { 7884 this._super(row); 7885 this._super(this.getTwinRow(row)); 7886 }, 7887 7888 //@Override 7889 displayExpandedRow: function(row, content) { 7890 var twinRow = this.getTwinRow(row); 7891 row.after(content); 7892 this.updateRowspan(row); 7893 var expansionRow = row.next(); 7894 this.updateColspan(expansionRow); 7895 expansionRow.show(); 7896 7897 twinRow.after('<tr class="ui-expanded-row-content ui-widget-content"><td></td></tr>'); 7898 twinRow.next().children('td').attr('colspan', this.updateColspan(twinRow)).height(expansionRow.children('td').height()); 7899 }, 7900 7901 //@Override 7902 collapseRow: function(row) { 7903 this._super(row); 7904 this._super(this.getTwinRow(row)); 7905 }, 7906 7907 //@Override 7908 getExpandedRows: function() { 7909 return this.frozenTbody.children('.ui-expanded-row'); 7910 }, 7911 7912 //@Override 7913 showRowEditors: function(row) { 7914 this._super(row); 7915 this._super(this.getTwinRow(row)); 7916 }, 7917 7918 //@Override 7919 updateRow: function(row, content) { 7920 var table = $('<table><tbody>' + content + '</tbody></table>'),
7921 newRow = table.find('> tbody > tr'), 7922 columns = newRow.children('td'), 7923 frozenRow = this.copyRow(newRow), 7924 scrollableRow = this.copyRow(newRow), 7925 twinRow = this.getTwinRow(row); 7926 7927 frozenRow.append(columns.slice(0, this.cfg.frozenColumns)); 7928 scrollableRow.append(columns.slice(this.cfg.frozenColumns)); 7929 7930 row.replaceWith(frozenRow); 7931 twinRow.replaceWith(scrollableRow); 7932 }, 7933 7934 //@Override 7935 invalidateRow: function(index) { 7936 this.frozenTbody.children('tr').eq(index).addClass('ui-widget-content ui-row-editing ui-state-error'); 7937 this.scrollTbody.children('tr').eq(index).addClass('ui-widget-content ui-row-editing ui-state-error'); 7938 }, 7939 7940 //@Override 7941 getRowEditors: function(row) { 7942 return row.find('div.ui-cell-editor').add(this.getTwinRow(row).find('div.ui-cell-editor')); 7943 }, 7944 7945 //@Override 7946 findGroupResizer: function(ui) { 7947 var resizer = this._findGroupResizer(ui, this.frozenGroupResizers); 7948 if(resizer) { 7949 return resizer; 7950 } 7951 else { 7952 return this._findGroupResizer(ui, this.scrollGroupResizers); 7953 } 7954 }, 7955 7956 _findGroupResizer: function(ui, resizers) { 7957 for(var i = 0; i < resizers.length; i++) { 7958 var groupResizer = resizers.eq(i); 7959 if(groupResizer.offset().left === ui.helper.data('originalposition').left) { 7960 return groupResizer; 7961 } 7962 } 7963 7964 return null; 7965 }, 7966 7967 //@Override 7968 addResizers: function() { 7969 var frozenColumns = this.frozenThead.find('> tr > th.ui-resizable-column'), 7970 scrollableColumns = this.scrollThead.find('> tr > th.ui-resizable-column'); 7971 7972 frozenColumns.prepend('<span class="ui-column-resizer"> </span>'); 7973 scrollableColumns.prepend('<span class="ui-column-resizer"> </span>') 7974 7975 if(this.cfg.resizeMode === 'fit') { 7976 frozenColumns.filter(':last-child').addClass('ui-frozen-column-last'); 7977 scrollableColumns.filter(':last-child').children('span.ui-column-resizer').hide(); 7978 } 7979 7980 if(this.hasColumnGroup) { 7981 this.frozenGroupResizers = this.frozenThead.find('> tr:first > th > .ui-column-resizer'); 7982 this.scrollGroupResizers = this.scrollThead.find('> tr:first > th > .ui-column-resizer'); 7983 } 7984 }, 7985 7986 //@Override 7987 resize: function(event, ui) { 7988 var columnHeader = null, 7989 change = null, 7990 newWidth = null, 7991 nextColumnWidth = null, 7992 expandMode = (this.cfg.resizeMode === 'expand'); 7993 7994 if(this.hasColumnGroup) { 7995 var groupResizer = this.findGroupResizer(ui); 7996 if(!groupResizer) { 7997 return; 7998 } 7999 8000 columnHeader = groupResizer.parent(); 8001 } 8002 else { 8003 columnHeader = ui.helper.parent(); 8004 } 8005 8006 var nextColumnHeader = columnHeader.next(); 8007 8008 var colIndex = columnHeader.index(), 8009 lastFrozen = columnHeader.hasClass('ui-frozen-column-last'); 8010 8011 if(this.cfg.liveResize) { 8012 change = columnHeader.outerWidth() - (event.pageX - columnHeader.offset().left), 8013 newWidth = (columnHeader.width() - change), 8014 nextColumnWidth = (nextColumnHeader.width() + change); 8015 } 8016 else { 8017 change = (ui.position.left - ui.originalPosition.left), 8018 newWidth = (columnHeader.width() + change), 8019 nextColumnWidth = (nextColumnHeader.width() - change); 8020 } 8021 8022 var minWidth = parseInt(columnHeader.css('min-width')); 8023 minWidth = (minWidth == 0) ? 15 : minWidth; 8024 var shouldChange = (expandMode && newWidth > minWidth) || (lastFrozen ? (newWidth > minWidth) : (newWidth > minWidth && nextColumnWidth > minWidth)); 8025 if(shouldChange) { 8026 var frozenColumn = columnHeader.hasClass('ui-frozen-column'), 8027 theadClone = frozenColumn ? this.frozenTheadClone : this.scrollTheadClone, 8028 originalTable = frozenColumn ? this.frozenThead.parent() : this.scrollThead.parent(), 8029 cloneTable = theadClone.parent(), 8030 footerCols = frozenColumn ? this.frozenFooterCols : this.scrollFooterCols, 8031 footerTable = frozenColumn ? this.frozenFooterTable: this.scrollFooterTable, 8032 $this = this; 8033 8034 if(expandMode) { 8035 if(lastFrozen) { 8036 this.frozenLayout.width(this.frozenLayout.width() + change); 8037 } 8038 8039 var originalTableWidth = originalTable.width(), 8040 cloneTableWidth = cloneTable.width(), 8041 footerTableWidth = footerTable.width(); 8042 8043 //header 8044 originalTable.width(originalTableWidth + change); 8045 8046 //body 8047 cloneTable.width(cloneTableWidth + change); 8048 8049 //footer 8050 footerTable.width(footerTableWidth + change); 8051 8052 setTimeout(function() { 8053 columnHeader.width(newWidth); 8054 8055 if($this.hasColumnGroup) { 8056 theadClone.find('> tr:first').children('th').eq(colIndex).width(newWidth); //body 8057 footerTable.find('> tfoot > tr:first').children('th').eq(colIndex).width(newWidth); //footer 8058 } 8059 else { 8060 theadClone.find(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); //body 8061 footerCols.eq(colIndex).width(newWidth); //footer 8062 } 8063 }, 1); 8064 8065 8066 } 8067 else { 8068 if(lastFrozen) { 8069 this.frozenLayout.width(this.frozenLayout.width() + change); 8070 } 8071 8072 columnHeader.width(newWidth); 8073 nextColumnHeader.width(nextColumnWidth); 8074 8075 if(this.hasColumnGroup) { 8076 //body 8077 theadClone.find('> tr:first').children('th').eq(colIndex).width(newWidth); 8078 theadClone.find('> tr:first').children('th').eq(colIndex + 1).width(nextColumnWidth); 8079 8080 //footer 8081 footerTable.find('> tfoot > tr:first').children('th').eq(colIndex).width(newWidth); 8082 footerTable.find('> tfoot > tr:first').children('th').eq(colIndex + 1).width(nextColumnWidth); 8083 } 8084 else { 8085 theadClone.find(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); 8086 theadClone.find(PrimeFaces.escapeClientId(nextColumnHeader.attr('id') + '_clone')).width(nextColumnWidth); 8087 8088 if(footerCols.length > 0) { 8089 var footerCol = footerCols.eq(colIndex), 8090 nextFooterCol = footerCol.next(); 8091 8092 footerCol.width(newWidth); 8093 nextFooterCol.width(nextColumnWidth); 8094 } 8095 } 8096 } 8097 } 8098 }, 8099 8100 //@Override 8101 hasColGroup: function() { 8102 return this.frozenThead.children('tr').length > 1 || this.scrollThead.children('tr').length > 1; 8103 }, 8104 8105 //@Override 8106 addGhostRow: function() { 8107 this._addGhostRow(this.frozenTbody, this.frozenThead, this.frozenTheadClone, this.frozenFooter.find('table'), 'ui-frozen-column'); 8108 this._addGhostRow(this.scrollTbody, this.scrollThead, this.scrollTheadClone, this.scrollFooterTable); 8109 }, 8110 8111 _addGhostRow: function(body, header, headerClone, footerTable, columnClass) { 8112 var dataColumns = body.find('tr:first').children('td'), 8113 dataColumnsCount = dataColumns.length, 8114 columnMarkup = '', 8115 columnStyleClass = columnClass ? 'ui-resizable-column ' + columnClass : 'ui-resizable-column'; 8116 8117 for(var i = 0; i < dataColumnsCount; i++) { 8118 columnMarkup += '<th style="height:0px;border-bottom-width: 0px;border-top-width: 0px;padding-top: 0px;padding-bottom: 0px;outline: 0 none;width:' + dataColumns.eq(i).width() + 'px" class="' + columnStyleClass + '"></th>'; 8119 } 8120 8121 header.prepend('<tr>' + columnMarkup + '</tr>'); 8122 8123 if(this.cfg.scrollable) { 8124 headerClone.prepend('<tr>' + columnMarkup + '</tr>'); 8125 footerTable.children('tfoot').prepend('<tr>' + columnMarkup + '</tr>'); 8126 } 8127 }, 8128 8129 getFocusableTbody: function() { 8130 return this.tbody.eq(0); 8131 }, 8132 8133 highlightFocusedRow: function() { 8134 this._super(); 8135 this.getTwinRow(this.focusedRow).addClass('ui-state-hover'); 8136 }, 8137 8138 unhighlightFocusedRow: function() { 8139 this._super(); 8140 this.getTwinRow(this.focusedRow).removeClass('ui-state-hover'); 8141 }, 8142 8143 assignFocusedRow: function(row) { 8144 this._super(row); 8145 8146 if(!row.parent().attr('tabindex')) { 8147 this.frozenTbody.trigger('focus'); 8148 } 8149 }, 8150 8151 //@Override 8152 saveColumnOrder: function() { 8153 var columnIds = [], 8154 columns = $(this.jqId + '_frozenThead:first th,' + this.jqId + '_scrollableThead:first th'); 8155 8156 columns.each(function(i, item) { 8157 columnIds.push($(item).attr('id')); 8158 }); 8159 8160 this.orderStateHolder.val(columnIds.join(',')); 8161 }, 8162 8163 //Override 8164 resetVirtualScrollBody: function() { 8165 this.scrollBodyTable.css('top', '0px'); 8166 this.frozenBodyTable.css('top', '0px'); 8167 this.scrollBody.scrollTop(0); 8168 this.frozenBody.scrollTop(0); 8169 this.clearScrollState(); 8170 }, 8171 8172 //Override 8173 groupRows: function() { 8174 var scrollRows = this.scrollTbody.children('tr'), 8175 frozenRows = this.frozenTbody.children('tr'); 8176 8177 for (var i = 0; i < this.cfg.groupColumnIndexes.length; i++) { 8178 var groupColumnIndex = this.cfg.groupColumnIndexes[i]; 8179 8180 if (groupColumnIndex >= this.cfg.frozenColumns) { 8181 this.groupRow(groupColumnIndex - this.cfg.frozenColumns, scrollRows); 8182 } 8183 else { 8184 this.groupRow(groupColumnIndex, frozenRows); 8185 } 8186 } 8187 8188 scrollRows.children('td.ui-duplicated-column').remove(); 8189 frozenRows.children('td.ui-duplicated-column').remove(); 8190 } 8191}); 8192 8193/** 8194 * PrimeFaces Dialog Widget 8195 */ 8196PrimeFaces.widget.Dialog = PrimeFaces.widget.DynamicOverlayWidget.extend({ 8197 8198 init: function(cfg) { 8199 this._super(cfg); 8200 8201 this.content = this.jq.children('.ui-dialog-content'); 8202 this.titlebar = this.jq.children('.ui-dialog-titlebar'); 8203 this.footer = this.jq.find('.ui-dialog-footer'); 8204 this.icons = this.titlebar.children('.ui-dialog-titlebar-icon'); 8205 this.closeIcon = this.titlebar.children('.ui-dialog-titlebar-close'); 8206 this.minimizeIcon = this.titlebar.children('.ui-dialog-titlebar-minimize'); 8207 this.maximizeIcon = this.titlebar.children('.ui-dialog-titlebar-maximize'); 8208 this.cfg.absolutePositioned = this.jq.hasClass('ui-dialog-absolute'); 8209 this.jqEl = this.jq[0]; 8210 8211 this.positionInitialized = false;
8212 8213 //configuration 8214 this.cfg.width = this.cfg.width||'auto'; 8215 this.cfg.height = this.cfg.height||'auto'; 8216 this.cfg.draggable = this.cfg.draggable === false ? false : true; 8217 this.cfg.resizable = this.cfg.resizable === false ? false : true; 8218 this.cfg.minWidth = this.cfg.minWidth||150; 8219 this.cfg.minHeight = this.cfg.minHeight||this.titlebar.outerHeight(); 8220 this.cfg.my = this.cfg.my||'center'; 8221 this.cfg.position = this.cfg.position||'center'; 8222 this.parent = this.jq.parent(); 8223 8224 this.initSize(); 8225 8226 //events 8227 this.bindEvents(); 8228 8229 if(this.cfg.draggable) { 8230 this.setupDraggable(); 8231 } 8232 8233 if(this.cfg.resizable){ 8234 this.setupResizable(); 8235 } 8236 8237 //docking zone 8238 if($(document.body).children('.ui-dialog-docking-zone').length === 0) { 8239 $(document.body).append('<div class="ui-dialog-docking-zone"></div>'); 8240 } 8241 8242 //aria 8243 this.applyARIA(); 8244 8245 if(this.cfg.visible){ 8246 this.show(); 8247 } 8248 8249 if(this.cfg.responsive) { 8250 this.bindResizeListener(); 8251 } 8252 }, 8253 8254 //@Override 8255 refresh: function(cfg) { 8256 this.positionInitialized = false; 8257 this.loaded = false; 8258 8259 $(document).off('keydown.dialog_' + cfg.id); 8260 8261 if(this.minimized) { 8262 var dockingZone = $(document.body).children('.ui-dialog-docking-zone'); 8263 if(dockingZone.length && dockingZone.children(this.jqId).length) { 8264 this.removeMinimize(); 8265 dockingZone.children(this.jqId).remove(); 8266 } 8267 } 8268 8269 this.minimized = false; 8270 this.maximized = false; 8271 8272 this._super(cfg); 8273 }, 8274 8275 initSize: function() { 8276 this.jq.css({ 8277 'width': this.cfg.width, 8278 'height': 'auto' 8279 }); 8280 8281 this.content.height(this.cfg.height); 8282 8283 if(this.cfg.fitViewport) { 8284 this.fitViewport(); 8285 } 8286 }, 8287 8288 fitViewport: function() { 8289 var windowHeight = $(window).height(); 8290 8291 var margin = this.jq.outerHeight(true) - this.jq.outerHeight(); 8292 var headerHeight = this.titlebar.outerHeight(true); 8293 var contentPadding = this.content.innerHeight() - this.content.height(); 8294 var footerHeight = this.footer.outerHeight(true) || 0; 8295 8296 var maxHeight = windowHeight - (margin + headerHeight + contentPadding + footerHeight); 8297 8298 this.content.css('max-height', maxHeight + 'px'); 8299 }, 8300 8301 //@override 8302 getModalTabbables: function(){ 8303 return this.jq.find(':tabbable').add(this.footer.find(':tabbable')); 8304 }, 8305 8306 /** 8307 * Show the dialog with optional animation duration. 8308 * 8309 * @param [duration] Durations are given in milliseconds; higher values indicate slower animations, not faster ones. 8310 * The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, 8311 * respectively. 8312 */ 8313 show: function(duration) { 8314 if(this.isVisible()) { 8315 return; 8316 } 8317 8318 if(!this.loaded && this.cfg.dynamic) { 8319 this.loadContents(); 8320 } 8321 else { 8322 if (this.positionInitialized === false) { 8323 this.jqEl.style.visibility = "hidden"; 8324 this.jqEl.style.display = "block"; 8325 this.initPosition(); 8326 this.jqEl.style.display = "none"; 8327 this.jqEl.style.visibility = "visible"; 8328 } 8329 8330 this._show(duration); 8331 } 8332 }, 8333 8334 _show: function(duration) { 8335 this.moveToTop(); 8336 8337 //offset 8338 if(this.cfg.absolutePositioned) { 8339 var winScrollTop = $(window).scrollTop(); 8340 this.jq.css('top', parseFloat(this.jq.css('top')) + (winScrollTop - this.lastScrollTop) + 'px'); 8341 this.lastScrollTop = winScrollTop; 8342 } 8343 8344 var animated = this.cfg.showEffect; 8345 if(animated) { 8346 var $this = this; 8347 8348 this.jq.show(this.cfg.showEffect, duration, 'normal', function() { 8349 $this.postShow(); 8350 }); 8351 } 8352 else { 8353 //display dialog 8354 this.jq.show(duration); 8355 8356 this.postShow(); 8357 } 8358 8359 if(this.cfg.modal) { 8360 this.enableModality(); 8361 } 8362 }, 8363 8364 postShow: function() { 8365 if (this.cfg.fitViewport) { 8366 this.fitViewport(); 8367 } 8368 8369 this.callBehavior('open'); 8370 8371 PrimeFaces.invokeDeferredRenders(this.id); 8372 8373 //execute user defined callback 8374 if(this.cfg.onShow) { 8375 this.cfg.onShow.call(this); 8376 } 8377 8378 this.jq.attr({ 8379 'aria-hidden': false 8380 ,'aria-live': 'polite' 8381 }); 8382 8383 this.applyFocus(); 8384 }, 8385 8386 /** 8387 * Hide the dialog with optional duration animation. 8388 * 8389 * @param [duration] Durations are given in milliseconds; higher values indicate slower animations, not faster ones. 8390 * The strings 'fast' and 'slow' can be supplied to indicate durations of 200 and 600 milliseconds, 8391 * respectively. 8392 */ 8393 hide: function(duration) { 8394 if(!this.isVisible()) { 8395 return; 8396 } 8397 8398 var animated = this.cfg.hideEffect; 8399 if(animated) { 8400 var $this = this; 8401 8402 this.jq.hide(this.cfg.hideEffect, duration, 'normal', function() { 8403 if($this.cfg.modal) { 8404 $this.disableModality(); 8405 } 8406 $this.onHide(); 8407 }); 8408 } 8409 else { 8410 this.jq.hide(); 8411 if(this.cfg.modal) { 8412 this.disableModality(); 8413 } 8414 this.onHide(duration); 8415 } 8416 }, 8417 8418 applyFocus: function() { 8419 if(this.cfg.focus)
8420 PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.focus).focus(); 8421 else 8422 this.jq.find(':not(:submit):not(:button):not(:radio):not(:checkbox):input:visible:enabled:first').focus(); 8423 }, 8424 8425 bindEvents: function() { 8426 var $this = this; 8427 8428 //Move dialog to top if target is not a trigger for a PrimeFaces overlay 8429 this.jq.mousedown(function(e) { 8430 if(!$(e.target).data('primefaces-overlay-target')) { 8431 $this.moveToTop(); 8432 } 8433 }); 8434 8435 this.icons.on('mouseover', function() { 8436 $(this).addClass('ui-state-hover'); 8437 }).on('mouseout', function() { 8438 $(this).removeClass('ui-state-hover'); 8439 }).on('focus', function() { 8440 $(this).addClass('ui-state-focus'); 8441 }).on('blur', function() { 8442 $(this).removeClass('ui-state-focus'); 8443 }); 8444 8445 this.closeIcon.on('click', function(e) { 8446 $this.hide(); 8447 e.preventDefault(); 8448 }); 8449 8450 this.maximizeIcon.click(function(e) { 8451 $this.toggleMaximize(); 8452 e.preventDefault(); 8453 }); 8454 8455 this.minimizeIcon.click(function(e) { 8456 $this.toggleMinimize(); 8457 e.preventDefault(); 8458 }); 8459 8460 if(this.cfg.closeOnEscape) { 8461 $(document).on('keydown.dialog_' + this.id, function(e) { 8462 var keyCode = $.ui.keyCode, 8463 active = parseInt($this.jq.css('z-index')) === PrimeFaces.zindex; 8464 8465 if(e.which === keyCode.ESCAPE && $this.isVisible() && active) { 8466 $this.hide(); 8467 }; 8468 }); 8469 } 8470 }, 8471 8472 setupDraggable: function() { 8473 var $this = this; 8474 8475 this.jq.draggable({ 8476 cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', 8477 handle: '.ui-dialog-titlebar', 8478 containment : $this.cfg.absolutePositioned ? 'document' : 'window', 8479 stop: function( event, ui ) { 8480 if($this.hasBehavior('move')) { 8481 var ext = { 8482 params: [ 8483 {name: $this.id + '_top', value: ui.offset.top}, 8484 {name: $this.id + '_left', value: ui.offset.left} 8485 ] 8486 }; 8487 $this.callBehavior('move', ext); 8488 } 8489 } 8490 }); 8491 }, 8492 8493 setupResizable: function() { 8494 var $this = this; 8495 8496 this.jq.resizable({ 8497 handles : 'n,s,e,w,ne,nw,se,sw', 8498 minWidth : this.cfg.minWidth, 8499 minHeight : this.cfg.minHeight, 8500 alsoResize : this.content, 8501 containment: 'document', 8502 start: function(event, ui) { 8503 $this.jq.data('offset', $this.jq.offset()); 8504 8505 if($this.cfg.hasIframe) { 8506 $this.iframeFix = $('<div style="position:absolute;background-color:transparent;width:100%;height:100%;top:0;left:0;"></div>').appendTo($this.content); 8507 } 8508 8509 if ($this.hasBehavior('resizeStart')) { 8510 var ext = { 8511 params: [ 8512 {name: $this.id + '_width', value: ui.size.width}, 8513 {name: $this.id + '_height', value: ui.size.height} 8514 ] 8515 }; 8516 $this.callBehavior('resizeStart', ext); 8517 } 8518 }, 8519 stop: function(event, ui) { 8520 $this.jq.css('position', 'fixed'); 8521 8522 if($this.cfg.hasIframe) { 8523 $this.iframeFix.remove(); 8524 } 8525 8526 if ($this.hasBehavior('resizeStop')) { 8527 var ext = { 8528 params: [ 8529 {name: $this.id + '_width', value: ui.size.width}, 8530 {name: $this.id + '_height', value: ui.size.height} 8531 ] 8532 }; 8533 $this.callBehavior('resizeStop', ext); 8534 } 8535 } 8536 }); 8537 8538 this.resizers = this.jq.children('.ui-resizable-handle'); 8539 }, 8540 8541 /** 8542 * Reset the dialog position based on the configured "position". 8543 */ 8544 resetPosition: function() { 8545 this.initPosition(); 8546 }, 8547 8548 initPosition: function() { 8549 var $this = this; 8550 8551 //reset 8552 this.jq.css({left:0,top:0}); 8553 8554 if(/(center|left|top|right|bottom)/.test(this.cfg.position)) { 8555 this.cfg.position = this.cfg.position.replace(',', ' '); 8556 8557 this.jq.position({ 8558 my: this.cfg.my 8559 ,at: this.cfg.position 8560 ,collision: 'fit' 8561 ,of: window 8562 //make sure dialog stays in viewport 8563 ,using: function(pos) { 8564 var l = pos.left < 0 ? 0 : pos.left, 8565 t = pos.top < 0 ? 0 : pos.top, 8566 scrollTop = $(window).scrollTop(); 8567 8568 //offset 8569 if($this.cfg.absolutePositioned) { 8570 t += scrollTop; 8571 $this.lastScrollTop = scrollTop; 8572 } 8573 8574 $(this).css({ 8575 left: l 8576 ,top: t 8577 }); 8578 } 8579 }); 8580 } 8581 else { 8582 var coords = this.cfg.position.split(','), 8583 x = $.trim(coords[0]), 8584 y = $.trim(coords[1]); 8585 8586 this.jq.offset({ 8587 left: x 8588 ,top: y 8589 }); 8590 } 8591 8592 this.positionInitialized = true; 8593 }, 8594 8595 onHide: function(event, ui) { 8596 this.callBehavior('close'); 8597 8598 this.jq.attr({ 8599 'aria-hidden': true 8600 ,'aria-live': 'off' 8601 }); 8602 8603 if(this.cfg.onHide) { 8604 this.cfg.onHide.call(this, event, ui); 8605 } 8606 }, 8607 8608 moveToTop: function() { 8609 this.jq.css('z-index', ++PrimeFaces.zindex); 8610 }, 8611 8612 toggleMaximize: function() { 8613 if(this.minimized) { 8614 this.toggleMinimize(); 8615 } 8616 8617 if(this.maximized) { 8618 this.jq.removeClass('ui-dialog-maximized'); 8619 this.restoreState(); 8620 8621 this.maximizeIcon.children('.ui-icon').removeClass('ui-icon-newwin').addClass('ui-icon-extlink'); 8622 this.maximized = false;
8623 8624 this.callBehavior('restoreMaximize'); 8625 } 8626 else { 8627 this.saveState(); 8628 8629 var win = $(window); 8630 8631 this.jq.addClass('ui-dialog-maximized').css({ 8632 'width': win.width() - 6 8633 ,'height': win.height() 8634 }).offset({ 8635 top: win.scrollTop() 8636 ,left: win.scrollLeft() 8637 }); 8638 8639 //maximize content 8640 var contentPadding = this.content.innerHeight() - this.content.height(); 8641 this.content.css({ 8642 width: 'auto', 8643 height: this.jq.height() - this.titlebar.outerHeight() - contentPadding 8644 }); 8645 8646 this.maximizeIcon.removeClass('ui-state-hover').children('.ui-icon').removeClass('ui-icon-extlink').addClass('ui-icon-newwin'); 8647 this.maximized = true; 8648 8649 this.callBehavior('maximize'); 8650 } 8651 }, 8652 8653 toggleMinimize: function() { 8654 var animate = true, 8655 dockingZone = $(document.body).children('.ui-dialog-docking-zone'); 8656 8657 if(this.maximized) { 8658 this.toggleMaximize(); 8659 animate = false; 8660 } 8661 8662 var $this = this; 8663 8664 if(this.minimized) { 8665 this.removeMinimize(); 8666 8667 this.callBehavior('restoreMinimize'); 8668 } 8669 else { 8670 this.saveState(); 8671 8672 if(animate) { 8673 this.jq.effect('transfer', { 8674 to: dockingZone 8675 ,className: 'ui-dialog-minimizing' 8676 }, 500, 8677 function() { 8678 $this.dock(dockingZone); 8679 $this.jq.addClass('ui-dialog-minimized'); 8680 }); 8681 } 8682 else { 8683 this.dock(dockingZone); 8684 this.jq.addClass('ui-dialog-minimized'); 8685 } 8686 } 8687 }, 8688 8689 dock: function(zone) { 8690 zone.css('z-index', this.jq.css('z-index')); 8691 this.jq.appendTo(zone).css('position', 'static'); 8692 this.jq.css({'height':'auto', 'width':'auto', 'float': 'left'}); 8693 this.content.hide(); 8694 this.footer.hide(); 8695 this.minimizeIcon.removeClass('ui-state-hover').children('.ui-icon').removeClass('ui-icon-minus').addClass('ui-icon-plus'); 8696 this.minimized = true; 8697 8698 if(this.cfg.resizable) { 8699 this.resizers.hide(); 8700 } 8701 8702 this.callBehavior('minimize'); 8703 }, 8704 8705 saveState: function() { 8706 this.state = { 8707 width: this.jq.width(), 8708 height: this.jq.height(), 8709 contentWidth: this.content.width(), 8710 contentHeight: this.content.height() 8711 }; 8712 8713 var win = $(window); 8714 this.state.offset = this.jq.offset(); 8715 this.state.windowScrollLeft = win.scrollLeft(); 8716 this.state.windowScrollTop = win.scrollTop(); 8717 }, 8718 8719 restoreState: function() { 8720 this.jq.width(this.state.width).height(this.state.height); 8721 this.content.width(this.state.contentWidth).height(this.state.contentHeight); 8722 8723 var win = $(window); 8724 this.jq.offset({ 8725 top: this.state.offset.top + (win.scrollTop() - this.state.windowScrollTop) 8726 ,left: this.state.offset.left + (win.scrollLeft() - this.state.windowScrollLeft) 8727 }); 8728 }, 8729 8730 loadContents: function() { 8731 var $this = this, 8732 options = { 8733 source: this.id, 8734 process: this.id, 8735 update: this.id, 8736 params: [ 8737 {name: this.id + '_contentLoad', value: true} 8738 ], 8739 onsuccess: function(responseXML, status, xhr) { 8740 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 8741 widget: $this, 8742 handle: function(content) { 8743 this.content.html(content); 8744 } 8745 }); 8746 8747 return true; 8748 }, 8749 oncomplete: function() { 8750 $this.loaded = true; 8751 $this.show(); 8752 } 8753 }; 8754 8755 if(this.hasBehavior('loadContent')) { 8756 this.callBehavior('loadContent', options); 8757 } 8758 else { 8759 PrimeFaces.ajax.Request.handle(options); 8760 } 8761 }, 8762 8763 applyARIA: function() { 8764 this.jq.attr({ 8765 'role': 'dialog' 8766 ,'aria-describedby': this.id + '_content' 8767 ,'aria-hidden': !this.cfg.visible
8768 ,'aria-modal': this.cfg.modal 8769 }); 8770 8771 // GitHub #4727 8772 var title = this.id + '_title'; 8773 if ($(PrimeFaces.escapeClientId(title)).length) { 8774 this.jq.attr('aria-labelledby', title); 8775 } 8776 8777 this.titlebar.children('a.ui-dialog-titlebar-icon').attr('role', 'button'); 8778 }, 8779 8780 isVisible: function() { 8781 return this.jq.is(':visible'); 8782 }, 8783 8784 bindResizeListener: function() { 8785 var $this = this; 8786 8787 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', null, function() { 8788 if ($this.cfg.fitViewport) { 8789 $this.fitViewport(); 8790 } 8791 8792 if ($this.isVisible()) { 8793 // instant reinit position 8794 $this.initPosition(); 8795 } 8796 else { 8797 // reset, so the dialog will be positioned again when showing the dialog next time 8798 $this.positionInitialized = false; 8799 } 8800 }); 8801 }, 8802 8803 removeMinimize: function() { 8804 this.jq.appendTo(this.parent).removeClass('ui-dialog-minimized').css({'position':'fixed', 'float':'none'}); 8805 this.restoreState(); 8806 this.content.show(); 8807 this.footer.show(); 8808 this.minimizeIcon.removeClass('ui-state-hover').children('.ui-icon').removeClass('ui-icon-plus').addClass('ui-icon-minus'); 8809 this.minimized = false; 8810 8811 if(this.cfg.resizable) { 8812 this.resizers.show(); 8813 } 8814 } 8815 8816}); 8817 8818/** 8819 * PrimeFaces ConfirmDialog Widget 8820 */ 8821PrimeFaces.widget.ConfirmDialog = PrimeFaces.widget.Dialog.extend({ 8822 8823 init: function(cfg) { 8824 cfg.draggable = false; 8825 cfg.resizable = false; 8826 cfg.modal = true; 8827 8828 if (!cfg.appendTo && cfg.global) { 8829 cfg.appendTo = '@(body)'; 8830 } 8831 8832 this._super(cfg); 8833 8834 this.title = this.titlebar.children('.ui-dialog-title'); 8835 this.message = this.content.children('.ui-confirm-dialog-message'); 8836 this.icon = this.content.children('.ui-confirm-dialog-severity'); 8837 8838 if(this.cfg.global) { 8839 PrimeFaces.confirmDialog = this; 8840 8841 this.jq.on('click.ui-confirmdialog', '.ui-confirmdialog-yes, .ui-confirmdialog-no', null, function(e) { 8842 var el = $(this); 8843 8844 if(el.hasClass('ui-confirmdialog-yes') && PrimeFaces.confirmSource) { 8845 var id = PrimeFaces.confirmSource.get(0); 8846 var js = PrimeFaces.confirmSource.data('pfconfirmcommand'); 8847 8848 PrimeFaces.csp.executeEvent(id, js, e); 8849 8850 PrimeFaces.confirmDialog.hide(); 8851 PrimeFaces.confirmSource = null; 8852 } 8853 else if(el.hasClass('ui-confirmdialog-no')) { 8854 PrimeFaces.confirmDialog.hide(); 8855 PrimeFaces.confirmSource = null; 8856 } 8857 8858 e.preventDefault(); 8859 }); 8860 } 8861 }, 8862 8863 applyFocus: function() { 8864 this.jq.find(':button,:submit').filter(':visible:enabled').eq(0).focus(); 8865 }, 8866 8867 showMessage: function(msg) { 8868 if(msg.beforeShow) { 8869 PrimeFaces.csp.eval(msg.beforeShow); 8870 } 8871 8872 var icon = (msg.icon === 'null') ? 'ui-icon-alert' : msg.icon; 8873 this.icon.removeClass().addClass('ui-icon ui-confirm-dialog-severity ' + icon); 8874 8875 if(msg.header) 8876 this.title.text(msg.header); 8877 8878 if(msg.message){ 8879 if (msg.escape){ 8880 this.message.text(msg.message); 8881 } 8882 else { 8883 this.message.html(msg.message); 8884 } 8885 } 8886 8887 this.show(); 8888 } 8889 8890}); 8891 8892/** 8893 * PrimeFaces Dynamic Dialog Widget for Dialog Framework 8894 */ 8895PrimeFaces.widget.DynamicDialog = PrimeFaces.widget.Dialog.extend({ 8896 8897 //@Override 8898 show: function() { 8899 if(this.jq.hasClass('ui-overlay-visible')) { 8900 return; 8901 } 8902 8903 if(this.positionInitialized === false) { 8904 this.initPosition(); 8905 } 8906 8907 this._show(); 8908 }, 8909 8910 //@Override 8911 _show: function() { 8912 //replace visibility hidden with display none for effect support, toggle marker class 8913 this.jq.removeClass('ui-overlay-hidden').addClass('ui-overlay-visible').css({ 8914 'display':'none' 8915 ,'visibility':'visible' 8916 }); 8917 8918 this.moveToTop(); 8919 8920 this.jq.show(); 8921 8922 if(this.cfg.height != "auto") { 8923 this.content.height(this.jq.outerHeight() - this.titlebar.outerHeight(true)); 8924 } 8925 8926 this.postShow(); 8927 8928 if(this.cfg.modal) { 8929 this.enableModality(); 8930 } 8931 }, 8932 8933 //@Override 8934 initSize: function() { 8935 this.jq.css({ 8936 'width': this.cfg.width, 8937 'height': this.cfg.height 8938 }); 8939 8940 if(this.cfg.fitViewport) { 8941 this.fitViewport(); 8942 } 8943 } 8944 8945}); 8946 8947/** 8948 * PrimeFaces Draggable Widget 8949 */ 8950PrimeFaces.widget.Draggable = PrimeFaces.widget.BaseWidget.extend({ 8951 8952 init: function(cfg) { 8953 this.cfg = cfg; 8954 this.id = this.cfg.id; 8955 this.jqId = PrimeFaces.escapeClientId(this.id); 8956 this.jq = $(PrimeFaces.escapeClientId(this.cfg.target)); 8957 this.cfg.cancel = this.cfg.cancel || "input,textarea,button,select,option"; 8958 8959 if(this.cfg.appendTo) { 8960 this.cfg.appendTo = PrimeFaces.expressions.SearchExpressionFacade.resolve
8960ComponentsAsSelector(this.cfg.appendTo); 8961 } 8962 8963 var $this = this; 8964 8965 this.cfg.start = function(event, ui) { 8966 if($this.cfg.onStart) { 8967 $this.cfg.onStart.call($this, event, ui); 8968 } 8969 }; 8970 8971 this.cfg.stop = function(event, ui) { 8972 if($this.cfg.onStop) { 8973 $this.cfg.onStop.call($this, event, ui); 8974 } 8975 }; 8976 8977 this.jq.draggable(this.cfg); 8978 8979 this.removeScriptElement(this.id); 8980 } 8981 8982}); 8983 8984/** 8985 * PrimeFaces Droppable Widget 8986 */ 8987PrimeFaces.widget.Droppable = PrimeFaces.widget.BaseWidget.extend({ 8988 8989 init: function(cfg) { 8990 this.cfg = cfg; 8991 this.id = this.cfg.id; 8992 this.jqId = PrimeFaces.escapeClientId(this.id); 8993 this.jq = $(PrimeFaces.escapeClientId(this.cfg.target)); 8994 8995 this.bindDropListener(); 8996 8997 this.jq.droppable(this.cfg); 8998 8999 this.removeScriptElement(this.id); 9000 }, 9001 9002 bindDropListener: function() { 9003 var _self = this; 9004 9005 this.cfg.drop = function(event, ui) { 9006 if(_self.cfg.onDrop) { 9007 _self.cfg.onDrop.call(_self, event, ui); 9008 } 9009 if(_self.cfg.behaviors) { 9010 var dropBehavior = _self.cfg.behaviors['drop']; 9011 9012 if(dropBehavior) { 9013 var ext = { 9014 params: [ 9015 {name: _self.id + '_dragId', value: ui.draggable.attr('id')}, 9016 {name: _self.id + '_dropId', value: _self.cfg.target} 9017 ] 9018 }; 9019 9020 dropBehavior.call(_self, ext); 9021 } 9022 } 9023 }; 9024 } 9025 9026}); 9027/** 9028 * PrimeFaces Effect Widget 9029 */ 9030PrimeFaces.widget.Effect = PrimeFaces.widget.BaseWidget.extend({ 9031 9032 init: function(cfg) { 9033 this.cfg = cfg; 9034 this.id = this.cfg.id; 9035 this.jqId = PrimeFaces.escapeClientId(this.id); 9036 this.source = $(PrimeFaces.escapeClientId(this.cfg.source)); 9037 var _self = this; 9038 9039 this.runner = function() { 9040 //avoid queuing multiple runs 9041 if(_self.timeoutId) { 9042 clearTimeout(_self.timeoutId); 9043 } 9044 9045 _self.timeoutId = setTimeout(_self.cfg.fn, _self.cfg.delay); 9046 }; 9047 9048 if(this.cfg.event == 'load') { 9049 this.runner.call(); 9050 } 9051 else { 9052 this.source.on(this.cfg.event, this.runner); 9053 } 9054 9055 this.removeScriptElement(this.id); 9056 } 9057 9058}); 9059/** 9060 * PrimeFaces Fieldset Widget 9061 */ 9062PrimeFaces.widget.Fieldset = PrimeFaces.widget.BaseWidget.extend({ 9063 9064 init: function(cfg) { 9065 this._super(cfg); 9066 9067 this.legend = this.jq.children('.ui-fieldset-legend'); 9068 9069 var $this = this; 9070 9071 if(this.cfg.toggleable) { 9072 this.content = this.jq.children('.ui-fieldset-content'); 9073 this.toggler = this.legend.children('.ui-fieldset-toggler'); 9074 this.stateHolder = $(this.jqId + '_collapsed'); 9075 9076 //Add clickable legend state behavior 9077 this.legend.on('click', function(e) { 9078 $this.toggle(e); 9079 }) 9080 .on('mouseover', function() { 9081 $this.legend.toggleClass('ui-state-hover'); 9082 }) 9083 .on('mouseout', function() { 9084 $this.legend.toggleClass('ui-state-hover'); 9085 }) 9086 .on('mousedown', function() { 9087 $this.legend.toggleClass('ui-state-active'); 9088 }) 9089 .on('mouseup', function() { 9090 $this.legend.toggleClass('ui-state-active'); 9091 }) 9092 .on('focus', function() { 9093 $this.legend.toggleClass('ui-state-focus'); 9094 }) 9095 .on('blur', function() { 9096 $this.legend.toggleClass('ui-state-focus'); 9097 }) 9098 .on('keydown', function(e) { 9099 var key = e.which, 9100 keyCode = $.ui.keyCode; 9101 9102 if((key === keyCode.ENTER)) { 9103 $this.toggle(e); 9104 e.preventDefault(); 9105 } 9106 }); 9107 } 9108 }, 9109 9110 /** 9111 * Toggles the content 9112 */ 9113 toggle: function(e) { 9114 this.updateToggleState(this.cfg.collapsed); 9115 9116 var $this = this; 9117 9118 this.content.slideToggle(this.cfg.toggleSpeed, 'easeInOutCirc', function() { 9119 $this.callBehavior('toggle'); 9120 }); 9121 9122 PrimeFaces.invokeDeferredRenders(this.id); 9123 }, 9124 9125 /** 9126 * Updates the visual toggler state and saves state 9127 */ 9128 updateToggleState: function(collapsed) { 9129 if(collapsed) 9130 this.toggler.removeClass('ui-icon-plusthick').addClass('ui-icon-minusthick'); 9131 else 9132 this.toggler.removeClass('ui-icon-minusthick').addClass('ui-icon-plusthick'); 9133 9134 this.cfg.collapsed = !collapsed; 9135 9136 this.stateHolder.val(!collapsed); 9137 } 9138 9139}); 9140/** 9141 * PrimeFaces InputText Widget 9142 */ 9143PrimeFaces.widget.InputText = PrimeFaces.widget.BaseWidget.extend({ 9144 9145 init: function(cfg) { 9146 this._super(cfg); 9147 9148 PrimeFaces.skinInput(this.jq); 9149 9150 //Counter 9151 if(this.cfg.counter) { 9152 this.counter = this.cfg.counter ? $(PrimeFaces.escapeClientId(this.cfg.counter)) : null; 9153 this.cfg.counterTemplate = this.cfg.counterTemplate||'{0}'; 9154 this.updateCounter(); 9155 9156 if(this.counter) { 9157 var $this = this; 9158 this.jq.on('input.inputtext-counter', function(e) { 9159 $this.updateCounter(); 9160 }); 9161 } 9162 } 9163 }, 9164 9165 disable: function() { 9166 this.jq.prop('disabled', true).addClass('ui-state-disabled'); 9167 }, 9168 9169 enable: function() { 9170 this.jq.prop('disabled', false).removeClass('ui-state-disabled'); 9171 }, 9172 9173 updateCounter: function() { 9174 var value = this.normalizeNewlines(this.jq.val()), 9175 length = value.length; 9176 9177 if(this.counter && this.cfg.maxlength) { 9178 var remaining = this.cfg.maxlength - length; 9179 if(remaining < 0) { 9180 remaining = 0; 9181 } 9182 9183 var counterText = this.cfg.counterTemplate 9184 .replace('{0}', remaining) 9185 .replace('{1}', length) 9186 .replace('{2}', this.cfg.maxlength); 9187 9188 this.counter.text(counterText); 9189 } 9190 }, 9191 9192 normalizeNewlines: function(text) { 9193 return text.replace(/(\r\n|\r|\n)/g, '\r\n'); 9194 } 9195}); 9196 9197/** 9198 * PrimeFaces InputTextarea Widget 9199 */ 9200PrimeFaces.widget.InputTextarea = PrimeFaces.widget.DeferredWidget.extend({ 9201 9202 init: function(cfg) { 9203 this._super(cfg); 9204 9205 if(this.cfg.autoResize) 9206 this.renderDeferred(); 9207 else 9208 this._render(); 9209 }, 9210 9211 _render: function() { 9212 //Visuals 9213 PrimeFaces.skinInput(this.jq); 9214 9215 //autoComplete 9216 if(this.cfg.autoComplete) { 9217 this.setupAutoComplete(); 9218 } 9219 9220 //Counter 9221 if(this.cfg.counter) { 9222 this.counter = this.cfg.counter ? $(PrimeFaces.escapeClientId(this.cfg.counter)) : null; 9223 this.cfg.counterTemplate = this.cfg.counterTemplate||'{0}'; 9224 this.updateCounter(); 9225 9226 if(this.counter) { 9227 var $this = this; 9228 this.jq.on('input.inputtextarea-counter', function(e) { 9229 $this.updateCounter(); 9230 }); 9231 } 9232 } 9233 9234 //maxLength 9235 if(this.cfg.maxlength) { 9236 this.applyMaxlength(); 9237 } 9238 9239 //autoResize 9240 if(this.cfg.autoResize) { 9241 this.setupAutoResize(); 9242 } 9243 }, 9244 9245 //@override 9246 refresh: function(cfg) { 9247 //remove autocomplete panel 9248 if(cfg.autoComplete) { 9249 $(PrimeFaces.escapeClientId(cfg.id + '_panel')).remove(); 9250 } 9251 9252 this._super(cfg); 9253 }, 9254 9255 setupAutoResize: function() { 9256 autosize(this.jq); 9257 }, 9258 9259 applyMaxlength: function() { 9260 var _self = this; 9261 9262 this.jq.on('keyup.inputtextarea-maxlength', function(e) { 9263 var value = _self.jq.val(), 9264 length = value.length; 9265 9266 if(length > _self.cfg.maxlength) { 9267 _self.jq.val(value.substr(0, _self.cfg.maxlength)); 9268 } 9269 }); 9270 }, 9271 9272 updateCounter: function() { 9273 var value = this.jq.val(), 9274 length = value.length; 9275 9276 if(this.counter) { 9277 var remaining = this.cfg.maxlength - length; 9278 if(remaining < 0) { 9279 remaining = 0; 9280 } 9281 9282 var counterText = this.cfg.counterTemplate 9283 .replace('{0}', remaining) 9284 .replace('{1}', length) 9285 .replace('{2}', this.cfg.maxlength); 9286 9287 this.counter.text(counterText); 9288 } 9289 }, 9290 9291 setupAutoComplete: function() { 9292 var panelMarkup = '<div id="' + this.id + '_panel" class="ui-autocomplete-panel ui-widget-content ui-corner-all ui-helper-hidden ui-shadow"></div>', 9293 _self = this; 9294 9295 this.panel = $(panelMarkup).appendTo(document.body); 9296 9297 this.jq.keyup(function(e) { 9298 var keyCode = $.ui.keyCode; 9299 9300 switch(e.which) { 9301 9302 case keyCode.UP: 9303 case keyCode.LEFT: 9304 case keyCode.DOWN: 9305 case keyCode.RIGHT: 9306 case keyCode.ENTER: 9307 case keyCode.TAB: 9308 case keyCode.SPACE: 9309 case 17: //keyCode.CONTROL: 9310 case 18: //keyCode.ALT: 9311 case keyCode.ESCAPE: 9312 case 224: //mac command 9313 //do not search 9314 break; 9315 9316 default: 9317 var query = _self.extractQuery(); 9318 if(query && query.length >= _self.cfg.minQueryLength) { 9319 9320 //Cancel the search request if user types within the timeout 9321 if(_self.timeout) { 9322 _self.clearTimeout(_self.timeout); 9323 } 9324 9325 _self.timeout = setTimeout(function() { 9326 _self.search(query); 9327 }, _self.cfg.queryDelay); 9328 9329 } 9330 break; 9331 } 9332 9333 }).keydown(function(e) { 9334 var overlayVisible = _self.panel.is(':visible'), 9335 keyCode = $.ui.keyCode; 9336 9337 switch(e.which) { 9338 case keyCode.UP: 9339 case keyCode.LEFT: 9340 if(overlayVisible) { 9341 var highlightedItem = _self.items.filter('.ui-state-highlight'), 9342 prev = highlightedItem.length == 0 ? _self.items.eq(0) : highlightedItem.prev(); 9343 9344 if(prev.length == 1) { 9345 highlightedItem.removeClass('ui-state-highlight'); 9346 prev.addClass('ui-state-highlight'); 9347 9348 if(_self.cfg.scrollHeight) { 9349 PrimeFaces.scrollInView(_self.panel, prev); 9350 } 9351 } 9352 9353 e.preventDefault(); 9354 } 9355 else { 9356 _self.clearTimeout(); 9357 } 9358 break; 9359 9360 case keyCode.DOWN: 9361 case keyCode.RIGHT: 9362 if(overlayVisible) { 9363 var highlightedItem = _self.items.filter('.ui-state-highlight'), 9364 next = highlightedItem.length == 0 ? _self.items.eq(0) : highlightedItem.next(); 9365 9366 if(next.length == 1) { 9367 highlightedItem.removeClass('ui-state-highlight'); 9368 next.addClass('ui-state-highlight'); 9369 9370 if(_self.cfg.scrollHeight) { 9371 PrimeFaces.scrollInView(_self.panel, next); 9372 } 9373 } 9374 9375 e.preventDefault(); 9376 } 9377 else { 9378 _self.clearTimeout(); 9379 } 9380 break; 9381 9382 case keyCode.ENTER: 9383 if(overlayVisible) { 9384 _self.items.filter('.ui-state-highlight').trigger('click'); 9385 9386 e.preventDefault(); 9387 } 9388 else { 9389 _self.clearTimeout(); 9390 } 9391 break; 9392 9393 case keyCode.SPACE: 9394 case 17: //keyCode.CONTROL: 9395 case 18: //keyCode.ALT: 9396 case keyCode.BACKSPACE: 9397 case keyCode.ESCAPE: 9398 case 224: //mac command 9399 _self.clearTimeout(); 9400 9401 if(overlayVisible) { 9402 _self.hide(); 9403 } 9404 break; 9405 9406 case keyCode.TAB: 9407 _self.clearTimeout(); 9408 9409 if(overlayVisible) { 9410 _self.items.filter('.ui-state-highlight').trigger('click'); 9411 _self.hide(); 9412 } 9413 break; 9414 } 9415 }); 9416 9417 //hide panel when outside is clicked 9418 $(document.body).on('mousedown.ui-inputtextarea', function (e) { 9419 if(_self.panel.is(":hidden")) { 9420 return; 9421 } 9422 var offset = _self.panel.offset(); 9423 if(e.target === _self.jq.get(0)) { 9424 return; 9425 } 9426 9427 if (e.pageX < offset.left || 9428 e.pageX > offset.left + _self.panel.width() || 9429 e.pageY < offset.top || 9430 e.pageY > offset.top + _self.panel.height()) { 9431 _self.hide(); 9432 } 9433 }); 9434 9435 //Hide overlay on resize 9436 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', _self.panel, function() { 9437 _self.hide(); 9438 }); 9439 9440 //dialog support 9441 this.setupDialogSupport(); 9442 }, 9443 9444 bindDynamicEvents: function() { 9445 var _self = this; 9446 9447 //visuals and click handler for items 9448 this.items.on('mouseover', function() { 9449 var item = $(this); 9450 9451 if(!item.hasClass('ui-state-highlight')) { 9452 _self.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); 9453 item.addClass('ui-state-highlight'); 9454 } 9455 }) 9456 .on('click', function(event) { 9457 var item = $(this), 9458 itemValue = item.attr('data-item-value'), 9459 selectionStart = _self.jq.getSelection().start, 9460 queryLength = _self.query.length; 9461 9462 _self.jq.focus(); 9463 9464 _self.jq.setSelection(selectionStart-queryLength, selectionStart); 9465 _self.jq.replaceSelectedText(itemValue); 9466 9467 _self.invokeItemSelectBehavior(event, itemValue); 9468 9469 _self.hide(); 9470 }); 9471 }, 9472 9473 invokeItemSelectBehavior: function(event, itemValue) { 9474 if(this.hasBehavior('itemSelect')) { 9475 var ext = { 9476 params : [ 9477 {name: this.id + '_itemSelect', value: itemValue} 9478 ] 9479 }; 9480 9481 this.callBehavior('itemSelect', ext); 9482 } 9483 }, 9484 9485 clearTimeout: function() { 9486 if(this.timeout) { 9487 clearTimeout(this.timeout); 9488 } 9489 9490 this.timeout = null; 9491 }, 9492 9493 extractQuery: function() { 9494 var end = this.jq.getSelection().end, 9495 result = /\S+$/.exec(this.jq.get(0).value.slice(0, end)), 9496 lastWord = result ? result[0] : null; 9497 9498 return lastWord; 9499 }, 9500 9501 search: function(query) { 9502 this.query = query; 9503 9504 var $this = this, 9505 options = { 9506 source: this.id, 9507 update: this.id, 9508 process: this.id, 9509 params: [ 9510 {name: this.id + '_query', value: query} 9511 ], 9512 onsuccess: function(responseXML, status, xhr) { 9513 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 9514 widget: $this, 9515 handle: function(content) { 9516 this.panel.html(content); 9517 this.items = $th
9517is.panel.find('.ui-autocomplete-item'); 9518 9519 this.bindDynamicEvents(); 9520 9521 if(this.items.length > 0) { 9522 //highlight first item 9523 this.items.eq(0).addClass('ui-state-highlight'); 9524 9525 //adjust height 9526 if(this.cfg.scrollHeight && this.panel.height() > this.cfg.scrollHeight) { 9527 this.panel.height(this.cfg.scrollHeight); 9528 } 9529 9530 if(this.panel.is(':hidden')) { 9531 this.show(); 9532 } else { 9533 this.alignPanel(); //with new items 9534 } 9535 9536 } 9537 else { 9538 this.panel.hide(); 9539 } 9540 } 9541 }); 9542 9543 return true; 9544 } 9545 }; 9546 9547 if (this.hasBehavior('query')) { 9548 this.callBehavior('query', options); 9549 } 9550 else { 9551 PrimeFaces.ajax.Request.handle(options); 9552 } 9553 }, 9554 9555 alignPanel: function() { 9556 var pos = this.jq.getCaretPosition(), 9557 posLeft = (pos.left > 0 ? '+' : '-') + pos.left, 9558 posTop = (pos.top > 0 ? '+' : '-') + pos.top; 9559 9560 this.panel.css({left:'', top:''}).position({ 9561 my: 'left top' 9562 ,at: 'left' + posLeft + ' top' + posTop 9563 ,of: this.jq 9564 }); 9565 }, 9566 9567 show: function() { 9568 this.panel.css({ 9569 'z-index': ++PrimeFaces.zindex, 9570 'width': this.jq.innerWidth(), 9571 'visibility': 'hidden' 9572 }).show(); 9573 9574 this.alignPanel(); 9575 9576 this.panel.css('visibility', ''); 9577 }, 9578 9579 hide: function() { 9580 this.panel.hide(); 9581 }, 9582 9583 setupDialogSupport: function() { 9584 var dialog = this.jq.parents('.ui-dialog:first'); 9585 9586 if(dialog.length == 1 && dialog.css('position') === 'fixed') { 9587 this.panel.css('position', 'fixed'); 9588 } 9589 } 9590 9591}); 9592 9593/** 9594 * PrimeFaces SelectOneMenu Widget 9595 */ 9596PrimeFaces.widget.SelectOneMenu = PrimeFaces.widget.DeferredWidget.extend({ 9597 9598 init: function(cfg) { 9599 this._super(cfg); 9600 9601 this.panelId = this.jqId + '_panel'; 9602 this.input = $(this.jqId + '_input'); 9603 this.focusInput = $(this.jqId + '_focus'); 9604 this.label = this.jq.find('.ui-selectonemenu-label'); 9605 this.menuIcon = this.jq.children('.ui-selectonemenu-trigger'); 9606 9607 this.panel = $(this.panelId); 9608 this.disabled = this.jq.hasClass('ui-state-disabled'); 9609 this.itemsWrapper = this.panel.children('.ui-selectonemenu-items-wrapper'); 9610 this.options = this.input.children('option'); 9611 this.cfg.effect = this.cfg.effect||'fade'; 9612 9613 this.cfg.effectSpeed = this.cfg.effectSpeed||'normal'; 9614 this.cfg.autoWidth = this.cfg.autoWidth === false ? false : true; 9615 this.cfg.dynamic = this.cfg.dynamic === true ? true : false; 9616 this.cfg.appendTo = this.getAppendTo(); 9617 this.isDynamicLoaded = false; 9618 9619 if(this.cfg.dynamic) { 9620 var selectedOption = this.options.filter(':selected'), 9621 labelVal = this.cfg.editable ? this.label.val() : selectedOption.text(); 9622 9623 this.setLabel(labelVal); 9624 } 9625 else { 9626 this.initContents(); 9627 this.bindItemEvents(); 9628 } 9629 9630 //triggers 9631 this.triggers = this.cfg.editable ? this.jq.find('.ui-selectonemenu-trigger') : this.jq.find('.ui-selectonemenu-trigger, .ui-selectonemenu-label'); 9632 9633 //mark trigger and descandants of trigger as a trigger for a primefaces overlay 9634 this.triggers.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 9635 9636 if(!this.disabled) { 9637 this.bindEvents(); 9638 this.bindConstantEvents(); 9639 9640 PrimeFaces.utils.registerDynamicOverlay(this, this.panel, this.id + '_panel'); 9641 } 9642 9643 // see #7602 9644 if (PrimeFaces.env.touch) { 9645 this.focusInput.attr('readonly', true); 9646 } 9647 9648 this.renderDeferred(); 9649 }, 9650
9651 initContents: function() { 9652 this.itemsContainer = this.itemsWrapper.children('.ui-selectonemenu-items'); 9653 this.items = this.itemsContainer.find('.ui-selectonemenu-item'); 9654 this.optGroupsSize = this.itemsContainer.children('li.ui-selectonemenu-item-group').length; 9655 9656 var $this = this, 9657 selectedOption = this.options.filter(':selected'), 9658 highlightedItem = this.items.eq(selectedOption.index()); 9659 9660 //disable options 9661 this.options.filter(':disabled').each(function() { 9662 $this.items.eq($(this).index()).addClass('ui-state-disabled'); 9663 }); 9664 9665 //activate selected 9666 if(this.cfg.editable) { 9667 var customInputVal = this.label.val(); 9668 9669 //predefined input 9670 if(customInputVal === selectedOption.text()) { 9671 this.highlightItem(highlightedItem); 9672 } 9673 //custom input 9674 else { 9675 this.items.eq(0).addClass('ui-state-highlight'); 9676 this.customInput = true; 9677 this.customInputVal = customInputVal; 9678 } 9679 } 9680 else { 9681 this.highlightItem(highlightedItem); 9682 } 9683 9684 if(this.cfg.syncTooltip) { 9685 this.syncTitle(selectedOption); 9686 } 9687 9688 //pfs metadata 9689 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 9690 9691 //for Screen Readers 9692 for(var i = 0; i < this.items.length; i++) { 9693 this.items.eq(i).attr('id', this.id + '_' + i); 9694 } 9695 9696 var highlightedItemId = highlightedItem.attr('id'); 9697 this.jq.attr('aria-owns', this.itemsContainer.attr('id')); 9698 this.focusInput.attr('aria-autocomplete', 'list') 9699 .attr('aria-activedescendant', highlightedItemId) 9700 .attr('aria-describedby', highlightedItemId) 9701 .attr('aria-disabled', this.disabled); 9702 this.itemsContainer.attr('aria-activedescendant', highlightedItemId); 9703 }, 9704 9705 _render: function() { 9706 var contentStyle = this.jq.attr('style'), 9707 hasWidth = contentStyle && contentStyle.indexOf('width') != -1; 9708 9709 if(this.cfg.autoWidth && !hasWidth) { 9710 this.jq.css('min-width', this.input.outerWidth()); 9711 } 9712 }, 9713 9714 //@override 9715 refresh: function(cfg) { 9716 this.panelWidthAdjusted = false; 9717 9718 this._super(cfg); 9719 }, 9720 9721 alignPanelWidth: function() { 9722 //align panel and container 9723 if(!this.panelWidthAdjusted) { 9724 var jqWidth = this.jq.outerWidth(); 9725 if(this.panel.outerWidth() < jqWidth) { 9726 this.panel.width(jqWidth); 9727 } 9728 else { 9729 this.panel.width(this.panel.width()); 9730 } 9731 9732 this.panelWidthAdjusted = true; 9733 } 9734 }, 9735 9736 bindEvents: function() { 9737 var $this = this; 9738 9739 // Screen Reader(JAWS) hack on Chrome 9740 if(PrimeFaces.env.browser.webkit) { 9741 this.input.on('focus', function(){ 9742 setTimeout(function(){ 9743 $this.focusInput.trigger('focus.ui-selectonemenu'); 9744 },2); 9745 }); 9746 } 9747 9748 //Triggers 9749 this.triggers.mouseenter(function() { 9750 if(!$this.jq.hasClass('ui-state-focus')) { 9751 $this.jq.addClass('ui-state-hover'); 9752 $this.menuIcon.addClass('ui-state-hover'); 9753 } 9754 }) 9755 .mouseleave(function() { 9756 $this.jq.removeClass('ui-state-hover'); 9757 $this.menuIcon.removeClass('ui-state-hover'); 9758 }) 9759 .click(function(e) { 9760 if($this.panel.is(":hidden")) { 9761 $this.show(); 9762 } 9763 else { 9764 $this.hide(); 9765 9766 $this.revert(); 9767 $this.changeAriaValue($this.getActiveItem()); 9768 } 9769 9770 $this.jq.removeClass('ui-state-hover'); 9771 $this.menuIcon.removeClass('ui-state-hover'); 9772 $this.focusInput.trigger('focus.ui-selectonemenu'); 9773 e.preventDefault(); 9774 }); 9775 9776 this.focusInput.on('focus.ui-selectonemenu', function() { 9777 $this.jq.addClass('ui-state-focus'); 9778 $this.menuIcon.addClass('ui-state-focus'); 9779 }) 9780 .on('blur.ui-selectonemenu', function(){ 9781 $this.jq.removeClass('ui-state-focus'); 9782 $this.menuIcon.removeClass('ui-state-focus'); 9783 9784 $this.callBehavior('blur'); 9785 }); 9786 9787 //onchange handler for editable input 9788 if(this.cfg.editable) { 9789 this.label.change(function(e) { 9790 $this.triggerChange(true); 9791 $this.callHandleMethod($this.handleLabelChange, e); 9792 }); 9793 } 9794 9795 //key bindings 9796 this.bindKeyEvents(); 9797 9798 //filter 9799 if(this.cfg.filter) { 9800 this.cfg.initialHeight = this.itemsWrapper.height(); 9801 this.setupFilterMatcher(); 9802 this.filterInput = this.panel.find('> div.ui-selectonemenu-filter-container > input.ui-selectonemenu-filter'); 9803 PrimeFaces.skinInput(this.filterInput); 9804 9805 this.bindFilterEvents(); 9806 } 9807 }, 9808 9809 bindItemEvents: function() { 9810 var $this = this; 9811 9812 //Items 9813 this.items.filter(':not(.ui-state-disabled)').on('mouseover.selectonemenu', function() { 9814 var el = $(this); 9815 9816 if(!el.hasClass('ui-state-highlight')) 9817 $(this).addClass('ui-state-hover'); 9818 }) 9819 .on('mouseout.selectonemenu', function() { 9820 $(this).removeClass('ui-state-hover'); 9821 }) 9822 .on('click.selectonemenu', function() { 9823 $this.revert(); 9824 $this.selectItem($(this)); 9825 $this.changeAriaValue($(this)); 9826 }); 9827 }, 9828 9829 bindConstantEvents: function() { 9830 var $this = this; 9831 9832 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.panel, 9833 function() { return $this.label.add($this.menuIcon); }, 9834 function(e, eventTarget) { 9835 if(!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { 9836 $this.hide(); 9837 setTimeout(function() { 9838 $this.revert(); 9839 $this.changeAriaValue($this.getActiveItem()); 9840 }, 2); 9841 } 9842 }); 9843 9844 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { 9845 $this.alignPanel(); 9846 }); 9847 }, 9848 9849 unbindEvents: function() { 9850 this.items.off(); 9851 this.triggers.off(); 9852 this.input.off(); 9853 this.focusInput.off(); 9854 this.label.off(); 9855 }, 9856 9857 revert: function() { 9858 if(this.cfg.editable && this.customInput) { 9859 this.setLabel(this.customInputVal); 9860 this.items.filter('.ui-state-active').removeClass('ui-state-active'); 9861 this.items.eq(0).addClass('ui-state-active'); 9862 } 9863 else { 9864 this.highlightItem(this.items.eq(this.preShowValue.index())); 9865 } 9866 }, 9867 9868 highlightItem: function(item) { 9869 this.items.attr('aria-selected', false); 9870 this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight'); 9871 9872 if(item.length > 0) { 9873 item.addClass('ui-state-highlight'); 9874 item.attr('aria-selected', true); 9875 this.setLabel(item.data('label')); 9876 } 9877 }, 9878 9879 triggerChange: function(edited) { 9880 this.changed = false;
9881 9882 this.input.trigger('change'); 9883 9884 if(!edited) { 9885 this.value = this.options.filter(':selected').val(); 9886 } 9887 }, 9888 9889 /** 9890 * Handler to process item selection with mouse 9891 */ 9892 selectItem: function(item, silent) { 9893 var selectedOption = this.options.eq(this.resolveItemIndex(item)), 9894 currentOption = this.options.filter(':selected'), 9895 sameOption = selectedOption.val() == currentOption.val(), 9896 shouldChange = null; 9897 9898 if(this.cfg.editable) { 9899 shouldChange = (!sameOption)||(selectedOption.text() != this.label.val()); 9900 } 9901 else { 9902 shouldChange = !sameOption; 9903 } 9904 9905 if(shouldChange) { 9906 this.highlightItem(item); 9907 this.input.val(selectedOption.val()) 9908 9909 this.triggerChange(); 9910 9911 if(this.cfg.editable) { 9912 this.customInput = false; 9913 } 9914 9915 if(this.cfg.syncTooltip) { 9916 this.syncTitle(selectedOption); 9917 } 9918 } 9919 9920 if(!silent) { 9921 this.callBehavior('itemSelect'); 9922 this.focusInput.trigger('focus'); 9923 } 9924 9925 if(this.panel.is(':visible')) { 9926 this.hide(); 9927 } 9928 }, 9929 9930 syncTitle: function(option) { 9931 var optionTitle = this.items.eq(option.index()).attr('title'); 9932 if(optionTitle) 9933 this.jq.attr('title', this.items.eq(option.index()).attr('title')); 9934 else 9935 this.jq.removeAttr('title'); 9936 }, 9937 9938 resolveItemIndex: function(item) { 9939 if(this.optGroupsSize === 0) 9940 return item.index(); 9941 else 9942 return item.index() - item.prevAll('li.ui-selectonemenu-item-group').length; 9943 }, 9944 9945 bindKeyEvents: function() { 9946 var $this = this; 9947 9948 this.focusInput.on('keydown.ui-selectonemenu', function(e) { 9949 var keyCode = $.ui.keyCode, 9950 key = e.which; 9951 9952 switch(key) { 9953 case keyCode.UP: 9954 case keyCode.LEFT: 9955 $this.callHandleMethod($this.highlightPrev, e); 9956 break; 9957 9958 case keyCode.DOWN: 9959 case keyCode.RIGHT: 9960 $this.callHandleMethod($this.highlightNext, e); 9961 break; 9962 9963 case keyCode.ENTER: 9964 $this.handleEnterKey(e); 9965 break; 9966 9967 case keyCode.TAB: 9968 $this.handleTabKey(); 9969 break; 9970 9971 case keyCode.ESCAPE: 9972 $this.handleEscapeKey(e); 9973 break; 9974 9975 case keyCode.SPACE: 9976 $this.handleSpaceKey(e); 9977 break; 9978 } 9979 }) 9980 .on('keyup.ui-selectonemenu', function(e) { 9981 var keyCode = $.ui.keyCode, 9982 key = e.which; 9983 9984 switch(key) { 9985 case keyCode.UP: 9986 case keyCode.LEFT: 9987 case keyCode.DOWN: 9988 case keyCode.RIGHT: 9989 case keyCode.ENTER: 9990 case keyCode.TAB: 9991 case keyCode.ESCAPE: 9992 case keyCode.SPACE: 9993 case keyCode.HOME: 9994 case keyCode.PAGE_DOWN: 9995 case keyCode.PAGE_UP: 9996 case keyCode.END: 9997 case keyCode.DELETE: 9998 case 16: //shift 9999 case 17: //keyCode.CONTROL: 10000 case 18: //keyCode.ALT: 10001 case 19: //Pause/Break: 10002 case 20: //capslock: 10003 case 44: //Print Screen: 10004 case 45: //Insert: 10005 case 91: //left window or cmd: 10006 case 92: //right window: 10007 case 93: //right cmd: 10008 case 144: //num lock: 10009 case 145: //scroll lock: 10010 break; 10011 10012 default: 10013 //function keys (F1,F2 etc.) 10014 if(key >= 112 && key <= 123) { 10015 break; 10016 } 10017 10018 10019 var matchedOptions = null, 10020 metaKey = e.metaKey||e.ctrlKey||e.shiftKey; 10021 10022 if(!metaKey) { 10023 clearTimeout($this.searchTimer); 10024 10025 // #4682: check for word match 10026 var text = $(this).val(); 10027 matchedOptions = $this.matchOptions(text); 10028 if(matchedOptions.length) { 10029 var highlightItem = $this.items.eq(matchedOptions.index()); 10030 if($this.panel.is(':hidden')) { 10031 $this.selectItem(highlightItem); 10032 } 10033 else { 10034 $this.highlightItem(highlightItem); 10035 PrimeFaces.scrollInView($this.itemsWrapper, highlightItem); 10036 } 10037 } else { 10038 // #4682: check for first letter match 10039 text = String.fromCharCode(key).toLowerCase(); 10040 // find all options with the same first letter 10041 matchedOptions = $this.matchOptions(text); 10042 if(matchedOptions.length) { 10043 var selectedIndex = -1; 10044 10045 // is current selection one of our matches? 10046 matchedOptions.each(function() { 10047 var option = $(this); 10048 var currentIndex = option.index(); 10049 var currentItem = $this.items.eq(currentIndex); 10050 if (currentItem.hasClass('ui-state-highlight')) { 10051 selectedIndex = currentIndex; 10052 return false;
10053 } 10054 }); 10055 10056 matchedOptions.each(function() { 10057 var option = $(this); 10058 var currentIndex = option.index(); 10059 var currentItem = $this.items.eq(currentIndex); 10060 10061 // select next item after the current selection 10062 if (currentIndex > selectedIndex) { 10063 if($this.panel.is(':hidden')) { 10064 $this.selectItem(currentItem); 10065 } 10066 else { 10067 $this.highlightItem(currentItem); 10068 PrimeFaces.scrollInView($this.itemsWrapper, currentItem); 10069 } 10070 return false; 10071 } 10072 }); 10073 } 10074 } 10075 10076 $this.searchTimer = setTimeout(function(){ 10077 $this.focusInput.val(''); 10078 }, 1000); 10079 } 10080 break; 10081 } 10082 }); 10083 }, 10084 10085 matchOptions: function(text) { 10086 return this.options.filter(function() { 10087 var option = $(this); 10088 return (option.is(':not(:disabled)') && (option.text().toLowerCase().indexOf(text) === 0)); 10089 }); 10090 }, 10091 10092 bindFilterEvents: function() { 10093 var $this = this; 10094 10095 this.filterInput.on('keyup.ui-selectonemenu', function(e) { 10096 var keyCode = $.ui.keyCode, 10097 key = e.which; 10098 10099 switch(key) { 10100 case keyCode.UP: 10101 case keyCode.LEFT: 10102 case keyCode.DOWN: 10103 case keyCode.RIGHT: 10104 case keyCode.ENTER: 10105 case keyCode.TAB: 10106 case keyCode.ESCAPE: 10107 case keyCode.SPACE: 10108 case keyCode.HOME: 10109 case keyCode.PAGE_DOWN: 10110 case keyCode.PAGE_UP: 10111 case keyCode.END: 10112 case 16: //shift 10113 case 17: //keyCode.CONTROL: 10114 case 18: //keyCode.ALT: 10115 case 91: //left window or cmd: 10116 case 92: //right window: 10117 case 93: //right cmd: 10118 case 20: //capslock: 10119 break; 10120 10121 default: 10122 //function keys (F1,F2 etc.) 10123 if(key >= 112 && key <= 123) { 10124 break; 10125 } 10126 10127 var metaKey = e.metaKey||e.ctrlKey; 10128 10129 if(!metaKey) { 10130 $this.filter($(this).val()); 10131 } 10132 break; 10133 } 10134 }) 10135 .on('keydown.ui-selectonemenu',function(e) { 10136 var keyCode = $.ui.keyCode, 10137 key = e.which; 10138 10139 switch(key) { 10140 case keyCode.UP: 10141 $this.highlightPrev(e); 10142 break; 10143 10144 case keyCode.DOWN: 10145 $this.highlightNext(e); 10146 break; 10147 10148 case keyCode.ENTER: 10149 $this.handleEnterKey(e); 10150 e.stopPropagation(); 10151 break; 10152 10153 case keyCode.TAB: 10154 $this.handleTabKey(); 10155 break; 10156 10157 case keyCode.ESCAPE: 10158 $this.handleEscapeKey(e); 10159 break; 10160 10161 case keyCode.SPACE: 10162 $this.handleSpaceKey(e); 10163 break; 10164 10165 default: 10166 break; 10167 } 10168 }).on('paste.ui-selectonemenu', function() { 10169 setTimeout(function(){ 10170 $this.filter($this.filterInput.val()); 10171 },2); 10172 }); 10173 }, 10174 10175 highlightNext: function(event) { 10176 var activeItem = this.getActiveItem(), 10177 next = this.panel.is(':hidden') ? activeItem.nextAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):first') 10178 : activeItem.nextAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):visible:first'); 10179 10180 if(event.altKey) { 10181 this.show(); 10182 } 10183 else { 10184 if(next.length === 1) { 10185 if(this.panel.is(':hidden')) { 10186 this.selectItem(next); 10187 } 10188 else { 10189 this.highlightItem(next); 10190 PrimeFaces.scrollInView(this.itemsWrapper, next); 10191 } 10192 this.changeAriaValue(next); 10193 } 10194 } 10195 10196 event.preventDefault(); 10197 }, 10198 10199 highlightPrev: function(event) { 10200 var activeItem = this.getActiveItem(), 10201 prev = this.panel.is(':hidden') ? activeItem.prevAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):first') 10202 : activeItem.prevAll(':not(.ui-state-disabled,.ui-selectonemenu-item-group):visible:first'); 10203 10204 if(prev.length === 1) { 10205 if(this.panel.is(':hidden')) { 10206 this.selectItem(prev); 10207 } 10208 else { 10209 this.highlightItem(prev); 10210 PrimeFaces.scrollInView(this.itemsWrapper, prev); 10211 } 10212 this.changeAriaValue(prev); 10213 } 10214 10215 event.preventDefault(); 10216 }, 10217 10218 handleEnterKey: function(event) { 10219 if(this.panel.is(':visible')) { 10220 this.selectItem(this.getActiveItem()); 10221 } 10222 10223 event.preventDefault(); 10224 }, 10225 10226 handleSpaceKey: function(event) { 10227 var target = $(event.target); 10228 10229 if(target.is('input') && target.hasClass('ui-selectonemenu-filter')) { 10230 return; 10231 } 10232 10233 if(this.panel.is(":hidden")) { 10234 this.show(); 10235 } 10236 else { 10237 this.hide(); 10238 10239 this.revert(); 10240 this.changeAriaValue(this.getActiveItem()); 10241 } 10242 10243 event.preventDefault(); 10244 }, 10245 10246 handleEscapeKey: function(event) { 10247 if(this.panel.is(':visible')) { 10248 this.revert(); 10249 this.hide(); 10250 } 10251 10252 event.preventDefault(); 10253 }, 10254 10255 handleTabKey: function() { 10256 if(this.panel.is(':visible')) { 10257 this.selectItem(this.getActiveItem()); 10258 } 10259 }, 10260 10261 handleLabelChange: function(event) { 10262 this.customInput = true; 10263 this.customInputVal = $(event.target).val(); 10264 this.items.filter('.ui-state-active').removeClass('ui-state-active'); 10265 this.items.eq(0).addClass('ui-state-active'); 10266 }, 10267 10268 show: function() { 10269 this.callHandleMethod(this._show, null); 10270 }, 10271 10272 _show: function() { 10273 var $this = this; 10274 10275 this.panel.css({'display':'block', 'opacity':0, 'pointer-events': 'none'}); 10276 this.itemsWrapper.css({'overflow': 'scroll'}); 10277 10278 this.alignPanel(); 10279 10280 this.panel.css({'display':'none', 'opacity':'', 'pointer-events': '', 'z-index': ++PrimeFaces.zindex}); 10281 this.itemsWrapper.css({'overflow': ''}); 10282 10283 if(this.cfg.effect !== 'none') { 10284 this.panel.show(this.cfg.effect, {}, this.cfg.effectSpeed, function() { 10285 PrimeFaces.scrollInView($this.itemsWrapper, $this.getActiveItem()); 10286 10287 if($this.cfg.filter) 10288 $this.focusFilter(); 10289 }); 10290 } 10291 else { 10292 this.panel.show(); 10293 PrimeFaces.scrollInView(this.itemsWrapper, this.getActiveItem()); 10294 10295 if($this.cfg.filter) 10296 this.focusFilter(10); 10297 } 10298 10299 //value before panel is shown 10300 this.preShowValue = this.options.filter(':selected'); 10301 this.focusInput.attr('aria-expanded', true); 10302 this.jq.attr('aria-expanded', true); 10303 }, 10304 10305 hide: function() { 10306 this.panel.css('z-index', '').hide(); 10307 this.focusInput.attr('aria-expanded', false); 10308 this.jq.attr('aria-expanded', false); 10309 }, 10310 10311 focus: function() { 10312 this.focusInput.focus(); 10313 }, 10314 10315 focusFilter: function(timeout) { 10316 if(timeout) { 10317 var $this = this; 10318 setTimeout(function() { 10319 $this.focusFilter(); 10320 }, timeout); 10321 } 10322 else { 10323 this.filterInput.focus(); 10324 } 10325 }, 10326 10327 blur: function() { 10328 this.focusInput.blur(); 10329 10330 this.callBehavior('blur'); 10331 }, 10332 10333 disable: function() { 10334 if (!this.disabled) { 10335 this.disabled = true; 10336 this.jq.addClass('ui-state-disabled'); 10337 this.input.attr('disabled', 'disabled'); 10338 if(this.cfg.editable) { 10339 this.label.attr('disabled', 'disabled'); 10340 } 10341 this.unbindEvents(); 10342 } 10343 }, 10344 10345 enable: function() { 10346 if (this.disabled) { 10347 this.disabled = false;
10348 this.jq.removeClass('ui-state-disabled'); 10349 this.input.removeAttr('disabled'); 10350 if(this.cfg.editable) { 10351 this.label.removeAttr('disabled'); 10352 } 10353 10354 this.bindEvents(); 10355 this.bindItemEvents(); 10356 } 10357 }, 10358 10359 alignPanel: function() { 10360 this.alignPanelWidth(); 10361 10362 if(this.panel.parent().is(this.jq)) { 10363 this.panel.css({ 10364 left: 0, 10365 top: this.jq.innerHeight() 10366 }); 10367 } 10368 else { 10369 this.panel.css({left:0, top:0}).position({ 10370 my: 'left top' 10371 ,at: 'left bottom' 10372 ,of: this.jq 10373 ,collision: 'flipfit' 10374 }); 10375 } 10376 }, 10377 10378 setLabel: function(value) { 10379 var displayedLabel = this.getLabelToDisplay(value); 10380 10381 if (this.cfg.editable) { 10382 if (value === ' ') 10383 this.label.val(''); 10384 else 10385 this.label.val(displayedLabel); 10386 10387 var hasPlaceholder = this.label[0].hasAttribute('placeholder'); 10388 this.updatePlaceholderClass((hasPlaceholder && value === ' ')); 10389 } 10390 else { 10391 var labelText = this.label.data('placeholder'); 10392 if (labelText == null || labelText == "") { 10393 labelText = ' '; 10394 } 10395 10396 this.updatePlaceholderClass((value === ' ' && labelText !== ' ')); 10397 10398 if (value === ' ') { 10399 if (labelText != ' ') { 10400 this.label.text(labelText); 10401 } else { 10402 this.label.html(labelText); 10403 } 10404 } 10405 else { 10406 this.label.removeClass('ui-state-disabled'); 10407 10408 var option = null; 10409 if(this.items) { 10410 var selectedItem = this.items.filter('[data-label="' + $.escapeSelector(value) + '"]'); 10411 option = this.options.eq(this.resolveItemIndex(selectedItem)); 10412 } 10413 else { 10414 option = this.options.filter(':selected'); 10415 } 10416 10417 if (option && option.data('escape') == false) { 10418 this.label.html(displayedLabel); 10419 } else { 10420 this.label.text(displayedLabel); 10421 } 10422 } 10423 } 10424 }, 10425 10426 selectValue : function(value) { 10427 var option = this.options.filter('[value="' + $.escapeSelector(value) + '"]'); 10428 10429 this.selectItem(this.items.eq(option.index()), true); 10430 }, 10431 10432 getActiveItem: function() { 10433 return this.items.filter('.ui-state-highlight'); 10434 }, 10435 10436 setupFilterMatcher: function() { 10437 this.cfg.filterMatchMode = this.cfg.filterMatchMode||'startsWith'; 10438 this.filterMatchers = { 10439 'startsWith': this.startsWithFilter 10440 ,'contains': this.containsFilter 10441 ,'endsWith': this.endsWithFilter 10442 ,'custom': this.cfg.filterFunction 10443 }; 10444 10445 this.filterMatcher = this.filterMatchers[this.cfg.filterMatchMode]; 10446 }, 10447 10448 startsWithFilter: function(value, filter) { 10449 return value.indexOf(filter) === 0; 10450 }, 10451 10452 containsFilter: function(value, filter) { 10453 return value.indexOf(filter) !== -1; 10454 }, 10455 10456 endsWithFilter: function(value, filter) { 10457 return value.indexOf(filter, value.length - filter.length) !== -1; 10458 }, 10459 10460 filter: function(value) { 10461 this.cfg.initialHeight = this.cfg.initialHeight||this.itemsWrapper.height(); 10462 var filterValue = this.cfg.caseSensitive ? $.trim(value) : $.trim(value).toLowerCase(); 10463 10464 if(filterValue === '') { 10465 this.items.filter(':hidden').show(); 10466 this.itemsContainer.children('.ui-selectonemenu-item-group').show(); 10467 } 10468 else { 10469 var hide = []; 10470 var show = []; 10471 10472 for(var i = 0; i < this.options.length; i++) { 10473 var option = this.options.eq(i), 10474 itemLabel = this.cfg.caseSensitive ? option.text() : option.text().toLowerCase(), 10475 item = this.items.eq(i); 10476 10477 if(item.hasClass('ui-noselection-option')) { 10478 hide.push(item); 10479 } 10480 else { 10481 if(this.filterMatcher(itemLabel, filterValue)) 10482 show.push(item); 10483 else 10484 hide.push(item); 10485 } 10486 } 10487 10488 $.each(hide, function(i, o) { o.hide() }); 10489 $.each(show, function(i, o) { o.show() }); 10490 hide = []; 10491 show = []; 10492 10493 //Toggle groups 10494 var groups = this.itemsContainer.children('.ui-selectonemenu-item-group'); 10495 for(var g = 0; g < groups.length; g++) { 10496 var group = groups.eq(g); 10497 10498 if(g === (groups.length - 1)) { 10499 if(group.nextAll().filter(':visible').length === 0) 10500 hide.push(group); 10501 else 10502 show.push(group); 10503 } 10504 else { 10505 if(group.nextUntil('.ui-selectonemenu-item-group').filter(':visible').length === 0) 10506 hide.push(group); 10507 else 10508 show.push(group); 10509 } 10510 } 10511 10512 $.each(hide, function(i, o) { o.hide() }); 10513 $.each(show, function(i, o) { o.show() }); 10514 } 10515 10516 var firstVisibleItem = this.items.filter(':visible:not(.ui-state-disabled):first'); 10517 if(firstVisibleItem.length) { 10518 this.highlightItem(firstVisibleItem); 10519 } 10520 10521 if(this.itemsContainer.height() < this.cfg.initialHeight) { 10522 this.itemsWrapper.css('height', 'auto'); 10523 } 10524 else { 10525 this.itemsWrapper.height(this.cfg.initialHeight); 10526 } 10527 10528 this.alignPanel(); 10529 }, 10530 10531 getSelectedValue: function() { 10532 return this.input.val(); 10533 }, 10534 10535 getSelectedLabel: function() { 10536 return this.options.filter(':selected').text(); 10537 }, 10538 10539 getLabelToDisplay: function(value) { 10540 if(this.cfg.labelTemplate && value !== ' ') { 10541 return this.cfg.labelTemplate.replace('{0}', value); 10542 } 10543 return String(value); 10544 }, 10545 10546 changeAriaValue: function (item) { 10547 var itemId = item.attr('id'); 10548 10549 this.focusInput.attr('aria-activedescendant', itemId) 10550 .attr('aria-describedby', itemId); 10551 this.itemsContainer.attr('aria-activedescendant', itemId); 10552 }, 10553 10554 dynamicPanelLoad: function() { 10555 var $this = this, 10556 options = { 10557 source: this.id, 10558 process: this.id, 10559 update: this.id, 10560 global: false, 10561 params: [{name: this.id + '_dynamicload', value: true}], 10562 onsuccess: function(responseXML, status, xhr) { 10563 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 10564 widget: $this, 10565 handle: function(content) { 10566 var $content = $($.parseHTML(content)); 10567 10568 var $ul = $content.filter('ul'); 10569 $this.itemsWrapper.empty(); 10570 $this.itemsWrapper.append($ul); 10571 10572 var $select = $content.filter('select'); 10573 $this.input.replaceWith($select); 10574 } 10575 }); 10576 10577 return true; 10578 }, 10579 oncomplete: function(xhr, status, args, data) { 10580 $this.isDynamicLoaded = true; 10581 $this.input = $($this.jqId + '_input'); 10582 $this.options = $this.input.children('option'); 10583 $this.initContents(); 10584 $this.bindItemEvents(); 10585 } 10586 }; 10587 10588 PrimeFaces.ajax.Request.handle(options); 10589 }, 10590 10591 callHandleMethod: function(handleMethod, event) { 10592 var $this = this; 10593 if(this.cfg.dynamic && !this.isDynamicLoaded) { 10594 this.dynamicPanelLoad(); 10595 10596 var interval = setInterval(function() { 10597 if($this.isDynamicLoaded) { 10598 handleMethod.call($this, event); 10599 10600 clearInterval(interval); 10601 } 10602 }, 10); 10603 } 10604 else { 10605 handleMethod.call(this, event); 10606 } 10607 }, 10608 10609 getAppendTo: function() { 10610 var dialog = this.jq[0].closest('.ui-dialog'); 10611 if (dialog) { 10612 var $dialog = $(dialog); 10613 //set position as fixed to scroll with dialog 10614 if ($dialog.css('position') === 'fixed') { 10615 this.panel.css('position', 'fixed'); 10616 } 10617 10618 //append to body if not already appended by user choice 10619 if(!this.panel.parent().is(document.body)) { 10620 return "@(body)"; 10621 } 10622 } 10623 10624 return this.cfg.appendTo; 10625 }, 10626 10627 updatePlaceholderClass: function(add) { 10628 if (add) { 10629 this.label.addClass('ui-selectonemenu-label-placeholder'); 10630 } 10631 else { 10632 this.label.removeClass('ui-selectonemenu-label-placeholder'); 10633 } 10634 } 10635 10636}); 10637 10638/** 10639 * PrimeFaces SelectOneRadio Widget 10640 */ 10641PrimeFaces.widget.SelectOneRadio = PrimeFaces.widget.BaseWidget.extend({ 10642 10643 init: function(cfg) { 10644 this._super(cfg); 10645 10646 //custom layout 10647 if(this.cfg.custom) { 10648 this.originalInputs = this.jq.find(':radio'); 10649 this.inputs = $('input:radio[name="' + this.id + '"].ui-radio-clone'); 10650 this.outputs = this.inputs.parent().next('.ui-radiobutton-box'); 10651 this.labels = $(); 10652 10653 //labels 10654 for(var i=0; i < this.outputs.length; i++) { 10655 this.labels = this.labels.add('label[for="' + this.outputs.eq(i).parent().attr('id') + '"]'); 10656 } 10657 10658 //update radio state 10659 for(var i = 0; i < this.inputs.length; i++) { 10660 var input = this.inputs.eq(i), 10661 itemindex = input.data('itemindex'), 10662 original = this.originalInputs.eq(itemindex); 10663 10664 input.val(original.val()); 10665 10666 if(original.is(':checked')) { 10667 input.prop('checked', true).parent().next().addClass('ui-state-active').children('.ui-radiobutton-icon') 10668 .addClass('ui-icon-bullet').removeClass('ui-icon-blank'); 10669 } 10670 10671 if(original.is(':disabled')) { 10672 this.disable(i); 10673 } 10674 } 10675 10676 //pfs metadata 10677 this.originalInputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 10678 } 10679 //regular layout 10680 else { 10681 this.outputs = this.jq.find('.ui-radiobutton-box'); 10682 this.inputs = this.jq.find(':radio'); 10683 this.labels = this.jq.find('label'); 10684 10685 //pfs metadata 10686 this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 10687 } 10688 10689 this.enabledInputs = this.inputs.filter(':not(:disabled)'); 10690 this.checkedRadio = this.outputs.filter('.ui-state-active'); 10691 10692 this.bindEvents(); 10693 }, 10694 10695 refresh: function(cfg) { 10696 if(this.cfg.custom) { 10697 for(var i = 0; i < this.inputs.length; i++) { 10698 var input = this.inputs.eq(i); 10699 10700 this.enable(i); 10701 input.prop('checked', false).parent().next().removeClass('ui-state-active').children('.ui-radiobutton-icon') 10702 .removeClass('ui-icon-bullet').addClass('ui-icon-blank'); 10703 } 10704 } 10705 10706 this.init(cfg); 10707 }, 10708 10709 bindEvents: function() { 10710 var $this = this; 10711 10712 this.outputs.filter(':not(.ui-state-disabled)').on('mouseover.selectOneRadio', function() { 10713 $(this).addClass('ui-state-hover'); 10714 }) 10715 .on('mouseout.selectOneRadio', function() { 10716 $(this).removeClass('ui-state-hover'); 10717 }) 10718 .on('click.selectOneRadio', function(e) { 10719 var radio = $(this), 10720 input = radio.prev().children(':radio'); 10721 10722 if(!radio.hasClass('ui-state-active')) { 10723 $this.unselect($this.checkedRadio); 10724 $this.select(radio); 10725 $this.fireClickEvent(input, e); 10726 input.trigger('change'); 10727 } 10728 else { 10729 if ($this.cfg.unselectable) { 10730 $this.unselect($this.checkedRadio); 10731 } 10732 $this.fireClickEvent(input, e); 10733 } 10734 10735 // Github issue #4467 10736 e.stopPropagation(); 10737 e.preventDefault(); 10738 }); 10739 10740 this.labels.filter(':not(.ui-state-disabled)').on('click.selectOneRadio', function(e) { 10741 var target = $(PrimeFaces.escapeClientId($(this).attr('for'))), 10742 radio = null; 10743
10744 //checks if target is input or not(custom labels) 10745 if(target.is(':input')) 10746 radio = target.parent().next(); 10747 else 10748 radio = target.children('.ui-radiobutton-box'); //custom layout 10749 10750 radio.trigger('click.selectOneRadio'); 10751 10752 e.preventDefault(); 10753 }); 10754 10755 this.enabledInputs.on('focus.selectOneRadio', function() { 10756 var input = $(this), 10757 radio = input.parent().next(); 10758 10759 radio.addClass('ui-state-focus'); 10760 }) 10761 .on('blur.selectOneRadio', function() { 10762 var input = $(this), 10763 radio = input.parent().next(); 10764 10765 radio.removeClass('ui-state-focus'); 10766 }) 10767 .on('keydown.selectOneRadio', function(e) { 10768 var input = $(this), 10769 currentRadio = input.parent().next(), 10770 index = $this.enabledInputs.index(input), 10771 size = $this.enabledInputs.length, 10772 keyCode = $.ui.keyCode, 10773 key = e.which; 10774 10775 switch(key) { 10776 case keyCode.UP: 10777 case keyCode.LEFT: 10778 var prevRadioInput = (index === 0) ? $this.enabledInputs.eq((size - 1)) : $this.enabledInputs.eq(--index), 10779 prevRadio = prevRadioInput.parent().next(); 10780 10781 input.blur(); 10782 $this.unselect(currentRadio); 10783 $this.select(prevRadio); 10784 prevRadioInput.trigger('focus').trigger('change'); 10785 e.preventDefault(); 10786 break; 10787 10788 case keyCode.DOWN: 10789 case keyCode.RIGHT: 10790 var nextRadioInput = (index === (size - 1)) ? $this.enabledInputs.eq(0) : $this.enabledInputs.eq(++index), 10791 nextRadio = nextRadioInput.parent().next(); 10792 10793 input.blur(); 10794 $this.unselect(currentRadio); 10795 $this.select(nextRadio); 10796 nextRadioInput.trigger('focus').trigger('change'); 10797 e.preventDefault(); 10798 break; 10799 10800 case keyCode.SPACE: 10801 if(!input.prop('checked')) { 10802 $this.select(currentRadio); 10803 input.trigger('focus').trigger('change'); 10804 } 10805 10806 e.preventDefault(); 10807 break; 10808 } 10809 }); 10810 }, 10811 10812 unselect: function(radio) { 10813 var radioInput = radio.prev().children(':radio'); 10814 radioInput.prop('checked', false); 10815 radio.removeClass('ui-state-active').children('.ui-radiobutton-icon').removeClass('ui-icon-bullet').addClass('ui-icon-blank'); 10816 10817 if (this.cfg.custom) { 10818 var itemindex = radioInput.data('itemindex'); 10819 this.originalInputs.eq(itemindex).prop('checked', false); 10820 } 10821 }, 10822 10823 select: function(radio) { 10824 var radioInput = radio.prev().children(':radio'); 10825 this.checkedRadio = radio; 10826 radio.addClass('ui-state-active').children('.ui-radiobutton-icon').addClass('ui-icon-bullet').removeClass('ui-icon-blank'); 10827 radioInput.prop('checked', true); 10828 10829 if (this.cfg.custom) { 10830 var itemindex = radioInput.data('itemindex'); 10831 this.originalInputs.eq(itemindex).prop('checked', true); 10832 } 10833 }, 10834 10835 unbindEvents: function(input) { 10836 if(input) { 10837 input.off(); 10838 input.parent().nextAll('.ui-radiobutton-box').off(); 10839 this.labels.filter("label[for='" + input.attr('id') + "']").off(); 10840 } 10841 else { 10842 this.inputs.off(); 10843 this.labels.off(); 10844 this.outputs.off(); 10845 } 10846 }, 10847 10848 disable: function(index) { 10849 if(index == null) { 10850 this.inputs.attr('disabled', 'disabled'); 10851 this.labels.addClass('ui-state-disabled'); 10852 this.outputs.addClass('ui-state-disabled'); 10853 this.unbindEvents(); 10854 } 10855 else { 10856 var input = this.inputs.eq(index), 10857 label = this.labels.filter("label[for='" + input.attr('id') + "']"); 10858 input.attr('disabled', 'disabled').parent().nextAll('.ui-radiobutton-box').addClass('ui-state-disabled'); 10859 label.addClass('ui-state-disabled'); 10860 this.unbindEvents(input); 10861 } 10862 10863 }, 10864 10865 enable: function(index) { 10866 if(index == null) { 10867 this.inputs.removeAttr('disabled'); 10868 this.labels.removeClass('ui-state-disabled'); 10869 this.outputs.removeClass('ui-state-disabled'); 10870 } 10871 else { 10872 var input = this.inputs.eq(index), 10873 label = this.labels.filter("label[for='" + input.attr('id') + "']"); 10874 input.removeAttr('disabled').parent().nextAll('.ui-radiobutton-box').removeClass('ui-state-disabled'); 10875 label.removeClass('ui-state-disabled'); 10876 } 10877 this.bindEvents(); 10878 }, 10879 10880 fireClickEvent: function(input, event) { 10881 var userOnClick = input.prop('onclick'); 10882 if (userOnClick) { 10883 userOnClick.call(this, event); 10884 } 10885 } 10886 10887}); 10888 10889/** 10890 * PrimeFaces SelectBooleanCheckbox Widget 10891 */ 10892PrimeFaces.widget.SelectBooleanCheckbox = PrimeFaces.widget.BaseWidget.extend({ 10893 10894 init: function(cfg) { 10895 this._super(cfg); 10896 10897 this.input = $(this.jqId + '_input'); 10898 this.box = this.jq.find('.ui-chkbox-box'); 10899 this.icon = this.box.children('.ui-chkbox-icon'); 10900 this.itemLabel = this.jq.find('.ui-chkbox-label'); 10901 this.disabled = this.input.is(':disabled'); 10902 10903 var $this = this; 10904 10905 //bind events if not disabled 10906 if(!this.disabled) { 10907 this.box.on('mouseover.selectBooleanCheckbox', function() { 10908 $this.box.addClass('ui-state-hover'); 10909 }) 10910 .on('mouseout.selectBooleanCheckbox', function() { 10911 $this.box.removeClass('ui-state-hover'); 10912 }) 10913 .on('click.selectBooleanCheckbox', function() { 10914 $this.input.trigger('click'); 10915 }); 10916 10917 this.input.on('focus.selectBooleanCheckbox', function() { 10918 $this.box.addClass('ui-state-focus'); 10919 }) 10920 .on('blur.selectBooleanCheckbox', function() { 10921 $this.box.removeClass('ui-state-focus'); 10922 }) 10923 .on('change.selectBooleanCheckbox', function(e) { 10924 if($this.isChecked()) { 10925 $this.input.prop('checked', true).attr('aria-checked', true); 10926 $this.box.addClass('ui-state-active').children('.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 10927 } 10928 else { 10929 $this.input.prop('checked', false).attr('aria-checked', false); 10930 $this.box.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 10931 } 10932 }); 10933 10934 //toggle state on label click 10935 this.itemLabel.click(function() { 10936 $this.toggle(); 10937 $this.input.trigger('focus'); 10938 }); 10939 } 10940 10941 //pfs metadata 10942 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 10943 }, 10944 10945 toggle: function() { 10946 if(this.isChecked()) 10947 this.uncheck(); 10948 else 10949 this.check(); 10950 }, 10951 10952 isChecked: function() { 10953 return this.input.prop('checked'); 10954 }, 10955 10956 check: function() { 10957 if(!this.isChecked()) { 10958 this.input.prop('checked', true).trigger('change'); 10959 this.input.attr('aria-checked', true); 10960 this.box.addClass('ui-state-active').children('.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 10961 } 10962 }, 10963 10964 uncheck: function() { 10965 if(this.isChecked()) { 10966 this.input.prop('checked', false).trigger('change'); 10967 this.input.attr('aria-checked', false); 10968 this.box.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 10969 } 10970 } 10971 10972}); 10973 10974/** 10975 * PrimeFaces SelectManyCheckbox Widget 10976 */ 10977PrimeFaces.widget.SelectManyCheckbox = PrimeFaces.widget.BaseWidget.extend({ 10978 10979 init: function(cfg) { 10980 this._super(cfg); 10981 10982 if(this.cfg.custom) { 10983 this.originalInputs = this.jq.find(':checkbox'); 10984 this.inputs = $('input:checkbox[name="' + this.id + '"].ui-chkbox-clone'); 10985 this.outputs = this.inputs.parent().next('.ui-chkbox-box'); 10986 10987 //update checkbox state 10988 for(var i = 0; i < this.inputs.length; i++) { 10989 var input = this.inputs.eq(i), 10990 itemindex = input.data('itemindex'), 10991 original = this.originalInputs.eq(itemindex); 10992 10993 input.val(original.val()); 10994 10995 if(original.is(':checked')) { 10996 input.prop('checked', true).parent().next().addClass('ui-state-active').children('.ui-chkbox-icon') 10997 .addClass('ui-icon-check').removeClass('ui-icon-blank'); 10998 } 10999 } 11000 } 11001 else { 11002 this.outputs = this.jq.find('.ui-chkbox-box:not(.ui-state-disabled)'); 11003 this.inputs = this.jq.find(':checkbox:not(:disabled)'); 11004 } 11005 11006 this.enabledInputs = this.inputs.filter(':not(:disabled)'); 11007 11008 this.bindEvents(); 11009 11010 //pfs metadata 11011 this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11012 }, 11013 11014 bindEvents: function() { 11015 this.outputs.filter(':not(.ui-state-disabled)').on('mouseover', function() { 11016 $(this).addClass('ui-state-hover'); 11017 }) 11018 .on('mouseout', function() { 11019 $(this).removeClass('ui-state-hover'); 11020 }) 11021 .on('click', function() { 11022 var checkbox = $(this), 11023 input = checkbox.prev().children(':checkbox'); 11024 11025 input.trigger('click'); 11026 11027 if($.browser.msie && parseInt($.browser.version) < 9) { 11028 input.trigger('change'); 11029 } 11030 }); 11031 11032 //delegate focus-blur-change states 11033 this.enabledInputs.on('focus', function() { 11034 var input = $(this), 11035 checkbox = input.parent().next(); 11036 11037 checkbox.addClass('ui-state-focus'); 11038 }) 11039 .on('blur', function() { 11040 var input = $(this), 11041 checkbox = input.parent().next(); 11042 11043 checkbox.removeClass('ui-state-focus'); 11044 }) 11045 .on('change', function(e) { 11046 var input = $(this), 11047 checkbox = input.parent().next(), 11048 disabled = input.is(':disabled'); 11049 11050 if(disabled) { 11051 return; 11052 } 11053 11054 if(input.is(':checked')) { 11055 checkbox.children('.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 11056 11057 checkbox.addClass('ui-state-active'); 11058 } 11059 else { 11060 checkbox.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 11061 } 11062 }); 11063 } 11064 11065}); 11066 11067/** 11068 * PrimeFaces SelectListbox Widget 11069 */ 11070PrimeFaces.widget.SelectListbox = PrimeFaces.widget.BaseWidget.extend({ 11071 11072 init: function(cfg) { 11073 this._super(cfg); 11074 11075 this.input = $(this.jqId + '_input'), 11076 this.listContainer = this.jq.children('.ui-selectlistbox-listcontainer'); 11077 this.listElement = this.listContainer.children('.ui-selectlistbox-list'); 11078 this.options = $(this.input).children('option'); 11079 this.allItems = this.listElement.find('.ui-selectlistbox-item'); 11080 this.items = this.allItems.filter(':not(.ui-state-disabled)'); 11081 11082 //scroll to selected 11083 var selected = this.options.filter(':selected:not(:disabled)'); 11084 if(selected.length) { 11085 PrimeFaces.scrollInView(this.listContainer, this.items.eq(selected.eq(0).index())); 11086 } 11087 11088 this.bindEvents(); 11089 11090 //pfs metadata 11091 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11092 }, 11093 11094 bindEvents: function() { 11095 var $this = this; 11096 11097 //items 11098 this.items.on('mouseover.selectListbox', function() { 11099 var item = $(this); 11100 if(!item.hasClass('ui-state-highlight')) { 11101 item.addClass('ui-state-hover'); 11102 } 11103 }) 11104 .on('mouseout.selectListbox', function() { 11105 $(this).removeClass('ui-state-hover'); 11106 }) 11107 .on('dblclick.selectListbox', function(e) { 11108 $this.input.trigger('dblclick'); 11109 11110 PrimeFaces.clearSelection(); 11111 e.preventDefault(); 11112 }); 11113 11114 //input 11115 this.input.on('focus.selectListbox', function() { 11116 $this.jq.addClass('ui-state-focus'); 11117 }).on('blur.selectListbox', function() { 11118 $this.jq.removeClass('ui-state-focus'); 11119 }); 11120 11121 if(this.cfg.filter) { 11122 this.filterInput = this.jq.find('> div.ui-selectlistbox-filter-container > input.ui-selectlistbox-filter'); 11123 PrimeFaces.skinInput(this.filterInput); 11124 this.filterInput.on('keyup.selectListbox', function(e) { 11125 $this.filter(this.value); 11126 }); 11127 11128 this.setupFilterMatcher(); 11129 } 11130 }, 11131 11132 unselectAll: function() { 11133 this.items.removeClass('ui-state-highlight ui-state-hover'); 11134 this.options.filter(':selected').prop('selected', false); 11135 }, 11136 11137 selectItem: function(item) { 11138 item.addClass('ui-state-highlight').removeClass('ui-state-hover'); 11139 this.options.eq(item.index()).prop('selected', true); 11140 }, 11141 11142 unselectItem: function(item) { 11143 item.removeClass('ui-state-highlight'); 11144 this.options.eq(item.index()).prop('selected', false); 11145 }, 11146 11147 setupFilterMatcher: function() { 11148 this.cfg.filterMatchMode = this.cfg.filterMatchMode||'startsWith'; 11149 this.filterMatchers = { 11150 'startsWith': this.startsWithFilter 11151 ,'contains': this.containsFilter 11152 ,'endsWith': this.endsWithFilter 11153 ,'custom': this.cfg.filterFunction 11154 }; 11155 11156 this.filterMatcher = this.filterMatchers[this.cfg.filterMatchMode]; 11157 }, 11158 11159 startsWithFilter: function(value, filter) { 11160 return value.indexOf(filter) === 0; 11161 }, 11162 11163 containsFilter: function(value, filter) { 11164 return value.indexOf(filter) !== -1; 11165 }, 11166 11167 endsWithFilter: function(value, filter) { 11168 return value.indexOf(filter, value.length - filter.length) !== -1; 11169 }, 11170 11171 filter: function(value) { 11172 var filterValue = this.cfg.caseSensitive ? $.trim(value) : $.trim(value).toLowerCase(); 11173 11174 if(filterValue === '') { 11175 this.items.filter(':hidden').show(); 11176 } 11177 else { 11178 for(var i = 0; i < this.options.length; i++) { 11179 var option = this.options.eq(i), 11180 itemLabel = this.cfg.caseSensitive ? option.text() : option.text().toLowerCase(), 11181 item = this.items.eq(i); 11182 11183 if(this.filterMatcher(itemLabel, filterValue)) 11184 item.show(); 11185 else 11186 item.hide(); 11187 } 11188 } 11189 } 11190}); 11191 11192/** 11193 * PrimeFaces SelectOneListbox Widget 11194 */ 11195PrimeFaces.widget.SelectOneListbox = PrimeFaces.widget.SelectListbox.extend({ 11196 11197 bindEvents: function() { 11198 this._super(); 11199 var $this = this; 11200 11201 if(!this.cfg.disabled) { 11202 this.focusedItem = null; 11203 11204 this.items.on('click.selectListbox', function(e) { 11205 var item = $(this), 11206 selectedItem = $this.items.filter('.ui-state-highlight'); 11207 11208 if(item.index() !== selectedItem.index()) { 11209 if(selectedItem.length) { 11210 $this.unselectItem(selectedItem); 11211 } 11212 11213 $this.selectItem(item); 11214 $this.input.trigger('change'); 11215 } 11216 11217 /* For keyboard navigation */ 11218 $this.removeOutline(); 11219 $this.focusedItem = item; 11220 $this.input.trigger('focus'); 11221 11222 $this.input.trigger('click'); 11223 11224 PrimeFaces.clearSelection(); 11225 e.preventDefault(); 11226 }); 11227 } 11228 11229 this.bindKeyEvents(); 11230 }, 11231 11232 bind
11232KeyEvents: function() { 11233 var $this = this; 11234 11235 this.input.off('focus.selectListbox blur.selectListbox keydown.selectListbox').on('focus.selectListbox', function(e) { 11236 $this.jq.addClass('ui-state-focus'); 11237 11238 var activeItem = $this.focusedItem||$this.items.filter('.ui-state-highlight:visible:first'); 11239 if(activeItem.length) { 11240 $this.focusedItem = activeItem; 11241 } 11242 else { 11243 $this.focusedItem = $this.items.filter(':visible:first'); 11244 } 11245 11246 setTimeout(function() { 11247 if($this.focusedItem) { 11248 PrimeFaces.scrollInView($this.listContainer, $this.focusedItem); 11249 $this.focusedItem.addClass('ui-listbox-outline'); 11250 } 11251 }, 100); 11252 }) 11253 .on('blur.selectListbox', function() { 11254 $this.jq.removeClass('ui-state-focus'); 11255 $this.removeOutline(); 11256 $this.focusedItem = null; 11257 }) 11258 .on('keydown.selectListbox', function(e) { 11259 if(!$this.focusedItem) { 11260 return; 11261 } 11262 11263 var keyCode = $.ui.keyCode, 11264 key = e.which; 11265 11266 switch(key) { 11267 case keyCode.UP: 11268 if(!$this.focusedItem.hasClass('ui-state-highlight')) { 11269 $this.focusedItem.trigger('click.selectListbox'); 11270 } 11271 else { 11272 var prevItem = $this.focusedItem.prevAll('.ui-selectlistbox-item:visible:first'); 11273 if(prevItem.length) { 11274 prevItem.trigger('click.selectListbox'); 11275 11276 PrimeFaces.scrollInView($this.listContainer, $this.focusedItem); 11277 } 11278 } 11279 e.preventDefault(); 11280 break; 11281 11282 case keyCode.DOWN: 11283 if(!$this.focusedItem.hasClass('ui-state-highlight')) { 11284 $this.focusedItem.trigger('click.selectListbox'); 11285 } 11286 else { 11287 var nextItem = $this.focusedItem.nextAll('.ui-selectlistbox-item:visible:first'); 11288 if(nextItem.length) { 11289 nextItem.trigger('click.selectListbox'); 11290 11291 PrimeFaces.scrollInView($this.listContainer, $this.focusedItem); 11292 } 11293 } 11294 e.preventDefault(); 11295 break; 11296 }; 11297 }); 11298 11299 }, 11300 11301 removeOutline: function() { 11302 if(this.focusedItem && this.focusedItem.hasClass('ui-listbox-outline')) { 11303 this.focusedItem.removeClass('ui-listbox-outline'); 11304 } 11305 } 11306}); 11307/** 11308 * PrimeFaces SelectManyMenu Widget 11309 */ 11310PrimeFaces.widget.SelectManyMenu = PrimeFaces.widget.SelectListbox.extend({ 11311 11312 init: function(cfg) { 11313 this._super(cfg); 11314 11315 this.allItems.filter('.ui-state-highlight').find('> .ui-chkbox > .ui-chkbox-box').addClass('ui-state-active'); 11316 }, 11317 11318 bindEvents: function() { 11319 this._super(); 11320 var $this = this; 11321 11322 if(!this.cfg.disabled) { 11323 this.items.on('click.selectListbox', function(e) { 11324 //stop propagation 11325 if($this.checkboxClick) { 11326 $this.checkboxClick = false; 11327 return; 11328 } 11329 11330 var item = $(this), 11331 selectedItems = $this.items.filter('.ui-state-highlight'), 11332 metaKey = (e.metaKey||e.ctrlKey); 11333 11334 if(!e.shiftKey) { 11335 if(!metaKey && !$this.cfg.showCheckbox) { 11336 $this.unselectAll(); 11337 } 11338 11339 if((metaKey || $this.cfg.showCheckbox) && item.hasClass('ui-state-highlight')) { 11340 $this.unselectItem(item); 11341 } 11342 else { 11343 $this.selectItem(item); 11344 $this.cursorItem = item; 11345 } 11346 } 11347 else { 11348 //range selection 11349 if($this.cursorItem) { 11350 $this.unselectAll(); 11351 11352 var currentItemIndex = item.index(), 11353 cursorItemIndex = $this.cursorItem.index(), 11354 startIndex = (currentItemIndex > cursorItemIndex) ? cursorItemIndex : currentItemIndex, 11355 endIndex = (currentItemIndex > cursorItemIndex) ? (currentItemIndex + 1) : (cursorItemIndex + 1); 11356 11357 for(var i = startIndex ; i < endIndex; i++) { 11358 var it = $this.allItems.eq(i); 11359 11360 if(it.is(':visible') && !it.hasClass('ui-state-disabled')) { 11361 $this.selectItem(it); 11362 } 11363 } 11364 } 11365 else { 11366 $this.selectItem(item); 11367 $this.cursorItem = item; 11368 } 11369 } 11370 11371 $this.input.trigger('change'); 11372 $this.input.trigger('click'); 11373 PrimeFaces.clearSelection(); 11374 e.preventDefault(); 11375 }); 11376 11377 if(this.cfg.showCheckbox) { 11378 this.checkboxes = this.jq.find('.ui-selectlistbox-item:not(.ui-state-disabled) div.ui-chkbox > div.ui-chkbox-box'); 11379 11380 this.checkboxes.on('mouseover.selectManyMenu', function(e) { 11381 var chkbox = $(this); 11382 11383 if(!chkbox.hasClass('ui-state-active')) 11384 chkbox.addClass('ui-state-hover'); 11385 }) 11386 .on('mouseout.selectManyMenu', function(e) { 11387 $(this).removeClass('ui-state-hover'); 11388 }) 11389 .on('click.selectManyMenu', function(e) { 11390 $this.checkboxClick = true; 11391 11392 var item = $(this).closest('.ui-selectlistbox-item'); 11393 if(item.hasClass('ui-state-highlight')) 11394 $this.unselectItem(item); 11395 else 11396 $this.selectItem(item); 11397 11398 $this.input.trigger('change'); 11399 }); 11400 } 11401 } 11402 }, 11403 11404 selectAll: function() { 11405 // ~~~ PERF ~~~ 11406 // See https://github.com/primefaces/primefaces/issues/2089 11407 // 11408 // 1) don't use jquery wrappers 11409 // 2) don't use existing methods like selectItem 11410 11411 for(var i = 0; i < this.items.length; i++) { 11412 var item = this.items.eq(i); 11413 var itemNative = item[0]; 11414 11415 itemNative.classList.add('ui-state-highlight'); 11416 itemNative.classList.remove('ui-state-hover'); 11417 11418 if(this.cfg.showCheckbox) { 11419 var checkbox = item.find('div.ui-chkbox').children('div.ui-chkbox-box'); 11420 11421 var checkboxNative = checkbox[0]; 11422 checkboxNative.classList.remove('ui-state-hover'); 11423 checkboxNative.classList.add('ui-state-active'); 11424 11425 var checkboxIconNative = checkbox.children('span.ui-chkbox-icon')[0]; 11426 checkboxIconNative.classList.remove('ui-icon-blank'); 11427 checkboxIconNative.classList.add('ui-icon-check'); 11428 } 11429 } 11430 11431 for(var i = 0; i < this.options.length; i++) { 11432 this.options[i].selected = true; 11433 } 11434 }, 11435 11436 unselectAll: function() { 11437 // ~~~ PERF ~~~ 11438 // See https://github.com/primefaces/primefaces/issues/2089 11439 // 11440 // 1) don't use jquery wrappers 11441 // 2) don't use existing methods like unselectItem 11442 11443 for(var i = 0; i < this.items.length; i++) { 11444 var item = this.items.eq(i); 11445 var itemNative = item[0]; 11446 11447 itemNative.classList.remove('ui-state-highlight'); 11448 11449 if(this.cfg.showCheckbox) { 11450 var checkbox = item.find('div.ui-chkbox').children('div.ui-chkbox-box'); 11451 11452 var checkboxNative = checkbox[0]; 11453 checkboxNative.classList.remove('ui-state-active'); 11454 11455 var checkboxIconNative = checkbox.children('span.ui-chkbox-icon')[0]; 11456 checkboxIconNative.classList.add('ui-icon-blank'); 11457 checkboxIconNative.classList.remove('ui-icon-check'); 11458 } 11459 } 11460 11461 for(var i = 0; i < this.options.length; i++) { 11462 this.options[i].selected = false;
11463 } 11464 }, 11465 11466 selectItem: function(item) { 11467 this._super(item); 11468 11469 if(this.cfg.showCheckbox) { 11470 this.selectCheckbox(item.find('div.ui-chkbox-box')); 11471 } 11472 }, 11473 11474 unselectItem: function(item) { 11475 this._super(item); 11476 11477 if(this.cfg.showCheckbox) { 11478 this.unselectCheckbox(item.find('div.ui-chkbox-box')); 11479 } 11480 }, 11481 11482 selectCheckbox: function(chkbox) { 11483 chkbox.removeClass('ui-state-hover').addClass('ui-state-active').children('span.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 11484 }, 11485 11486 unselectCheckbox: function(chkbox) { 11487 chkbox.removeClass('ui-state-active').children('span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 11488 } 11489}); 11490 11491/** 11492 * PrimeFaces CommandButton Widget 11493 */ 11494PrimeFaces.widget.CommandButton = PrimeFaces.widget.BaseWidget.extend({ 11495 11496 init: function(cfg) { 11497 this._super(cfg); 11498 11499 PrimeFaces.skinButton(this.jq); 11500 }, 11501 11502 disable: function() { 11503 this.jq.removeClass('ui-state-hover ui-state-focus ui-state-active') 11504 .addClass('ui-state-disabled').attr('disabled', 'disabled'); 11505 }, 11506 11507 enable: function() { 11508 this.jq.removeClass('ui-state-disabled').removeAttr('disabled'); 11509 } 11510 11511}); 11512/* 11513 * PrimeFaces Button Widget 11514 */ 11515PrimeFaces.widget.Button = PrimeFaces.widget.BaseWidget.extend({ 11516 11517 init: function(cfg) { 11518 this._super(cfg); 11519 11520 PrimeFaces.skinButton(this.jq); 11521 }, 11522 11523 disable: function() { 11524 this.jq.removeClass('ui-state-hover ui-state-focus ui-state-active') 11525 .addClass('ui-state-disabled').attr('disabled', 'disabled'); 11526 }, 11527 11528 enable: function() { 11529 this.jq.removeClass('ui-state-disabled').removeAttr('disabled'); 11530 } 11531 11532}); 11533 11534/** 11535 * PrimeFaces LinkButton Widget 11536 */ 11537PrimeFaces.widget.LinkButton = PrimeFaces.widget.BaseWidget.extend({ 11538 11539 init: function(cfg) { 11540 this._super(cfg); 11541 11542 PrimeFaces.skinButton(this.jq); 11543 } 11544 11545}); 11546/** 11547 * PrimeFaces SelecyManyButton Widget 11548 */ 11549PrimeFaces.widget.SelectManyButton = PrimeFaces.widget.BaseWidget.extend({ 11550 11551 init: function(cfg) { 11552 this._super(cfg); 11553 11554 this.buttons = this.jq.children('div:not(.ui-state-disabled)'); 11555 this.inputs = this.jq.find(':checkbox:not(:disabled)'); 11556 this.bindEvents(); 11557 11558 //pfs metadata 11559 this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11560 }, 11561 11562 bindEvents: function() { 11563 var $this = this; 11564 11565 this.buttons.on('mouseover', function() { 11566 var button = $(this); 11567 if(!button.hasClass('ui-state-active')) { 11568 button.addClass('ui-state-hover'); 11569 } 11570 }) 11571 .on('mouseout', function() { 11572 $(this).removeClass('ui-state-hover'); 11573 }) 11574 .on('click', function(e) { 11575 var button = $(this), 11576 input = button.children(':checkbox'); 11577 11578 if(button.hasClass('ui-state-active')) 11579 button.addClass('ui-state-hover'); 11580 else 11581 button.removeClass('ui-state-hover'); 11582 11583 input.trigger('focus').trigger('click'); 11584 }); 11585 11586 /* Keyboard support */ 11587 this.inputs.on('focus', function() { 11588 var input = $(this), 11589 button = input.parent(); 11590 11591 button.addClass('ui-state-focus'); 11592 }) 11593 .on('blur', function() { 11594 var input = $(this), 11595 button = input.parent(); 11596 11597 button.removeClass('ui-state-focus'); 11598 }) 11599 .on('change', function() { 11600 var input = $(this), 11601 button = input.parent(); 11602 11603 if(input.prop('checked')) 11604 button.addClass('ui-state-active'); 11605 else 11606 button.removeClass('ui-state-active'); 11607 }) 11608 .on('click', function(e) { 11609 e.stopPropagation(); 11610 }); 11611 }, 11612 11613 select: function(button) { 11614 button.children(':checkbox').prop('checked', true).change(); 11615 }, 11616 11617 unselect: function(button) { 11618 button.children(':checkbox').prop('checked', false).change(); 11619 } 11620 11621}); 11622 11623/** 11624 * PrimeFaces SelectOneButton Widget 11625 */ 11626PrimeFaces.widget.SelectOneButton = PrimeFaces.widget.BaseWidget.extend({ 11627 11628 init: function(cfg) { 11629 this._super(cfg); 11630 11631 this.buttons = this.jq.children('div:not(.ui-state-disabled)'); 11632 this.inputs = this.jq.find(':radio:not(:disabled)'); 11633 this.cfg.unselectable = this.cfg.unselectable === false ? false : true; 11634 11635 this.bindEvents(); 11636 11637 //pfs metadata 11638 this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11639 }, 11640 11641 bindEvents: function() { 11642 var $this = this; 11643 11644 this.buttons.on('mouseover', function() { 11645 var button = $(this); 11646 button.addClass('ui-state-hover'); 11647 }) 11648 .on('mouseout', function() { 11649 $(this).removeClass('ui-state-hover'); 11650 }) 11651 .on('click', function() { 11652 var button = $(this), 11653 radio = button.children(':radio'); 11654 11655 if(button.hasClass('ui-state-active') || radio.prop('checked')) { 11656 $this.unselect(button); 11657 } 11658 else { 11659 $this.select(button); 11660 } 11661 }); 11662 11663 /* For keyboard accessibility */ 11664 this.buttons.on('focus.selectOneButton', function(){ 11665 var button = $(this); 11666 button.addClass('ui-state-focus'); 11667 }) 11668 .on('blur.selectOneButton', function(){ 11669 var button = $(this); 11670 button.removeClass('ui-state-focus'); 11671 }) 11672 .on('keydown.selectOneButton', function(e) { 11673 var keyCode = $.ui.keyCode, 11674 key = e.which; 11675 11676 if(key === keyCode.SPACE || key === keyCode.ENTER) { 11677 var button = $(this), 11678 radio = button.children(':radio'); 11679 11680 if(radio.prop('checked')) { 11681 $this.unselect(button); 11682 } 11683 else { 11684 $this.select(button); 11685 } 11686 e.preventDefault(); 11687 } 11688 }); 11689 }, 11690 11691 select: function(button) { 11692 this.buttons.filter('.ui-state-active').removeClass('ui-state-active ui-state-hover').children(':radio').prop('checked', false); 11693 11694 button.addClass('ui-state-active').children(':radio').prop('checked', true); 11695 11696 this.triggerChange(); 11697 }, 11698 11699 unselect: function(button) { 11700 if(this.cfg.unselectable) { 11701 button.removeClass('ui-state-active ui-state-hover').children(':radio').prop('checked', false).change(); 11702 11703 this.triggerChange(); 11704 } 11705 }, 11706 11707 triggerChange: function() { 11708 if(this.cfg.change) { 11709 this.cfg.change.call(this); 11710 } 11711 11712 this.callBehavior('change'); 11713 }, 11714 11715 disable: function() { 11716 this.buttons.removeClass('ui-state-hover ui-state-focus ui-state-active') 11717 .addClass('ui-state-disabled').attr('disabled', 'disabled'); 11718 }, 11719 11720 enable: function() { 11721 this.buttons.removeClass('ui-state-disabled').removeAttr('disabled'); 11722 } 11723 11724}); 11725 11726/** 11727 * PrimeFaces SelectBooleanButton Widget 11728 */ 11729PrimeFaces.widget.SelectBooleanButton = PrimeFaces.widget.BaseWidget.extend({ 11730 11731 init: function(cfg) { 11732 this._super(cfg); 11733 11734 this.input = $(this.jqId + '_input'); 11735 this.disabled = this.input.is(':disabled'); 11736 this.icon = this.jq.children('.ui-button-icon-left'); 11737 var $this = this; 11738 11739 //bind events if not disabled 11740 if(!this.disabled) { 11741 this.jq.on('mouseover', function() { 11742 if(!$this.jq.hasClass('ui-state-active')) { 11743 $this.jq.addClass('ui-state-hover'); 11744 } 11745 }).on('mouseout', function() { 11746 $this.jq.removeClass('ui-state-hover'); 11747 }) 11748 .on('click', function() { 11749 $this.toggle(); 11750 $this.input.trigger('focus'); 11751 }); 11752 } 11753 11754 this.input.on('focus', function() { 11755 $this.jq.addClass('ui-state-focus'); 11756 }) 11757 .on('blur', function() { 11758 $this.jq.removeClass('ui-state-focus'); 11759 }) 11760 .on('keydown', function(e) { 11761 var keyCode = $.ui.keyCode; 11762 if(e.which === keyCode.SPACE) { 11763 e.preventDefault(); 11764 } 11765 }) 11766 .on('keyup', function(e) { 11767 var keyCode = $.ui.keyCode; 11768 if(e.which === keyCode.SPACE) { 11769 $this.toggle(); 11770 11771 e.preventDefault(); 11772 } 11773 }); 11774 11775 //pfs metadata 11776 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11777 }, 11778 11779 toggle: function() { 11780 if(!this.disabled) { 11781 if(this.input.prop('checked')) 11782 this.uncheck(); 11783 else 11784 this.check(); 11785 } 11786 }, 11787 11788 check: function() { 11789 if(!this.disabled) { 11790 this.input.prop('checked', true); 11791 this.jq.addClass('ui-state-active').children('.ui-button-text').text(this.cfg.onLabel); 11792 11793 if(this.icon.length > 0) { 11794 this.icon.removeClass(this.cfg.offIcon).addClass(this.cfg.onIcon); 11795 } 11796 11797 this.input.trigger('change'); 11798 } 11799 }, 11800 11801 uncheck: function() { 11802 if(!this.disabled) { 11803 this.input.prop('checked', false); 11804 this.jq.removeClass('ui-state-active').children('.ui-button-text').text(this.cfg.offLabel); 11805 11806 if(this.icon.length > 0) { 11807 this.icon.removeClass(this.cfg.onIcon).addClass(this.cfg.offIcon); 11808 } 11809 11810 this.input.trigger('change'); 11811 } 11812 } 11813 11814}); 11815 11816/** 11817 * PrimeFaces SelectCheckboxMenu Widget 11818 */ 11819PrimeFaces.widget.SelectCheckboxMenu = PrimeFaces.widget.BaseWidget.extend({ 11820 11821 init: function(cfg) { 11822 this._super(cfg); 11823 11824 this.labelContainer = this.jq.find('.ui-selectcheckboxmenu-label-container'); 11825 this.label = this.jq.find('.ui-selectcheckboxmenu-label'); 11826 this.menuIcon = this.jq.children('.ui-selectcheckboxmenu-trigger'); 11827 this.triggers = this.jq.find('.ui-selectcheckboxmenu-trigger, .ui-selectcheckboxmenu-label'); 11828 this.disabled = this.jq.hasClass('ui-state-disabled'); 11829 this.inputs = this.jq.find(':checkbox'); 11830 this.panelId = this.id + '_panel'; 11831 this.labelId = this.id + '_label'; 11832 this.keyboardTarget = $(this.jqId + '_focus'); 11833 this.tabindex = this.keyboardTarget.attr('tabindex'); 11834 this.cfg.showHeader = (this.cfg.showHeader === undefined) ? true : this.cfg.showHeader; 11835 this.cfg.dynamic = this.cfg.dynamic === true ? true : false;
11836 this.isDynamicLoaded = false; 11837 this.cfg.labelSeparator = (this.cfg.labelSeparator === undefined) ? ', ' : this.cfg.labelSeparator; 11838 11839 if(!this.disabled) { 11840 if(this.cfg.multiple) { 11841 this.triggers = this.jq.find('.ui-selectcheckboxmenu-trigger, .ui-selectcheckboxmenu-multiple-container'); 11842 } 11843 11844 if(!this.cfg.dynamic) { 11845 this._renderPanel(); 11846 } 11847 11848 this.bindEvents(); 11849 this.bindKeyEvents(); 11850 11851 //mark trigger and descandants of trigger as a trigger for a primefaces overlay 11852 this.triggers.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 11853 11854 if(!this.cfg.multiple) { 11855 if(this.cfg.updateLabel) { 11856 this.defaultLabel = this.label.text(); 11857 this.label.css({ 11858 'text-overflow': 'ellipsis', 11859 overflow: 'hidden' 11860 }); 11861 11862 this.updateLabel(); 11863 } 11864 11865 this.label.attr('id', this.labelId); 11866 this.keyboardTarget.attr('aria-expanded', false).attr('aria-labelledby', this.labelId); 11867 } 11868 } else { 11869 // disabled 11870 if(!this.cfg.multiple) { 11871 if (this.cfg.updateLabel) { 11872 this.defaultLabel = this.label.text(); 11873 this.label.css({ 11874 'text-overflow': 'ellipsis', 11875 overflow: 'hidden' 11876 }); 11877 11878 this.updateLabel(); 11879 } 11880 } 11881 } 11882 11883 //pfs metadata 11884 this.inputs.data(PrimeFaces.CLIENT_ID_DATA, this.id); 11885 }, 11886 11887 //@override 11888 refresh: function(cfg) { 11889 this._super(cfg); 11890 }, 11891 11892 _renderPanel: function() { 11893 this.renderPanel(); 11894 11895 if(this.tabindex) { 11896 this.panel.find('a, input').attr('tabindex', this.tabindex); 11897 } 11898 11899 this.checkboxes = this.itemContainer.find('.ui-chkbox-box:not(.ui-state-disabled)'); 11900 this.labels = this.itemContainer.find('label'); 11901 11902 this.bindPanelEvents(); 11903 this.bindPanelKeyEvents(); 11904 11905 this.isDynamicLoaded = true; 11906 }, 11907 11908 renderPanel: function() { 11909 this.panel = $('<div id="' + this.panelId + '" class="ui-selectcheckboxmenu-panel ui-widget ui-widget-content ui-corner-all ui-helper-hidden ui-input-overlay" role="dialog"></div>'); 11910 this.cfg.appendTo = this.getAppendTo(); 11911 11912 PrimeFaces.utils.registerDynamicOverlay(this, this.panel, this.id + '_panel'); 11913 11914 if(this.cfg.panelStyle) { 11915 this.panel.attr('style', this.cfg.panelStyle); 11916 } 11917 11918 if(this.cfg.panelStyleClass) { 11919 this.panel.addClass(this.cfg.panelStyleClass); 11920 } 11921 11922 this.renderHeader(); 11923 11924 this.renderItems(); 11925 11926 if(this.cfg.scrollHeight) { 11927 this.itemContainerWrapper.height(this.cfg.scrollHeight); 11928 } 11929 else if(this.inputs.length > 10) { 11930 this.itemContainerWrapper.height(200); 11931 } 11932 }, 11933 11934 renderHeader: function() { 11935 this.header = $('<div class="ui-widget-header ui-corner-all ui-selectcheckboxmenu-header ui-helper-clearfix"></div>') 11936 .appendTo(this.panel); 11937 11938 if(!this.cfg.showHeader) { 11939 this.header.removeClass('ui-helper-clearfix').addClass('ui-helper-hidden'); 11940 } 11941 //toggler 11942 this.toggler = $('<div class="ui-chkbox ui-widget"><div class="ui-helper-hidden-accessible"><input type="checkbox" role="checkbox" aria-label="Select All" readonly="readonly"></div><div class="ui-chkbox-box ui-widget ui-corner-all ui-state-default"><span class="ui-chkbox-icon ui-icon ui-icon-blank"></span></div></div>') 11943 .appendTo(this.header); 11944 this.togglerBox = this.toggler.children('.ui-chkbox-box'); 11945 if(this.inputs.filter(':not(:checked)').length === 0) { 11946 this.check(this.togglerBox); 11947 } 11948 11949 //filter 11950 if(this.cfg.filter) {
11951 this.filterInputWrapper = $('<div class="ui-selectcheckboxmenu-filter-container"></div>').appendTo(this.header); 11952 this.filterInput = $('<input type="text" aria-multiline="false" aria-readonly="false" aria-disabled="false" aria-label="Filter Input" role="textbox" class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all">') 11953 .appendTo(this.filterInputWrapper); 11954 11955 if(this.cfg.filterPlaceholder) { 11956 this.filterInput.attr('placeholder', this.cfg.filterPlaceholder); 11957 } 11958 11959 this.filterInputWrapper.append("<span class='ui-icon ui-icon-search'></span>"); 11960 } 11961 11962 //closer 11963 this.closer = $('<a class="ui-selectcheckboxmenu-close ui-corner-all" href="#"><span class="ui-icon ui-icon-circle-close"></span></a>') 11964 .attr('aria-label', 'Close').appendTo(this.header); 11965 11966 }, 11967 11968 renderItems: function() { 11969 var $this = this; 11970 11971 this.itemContainerWrapper = $('<div class="ui-selectcheckboxmenu-items-wrapper"><ul class="ui-selectcheckboxmenu-items ui-selectcheckboxmenu-list ui-widget-content ui-widget ui-corner-all ui-helper-reset"></ul></div>') 11972 .appendTo(this.panel); 11973 11974 this.itemContainer = this.itemContainerWrapper.children('ul.ui-selectcheckboxmenu-items'); 11975 11976 //check if inputs must be grouped 11977 var grouped = this.inputs.filter('[group-label]'); 11978 11979 var currentGroupName = null; 11980 for(var i = 0; i < this.inputs.length; i++) { 11981 var input = this.inputs.eq(i), 11982 label = input.next(), 11983 disabled = input.is(':disabled'), 11984 checked = input.is(':checked'), 11985 title = input.attr('title'), 11986 boxClass = 'ui-chkbox-box ui-widget ui-corner-all ui-state-default', 11987 itemClass = 'ui-selectcheckboxmenu-item ui-selectcheckboxmenu-list-item ui-corner-all', 11988 escaped = input.data('escaped'); 11989 11990 if(grouped.length && currentGroupName !== input.attr('group-label')) { 11991 currentGroupName = input.attr('group-label'); 11992 var itemGroup = $('<li class="ui-selectcheckboxmenu-item-group ui-selectcheckboxmenu-group-list-item ui-corner-all"></li>'); 11993 itemGroup.text(currentGroupName); 11994 $this.itemContainer.append(itemGroup); 11995 } 11996 11997 if(disabled) { 11998 boxClass += " ui-state-disabled"; 11999 } 12000 12001 if(checked) { 12002 boxClass += " ui-state-active"; 12003 } 12004 12005 var iconClass = checked ? 'ui-chkbox-icon ui-icon ui-icon-check' : 'ui-chkbox-icon ui-icon ui-icon-blank', 12006 itemClass = checked ? itemClass + ' ui-selectcheckboxmenu-checked' : itemClass + ' ui-selectcheckboxmenu-unchecked'; 12007 12008 var item = $('<li class="' + itemClass + '"></li>'); 12009 item.append('<div class="ui-chkbox ui-widget"><div class="ui-helper-hidden-accessible"><input type="checkbox" role="checkbox" readonly="readonly"></input></div>' + 12010 '<div class="' + boxClass + '"><span class="' + iconClass + '"></span></div></div>'); 12011 12012 var uuid = PrimeFaces.uuid(); 12013 var itemLabel = $('<label for='+uuid+'></label>'), 12014 labelHtml = label.html().trim(), 12015 labelLength = labelHtml.length; 12016 if (labelLength > 0 && labelHtml !== ' ') 12017 if(escaped) 12018 itemLabel.text(label.text()); 12019 else 12020 itemLabel.html(label.html()); 12021 else 12022 itemLabel.text(input.val()); 12023 12024 itemLabel.appendTo(item); 12025 12026 if(title) { 12027 item.attr('title', title); 12028 } 12029 12030 if($this.cfg.multiple) { 12031 item.attr('data-item-value', input.val()); 12032 } 12033 12034 item.find('> .ui-chkbox > .ui-helper-hidden-accessible > input').prop('checked', checked).attr('aria-checked', checked).attr('id', uuid); 12035 $this.itemContainer.attr('role', 'group'); 12036 12037 $this.itemContainer.append(item); 12038 } 12039 12040 this.items = this.itemContainer.children('li.ui-selectcheckboxmenu-item'); 12041 this.groupHeaders = this.itemContainer.children('li.ui-selectcheckboxmenu-item-group'); 12042 }, 12043 12044 bindEvents: function() { 12045 var $this = this; 12046 12047 //Events to show/hide the panel 12048 this.triggers.on('mouseover.selectCheckboxMenu', function() { 12049 if(!$this.disabled&&!$this.triggers.hasClass('ui-state-focus')) { 12050 $this.jq.addClass('ui-state-hover'); 12051 $this.triggers.addClass('ui-state-hover'); 12052 } 12053 }).on('mouseout.selectCheckboxMenu', function() { 12054 if(!$this.disabled) { 12055 $this.jq.removeClass('ui-state-hover'); 12056 $this.triggers.removeClass('ui-state-hover'); 12057 } 12058 }).on('mousedown.selectCheckboxMenu', function(e) { 12059 if(!$this.disabled) { 12060 if($this.cfg.multiple && $(e.target).is('.ui-selectcheckboxmenu-token-icon')) { 12061 return; 12062 } 12063 12064 if($this.cfg.dynamic && !$this.isDynamicLoaded) { 12065 $this._renderPanel(); 12066 } 12067 12068 if($this.panel.is(":hidden")) { 12069 $this.show(); 12070 } 12071 else { 12072 $this.hide(true); 12073 } 12074 } 12075 }).on('click.selectCheckboxMenu', function(e) { 12076 $this.jq.removeClass('ui-state-hover'); 12077 $this.triggers.removeClass('ui-state-hover'); 12078 $this.keyboardTarget.trigger('focus'); 12079 e.preventDefault(); 12080 }); 12081 12082 if(this.cfg.multiple) { 12083 this.bindMultipleModeEvents(); 12084 } 12085 12086 //Client Behaviors 12087 if(this.cfg.behaviors) { 12088 PrimeFaces.attachBehaviors(this.inputs, this.cfg.behaviors); 12089 } 12090 }, 12091 12092 bindPanelEvents: function() { 12093 var $this = this; 12094 12095 //Events for checkboxes 12096 this.bindCheckboxHover(this.checkboxes); 12097 this.checkboxes.on('click.selectCheckboxMenu', function() { 12098 $this.toggleItem($(this)); 12099 }); 12100 12101 //Toggler 12102 this.bindCheckboxHover(this.togglerBox); 12103 this.togglerBox.on('click.selectCheckboxMenu', function() { 12104 var el = $(this); 12105 if(el.hasClass('ui-state-active')) { 12106 $this.uncheckAll(); 12107 el.addClass('ui-state-hover'); 12108 } 12109 else { 12110 $this.checkAll(); 12111 el.removeClass('ui-state-hover'); 12112 } 12113 }); 12114 12115 //filter 12116 if(this.cfg.filter) { 12117 this.setupFilterMatcher(); 12118 12119 PrimeFaces.skinInput(this.filterInput); 12120 12121 this.filterInput.on('keyup.selectCheckboxMenu', function() { 12122 $this.filter($(this).val()); 12123 }).on('keydown.selectCheckboxMenu', function(e) { 12124 if(e.which === $.ui.keyCode.ESCAPE) { 12125 $this.hide(); 12126 } 12127 }); 12128 } 12129 12130 //Closer 12131 this.closer.on('mouseenter.selectCheckboxMenu', function(){ 12132 $(this).addClass('ui-state-hover'); 12133 }
12133).on('mouseleave.selectCheckboxMenu', function() { 12134 $(this).removeClass('ui-state-hover'); 12135 }).on('click.selectCheckboxMenu', function(e) { 12136 $this.hide(true); 12137 12138 e.preventDefault(); 12139 }); 12140 12141 //Labels 12142 this.labels.on('click.selectCheckboxMenu', function(e) { 12143 var checkbox = $(this).prev().children('.ui-chkbox-box'); 12144 $this.toggleItem(checkbox); 12145 checkbox.removeClass('ui-state-hover'); 12146 PrimeFaces.clearSelection(); 12147 e.preventDefault(); 12148 }); 12149 12150 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.panel, 12151 function() { return $this.triggers; }, 12152 function(e, eventTarget) { 12153 if(!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { 12154 $this.hide(true); 12155 } 12156 }); 12157 12158 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { 12159 $this.alignPanel(); 12160 }); 12161 }, 12162 12163 bindKeyEvents: function() { 12164 var $this = this; 12165 12166 this.keyboardTarget.on('focus.selectCheckboxMenu', function() { 12167 $this.jq.addClass('ui-state-focus'); 12168 $this.menuIcon.addClass('ui-state-focus'); 12169 }).on('blur.selectCheckboxMenu', function() { 12170 $this.jq.removeClass('ui-state-focus'); 12171 $this.menuIcon.removeClass('ui-state-focus'); 12172 }).on('keydown.selectCheckboxMenu', function(e) { 12173 var keyCode = $.ui.keyCode, 12174 key = e.which; 12175 12176 if($this.cfg.dynamic && !$this.isDynamicLoaded) { 12177 $this._renderPanel(); 12178 } 12179 12180 switch(key) { 12181 case keyCode.ENTER: 12182 case keyCode.SPACE: 12183 if ($this.panel.is(":hidden")) 12184 $this.show(); 12185 else 12186 $this.hide(true); 12187 12188 e.preventDefault(); 12189 break; 12190 12191 case keyCode.DOWN: 12192 if (e.altKey) { 12193 if ($this.panel.is(":hidden")) 12194 $this.show(); 12195 else 12196 $this.hide(true); 12197 } 12198 12199 e.preventDefault(); 12200 break; 12201 12202 case keyCode.TAB: 12203 if($this.panel.is(':visible')) { 12204 if(!$this.cfg.showHeader) { 12205 $this.itemContainer.children('li:not(.ui-state-disabled):first').find('div.ui-helper-hidden-accessible > input').trigger('focus'); 12206 } 12207 else { 12208 $this.toggler.find('> div.ui-helper-hidden-accessible > input').trigger('focus'); 12209 } 12210 e.preventDefault(); 12211 } 12212 12213 break; 12214 12215 case keyCode.ESCAPE: 12216 $this.hide(); 12217 break; 12218 }; 12219 }); 12220 }, 12221 12222 bindPanelKeyEvents: function() { 12223 var $this = this; 12224 12225 this.closer.on('focus.selectCheckboxMenu', function(e) { 12226 $this.closer.addClass('ui-state-focus'); 12227 }) 12228 .on('blur.selectCheckboxMenu', function(e) { 12229 $this.closer.removeClass('ui-state-focus'); 12230 }) 12231 .on('keydown.selectCheckboxMenu', function(e) { 12232 var keyCode = $.ui.keyCode, 12233 key = e.which; 12234 12235 switch(key) { 12236 case keyCode.ENTER: 12237 $this.hide(true); 12238 12239 e.preventDefault(); 12240 break; 12241 12242 case keyCode.ESCAPE: 12243 $this.hide(); 12244 break; 12245 }; 12246 }); 12247 12248 var togglerCheckboxInput = this.toggler.find('> div.ui-helper-hidden-accessible > input'); 12249 this.bindCheckboxKeyEvents(togglerCheckboxInput); 12250 togglerCheckboxInput.on('keyup.selectCheckboxMenu', function(e) { 12251 if(e.which === $.ui.keyCode.SPACE) { 12252 var input = $(this); 12253 12254 if(input.prop('checked')) 12255 $this.uncheckAll(); 12256 else 12257 $this.checkAll(); 12258 12259 e.preventDefault(); 12260 } 12261 }) 12262 .on('change.selectCheckboxMenu', function(e) { 12263 var input = $(this); 12264 12265 if(input.prop('checked')) { 12266 $this.checkAll(); 12267 } 12268 else { 12269 $this.uncheckAll(); 12270 } 12271 }); 12272 12273 var itemKeyInputs = this.itemContainer.find('> li > div.ui-chkbox > div.ui-helper-hidden-accessible > input'); 12274 this.bindCheckboxKeyEvents(itemKeyInputs); 12275 itemKeyInputs.on('keyup.selectCheckboxMenu', function(e) { 12276 if(e.which === $.ui.keyCode.SPACE) { 12277 var input = $(this), 12278 box = input.parent().next(); 12279 12280 if(input.prop('checked')) 12281 $this.uncheck(box, true); 12282 else 12283 $this.check(box, true); 12284 12285 e.preventDefault(); 12286 } 12287 }) 12288 .on('change.selectCheckboxMenu', function(e) { 12289 var input = $(this), 12290 box = input.parent().next(); 12291 12292 if(input.prop('checked')) { 12293 $this.check(box, true); 12294 } 12295 else { 12296 $this.uncheck(box, true); 12297 } 12298 }); 12299 }, 12300 12301 bindMultipleModeEvents: function() { 12302 var $this = this; 12303 this.multiItemContainer = this.jq.children('.ui-selectcheckboxmenu-multiple-container'); 12304 12305 var closeSelector = '> li.ui-selectcheckboxmenu-token > .ui-selectcheckboxmenu-token-icon'; 12306 this.multiItemContainer.off('click', closeSelector).on('click', closeSelector, null, function(e) { 12307 var itemValue = $(this).parent().data("item-value"); 12308 var item = $this.items.filter('[data-item-value="' + $.escapeSelector(itemValue) +'"]'); 12309 if(item && item.length) { 12310 if($this.cfg.dynamic && !$this.isDynamicLoaded) { 12311 $this._renderPanel(); 12312 } 12313 12314 $this.uncheck(item.children('.ui-chkbox').children('.ui-chkbox-box'), true); 12315 12316 if($this.hasBehavior('itemUnselect')) { 12317 var ext = { 12318 params : [ 12319 {name: $this.id + '_itemUnselect', value: itemValue} 12320 ] 12321 }; 12322 12323 $this.callBehavior('itemUnselect', ext); 12324 } 12325 } 12326 12327 e.stopPropagation(); 12328 }); 12329 }, 12330 12331 bindCheckboxHover: function(item) { 12332 item.on('mouseenter.selectCheckboxMenu', function() { 12333 var item = $(this); 12334 if(!item.hasClass('ui-state-active')&&!item.hasClass('ui-state-disabled')) { 12335 item.addClass('ui-state-hover'); 12336 } 12337 }
12337).on('mouseleave.selectCheckboxMenu', function() { 12338 $(this).removeClass('ui-state-hover'); 12339 }); 12340 }, 12341 12342 filter: function(value) { 12343 var filterValue = this.cfg.caseSensitive ? $.trim(value) : $.trim(value).toLowerCase(); 12344 12345 if(filterValue === '') { 12346 this.itemContainer.children('li.ui-selectcheckboxmenu-item').filter(':hidden').show(); 12347 } 12348 else { 12349 for(var i = 0; i < this.labels.length; i++) { 12350 var labelElement = this.labels.eq(i), 12351 item = labelElement.parent(), 12352 itemLabel = this.cfg.caseSensitive ? labelElement.text() : labelElement.text().toLowerCase(); 12353 12354 if(this.filterMatcher(itemLabel, filterValue)) { 12355 item.show(); 12356 } 12357 else { 12358 item.hide(); 12359 } 12360 } 12361 } 12362 12363 var groupHeaderLength = this.groupHeaders.length; 12364 for(var i = 0; i < groupHeaderLength; i++) { 12365 var header = $(this.groupHeaders[i]), 12366 groupedItems = header.nextUntil('li.ui-selectcheckboxmenu-item-group'); 12367 12368 if(groupedItems.length === groupedItems.filter(':hidden').length) { 12369 header.hide(); 12370 } 12371 else { 12372 header.show(); 12373 } 12374 } 12375 12376 if(this.cfg.scrollHeight) { 12377 if(this.itemContainer.height() < this.cfg.initialHeight) { 12378 this.itemContainerWrapper.css('height', 'auto'); 12379 } 12380 else { 12381 this.itemContainerWrapper.height(this.cfg.initialHeight); 12382 } 12383 } 12384 12385 this.updateToggler(); 12386 this.alignPanel(); 12387 }, 12388 12389 setupFilterMatcher: function() { 12390 this.cfg.filterMatchMode = this.cfg.filterMatchMode||'startsWith'; 12391 this.filterMatchers = { 12392 'startsWith': this.startsWithFilter 12393 ,'contains': this.containsFilter 12394 ,'endsWith': this.endsWithFilter 12395 ,'custom': this.cfg.filterFunction 12396 }; 12397 12398 this.filterMatcher = this.filterMatchers[this.cfg.filterMatchMode]; 12399 }, 12400 12401 startsWithFilter: function(value, filter) { 12402 return value.indexOf(filter) === 0; 12403 }, 12404 12405 containsFilter: function(value, filter) { 12406 return value.indexOf(filter) !== -1; 12407 }, 12408 12409 endsWithFilter: function(value, filter) { 12410 return value.indexOf(filter, value.length - filter.length) !== -1; 12411 }, 12412 12413 checkAll: function() { 12414 for(var i = 0; i < this.items.length; i++) { 12415 var el = this.items.eq(i); 12416 12417 if(el.is(':visible')) { 12418 var input = this.inputs.eq(i); 12419 var inputNative = input[0]; 12420 12421 if(!inputNative.disabled) { 12422 input.prop('checked', true).attr('aria-checked', true); 12423 this.check(el.children('.ui-chkbox').children('.ui-chkbox-box')); 12424 12425 if (this.cfg.multiple) { 12426 this.createMultipleItem(el); 12427 } 12428 } 12429 } 12430 } 12431 12432 this.check(this.togglerBox); 12433 12434 var togglerInput = this.togglerBox.prev().children('input'); 12435 if(this.cfg.onChange) { 12436 this.cfg.onChange.call(this); 12437 } 12438 12439 if(!this.togglerBox.hasClass('ui-state-disabled')) { 12440 togglerInput.trigger('focus.selectCheckboxMenu'); 12441 this.togglerBox.addClass('ui-state-active'); 12442 } 12443 12444 if(this.cfg.multiple) { 12445 this.alignPanel(); 12446 } 12447 12448 this.fireToggleSelectEvent(true); 12449 }, 12450 12451 uncheckAll: function() { 12452 for(var i = 0; i < this.items.length; i++) { 12453 var el = this.items.eq(i); 12454 12455 if(el.is(':visible')) { 12456 var input = this.inputs.eq(i); 12457 var inputNative = input[0]; 12458 12459 if(!inputNative.disabled) { 12460 this.inputs.eq(i).prop('checked', false).attr('aria-checked', false); 12461 this.uncheck(el.children('.ui-chkbox').children('.ui-chkbox-box')); 12462 12463 if (this.cfg.multiple) { 12464 this.multiItemContainer.children().remove(); 12465 } 12466 } 12467 } 12468 } 12469 12470 this.uncheck(this.togglerBox); 12471 12472 var togglerInput = this.togglerBox.prev().children('input'); 12473 if(this.cfg.onChange) { 12474 this.cfg.onChange.call(this); 12475 } 12476 12477 if(!this.togglerBox.hasClass('ui-state-disabled')) { 12478 togglerInput.trigger('focus.selectCheckboxMenu'); 12479 } 12480 12481 if(this.cfg.multiple) { 12482 this.alignPanel(); 12483 } 12484 12485 this.fireToggleSelectEvent(false); 12486 }, 12487 12488 fireToggleSelectEvent: function(checked) { 12489 if(this.hasBehavior('toggleSelect')) { 12490 var ext = { 12491 params: [{name: this.id + '_checked', value: checked}] 12492 }; 12493 12494 this.callBehavior('toggleSelect', ext); 12495 } 12496 }, 12497 12498 check: function(checkbox, updateInput) { 12499 if(!checkbox.hasClass('ui-state-disabled')) { 12500 var checkedInput = checkbox.prev().children('input'), 12501 item = checkbox.closest('li.ui-selectcheckboxmenu-item'); 12502 12503 checkedInput.prop('checked', true).attr('aria-checked', true); 12504 if(updateInput) { 12505 checkedInput.trigger('focus.selectCheckboxMenu'); 12506 } 12507 12508 checkbox.addClass('ui-state-active').children('.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check');
12509 item.removeClass('ui-selectcheckboxmenu-unchecked').addClass('ui-selectcheckboxmenu-checked'); 12510 12511 if(updateInput) { 12512 var itemGroups = item.prevAll('li.ui-selectcheckboxmenu-item-group'), 12513 input = this.inputs.eq(item.index() - itemGroups.length); 12514 input.prop('checked', true).attr('aria-checked', true).change(); 12515 12516 this.updateToggler(); 12517 12518 if(this.cfg.multiple) { 12519 this.createMultipleItem(item); 12520 this.alignPanel(); 12521 } 12522 } 12523 12524 if(this.cfg.updateLabel) { 12525 this.updateLabel(); 12526 } 12527 } 12528 }, 12529 12530 uncheck: function(checkbox, updateInput) { 12531 if(!checkbox.hasClass('ui-state-disabled')) { 12532 var uncheckedInput = checkbox.prev().children('input'), 12533 item = checkbox.closest('li.ui-selectcheckboxmenu-item'); 12534 checkbox.removeClass('ui-state-active').children('.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 12535 checkbox.closest('li.ui-selectcheckboxmenu-item').addClass('ui-selectcheckboxmenu-unchecked').removeClass('ui-selectcheckboxmenu-checked'); 12536 uncheckedInput.prop('checked', false).attr('aria-checked', false); 12537 12538 if(updateInput) { 12539 var itemGroups = item.prevAll('li.ui-selectcheckboxmenu-item-group'), 12540 input = this.inputs.eq(item.index() - itemGroups.length); 12541 input.prop('checked', false).attr('aria-checked', false).change(); 12542 uncheckedInput.trigger('focus.selectCheckboxMenu'); 12543 this.updateToggler(); 12544 12545 if(this.cfg.multiple) { 12546 this.removeMultipleItem(item); 12547 this.alignPanel(); 12548 } 12549 } 12550 12551 if(this.cfg.updateLabel) { 12552 this.updateLabel(); 12553 } 12554 } 12555 }, 12556 12557 show: function() { 12558 this.panel.css({'display':'block', 'opacity':0, 'pointer-events': 'none'}); 12559 12560 this.alignPanel(); 12561 12562 this.panel.css({'display':'none', 'opacity':'', 'pointer-events': ''}); 12563 12564 this.keyboardTarget.attr('aria-expanded', true); 12565 this.panel.show(); 12566 12567 this.postShow(); 12568 }, 12569 12570 hide: function(animate) { 12571 var $this = this; 12572 12573 this.keyboardTarget.attr('aria-expanded', false); 12574 12575 if(animate) { 12576 this.panel.fadeOut('fast', function() { 12577 $this.postHide(); 12578 }); 12579 } 12580 12581 else { 12582 this.panel.hide(); 12583 this.postHide(); 12584 } 12585 }, 12586 12587 postShow: function() { 12588 if(this.cfg.onShow) { 12589 this.cfg.onShow.call(this); 12590 } 12591 }, 12592 12593 postHide: function() { 12594 if(this.cfg.onHide) { 12595 this.cfg.onHide.call(this); 12596 } 12597 }, 12598 12599 alignPanel: function() { 12600 var fixedPosition = this.panel.css('position') == 'fixed', 12601 win = $(window), 12602 positionOffset = fixedPosition ? '-' + win.scrollLeft() + ' -' + win.scrollTop() : null, 12603 panelStyle = this.panel.attr('style'); 12604 12605 this.panel.css({ 12606 'left':'', 12607 'top':'', 12608 'z-index': ++PrimeFaces.zindex 12609 }); 12610 12611 if(this.panel.parent().attr('id') === this.id) { 12612 this.panel.css({ 12613 left: 0, 12614 top: this.jq.innerHeight() 12615 }); 12616 } 12617 else { 12618 this.panel.position({ 12619 my: 'left top' 12620 ,at: 'left bottom' 12621 ,of: this.jq 12622 ,offset : positionOffset 12623 ,collision: 'flipfit' 12624 }); 12625 } 12626 12627 if(!this.widthAligned && (this.panel.width() < this.jq.width()) && (!panelStyle||panelStyle.toLowerCase().indexOf('width') === -1)) { 12628 this.panel.width(this.jq.width()); 12629 this.widthAligned = true; 12630 } 12631 }, 12632 12633 toggleItem: function(checkbox) { 12634 if(!checkbox.hasClass('ui-state-disabled')) { 12635 if(checkbox.hasClass('ui-state-active')) { 12636 this.uncheck(checkbox, true); 12637 checkbox.addClass('ui-state-hover'); 12638 } 12639 else { 12640 this.check(checkbox, true); 12641 checkbox.removeClass('ui-state-hover'); 12642 } 12643 } 12644 }, 12645 12646 updateToggler: function() { 12647 var visibleItems = this.itemContainer.children('li.ui-selectcheckboxmenu-item:visible'); 12648 12649 if(visibleItems.length && visibleItems.filter('.ui-selectcheckboxmenu-unc
12649hecked').length === 0) { 12650 this.check(this.togglerBox); 12651 } 12652 else { 12653 this.uncheck(this.togglerBox); 12654 } 12655 }, 12656 12657 bindCheckboxKeyEvents: function(items) { 12658 var $this = this; 12659 12660 items.on('focus.selectCheckboxMenu', function(e) { 12661 var input = $(this), 12662 box = input.parent().next(); 12663 12664 box.addClass('ui-state-focus'); 12665 12666 PrimeFaces.scrollInView($this.itemContainerWrapper, box); 12667 }) 12668 .on('blur.selectCheckboxMenu', function(e) { 12669 var input = $(this), 12670 box = input.parent().next(); 12671 12672 box.removeClass('ui-state-focus'); 12673 }) 12674 .on('keydown.selectCheckboxMenu', function(e) { 12675 var keyCode = $.ui.keyCode, 12676 key = e.which; 12677 12678 if(key === keyCode.SPACE) { 12679 e.preventDefault(); 12680 } 12681 else if(key === keyCode.ESCAPE) { 12682 $this.hide(); 12683 } 12684 }); 12685 }, 12686 12687 updateLabel: function() { 12688 var checkedItems = this.jq.find(':checked'), 12689 labelText = ''; 12690 12691 if(checkedItems && checkedItems.length) { 12692 for(var i = 0; i < checkedItems.length; i++) { 12693 if(i != 0) { 12694 labelText = labelText + this.cfg.labelSeparator; 12695 } 12696 labelText = labelText + $(checkedItems[i]).next().text(); 12697 } 12698 } 12699 else { 12700 if (this.cfg.emptyLabel) { 12701 labelText = this.cfg.emptyLabel; 12702 } else { 12703 labelText = this.defaultLabel; 12704 } 12705 } 12706 12707 this.label.text(labelText); 12708 this.labelContainer.attr('title', labelText); 12709 }, 12710 12711 createMultipleItem: function(item) { 12712 var items = this.multiItemContainer.children(); 12713 if(items.length && items.filter('[data-item-value="' + $.escapeSelector(item.data('item-value')) + '"]').length > 0) { 12714 return; 12715 } 12716 12717 var itemGroups = item.prevAll('li.ui-selectcheckboxmenu-item-group'), 12718 input = this.inputs.eq(item.index() - itemGroups.length), 12719 escaped = input.data('escaped'), 12720 labelHtml = input.next().html().trim(), 12721 labelLength = labelHtml.length, 12722 label = labelLength > 0 && labelHtml !== ' ' ? (escaped ? PrimeFaces.escapeHTML(input.next().text()) : input.next().html()) : PrimeFaces.escapeHTML(input.val()), 12723 itemDisplayMarkup = '<li class="ui-selectcheckboxmenu-token ui-state-active ui-corner-all" data-item-value="' + PrimeFaces.escapeHTML(input.val()) +'">'; 12724 itemDisplayMarkup += '<span class="ui-selectcheckboxmenu-token-icon ui-icon ui-icon-close"></span>'; 12725 itemDisplayMarkup += '<span class="ui-selectcheckboxmenu-token-label">' + label + '</span></li>'; 12726 12727 this.multiItemContainer.append(itemDisplayMarkup); 12728 }, 12729 12730 removeMultipleItem: function(item) { 12731 var items = this.multiItemContainer.children(); 12732 if(items.length) { 12733 items.filter('[data-item-value="' + $.escapeSelector(item.data('item-value')) + '"]').remove(); 12734 } 12735 }, 12736 12737 selectValue: function(value) { // Patch 12738 var idx = -1; 12739 // find input-index 12740 for(var i = 0; i < this.inputs.length; i++) { 12741 if (this.inputs.eq(i).val() === value) { 12742 idx = i; 12743 break; 12744 } 12745 } 12746 if (idx === -1) { 12747 return; 12748 } 12749 var input = this.inputs.eq(idx); // the hidden input 12750 var item = this.items.eq(idx); // the Overlay-Panel-Item (li) 12751 12752 // check (see this.checkAll()) 12753 input.prop('checked', true).attr('aria-checked', true); 12754 this.check(item.children('.ui-chkbox').children('.ui-chkbox-box')); 12755 12756 if(this.cfg.multiple) { 12757 this.createMultipleItem(item); 12758 } 12759 }, 12760 12761 getAppendTo: function() { 12762 var dialog = this.jq.closest('.ui-dialog'); 12763 12764 if(dialog.length == 1) { 12765 //set position as fixed to scroll with dialog 12766 if(dialog.css('position') === 'fixed') { 12767 this.panel.css('position', 'fixed'); 12768 } 12769 12770 //append to body if not already appended by user choice 12771 if(!this.panel.parent().is(document.body)) { 12772 return "@(body)"; 12773 } 12774 } 12775 12776 return this.cfg.appendTo; 12777 } 12778 12779}); 12780 12781/** 12782 * PrimeFaces InputMask Widget 12783 */ 12784PrimeFaces.widget.InputMask = PrimeFaces.widget.BaseWidget.extend({ 12785 12786 init: function(cfg) { 12787 this._super(cfg); 12788 12789 if(this.cfg.mask) { 12790 var originalOnchange = this.jq.prop('onchange'); 12791 if(originalOnchange) { 12792 this.cfg.onChange = originalOnchange; 12793 this.jq.prop('onchange', null); 12794 } 12795 12796 this.jq.mask(this.cfg.mask, this.cfg); 12797 } 12798 12799 //Visuals 12800 PrimeFaces.skinInput(this.jq); 12801 }, 12802 12803 setValue: function(value) { 12804 this.jq.val(value); 12805 this.jq.unmask().mask(this.cfg.mask, this.cfg); 12806 }, 12807 12808 getValue: function() { 12809 return this.jq.val(); 12810 } 12811 12812}); 12813 12814/** 12815 * PrimeFaces Password 12816 */ 12817PrimeFaces.widget.Password = PrimeFaces.widget.BaseWidget.extend({ 12818 12819 init: function(cfg) { 12820 this._super(cfg); 12821 12822 if(!this.jq.is(':disabled')) { 12823 if(this.cfg.feedback) { 12824 this.setupFeedback(); 12825 } 12826 12827 PrimeFaces.skinInput(this.jq); 12828 } 12829 }, 12830 12831 setupFeedback: function() { 12832 var _self = this; 12833 12834 //remove previous panel if any 12835 var oldPanel = $(this.jqId + '_panel'); 12836 if(oldPanel.length == 1) { 12837 oldPanel.remove(); 12838 } 12839 12840 //config 12841 this.cfg.promptLabel = this.cfg.promptLabel||'Please enter a password'; 12842 this.cfg.weakLabel = this.cfg.weakLabel||'Weak'; 12843 this.cfg.goodLabel = this.cfg.goodLabel||'Medium'; 12844 this.cfg.strongLabel = this.cfg.strongLabel||'Strong'; 12845 12846 var panelStyle = this.cfg.inline ? 'ui-password-panel-inline' : 'ui-password-panel-overlay'; 12847 12848 //create panel element 12849 var panelMarkup = '<div id="' + this.id + '_panel" class="ui-password-panel ui-widget ui-state-highlight ui-corner-all ui-helper-hidden ' + panelStyle + '">'; 12850 panelMarkup += '<div class="ui-password-meter" style="background-position:0pt 0pt"> </div>'; 12851 panelMarkup += '<div class="ui-password-info">' + PrimeFaces.escapeHTML(this.cfg.promptLabel) + '</div>'; 12852 panelMarkup += '</div>'; 12853 12854 this.panel = $(panelMarkup).insertAfter(this.jq); 12855 this.meter = this.panel.children('div.ui-password-meter'); 12856 this.infoText = this.panel.children('div.ui-password-info'); 12857 12858 if(!this.cfg.inline) {
12859 this.panel.addClass('ui-shadow'); 12860 } 12861 12862 //events 12863 this.jq.focus(function() { 12864 _self.show(); 12865 }) 12866 .blur(function() { 12867 _self.hide(); 12868 }) 12869 .keyup(function() { 12870 var value = _self.jq.val(), 12871 label = null, 12872 meterPos = null; 12873 12874 if(value.length == 0) { 12875 label = _self.cfg.promptLabel; 12876 meterPos = '0px 0px'; 12877 } 12878 else { 12879 var score = _self.testStrength(_self.jq.val()); 12880 12881 if(score < 30) { 12882 label = _self.cfg.weakLabel; 12883 meterPos = '0px -10px'; 12884 } 12885 else if(score >= 30 && score < 80) { 12886 label = _self.cfg.goodLabel; 12887 meterPos = '0px -20px'; 12888 } 12889 else if(score >= 80) { 12890 label = _self.cfg.strongLabel; 12891 meterPos = '0px -30px'; 12892 } 12893 } 12894 12895 //update meter and info text 12896 _self.meter.css('background-position', meterPos); 12897 _self.infoText.text(label); 12898 }); 12899 12900 //overlay setting 12901 if(!this.cfg.inline) { 12902 this.panel.appendTo('body'); 12903 12904 //Hide overlay on resize 12905 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', _self.panel, function() { 12906 _self.align(); 12907 }); 12908 } 12909 }, 12910 12911 testStrength: function(password) { 12912 // return a number between 0 and 100. 12913 var score = 0; 12914 12915 // must be at least 8 characters 12916 if (!password || password.length < 8) 12917 return score; 12918 12919 12920 // require 3 of the following 4 categories 12921 var variations = { 12922 digits : /\d/.test(password), 12923 lower : /[a-z]/.test(password), 12924 upper : /[A-Z]/.test(password), 12925 nonWords : /\W/.test(password) 12926 } 12927 12928 variationCount = 0; 12929 for ( var check in variations) { 12930 variationCount += (variations[check] == true) ? 1 : 0; 12931 } 12932 score += variationCount * 28; 12933 12934 return parseInt(score); 12935 }, 12936 12937 normalize: function(x, y) { 12938 var diff = x - y; 12939 12940 if(diff <= 0) { 12941 return x / y; 12942 } 12943 else { 12944 return 1 + 0.5 * (x / (x + y/4)); 12945 } 12946 }, 12947 12948 align: function() { 12949 this.panel.css({ 12950 left:'', 12951 top:'', 12952 'z-index': ++PrimeFaces.zindex 12953 }) 12954 .position({ 12955 my: 'left top', 12956 at: 'right top', 12957 of: this.jq 12958 }); 12959 }, 12960 12961 show: function() { 12962 if(!this.cfg.inline) { 12963 this.align(); 12964 12965 this.panel.fadeIn(); 12966 } 12967 else { 12968 this.panel.slideDown(); 12969 } 12970 }, 12971 12972 hide: function() { 12973 if(this.cfg.inline) 12974 this.panel.slideUp(); 12975 else 12976 this.panel.fadeOut(); 12977 } 12978 12979}); 12980 12981/** 12982 * PrimeFaces DefaultCommand Widget 12983 */ 12984PrimeFaces.widget.DefaultCommand = PrimeFaces.widget.BaseWidget.extend({ 12985 12986 init: function(cfg) { 12987 this.cfg = cfg; 12988 this.id = this.cfg.id; 12989 this.jqId = PrimeFaces.escapeClientId(this.id); 12990 this.jqTarget = $(PrimeFaces.escapeClientId(this.cfg.target)); 12991 this.scope = this.cfg.scope ? $(PrimeFaces.escapeClientId(this.cfg.scope)) : null; 12992 var $this = this; 12993 12994 // container support - e.g. splitButton 12995 if (this.jqTarget.is(':not(:button):not(:input):not(a)')) { 12996 this.jqTarget = this.jqTarget.find('button,a').filter(':visible').first(); 12997 } 12998 12999 //attach keypress listener to parent form 13000 var closestForm = this.jqTarget.closest('form'); 13001 closestForm.off('keydown.' + this.id).on('keydown.' + this.id, {scopeEnter: false}, function (e, data) { 13002 var keyCode = $.ui.keyCode; 13003 13004 data = data || e.data; 13005 if (($this.scope && data.scopeEnter && data.scopeDefaultCommandId === $this.id) 13006 || (!$this.scope && !data.scopeEnter && (e.which == keyCode.ENTER))) { 13007 //do not proceed if target is a textarea,button or link 13008 if ($(e.target).is('textarea,button,input[type="submit"],a')) { 13009 return true; 13010 } 13011 13012 if (!$this.jqTarget.is(':disabled, .ui-state-disabled')) { 13013 $this.jqTarget.trigger(PrimeFaces.csp.clickEvent()); 13014 } 13015 e.preventDefault(); 13016 e.stopImmediatePropagation(); 13017 } 13018 }); 13019 13020 if (this.scope) { 13021 this.scope.off('keydown.' + this.id).on('keydown.' + this.id, function (e) { 13022 var keyCode = $.ui.keyCode; 13023 if (e.which == keyCode.ENTER) { 13024 closestForm.trigger(e, {scopeEnter: true, scopeDefaultCommandId: $this.id}); 13025 //e.preventDefault(); 13026 e.stopPropagation(); 13027 } 13028 }); 13029 } 13030
13031 this.removeScriptElement(this.id); 13032 } 13033}); 13034 13035/* 13036 * PrimeFaces SplitButton Widget 13037 */ 13038PrimeFaces.widget.SplitButton = PrimeFaces.widget.BaseWidget.extend({ 13039 13040 init: function(cfg) { 13041 this._super(cfg); 13042 this.button = $(this.jqId + '_button'); 13043 this.menuButton = $(this.jqId + '_menuButton'); 13044 this.menuId = this.jqId + "_menu"; 13045 this.menu = $(this.menuId); 13046 this.menuitemContainer = this.menu.find('.ui-menu-list'); 13047 this.menuitems = this.menuitemContainer.children('.ui-menuitem:not(.ui-state-disabled)'); 13048 this.cfg.disabled = this.button.is(':disabled'); 13049 13050 if(!this.cfg.disabled) { 13051 this.bindEvents(); 13052 13053 PrimeFaces.utils.registerDynamicOverlay(this, this.menu, this.id + '_menu'); 13054 } 13055 13056 //pfs metadata 13057 this.button.data(PrimeFaces.CLIENT_ID_DATA, this.id); 13058 this.menuButton.data(PrimeFaces.CLIENT_ID_DATA, this.id); 13059 }, 13060 13061 //@override 13062 refresh: function(cfg) { 13063 this._super(cfg); 13064 }, 13065 13066 bindEvents: function() { 13067 var $this = this; 13068 13069 PrimeFaces.skinButton(this.button).skinButton(this.menuButton); 13070 13071 //mark button and descandants of button as a trigger for a primefaces overlay 13072 this.button.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 13073 13074 //toggle menu 13075 this.menuButton.click(function() { 13076 if($this.menu.is(':hidden')) 13077 $this.show(); 13078 else 13079 $this.hide(); 13080 }); 13081 13082 //menuitem visuals 13083 this.menuitems.mouseover(function(e) { 13084 var menuitem = $(this), 13085 menuitemLink = menuitem.children('.ui-menuitem-link'); 13086 13087 if(!menuitemLink.hasClass('ui-state-disabled')) { 13088 menuitem.addClass('ui-state-hover'); 13089 } 13090 }).mouseout(function(e) { 13091 $(this).removeClass('ui-state-hover'); 13092 }).click(function() { 13093 $this.hide(); 13094 }); 13095 13096 //keyboard support 13097 this.menuButton.keydown(function(e) { 13098 var keyCode = $.ui.keyCode; 13099 13100 switch(e.which) { 13101 case keyCode.UP: 13102 $this.highlightPrev(e); 13103 break; 13104 13105 case keyCode.DOWN: 13106 $this.highlightNext(e); 13107 break; 13108 13109 case keyCode.ENTER: 13110 case keyCode.SPACE: 13111 $this.handleEnterKey(e); 13112 break; 13113 13114 13115 case keyCode.ESCAPE: 13116 case keyCode.TAB: 13117 $this.handleEscapeKey(); 13118 break; 13119 } 13120 }); 13121 13122 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.menu, null, 13123 function(e, eventTarget) { 13124 if(!($this.menu.is(eventTarget) || $this.menu.has(eventTarget).length > 0)) { 13125 $this.button.removeClass('ui-state-focus ui-state-hover'); 13126 $this.hide(); 13127 } 13128 }); 13129 13130 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.menu, function() { 13131 $this.alignPanel(); 13132 }); 13133 13134 if(this.cfg.filter) { 13135 this.setupFilterMatcher(); 13136 this.filterInput = this.menu.find('> div.ui-splitbuttonmenu-filter-container > input.ui-splitbuttonmenu-filter'); 13137 PrimeFaces.skinInput(this.filterInput); 13138 13139 this.bindFilterEvents(); 13140 } 13141 }, 13142 13143 bindFilterEvents: function() { 13144 var $this = this; 13145 13146 this.filterInput.on('keyup.ui-splitbutton', function(e) { 13147 var keyCode = $.ui.keyCode, 13148 key = e.which; 13149 13150 switch(key) { 13151 case keyCode.UP: 13152 case keyCode.LEFT: 13153 case keyCode.DOWN: 13154 case keyCode.RIGHT: 13155 case keyCode.ENTER: 13156 case keyCode.TAB: 13157 case keyCode.ESCAPE: 13158 case keyCode.SPACE: 13159 case keyCode.HOME: 13160 case keyCode.PAGE_DOWN: 13161 case keyCode.PAGE_UP: 13162 case keyCode.END: 13163 case 16: //shift 13164 case 17: //keyCode.CONTROL: 13165 case 18: //keyCode.ALT: 13166 case 91: //left window or cmd: 13167 case 92: //right window: 13168 case 93: //right cmd: 13169 case 20: //capslock: 13170 break; 13171 13172 default: 13173 //function keys (F1,F2 etc.) 13174 if(key >= 112 && key <= 123) { 13175 break; 13176 } 13177 13178 var metaKey = e.metaKey||e.ctrlKey; 13179 13180 if(!metaKey) { 13181 $this.filter($(this).val()); 13182 } 13183 break; 13184 } 13185 }) 13186 .on('keydown.ui-splitbutton',function(e) { 13187 var keyCode = $.ui.keyCode, 13188 key = e.which; 13189 13190 switch(key) { 13191 case keyCode.UP: 13192 $this.highlightPrev(e); 13193 break; 13194 13195 case keyCode.DOWN: 13196 $this.highlightNext(e); 13197 break; 13198 13199 case keyCode.ENTER: 13200 $this.handleEnterKey(e); 13201 break; 13202 13203 case keyCode.SPACE: 13204 var target = $(e.target); 13205 13206 if(target.is('input') && target.hasClass('ui-splitbuttonmenu-filter')) { 13207 return; 13208 } 13209 13210 $this.handleEnterKey(e); 13211 break; 13212 13213 case keyCode.ESCAPE: 13214 case keyCode.TAB: 13215 $this.handleEscapeKey(); 13216 break; 13217 13218 default: 13219 break; 13220 } 13221 }).on('paste.ui-splitbutton', function() { 13222 setTimeout(function(){ 13223 $this.filter($this.filterInput.val()); 13224 },2); 13225 }); 13226 }, 13227 13228 highlightNext: function(event) { 13229 var highlightedItem = this.menuitems.filter('.ui-state-hover'), 13230 nextItems = highlightedItem.length ? highlightedItem.nextAll(':not(.ui-separator, .ui-widget-header):visible') : this.menuitems.filter(':visible').eq(0); 13231 13232 if(nextItems.length) { 13233 highlightedItem.removeClass('ui-state-hover'); 13234 nextItems.eq(0).addClass('ui-state-hover'); 13235 } 13236 13237 event.preventDefault(); 13238 }, 13239 13240 highlightPrev: function(event) { 13241 var highlightedItem = this.menuitems.filter('.ui-state-hover'), 13242 prevItems = highlightedItem.length ? highlightedItem.prevAll(':not(.ui-separator, .ui-widget-header):visible') : null; 13243 13244 if(prevItems && prevItems.length) { 13245 highlightedItem.removeClass('ui-state-hover'); 13246 prevItems.eq(0).addClass('ui-state-hover'); 13247 } 13248 13249 event.preventDefault(); 13250 }, 13251 13252 handleEnterKey: function(event) { 13253 if(this.menu.is(':visible')) { 13254 var link = this.menuitems.filter('.ui-state-hover').children('a'); 13255 link.trigger('click'); 13256 13257 var href = link.attr('href'); 13258 if(href && href !== '#') { 13259 window.location.href = href; 13260 } 13261 } 13262 else { 13263 this.show(); 13264 } 13265 13266 event.preventDefault(); 13267 }, 13268 13269 handleEscapeKey: function() { 13270 this.hide(); 13271 }, 13272 13273 setupFilterMatcher: function() { 13274 this.cfg.filterMatchMode = this.cfg.filterMatchMode||'startsWith'; 13275 this.filterMatchers = { 13276 'startsWith': this.startsWithFilter 13277 ,'contains': this.containsFilter 13278 ,'endsWith': this.endsWithFilter 13279 ,'custom': this.cfg.filterFunction 13280 }; 13281 13282 this.filterMatcher = this.filterMatchers[this.cfg.filterMatchMode]; 13283 }, 13284 13285 startsWithFilter: function(value, filter) { 13286 return value.indexOf(filter) === 0; 13287 }, 13288 13289 containsFilter: function(value, filter) { 13290 return value.indexOf(filter) !== -1; 13291 }, 13292 13293 endsWithFilter: function(value, filter) { 13294 return value.indexOf(filter, value.length - filter.length) !== -1; 13295 }, 13296 13297 filter: function(value) { 13298 var filterValue = $.trim(value).toLowerCase(); 13299 13300 if(filterValue === '') { 13301 this.menuitems.filter(':hidden').show(); 13302 this.menuitemContainer.children('.ui-widget-header').show(); 13303 this.menuitemContainer.children('.ui-separator').show(); 13304 } 13305 else { 13306 for(var i = 0; i < this.menuitems.length; i++) { 13307 var menuitem = this.menuitems.eq(i), 13308 itemLabel = menuitem.find('.ui-menuitem-text').text().toLowerCase(); 13309 13310 /* for keyboard support */ 13311 menuitem.removeClass('ui-state-hover'); 13312 13313 if(this.filterMatcher(itemLabel, filterValue)) 13314 menuitem.show(); 13315 else 13316 menuitem.hide(); 13317 13318 } 13319 13320 //groups 13321 var groupHeaders = this.menuitemContainer.children('.ui-widget-header'); 13322 for(var g = 0; g < groupHeaders.length; g++) { 13323 var group = groupHeaders.eq(g); 13324 13325 if(g === (groupHeaders.length - 1)) { 13326 if(group.nextAll('.ui-submenu-child').filter(':visible').length === 0) 13327 group.hide(); 13328 else 13329 group.show(); 13330 } 13331 else { 13332 if(group.nextUntil('.ui-widget-header').filter(':visible').length === 0) 13333 group.hide(); 13334 else 13335 group.show(); 13336 } 13337 } 13338 13339 var separators = this.menuitemContainer.children('.ui-separator'); 13340 for(var s = 0; s < separators.length; s++) { 13341 var separator = separators.eq(s); 13342 if(separator.nextAll().filter(':visible').length === 0 || separator.prevAll().filter(':visible').length === 0) { 13343 separator.hide(); 13344 } 13345 else { 13346 separator.show(); 13347 } 13348 } 13349 } 13350 13351 this.alignPanel(); 13352 }, 13353 13354 show: function() { 13355 this.jq.attr('aria-expanded', true); 13356 this.alignPanel(); 13357 13358 this.menu.show(); 13359 13360 if(this.cfg.filter) { 13361 this.filterInput.focus(); 13362 } 13363 else { 13364 this.menuButton.focus(); 13365 } 13366 }, 13367 13368 hide: function() { 13369 this.jq.attr('aria-expanded', false); 13370 this.menuitems.filter('.ui-state-hover').removeClass('ui-state-hover'); 13371 this.menuButton.removeClass('ui-state-focus'); 13372 13373 this.menu.fadeOut('fast'); 13374 }, 13375 13376 alignPanel: function() { 13377 this.menu.css({left:'', top:'','z-index': ++PrimeFaces.zindex}); 13378 13379 if(this.menu.parent().is(this.jq)) { 13380 this.menu.css({ 13381 left: 0,
13382 top: this.jq.innerHeight() 13383 }); 13384 } 13385 else { 13386 this.menu.position({ 13387 my: 'left top' 13388 ,at: 'left bottom' 13389 ,of: this.button 13390 }); 13391 } 13392 } 13393 13394}); 13395 13396/* 13397 * PrimeFaces ThemeSwitcher Widget 13398 */ 13399PrimeFaces.widget.ThemeSwitcher = PrimeFaces.widget.SelectOneMenu.extend({ 13400 13401 init: function(cfg) { 13402 this._super(cfg); 13403 13404 var $this = this; 13405 this.input.on('change', function() { 13406 PrimeFaces.changeTheme($this.getSelectedValue()); 13407 }); 13408 } 13409}); 13410 13411/* 13412 * PrimeFaces MultiSelectListbox Widget 13413 */ 13414PrimeFaces.widget.MultiSelectListbox = PrimeFaces.widget.BaseWidget.extend({ 13415 13416 init: function(cfg) { 13417 this._super(cfg); 13418 13419 this.root = this.jq.children('div.ui-multiselectlistbox-listcontainer'); 13420 this.items = this.jq.find('li.ui-multiselectlistbox-item'); 13421 this.input = $(this.jqId + '_input'); 13422 this.cfg.disabled = this.jq.hasClass('ui-state-disabled'); 13423 13424 if(!this.cfg.disabled) { 13425 this.bindEvents(); 13426 } 13427 13428 var value = this.input.val(); 13429 if(value !== '') { 13430 this.preselect(value); 13431 } 13432 }, 13433 13434 bindEvents: function() { 13435 var $this = this; 13436 13437 this.items.on('mouseover.multiSelectListbox', function() { 13438 var item = $(this); 13439 13440 if(!item.hasClass('ui-state-highlight')) 13441 $(this).addClass('ui-state-hover'); 13442 }) 13443 .on('mouseout.multiSelectListbox', function() { 13444 var item = $(this); 13445 13446 if(!item.hasClass('ui-state-highlight')) 13447 $(this).removeClass('ui-state-hover'); 13448 }) 13449 .on('click.multiSelectListbox', function() { 13450 var item = $(this); 13451 13452 if(!item.hasClass('ui-state-highlight')){ 13453 $this.showOptionGroup(item); 13454 } 13455 }); 13456 }, 13457 13458 unbindEvents: function() { 13459 this.items.off('mouseover.multiSelectListbox mouseout.multiSelectListbox click.multiSelectListbox'); 13460 }, 13461 13462 showOptionGroup: function(item) { 13463 item.addClass('ui-state-highlight').removeClass('ui-state-hover').siblings().filter('.ui-state-highlight').removeClass('ui-state-highlight'); 13464 item.closest('.ui-multiselectlistbox-listcontainer').nextAll().remove(); 13465 this.input.val(item.attr('data-value')); 13466 13467 var childItemsContainer = item.children('ul'); 13468 13469 if(childItemsContainer.length) {
13470 var groupContainer = $('<div class="ui-multiselectlistbox-listcontainer" style="display:none"></div>'); 13471 childItemsContainer.clone(true).appendTo(groupContainer).addClass('ui-multiselectlistbox-list ui-inputfield ui-widget-content').removeClass('ui-helper-hidden'); 13472 13473 if(this.cfg.showHeaders) { 13474 groupContainer.prepend('<div class="ui-multiselectlistbox-header ui-widget-header ui-corner-top">' + PrimeFaces.escapeHTML(item.children('span').text()) + '</div>') 13475 .children('.ui-multiselectlistbox-list').addClass('ui-corner-bottom'); 13476 } else { 13477 groupContainer.children().addClass('ui-corner-all'); 13478 } 13479 13480 this.jq.append(groupContainer); 13481 13482 if(this.cfg.effect) 13483 groupContainer.show(this.cfg.effect); 13484 else 13485 groupContainer.show(); 13486 } 13487 else { 13488 this.triggerChange(); 13489 } 13490 }, 13491 13492 enable: function() { 13493 if(this.cfg.disabled) { 13494 this.cfg.disabled = false; 13495 this.jq.removeClass('ui-state-disabled'); 13496 this.bindEvents(); 13497 } 13498 13499 }, 13500 13501 disable: function() { 13502 if(!this.cfg.disabled) { 13503 this.cfg.disabled = true; 13504 this.jq.addClass('ui-state-disabled'); 13505 this.unbindEvents(); 13506 this.root.nextAll().remove(); 13507 } 13508 }, 13509 13510 preselect: function(value) { 13511 var $this = this, 13512 item = this.items.filter('[data-value="' + $.escapeSelector(value)+'"]'); 13513 13514 if(item.length === 0) { 13515 return; 13516 } 13517 13518 var ancestors = item.parentsUntil('.ui-multiselectlistbox-list'), 13519 selectedIndexMap = []; 13520 13521 for(var i = (ancestors.length - 1); i >= 0; i--) { 13522 var ancestor = ancestors.eq(i); 13523 13524 if(ancestor.is('li')) { 13525 selectedIndexMap.push(ancestor.index()); 13526 } 13527 else if(ancestor.is('ul')) {
13528 var groupContainer = $('<div class="ui-multiselectlistbox-listcontainer" style="display:none"></div>'); 13529 ancestor.clone(true).appendTo(groupContainer).addClass('ui-multiselectlistbox-list ui-inputfield ui-widget-content ui-corner-all').removeClass('ui-helper-hidden'); 13530 13531 if(this.cfg.showHeaders) { 13532 groupContainer.prepend('<div class="ui-multiselectlistbox-header ui-widget-header ui-corner-top">' + PrimeFaces.escapeHTML(ancestor.prev('span').text()) + '</div>') 13533 .children('.ui-multiselectlistbox-list').addClass('ui-corner-bottom').removeClass('ui-corner-all'); 13534 } 13535 13536 $this.jq.append(groupContainer); 13537 } 13538 } 13539 13540 //highlight item 13541 var lists = this.jq.children('div.ui-multiselectlistbox-listcontainer'), 13542 clonedItem = lists.find(' > ul.ui-multiselectlistbox-list > li.ui-multiselectlistbox-item').filter('[data-value="' + $.escapeSelector(value) + '"]'); 13543 clonedItem.addClass('ui-state-highlight'); 13544 13545 //highlight ancestors 13546 for(var i = 0; i < selectedIndexMap.length; i++) { 13547 lists.eq(i).find('> .ui-multiselectlistbox-list > li.ui-multiselectlistbox-item').eq(selectedIndexMap[i]).addClass('ui-state-highlight'); 13548 } 13549 13550 $this.jq.children('div.ui-multiselectlistbox-listcontainer:hidden').show(); 13551 }, 13552 13553 triggerChange: function () { 13554 this.callBehavior('change'); 13555 } 13556}); 13557 13558/** 13559 * PrimeFaces Growl Widget 13560 */ 13561PrimeFaces.widget.Growl = PrimeFaces.widget.BaseWidget.extend({ 13562 13563 init: function(cfg) { 13564 this.cfg = cfg; 13565 this.id = this.cfg.id; 13566 this.jqId = PrimeFaces.escapeClientId(this.id); 13567 13568 this.render(); 13569 13570 this.removeScriptElement(this.id); 13571 }, 13572 13573 //Override 13574 refresh: function(cfg) { 13575 this.cfg = cfg; 13576 this.show(cfg.msgs); 13577 13578 this.removeScriptElement(this.id); 13579 }, 13580 13581 show: function(msgs) { 13582 var $this = this; 13583 13584 this.jq.css('z-index', ++PrimeFaces.zindex); 13585 13586 if(!this.cfg.keepAlive) { 13587 //clear previous messages 13588 this.removeAll(); 13589 } 13590 13591 $.each(msgs, function(index, msg) { 13592 $this.renderMessage(msg); 13593 }); 13594 }, 13595 13596 removeAll: function() { 13597 this.jq.children('div.ui-growl-item-container').remove(); 13598 }, 13599 13600 render: function() { 13601 //create container 13602 this.jq = $('<div id="' + this.id + '_container" class="ui-growl ui-widget" aria-live="polite"></div>'); 13603 this.jq.appendTo($(document.body)); 13604 13605 //render messages 13606 this.show(this.cfg.msgs); 13607 }, 13608 13609 renderMessage: function(msg) { 13610 var markup = '<div class="ui-growl-item-container ui-state-highlight ui-corner-all ui-helper-hidden ui-shadow ui-growl-' + msg.severity + '">'; 13611 markup += '<div role="alert" class="ui-growl-item">'; 13612 markup += '<div class="ui-growl-icon-close ui-icon ui-icon-closethick" style="display:none"></div>'; 13613 markup += '<span class="ui-growl-image ui-growl-image-' + msg.severity + '" ></span>'; 13614 if (msg.severityText) { 13615 // GitHub #5153 for screen readers 13616 markup += '<span class="ui-growl-severity ui-helper-hidden-accessible">' + msg.severityText + '</span>'; 13617 } 13618 markup += '<div class="ui-growl-message">'; 13619 markup += '<span class="ui-growl-title"></span>'; 13620 markup += '<p></p>'; 13621 markup += '</div><div style="clear: both;"></div></div></div>'; 13622 13623 var message = $(markup), 13624 summaryEL = message.find('span.ui-growl-title'), 13625 detailEL = summaryEL.next(); 13626 13627 if(this.cfg.escape) { 13628 summaryEL.text(msg.summary); 13629 detailEL.text(msg.detail); 13630 } 13631 else { 13632 summaryEL.html(msg.summary); 13633 detailEL.html(msg.detail); 13634 } 13635 13636 this.bindEvents(message); 13637 13638 message.appendTo(this.jq).fadeIn(); 13639 }, 13640 13641 bindEvents: function(message) { 13642 var $this = this, 13643 sticky = this.cfg.sticky; 13644 13645 message.mouseover(function() { 13646 var msg = $(this); 13647 13648 //visuals 13649 if(!msg.is(':animated')) { 13650 msg.find('div.ui-growl-icon-close:first').show(); 13651 } 13652 13653 // clear hide timeout on mouseover 13654 if(!sticky) { 13655 clearTimeout(msg.data('timeout')); 13656 } 13657 }) 13658 .mouseout(function() { 13659 //visuals 13660 $(this).find('div.ui-growl-icon-close:first').hide(); 13661 13662 // setup hide timeout again after mouseout 13663 if(!sticky) { 13664 $this.setRemovalTimeout(message); 13665 } 13666 }); 13667 13668 //remove message on click of close icon 13669 message.find('div.ui-growl-icon-close').click(function() { 13670 $this.removeMessage(message); 13671 13672 //clear timeout if removed manually 13673 if(!sticky) { 13674 clearTimeout(message.data('timeout')); 13675 } 13676 }); 13677 13678 //hide the message after given time if not sticky 13679 if(!sticky) { 13680 this.setRemovalTimeout(message); 13681 } 13682 }, 13683 13684 removeMessage: function(message) { 13685 message.fadeTo('normal', 0, function() { 13686 message.slideUp('normal', 'easeInOutCirc', function() { 13687 message.remove(); 13688 }); 13689 }); 13690 }, 13691 13692 setRemovalTimeout: function(message) { 13693 var $this = this; 13694 13695 var timeout = setTimeout(function() { 13696 $this.removeMessage(message); 13697 }, this.cfg.life); 13698 13699 message.data('timeout', timeout); 13700 } 13701}); 13702/** 13703 * PrimeFaces Inplace Widget 13704 */ 13705PrimeFaces.widget.Inplace = PrimeFaces.widget.BaseWidget.extend({ 13706 13707 init: function(cfg) { 13708 this._super(cfg); 13709 13710 this.display = $(this.jqId + '_display'); 13711 this.content = $(this.jqId + '_content'); 13712 this.cfg.formId = this.jq.parents('form:first').attr('id'); 13713 13714 var $this = this; 13715 13716 if(!this.cfg.disabled) { 13717 13718 if(this.cfg.toggleable) { 13719 this.display.bind(this.cfg.event, function(){ 13720 $this.show(); 13721 }); 13722
13723 this.display.mouseover(function(){ 13724 $(this).toggleClass("ui-state-highlight"); 13725 }).mouseout(function(){ 13726 $(this).toggleClass("ui-state-highlight"); 13727 }); 13728 } 13729 else { 13730 this.display.css('cursor', 'default'); 13731 } 13732 13733 if(this.cfg.editor) { 13734 this.cfg.formId = $(this.jqId).parents('form:first').attr('id'); 13735 13736 this.editor = $(this.jqId + '_editor'); 13737 13738 var saveButton = this.editor.children('.ui-inplace-save'), 13739 cancelButton = this.editor.children('.ui-inplace-cancel'); 13740 13741 PrimeFaces.skinButton(saveButton).skinButton(cancelButton); 13742 13743 saveButton.click(function(e) {$this.save(e)}); 13744 cancelButton.click(function(e) {$this.cancel(e)}); 13745 } 13746 13747 /* to enter space in inplace input within multi-selection dataTable */ 13748 this.content.find('input:text,textarea').on('keydown.inplace-text', function(e) { 13749 var keyCode = $.ui.keyCode; 13750 13751 if(e.which === keyCode.SPACE) { 13752 e.stopPropagation(); 13753 } 13754 }); 13755 } 13756 }, 13757 13758 show: function() { 13759 this.toggle(this.content, this.display); 13760 }, 13761 13762 hide: function() { 13763 this.toggle(this.display, this.content); 13764 }, 13765 13766 toggle: function(elToShow, elToHide) { 13767 var $this = this; 13768 13769 if(this.cfg.effect === 'fade') { 13770 elToHide.fadeOut(this.cfg.effectSpeed, 13771 function() { 13772 elToShow.fadeIn($this.cfg.effectSpeed); 13773 $this.postShow(); 13774 }); 13775 } 13776 else if(this.cfg.effect === 'slide') { 13777 elToHide.slideUp(this.cfg.effectSpeed, 13778 function() { 13779 elToShow.slideDown($this.cfg.effectSpeed); 13780 $this.postShow(); 13781 }); 13782 } 13783 else if(this.cfg.effect === 'none') { 13784 elToHide.hide(); 13785 elToShow.show(); 13786 $this.postShow(); 13787 } 13788 }, 13789 13790 postShow: function() { 13791 this.content.find('input:text,textarea').filter(':visible:enabled:first').focus().select(); 13792 13793 PrimeFaces.invokeDeferredRenders(this.id); 13794 }, 13795 13796 getDisplay: function() { 13797 return this.display; 13798 }, 13799 13800 getContent: function() { 13801 return this.content; 13802 }, 13803 13804 save: function(e) { 13805 var options = { 13806 source: this.id, 13807 update: this.id, 13808 process: this.id, 13809 formId: this.cfg.formId 13810 }; 13811 13812 if(this.hasBehavior('save')) { 13813 this.callBehavior('save', options); 13814 } 13815 else { 13816 PrimeFaces.ajax.Request.handle(options); 13817 } 13818 }, 13819 13820 cancel: function(e) { 13821 var options = { 13822 source: this.id, 13823 update: this.id, 13824 process: this.id, 13825 formId: this.cfg.formId 13826 }; 13827 13828 options.params = [ 13829 {name: this.id + '_cancel', value: true} 13830 ]; 13831 13832 if(this.hasBehavior('cancel')) { 13833 this.callBehavior('cancel', options); 13834 } 13835 else { 13836 PrimeFaces.ajax.Request.handle(options); 13837 } 13838 } 13839 13840}); 13841 13842/** 13843 * PrimeFaces LightBox Widget 13844 */ 13845PrimeFaces.widget.LightBox = PrimeFaces.widget.BaseWidget.extend({ 13846 13847 init: function(cfg) { 13848 // the dynamic overlay must be appended to the body 13849 cfg.appendTo = '@(body)'; 13850 13851 this._super(cfg); 13852 13853 this.links = this.jq.children(':not(.ui-lightbox-inline)'); 13854 13855 this.createPanel(); 13856 13857 if(this.cfg.mode === 'image') { 13858 this.setupImaging(); 13859 } else if(this.cfg.mode === 'inline') { 13860 this.setupInline(); 13861 } else if(this.cfg.mode === 'iframe') { 13862 this.setupIframe(); 13863 } 13864 13865 this.bindCommonEvents(); 13866 13867 if(this.cfg.visible) { 13868 this.links.eq(0).click(); 13869 } 13870 }, 13871 13872 //@override 13873 refresh: function(cfg) { 13874 PrimeFaces.utils.removeDynamicOverlay(this, this.panel, this.id + '_panel', $(document.body)); 13875 13876 this._super(cfg); 13877 }, 13878 13879 createPanel: function() { 13880 this.panel = $('<div id="' + this.id + '_panel" class="ui-lightbox ui-widget ui-helper-hidden ui-corner-all ui-sha
13880dow">' 13881 + '<div class="ui-lightbox-content-wrapper">' 13882 + '<a class="ui-state-default ui-lightbox-nav-left ui-corner-right ui-helper-hidden"><span class="ui-icon ui-icon-carat-1-w">go</span></a>' 13883 + '<div class="ui-lightbox-content ui-corner-all"></div>' 13884 + '<a class="ui-state-default ui-lightbox-nav-right ui-corner-left ui-helper-hidden"><span class="ui-icon ui-icon-carat-1-e">go</span></a>' 13885 + '</div>' 13886 + '<div class="ui-lightbox-caption ui-widget-header"><span class="ui-lightbox-caption-text"></span>' 13887 + '<a class="ui-lightbox-close ui-corner-all" href="#"><span class="ui-icon ui-icon-closethick"></span></a><div style="clear:both"></div></div>' 13888 + '</div>'); 13889 13890 PrimeFaces.utils.registerDynamicOverlay(this, this.panel, this.id + '_panel'); 13891 13892 this.contentWrapper = this.panel.children('.ui-lightbox-content-wrapper'); 13893 this.content = this.contentWrapper.children('.ui-lightbox-content'); 13894 this.caption = this.panel.children('.ui-lightbox-caption'); 13895 this.captionText = this.caption.children('.ui-lightbox-caption-text'); 13896 this.closeIcon = this.caption.children('.ui-lightbox-close'); 13897 }, 13898 13899 setupImaging: function() { 13900 var $this = this; 13901 13902 this.content.append('<img class="ui-helper-hidden"></img>'); 13903 this.imageDisplay = this.content.children('img'); 13904 this.navigators = this.contentWrapper.children('a'); 13905 13906 this.imageDisplay.on('load', function() { 13907 var image = $(this); 13908 13909 $this.scaleImage(image); 13910 13911 //coordinates to center overlay 13912 var leftOffset = ($this.panel.width() - image.width()) / 2, 13913 topOffset = ($this.panel.height() - image.height()) / 2; 13914 13915 //resize content for new image 13916 $this.content.removeClass('ui-lightbox-loading'); 13917 $this.content.stop().animate({ width: image.width(), height: image.height() }, 13918 500, 13919 function() { 13920 //show image 13921 image.fadeIn(); 13922 $this.showNavigators(); 13923 $this.caption.slideDown(); 13924 }); 13925 13926 $this.panel.stop().animate({ left: '+=' + leftOffset, top: '+=' + topOffset}, 500); 13927 }); 13928 13929 this.navigators.mouseover(function() { 13930 $(this).addClass('ui-state-hover'); 13931 }) 13932 .mouseout(function() { 13933 $(this).removeClass('ui-state-hover'); 13934 }) 13935 .click(function(e) { 13936 var nav = $(this); 13937 13938 $this.hideNavigators(); 13939 13940 if(nav.hasClass('ui-lightbox-nav-left')) { 13941 var index = $this.current == 0 ? $this.links.length - 1 : $this.current - 1; 13942 13943 $this.links.eq(index).trigger('click'); 13944 } 13945 else { 13946 var index = $this.current == $this.links.length - 1 ? 0 : $this.current + 1; 13947 13948 $this.links.eq(index).trigger('click'); 13949 } 13950 13951 e.preventDefault(); 13952 }); 13953 13954 this.links.click(function(e) { 13955 var link = $(this); 13956 13957 if($this.isHidden()) { 13958 $this.content.addClass('ui-lightbox-loading').width(32).height(32); 13959 $this.show(); 13960 } 13961 else { 13962 $this.imageDisplay.stop().fadeOut(function() { 13963 //clear for onload scaling 13964 $(this).css({ 13965 'width': 'auto' 13966 ,'height': 'auto' 13967 }); 13968 13969 $this.content.addClass('ui-lightbox-loading'); 13970 }); 13971 13972 $this.caption.stop().slideUp(); 13973 } 13974 13975 clearTimeout(this.timeout); 13976 this.timeout = setTimeout(function() { 13977 $this.imageDisplay.attr('src', link.attr('href')); 13978 $this.current = link.index(); 13979 13980 var title = link.attr('title'); 13981 if(title) { 13982 $this.captionText.text(title); 13983 } 13984 }, 1000); 13985 13986 e.preventDefault(); 13987 }); 13988 }, 13989 13990 scaleImage: function(image) { 13991 var win = $(window), 13992 winWidth = win.width(), 13993 winHeight = win.height(), 13994 imageWidth = image.width(), 13995 imageHeight = image.height(), 13996 ratio = imageHeight / imageWidth; 13997 13998 if(imageWidth >= winWidth && ratio <= 1){ 13999 imageWidth = winWidth * 0.75; 14000 imageHeight = imageWidth * ratio; 14001 } 14002 else if(imageHeight >= winHeight){ 14003 imageHeight = winHeight * 0.75; 14004 imageWidth = imageHeight / ratio; 14005 } 14006 14007 image.css({ 14008 'width':imageWidth + 'px' 14009 ,'height':imageHeight + 'px' 14010 }); 14011 }, 14012 14013 setupInline: function() { 14014 this.inline = this.jq.children('.ui-lightbox-inline'); 14015 this.inline.appendTo(this.content).show(); 14016 var $this = this; 14017 14018 this.links.click(function(e) { 14019 $this.show(); 14020 14021 var title = $(this).attr('title'); 14022 if(title) { 14023 $this.captionText.text(title); 14024 $this.caption.stop().slideDown(); 14025 } 14026 14027 e.preventDefault(); 14028 }); 14029 }, 14030 14031 setupIframe: function() { 14032 var $this = this; 14033 this.iframeLoaded = false;
14034 this.cfg.width = this.cfg.width||'640px'; 14035 this.cfg.height = this.cfg.height||'480px'; 14036 14037 this.iframe = $('<iframe frameborder="0" style="width:' + this.cfg.width + ';height:' 14038 + this.cfg.height + ';border:0 none; display: block;"></iframe>').appendTo(this.content); 14039 14040 if(this.cfg.iframeTitle) { 14041 this.iframe.attr('title', this.cfg.iframeTitle); 14042 } 14043 14044 this.links.click(function(e) { 14045 if(!$this.iframeLoaded) { 14046 $this.content.addClass('ui-lightbox-loading').css({ 14047 width: $this.cfg.width 14048 ,height: $this.cfg.height 14049 }); 14050 $this.show(); 14051 14052 $this.iframe.on('load', function() { 14053 $this.iframeLoaded = true; 14054 $this.content.removeClass('ui-lightbox-loading'); 14055 }) 14056 .attr('src', $this.links.eq(0).attr('href')); 14057 } 14058 else { 14059 $this.show(); 14060 } 14061 14062 var title = $this.links.eq(0).attr('title'); 14063 if(title) { 14064 $this.captionText.text(title); 14065 $this.caption.slideDown(); 14066 } 14067 14068 e.preventDefault(); 14069 }); 14070 }, 14071 14072 bindCommonEvents: function() { 14073 var $this = this; 14074 14075 this.closeIcon.mouseover(function() { 14076 $(this).addClass('ui-state-hover'); 14077 }) 14078 .mouseout(function() { 14079 $(this).removeClass('ui-state-hover'); 14080 }); 14081 14082 this.closeIcon.click(function(e) { 14083 $this.hide(); 14084 e.preventDefault(); 14085 }); 14086 14087 var hideEvent = PrimeFaces.env.ios ? 'touchstart' : 'click'; 14088 PrimeFaces.utils.registerHideOverlayHandler(this, hideEvent + '.' + this.id + '_hide', $this.panel, 14089 function() { return $this.links.add($this.closeIcon); }, 14090 function(e, eventTarget) { 14091 if(!($this.panel.is(eventTarget) || $this.panel.has(eventTarget).length > 0)) { 14092 e.preventDefault(); 14093 $this.hide(); 14094 } 14095 }); 14096 14097 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.panel, function() { 14098 $(document.body).children('.ui-widget-overlay').css({ 14099 'width': $(document).width() 14100 ,'height': $(document).height() 14101 }); 14102 }); 14103 }, 14104 14105 show: function() { 14106 this.center(); 14107 14108 this.panel.css('z-index', ++PrimeFaces.zindex).show(); 14109 14110 if(!PrimeFaces.utils.isModalActive(this.id)) { 14111 this.enableModality(); 14112 } 14113 14114 if(this.cfg.onShow) { 14115 this.cfg.onShow.call(this); 14116 } 14117 }, 14118 14119 hide: function() { 14120 this.panel.fadeOut(); 14121 this.disableModality(); 14122 this.caption.hide(); 14123 14124 if(this.cfg.mode == 'image') { 14125 this.imageDisplay.hide().attr('src', '').removeAttr('style'); 14126 this.hideNavigators(); 14127 } 14128 14129 if(this.cfg.onHide) { 14130 this.cfg.onHide.call(this); 14131 } 14132 }, 14133 14134 center: function() { 14135 var win = $(window), 14136 left = (win.width() / 2 ) - (this.panel.width() / 2), 14137 top = (win.height() / 2 ) - (this.panel.height() / 2); 14138 14139 this.panel.css({ 14140 'left': left, 14141 'top': top 14142 }); 14143 }, 14144 14145 enableModality: function() { 14146 PrimeFaces.utils.addModal(this, this.panel.css('z-index') - 1); 14147 }, 14148 14149 disableModality: function() { 14150 PrimeFaces.utils.removeModal(this); 14151 }, 14152 14153 showNavigators: function() { 14154 this.navigators.zIndex(this.imageDisplay.zIndex() + 1).show(); 14155 }, 14156 14157 hideNavigators: function() { 14158 this.navigators.hide(); 14159 }, 14160 14161 addOnshowHandler: function(fn) { 14162 this.onshowHandlers.push(fn); 14163 }, 14164 14165 isHidden: function() { 14166 return this.panel.is(':hidden'); 14167 }, 14168 14169 showURL: function(opt) { 14170 if(opt.width) 14171 this.iframe.attr('width', opt.width); 14172 if(opt.height) 14173 this.iframe.attr('height', opt.height); 14174 14175 this.iframe.attr('src', opt.src); 14176
14177 this.captionText.text(opt.title||''); 14178 this.caption.slideDown(); 14179 14180 this.show(); 14181 } 14182 14183}); 14184 14185PrimeFaces.widget.Menu = PrimeFaces.widget.BaseWidget.extend({ 14186 14187 init: function(cfg) { 14188 this._super(cfg); 14189 14190 if(this.cfg.overlay) { 14191 this.initOverlay(); 14192 } 14193 14194 this.keyboardTarget = this.jq.children('.ui-helper-hidden-accessible'); 14195 }, 14196 14197 initOverlay: function() { 14198 var $this = this; 14199 14200 this.jq.addClass('ui-menu-overlay'); 14201 14202 this.cfg.trigger = this.cfg.trigger.replace(/\\\\:/g,"\\:"); 14203 14204 this.trigger = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.trigger); 14205 14206 //mark trigger and descandants of trigger as a trigger for a primefaces overlay 14207 this.trigger.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 14208 14209 this.cfg.appendTo = '@(body)'; 14210 PrimeFaces.utils.registerDynamicOverlay(this, this.jq, this.id); 14211 14212 this.cfg.pos = { 14213 my: this.cfg.my, 14214 at: this.cfg.at, 14215 of: this.trigger, 14216 collision: this.cfg.collision || "flip" 14217 }; 14218 14219 this.trigger.off(this.cfg.triggerEvent + '.ui-menu').on(this.cfg.triggerEvent + '.ui-menu', function(e) { 14220 var trigger = $(this); 14221 14222 if($this.jq.is(':visible')) { 14223 $this.hide(); 14224 } 14225 else { 14226 $this.show(); 14227 14228 if(trigger.is(':button')) { 14229 trigger.addClass('ui-state-focus'); 14230 } 14231 14232 e.preventDefault(); 14233 } 14234 }); 14235 14236 //hide overlay on document click 14237 this.itemMouseDown = false; 14238 14239 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.jq, 14240 function() { return $this.trigger; }, 14241 function(e, eventTarget) { 14242 var menuItemLink = '.ui-menuitem-link:not(.ui-submenu-link, .ui-state-disabled)'; 14243 14244 if (eventTarget.is(menuItemLink) || eventTarget.closest(menuItemLink).length) { 14245 $this.itemMouseDown = true; 14246 } 14247 else if(!($this.jq.is(eventTarget) || $this.jq.has(eventTarget).length > 0)) { 14248 $this.hide(e); 14249 } 14250 }); 14251 14252 var hideUpNS = 'mouseup.' + this.id; 14253 $(document.body).off(hideUpNS).on(hideUpNS, function (e) { 14254 if($this.itemMouseDown) { 14255 $this.hide(e); 14256 $this.itemMouseDown = false; 14257 } 14258 }); 14259 14260 //Hide overlay on resize 14261 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 14262 $this.align(); 14263 }); 14264 14265 //dialog support 14266 this.setupDialogSupport(); 14267 }, 14268 14269 setupDialogSupport: function() { 14270 var dialog = this.trigger.parents('.ui-dialog:first'); 14271 14272 if(dialog.length == 1 && dialog.css('position') === 'fixed') { 14273 this.jq.css('position', 'fixed'); 14274 } 14275 }, 14276 14277 show: function() { 14278 this.jq.css({ 14279 'z-index': ++PrimeFaces.zindex, 14280 'visibility': 'hidden' 14281 }); 14282 this.align(); 14283 this.jq.show(); 14284 this.jq.css('visibility', ''); 14285 }, 14286 14287 hide: function() { 14288 this.jq.fadeOut('fast'); 14289 14290 if(this.trigger && this.trigger.is(':button')) { 14291 this.trigger.removeClass('ui-state-focus'); 14292 } 14293 }, 14294 14295 align: function() { 14296 this.jq.css({left:'', top:''}).position(this.cfg.pos); 14297 } 14298}); 14299 14300 14301 14302 14303 14304 14305PrimeFaces.widget.TieredMenu = PrimeFaces.widget.Menu.extend({ 14306 14307 init: function(cfg) { 14308 this._super(cfg); 14309 14310 this.cfg.toggleEvent = this.cfg.toggleEvent||'hover'; 14311 this.links = this.jq.find('a.ui-menuitem-link:not(.ui-state-disabled)'); 14312 this.rootLinks = this.jq.find('> ul.ui-menu-list > .ui-menuitem > .ui-menuitem-link'); 14313 14314 this.bindEvents(); 14315 }, 14316 14317 bindEvents: function() { 14318 this.bindItemEvents(); 14319 this.bindKeyEvents(); 14320 this.bindDocumentHandler(); 14321 }, 14322 14323 bindItemEvents: function() { 14324 if(this.cfg.toggleEvent === 'hover') 14325 this.bindHoverModeEvents(); 14326 else if(this.cfg.toggleEvent === 'click') 14327 this.bindClickModeEvents(); 14328 }, 14329 14330 bindHoverModeEvents: function() { 14331 var $this = this; 14332
14333 this.links.mouseenter(function() { 14334 var link = $(this), 14335 menuitem = link.parent(); 14336 14337 var activeSibling = menuitem.siblings('.ui-menuitem-active'); 14338 if(activeSibling.length === 1) { 14339 activeSibling.find('li.ui-menuitem-active').each(function() { 14340 $this.deactivate($(this)); 14341 }); 14342 $this.deactivate(activeSibling); 14343 } 14344 14345 if($this.cfg.autoDisplay||$this.active) { 14346 if(menuitem.hasClass('ui-menuitem-active')) 14347 $this.reactivate(menuitem); 14348 else 14349 $this.activate(menuitem); 14350 } 14351 else { 14352 $this.highlight(menuitem); 14353 } 14354 }); 14355 14356 this.rootLinks.click(function(e) { 14357 var link = $(this), 14358 menuitem = link.parent(), 14359 submenu = menuitem.children('ul.ui-menu-child'); 14360 14361 $this.itemClick = true; 14362 14363 if(submenu.length === 1) { 14364 if(submenu.is(':visible')) { 14365 $this.active = false; 14366 $this.deactivate(menuitem); 14367 } 14368 else { 14369 $this.active = true; 14370 $this.highlight(menuitem); 14371 $this.showSubmenu(menuitem, submenu); 14372 } 14373 } 14374 }); 14375 14376 this.links.filter('.ui-submenu-link').click(function(e) { 14377 $this.itemClick = true; 14378 e.preventDefault(); 14379 }); 14380 14381 this.jq.find('ul.ui-menu-list').mouseleave(function(e) { 14382 if($this.activeitem) { 14383 $this.deactivate($this.activeitem); 14384 } 14385 14386 e.stopPropagation(); 14387 }); 14388 }, 14389 14390 bindClickModeEvents: function() { 14391 var $this = this; 14392 14393 this.links.mouseenter(function() { 14394 var menuitem = $(this).parent(); 14395 14396 if(!menuitem.hasClass('ui-menuitem-active')) { 14397 menuitem.addClass('ui-menuitem-highlight').children('a.ui-menuitem-link').addClass('ui-state-hover'); 14398 } 14399 }) 14400 .mouseleave(function() { 14401 var menuitem = $(this).parent(); 14402 14403 if(!menuitem.hasClass('ui-menuitem-active')) { 14404 menuitem.removeClass('ui-menuitem-highlight').children('a.ui-menuitem-link').removeClass('ui-state-hover'); 14405 } 14406 }); 14407 14408 this.links.filter('.ui-submenu-link').on('click.tieredMenu', function(e) { 14409 var link = $(this), 14410 menuitem = link.parent(), 14411 submenu = menuitem.children('ul.ui-menu-child'); 14412 14413 $this.itemClick = true; 14414 14415 var activeSibling = menuitem.siblings('.ui-menuitem-active'); 14416 if(activeSibling.length) { 14417 activeSibling.find('li.ui-menuitem-active').each(function() { 14418 $this.deactivate($(this)); 14419 }); 14420 $this.deactivate(activeSibling); 14421 } 14422 14423 if(submenu.length) { 14424 if(submenu.is(':visible')) { 14425 $this.deactivate(menuitem); 14426 menuitem.addClass('ui-menuitem-highlight').children('a.ui-menuitem-link').addClass('ui-state-hover'); 14427 } 14428 else { 14429 menuitem.addClass('ui-menuitem-active').children('a.ui-menuitem-link').removeClass('ui-state-hover').addClass('ui-state-active'); 14430 $this.showSubmenu(menuitem, submenu); 14431 } 14432 } 14433 14434 e.preventDefault(); 14435 }).on('mousedown.tieredMenu', function(e) { 14436 e.stopPropagation(); 14437 }); 14438 }, 14439 14440 bindKeyEvents: function() { 14441 //not implemented 14442 }, 14443 14444 bindDocumentHandler: function() { 14445 var $this = this, 14446 clickNS = 'click.' + this.id; 14447 14448 $(document.body).off(clickNS).on(clickNS, function(e) { 14449 if($this.itemClick) { 14450 $this.itemClick = false; 14451 return; 14452 } 14453 14454 $this.reset(); 14455 }); 14456 }, 14457 14458 deactivate: function(menuitem, animate) { 14459 this.activeitem = null; 14460 menuitem.children('a.ui-menuitem-link').removeClass('ui-state-hover ui-state-active'); 14461 menuitem.removeClass('ui-menuitem-active ui-menuitem-highlight'); 14462 14463 if(animate) 14464 menuitem.children('ul.ui-menu-child').fadeOut('fast'); 14465 else 14466 menuitem.children('ul.ui-menu-child').hide(); 14467 }, 14468 14469 activate: function(menuitem) { 14470 this.highlight(menuitem); 14471 14472 var submenu = menuitem.children('ul.ui-menu-child'); 14473 if(submenu.length == 1) { 14474 this.showSubmenu(menuitem, submenu); 14475 } 14476 }, 14477 14478 reactivate: function(menuitem) { 14479 this.activeitem = menuitem; 14480 var submenu = menuitem.children('ul.ui-menu-child'), 14481 activeChilditem = submenu.children('li.ui-menuitem-active:first'), 14482 _self = this; 14483 14484 if(activeChilditem.length == 1) { 14485 _self.deactivate(activeChilditem); 14486 } 14487 }, 14488 14489 highlight: function(menuitem) { 14490 this.activeitem = menuitem; 14491 menuitem.children('a.ui-menuitem-link').addClass('ui-state-hover'); 14492 menuitem.addClass('ui-menuitem-active'); 14493 }, 14494 14495 showSubmenu: function(menuitem, submenu) { 14496 var pos ={ 14497 my: 'left top', 14498 at: 'right top', 14499 of: menuitem, 14500 collision: 'flipfit' 14501 }; 14502 14503 submenu.css('z-index', ++PrimeFaces.zindex) 14504 .show() 14505 .position(pos); 14506 }, 14507 14508 reset: function() { 14509 var $this = this; 14510 this.active = false;
14511 14512 this.jq.find('li.ui-menuitem-active').each(function() { 14513 $this.deactivate($(this), true); 14514 }); 14515 } 14516 14517}); 14518 14519PrimeFaces.widget.Menubar = PrimeFaces.widget.TieredMenu.extend({ 14520 14521 showSubmenu: function(menuitem, submenu) { 14522 var pos = null; 14523 14524 if(menuitem.parent().hasClass('ui-menu-child')) { 14525 pos = { 14526 my: 'left top', 14527 at: 'right top', 14528 of: menuitem, 14529 collision: 'flipfit' 14530 }; 14531 } 14532 else { 14533 pos = { 14534 my: 'left top', 14535 at: 'left bottom', 14536 of: menuitem, 14537 collision: 'flipfit' 14538 }; 14539 } 14540 14541 //avoid queuing multiple runs 14542 if(this.timeoutId) { 14543 clearTimeout(this.timeoutId); 14544 } 14545 14546 this.timeoutId = setTimeout(function () { 14547 submenu.css('z-index', ++PrimeFaces.zindex) 14548 .show() 14549 .position(pos) 14550 }, this.cfg.delay); 14551 }, 14552 14553 //@Override 14554 bindKeyEvents: function() { 14555 var $this = this; 14556 14557 this.keyboardTarget.on('focus.menubar', function(e) { 14558 $this.highlight($this.links.eq(0).parent()); 14559 }) 14560 .on('blur.menubar', function() { 14561 $this.reset(); 14562 }) 14563 .on('keydown.menu', function(e) { 14564 var currentitem = $this.activeitem; 14565 if(!currentitem) { 14566 return; 14567 } 14568 14569 var isRootLink = !currentitem.closest('ul').hasClass('ui-menu-child'), 14570 keyCode = $.ui.keyCode; 14571 14572 switch(e.which) { 14573 case keyCode.LEFT: 14574 if(isRootLink) { 14575 var prevItem = currentitem.prevAll('.ui-menuitem:not(.ui-menubar-options):first'); 14576 if(prevItem.length) { 14577 $this.deactivate(currentitem); 14578 $this.highlight(prevItem); 14579 } 14580 14581 e.preventDefault(); 14582 } 14583 else { 14584 if(currentitem.hasClass('ui-menu-parent') && currentitem.children('.ui-menu-child').is(':visible')) { 14585 $this.deactivate(currentitem); 14586 $this.highlight(currentitem); 14587 } 14588 else { 14589 var parentItem = currentitem.parent().parent(); 14590 $this.deactivate(currentitem); 14591 $this.deactivate(parentItem); 14592 $this.highlight(parentItem); 14593 } 14594 } 14595 break; 14596 14597 case keyCode.RIGHT: 14598 if(isRootLink) { 14599 var nextItem = currentitem.nextAll('.ui-menuitem:not(.ui-menubar-options):first'); 14600 if(nextItem.length) { 14601 $this.deactivate(currentitem); 14602 $this.highlight(nextItem); 14603 } 14604 14605 e.preventDefault(); 14606 } 14607 else { 14608 if(currentitem.hasClass('ui-menu-parent')) { 14609 var submenu = currentitem.children('.ui-menu-child'); 14610 14611 if(submenu.is(':visible')) 14612 $this.highlight(submenu.children('.ui-menuitem:first')); 14613 else 14614 $this.activate(currentitem); 14615 } 14616 } 14617 break; 14618 14619 case keyCode.UP: 14620 if(!isRootLink) { 14621 var prevItem = currentitem.prev('.ui-menuitem'); 14622 if(prevItem.length) { 14623 $this.deactivate(currentitem); 14624 $this.highlight(prevItem); 14625 } 14626 } 14627 14628 e.preventDefault(); 14629 break; 14630 14631 case keyCode.DOWN: 14632 if(isRootLink) { 14633 var submenu = currentitem.children('ul.ui-menu-child'); 14634 if(submenu.is(':visible')) 14635 $this.highlight(submenu.children('.ui-menuitem:first')); 14636 else 14637 $this.activate(currentitem); 14638 } 14639 else { 14640 var nextItem = currentitem.next('.ui-menuitem'); 14641 if(nextItem.length) { 14642 $this.deactivate(currentitem); 14643 $this.highlight(nextItem); 14644 } 14645 } 14646 14647 e.preventDefault(); 14648 break; 14649 14650 case keyCode.ENTER: 14651 var currentLink = currentitem.children('.ui-menuitem-link'); 14652 currentLink.trigger('click'); 14653 $this.jq.blur(); 14654 PrimeFaces.utils.openLink(e, currentLink); 14655 break; 14656 14657 } 14658 }); 14659 } 14660 14661}); 14662
14663PrimeFaces.widget.SlideMenu = PrimeFaces.widget.Menu.extend({ 14664 14665 init: function(cfg) { 14666 this._super(cfg); 14667 14668 //elements 14669 this.submenus = this.jq.find('ul.ui-menu-list'); 14670 this.wrapper = this.jq.children('div.ui-slidemenu-wrapper'); 14671 this.content = this.wrapper.children('div.ui-slidemenu-content'); 14672 this.rootList = this.content.children('ul.ui-menu-list'); 14673 this.links = this.jq.find('a.ui-menuitem-link:not(.ui-state-disabled)'); 14674 this.backward = this.wrapper.children('div.ui-slidemenu-backward'); 14675 this.rendered = false; 14676 14677 //config 14678 this.stack = []; 14679 this.jqWidth = this.jq.width(); 14680 14681 if(!this.jq.hasClass('ui-menu-dynamic')) { 14682 14683 if(this.jq.is(':not(:visible)')) { 14684 var hiddenParent = this.jq.closest('.ui-hidden-container'), 14685 $this = this; 14686 14687 if(hiddenParent.length) { 14688 PrimeFaces.addDeferredRender(this.id, hiddenParent.attr('id'), function() { 14689 return $this.render(); 14690 }); 14691 } 14692 } 14693 else { 14694 this.render(); 14695 } 14696 } 14697 14698 this.bindEvents(); 14699 }, 14700 14701 bindEvents: function() { 14702 var $this = this; 14703 14704 this.links.mouseenter(function() { 14705 $(this).addClass('ui-state-hover'); 14706 }) 14707 .mouseleave(function() { 14708 $(this).removeClass('ui-state-hover'); 14709 }) 14710 .click(function(e) { 14711 var link = $(this), 14712 submenu = link.next(); 14713 14714 if(submenu.length) { 14715 $this.forward(submenu); 14716 e.preventDefault(); 14717 } 14718 }); 14719 14720 this.backward.click(function() { 14721 $this.back(); 14722 }); 14723 }, 14724 14725 forward: function(submenu) { 14726 var _self = this; 14727 14728 this.push(submenu); 14729 14730 var rootLeft = -1 * (this.depth() * this.jqWidth); 14731 14732 submenu.show().css({ 14733 left: this.jqWidth 14734 }); 14735 14736 this.rootList.animate({ 14737 left: rootLeft 14738 }, 500, 'easeInOutCirc', function() { 14739 if(_self.backward.is(':hidden')) { 14740 _self.backward.fadeIn('fast'); 14741 } 14742 }); 14743 }, 14744 14745 back: function() { 14746 if(!this.rootList.is(':animated')) { 14747 var _self = this, 14748 last = this.pop(), 14749 depth = this.depth(); 14750 14751 var rootLeft = -1 * (depth * this.jqWidth); 14752 14753 this.rootList.animate({ 14754 left: rootLeft 14755 }, 500, 'easeInOutCirc', function() { 14756 if(last) { 14757 last.hide(); 14758 } 14759 14760 if(depth == 0) { 14761 _self.backward.fadeOut('fast'); 14762 } 14763 }); 14764 } 14765 }, 14766 14767 push: function(submenu) { 14768 this.stack.push(submenu); 14769 }, 14770 14771 pop: function() { 14772 return this.stack.length !== 0 ? this.stack.pop() : null; 14773 }, 14774 14775 last: function() { 14776 return this.stack[this.stack.length - 1]; 14777 }, 14778 14779 depth: function() { 14780 return this.stack.length; 14781 }, 14782 14783 render: function() { 14784 this.submenus.width(this.jq.width()); 14785 this.wrapper.height(this.rootList.outerHeight(true) + this.backward.outerHeight(true)); 14786 this.content.height(this.rootList.outerHeight(true)); 14787 this.rendered = true; 14788 }, 14789 14790 show: function() { 14791 this.align(); 14792 this.jq.css('z-index', ++PrimeFaces.zindex).show(); 14793 14794 if(!this.rendered) { 14795 this.render(); 14796 } 14797 } 14798}); 14799 14800PrimeFaces.widget.PlainMenu = PrimeFaces.widget.Menu.extend({ 14801 14802 init: function(cfg) { 14803 this._super(cfg); 14804 14805 this.menuitemLinks = this.jq.find('.ui-menuitem-link:not(.ui-state-disabled)'); 14806 14807 //events 14808 this.bindEvents(); 14809 14810 if(this.cfg.toggleable) { 14811 this.collapsedIds = []; 14812 this.stateKey = 'menu-' + this.id; 14813 this.restoreState(); 14814 } 14815 }, 14816 14817 bindEvents: function() { 14818 var $this = this; 14819 14820 this.menuitemLinks.mouseenter(function(e) { 14821 if($this.jq.is(':focus')) { 14822 $this.jq.blur(); 14823 } 14824 14825 $(this).addClass('ui-state-hover'); 14826 }) 14827 .mouseleave(function(e) { 14828 $(this).removeClass('ui-state-hover'); 14829 }); 14830 14831 if(this.cfg.overlay) { 14832 this.menuitemLinks.click(function() { 14833 $this.hide(); 14834 }); 14835 14836 this.trigger.on('keydown.ui-menu', function(e) { 14837 var keyCode = $.ui.keyCode; 14838 14839 switch(e.which) { 14840 case keyCode.DOWN: 14841 $this.keyboardTarget.trigger('focus.menu'); 14842 e.preventDefault(); 14843 break; 14844 14845 case keyCode.TAB: 14846 if($this.jq.is(':visible')) { 14847 $this.hide(); 14848 } 14849 break; 14850 } 14851 }); 14852 } 14853 14854 if(this.cfg.toggleable) { 14855 this.jq.find('> .ui-menu-list > .ui-widget-header').on('mouseover.menu', function() { 14856 $(this).addClass('ui-state-hover'); 14857 }) 14858 .on('mouseout.menu', function() { 14859 $(this).removeClass('ui-state-hover'); 14860 }) 14861 .on('click.menu', function(e) { 14862 var header = $(this); 14863 14864 if(header.find('> h3 > .ui-icon').hasClass('ui-icon-triangle-1-s')) 14865 $this.collapseSubmenu(header, true); 14866 else 14867 $this.expandSubmenu(header, true); 14868 14869 PrimeFaces.clearSelection(); 14870 e.preventDefault(); 14871 }); 14872 } 14873 14874 this.keyboardTarget.on('focus.menu', function() { 14875 $this.menuitemLinks.eq(0).addClass('ui-state-hover'); 14876 }) 14877 .on('blur.menu', function() { 14878 $this.menuitemLinks.filter('.ui-state-hover').removeClass('ui-state-hover'); 14879 }) 14880 .on('keydown.menu', function(e) { 14881 var currentLink = $this.menuitemLinks.filter('.ui-state-hover'), 14882 keyCode = $.ui.keyCode; 14883 14884 switch(e.which) { 14885 case keyCode.UP: 14886 var prevItem = currentLink.parent().prevAll('.ui-menuitem:first'); 14887 if(prevItem.length) { 14888 currentLink.removeClass('ui-state-hover'); 14889 prevItem.children('.ui-menuitem-link').addClass('ui-state-hover'); 14890 } 14891 14892 e.preventDefault(); 14893 break; 14894 14895 case keyCode.DOWN: 14896 var nextItem = currentLink.parent().nextAll('.ui-menuitem:first'); 14897 if(nextItem.length) { 14898 currentLink.removeClass('ui-state-hover'); 14899 nextItem.children('.ui-menuitem-link').addClass('ui-state-hover'); 14900 } 14901 14902 e.preventDefault(); 14903 break; 14904 14905 case keyCode.ENTER: 14906 currentLink.trigger('click'); 14907 $this.jq.blur(); 14908 PrimeFaces.utils.openLink(e, currentLink); 14909 break; 14910 14911 case keyCode.ESCAPE: 14912 $this.hide(); 14913 14914 if($this.cfg.overlay) { 14915 $this.trigger.focus(); 14916 } 14917 break; 14918 14919 } 14920 }); 14921 }, 14922 14923 collapseSubmenu: function(header, stateful) { 14924 var items = header.nextUntil('li.ui-widget-header'); 14925 14926 header.attr('aria-expanded', false) 14927 .find('> h3 > .ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e'); 14928 14929 items.filter('.ui-submenu-child').hide(); 14930 14931 if(stateful) { 14932 this.collapsedIds.push(header.attr('id')); 14933 this.saveState(); 14934 } 14935 }, 14936 14937 expandSubmenu: function(header, stateful) { 14938 var items = header.nextUntil('li.ui-widget-header'); 14939 14940 header.attr('aria-expanded', false) 14941 .find('> h3 > .ui-icon').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s'); 14942 14943 items.filter('.ui-submenu-child').show(); 14944 14945 if(stateful) { 14946 var id = header.attr('id'); 14947 this.collapsedIds = $.grep(this.collapsedIds, function(value) { 14948 return (value !== id); 14949 }); 14950 this.saveState(); 14951 } 14952 }, 14953 14954 saveState: function() {
14955 PrimeFaces.setCookie(this.stateKey, this.collapsedIds.join(',')); 14956 }, 14957 14958 restoreState: function() { 14959 var collapsedIdsAsString = PrimeFaces.getCookie(this.stateKey); 14960 14961 if(collapsedIdsAsString) { 14962 this.collapsedIds = collapsedIdsAsString.split(','); 14963 14964 for(var i = 0 ; i < this.collapsedIds.length; i++) { 14965 this.collapseSubmenu($(PrimeFaces.escapeClientId(this.collapsedIds[i])), false); 14966 } 14967 } 14968 }, 14969 14970 clearState: function() { 14971 PrimeFaces.setCookie(this.stateKey, null); 14972 } 14973 14974}); 14975 14976PrimeFaces.widget.MenuButton = PrimeFaces.widget.BaseWidget.extend({ 14977 14978 init: function(cfg) { 14979 this._super(cfg); 14980 14981 this.menuId = this.jqId + '_menu'; 14982 this.button = this.jq.children('button'); 14983 this.menu = this.jq.children('.ui-menu'); 14984 this.menuitems = this.jq.find('.ui-menuitem'); 14985 this.cfg.disabled = this.button.is(':disabled'); 14986 14987 if(!this.cfg.disabled) { 14988 this.bindEvents(); 14989 PrimeFaces.utils.registerDynamicOverlay(this, this.menu, this.id + '_menu'); 14990 } 14991 }, 14992 14993 //@override 14994 refresh: function(cfg) { 14995 this._super(cfg); 14996 }, 14997 14998 bindEvents: function() { 14999 var $this = this; 15000 15001 //button visuals 15002 this.button.mouseover(function(){ 15003 if(!$this.button.hasClass('ui-state-focus')) { 15004 $this.button.addClass('ui-state-hover'); 15005 } 15006 }).mouseout(function() { 15007 if(!$this.button.hasClass('ui-state-focus')) { 15008 $this.button.removeClass('ui-state-hover ui-state-active'); 15009 } 15010 }).mousedown(function() { 15011 $(this).removeClass('ui-state-focus ui-state-hover').addClass('ui-state-active'); 15012 }).mouseup(function() { 15013 var el = $(this); 15014 el.removeClass('ui-state-active') 15015 15016 if($this.menu.is(':visible')) { 15017 el.addClass('ui-state-hover'); 15018 $this.hide(); 15019 } 15020 else { 15021 el.addClass('ui-state-focus'); 15022 $this.show(); 15023 } 15024 }).focus(function() { 15025 $(this).addClass('ui-state-focus'); 15026 }).blur(function() { 15027 $(this).removeClass('ui-state-focus'); 15028 }); 15029 15030 //mark button and descandants of button as a trigger for a primefaces overlay 15031 this.button.data('primefaces-overlay-target', true).find('*').data('primefaces-overlay-target', true); 15032 15033 //menuitem visuals 15034 this.menuitems.mouseover(function(e) { 15035 var element = $(this); 15036 if(!element.hasClass('ui-state-disabled')) { 15037 element.addClass('ui-state-hover'); 15038 } 15039 }).mouseout(function(e) { 15040 $(this).removeClass('ui-state-hover'); 15041 }).click(function() { 15042 $this.button.removeClass('ui-state-focus'); 15043 $this.hide(); 15044 }); 15045 15046 //keyboard support 15047 this.button.keydown(function(e) { 15048 var keyCode = $.ui.keyCode; 15049 15050 switch(e.which) { 15051 case keyCode.UP: 15052 if($this.menu.is(':visible')) { 15053 var highlightedItem = $this.menuitems.filter('.ui-state-hover'), 15054 prevItems = highlightedItem.length ? highlightedItem.prevAll(':not(.ui-separator)') : null; 15055 15056 if(prevItems && prevItems.length) { 15057 highlightedItem.removeClass('ui-state-hover'); 15058 prevItems.eq(0).addClass('ui-state-hover'); 15059 } 15060 } 15061 e.preventDefault(); 15062 break; 15063 15064 case keyCode.DOWN: 15065 if($this.menu.is(':visible')) { 15066 var highlightedItem = $this.menuitems.filter('.ui-state-hover'), 15067 nextItems = highlightedItem.length ? highlightedItem.nextAll(':not(.ui-separator)') : $this.menuitems.eq(0); 15068 15069 if(nextItems.length) { 15070 highlightedItem.removeClass('ui-state-hover'); 15071 nextItems.eq(0).addClass('ui-state-hover'); 15072 } 15073 } 15074 e.preventDefault(); 15075 break; 15076 15077 case keyCode.ENTER: 15078 case keyCode.SPACE: 15079 if($this.menu.is(':visible')) 15080 $this.menuitems.filter('.ui-state-hover').children('a').trigger('click'); 15081 else 15082 $this.show(); 15083 15084 e.preventDefault(); 15085 break; 15086 15087 15088 case keyCode.ESCAPE: 15089 case keyCode.TAB: 15090 $this.hide(); 15091 break; 15092 } 15093 }); 15094 15095 if (!$this.cfg.disabled) { 15096 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.menu, 15097 function() { return $this.button; }, 15098 function(e, eventTarget) { 15099 if(!($this.menu.is(eventTarget) || $this.menu.has(eventTarget).length > 0)) { 15100 $this.button.removeClass('ui-state-focus ui-state-hover'); 15101 $this.hide(); 15102 } 15103 }); 15104 } 15105 15106 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.menu, function() { 15107 $this.alignPanel(); 15108 }); 15109 15110 //aria 15111 this.button.attr('role', 'button').attr('aria-disabled', this.button.is(':disabled')); 15112 }, 15113 15114 show: function() { 15115 this.alignPanel(); 15116 15117 this.menu.show(); 15118 }, 15119 15120 hide: function() { 15121 this.menuitems.filter('.ui-state-hover').removeClass('ui-state-hover'); 15122 15123 this.menu.fadeOut('fast'); 15124 }, 15125 15126 alignPanel: function() { 15127 this.menu.css({left:'', top:'','z-index': ++PrimeFaces.zindex}); 15128 15129 if(this.menu.parent().is(this.jq)) { 15130 this.menu.css({ 15131 left: 0,
15132 top: this.jq.innerHeight() 15133 }); 15134 } 15135 else { 15136 this.menu.position({ 15137 my: 'left top', 15138 at: 'left bottom', 15139 of: this.button, 15140 collision: this.cfg.collision || "flip" 15141 }); 15142 } 15143 } 15144 15145}); 15146 15147PrimeFaces.widget.ContextMenu = PrimeFaces.widget.TieredMenu.extend({ 15148 15149 init: function(cfg) { 15150 cfg.autoDisplay = true; 15151 this._super(cfg); 15152 this.cfg.selectionMode = this.cfg.selectionMode||'multiple'; 15153 15154 var $this = this, 15155 documentTarget = (this.cfg.target === undefined); 15156 15157 //event 15158 this.cfg.event = this.cfg.event||'contextmenu'; 15159 15160 //target 15161 this.jqTargetId = documentTarget ? document : PrimeFaces.escapeClientId(this.cfg.target); 15162 this.jqTarget = $(this.jqTargetId); 15163 15164 //append to body 15165 this.cfg.appendTo = '@(body)'; 15166 PrimeFaces.utils.registerDynamicOverlay(this, this.jq, this.id); 15167 15168 //attach contextmenu 15169 if(documentTarget) { 15170 var event = 'contextmenu.' + this.id + '_contextmenu'; 15171 15172 $(document).off(event).on(event, function(e) { 15173 $this.show(e); 15174 }); 15175 15176 if (PrimeFaces.env.touch) { 15177 $(document).swipe({ 15178 longTap:function(e, target) { 15179 $this.show(e); 15180 } 15181 }); 15182 } 15183 } 15184 else { 15185 var binded = false; 15186 15187 if (this.cfg.targetWidgetVar) { 15188 var targetWidget = PrimeFaces.widgets[this.cfg.targetWidgetVar]; 15189 15190 if (targetWidget) { 15191 if (typeof targetWidget.bindContextMenu === 'function') { 15192 targetWidget.bindContextMenu(this, targetWidget, this.jqTargetId, this.cfg); 15193 binded = true; 15194 } 15195 } 15196 else { 15197 PrimeFaces.warn("ContextMenu targets a widget which is not available yet. Please place the contextMenu after the target component. targetWidgetVar: " + this.cfg.targetWidgetVar); 15198 } 15199 } 15200 15201 if (binded === false) { 15202 var event = this.cfg.event + '.' + this.id + '_contextmenu'; 15203 15204 $(document).off(event, this.jqTargetId).on(event, this.jqTargetId, null, function(e) { 15205 $this.show(e); 15206 }); 15207 15208 if (PrimeFaces.env.touch) { 15209 $(this.jqTargetId).swipe({ 15210 longTap:function(e, target) { 15211 $this.show(e); 15212 } 15213 }); 15214 } 15215 } 15216 } 15217 15218 15219 PrimeFaces.utils.registerHideOverlayHandler(this, 'click.' + this.id + '_hide', this.jq, 15220 function(e) { return e.which == 3 ? $this.jqTarget : null; }, 15221 function(e, eventTarget) { 15222 if(!($this.jq.is(eventTarget) || $this.jq.has(eventTarget).length > 0)) { 15223 $this.hide(); 15224 } 15225 }); 15226 15227 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', this.jq, function() { 15228 $this.hide(); 15229 }); 15230 }, 15231 15232 // @Override 15233 bindItemEvents: function() { 15234 this._super(); 15235 15236 var $this = this; 15237 15238 //hide menu on item click 15239 this.links.on('click', function(e) { 15240 var target = $(e.target), 15241 submenuLink = target.hasClass('ui-submenu-link') ? target : target.closest('.ui-submenu-link'); 15242 15243 if (submenuLink.length) { 15244 return; 15245 } 15246 15247 $this.hide(); 15248 }); 15249 }, 15250 15251 show: function(e) { 15252 if(this.cfg.targetFilter && $(e.target).is(':not(' + this.cfg.targetFilter + ')')) { 15253 return; 15254 } 15255 15256 //hide other contextmenus if any 15257 $(document.body).children('.ui-contextmenu:visible').hide(); 15258 15259 if(this.cfg.beforeShow) { 15260 var retVal = this.cfg.beforeShow.call(this, e); 15261 if(retVal === false) { 15262 return; 15263 } 15264 } 15265 15266 var win = $(window), 15267 left = e.pageX, 15268 top = e.pageY, 15269 width = this.jq.outerWidth(), 15270 height = this.jq.outerHeight(); 15271 15272 //collision detection for window boundaries 15273 if((left + width) > (win.width())+ win.scrollLeft()) { 15274 left = left - width; 15275 } 15276 if((top + height ) > (win.height() + win.scrollTop())) { 15277 top = top - height; 15278 } 15279 if(top < 0) { 15280 top = e.pageY; 15281 } 15282 15283 this.jq.css({ 15284 'left': left, 15285 'top': top, 15286 'z-index': ++PrimeFaces.zindex 15287 }).show(); 15288 15289 e.preventDefault(); 15290 e.stopPropagation(); 15291 }, 15292 15293 hide: function() { 15294 var $this = this; 15295 15296 //hide submenus 15297 this.jq.find('li.ui-menuitem-active').each(function() { 15298 $this.deactivate($(this), true); 15299 }); 15300 15301 this.jq.fadeOut('fast'); 15302 }, 15303 15304 isVisible: function() { 15305 return this.jq.is(':visible'); 15306 }, 15307 15308 getTarget: function() { 15309 return this.jqTarget; 15310 } 15311 15312}); 15313 15314PrimeFaces.widget.MegaMenu = PrimeFaces.widget.BaseWidget.extend({ 15315 15316 init: function(cfg) { 15317 this._super(cfg); 15318 15319 this.cfg.vertical = this.jq.hasClass('ui-megamenu-vertical'); 15320 this.rootList = this.jq.children('ul.ui-menu-list'); 15321 this.rootLinks = this.rootList.find('> li.ui-menuitem > a.ui-menuitem-link:not(.ui-state-disabled)'); 15322 this.subLinks = this.jq.find('.ui-menu-child a.ui-menuitem-link:not(.ui-state-disabled)'); 15323 this.keyboardTarget = this.jq.children('.ui-helper-hidden-accessible'); 15324 15325 if(this.cfg.activeIndex !== undefined) { 15326 this.rootLinks.eq(this.cfg.activeIndex).addClass('ui-state-hover').closest('li.ui-menuitem').addClass('ui-menuitem-active'); 15327 } 15328 15329 this.bindEvents(); 15330 this.bindKeyEvents(); 15331 }, 15332 15333 bindEvents: function() { 15334 var $this = this; 15335 15336 this.rootLinks.mouseenter(function(e) { 15337 var link = $(this), 15338 menuitem = link.parent(); 15339 15340 var current = menuitem.siblings('.ui-menuitem-active'); 15341 if(current.length > 0) { 15342 current.find('li.ui-menuitem-active').each(function() { 15343 $this.deactivate($(this)); 15344 }); 15345 $this.deactivate(current, false); 15346 } 15347 15348 if($this.cfg.autoDisplay||$this.active) { 15349 $this.activate(menuitem); 15350 } 15351 else { 15352 $this.highlight(menuitem); 15353 } 15354 15355 }); 15356 15357 if(this.cfg.autoDisplay === false) { 15358 this.rootLinks.data('primefaces-megamenu', this.id).find('*').data('primefaces-megamenu', this.id) 15359 15360 this.rootLinks.click(function(e) { 15361 var link = $(this), 15362 menuitem = link.parent(), 15363 submenu = link.next(); 15364 15365 if(submenu.length === 1) { 15366 if(submenu.is(':visible')) { 15367 $this.active = false;
15368 $this.deactivate(menuitem, true); 15369 } 15370 else { 15371 $this.active = true; 15372 $this.activate(menuitem); 15373 } 15374 } 15375 else { 15376 PrimeFaces.utils.openLink(e, link); 15377 } 15378 15379 e.preventDefault(); 15380 }); 15381 } 15382 else { 15383 this.rootLinks.filter('.ui-submenu-link').click(function(e) { 15384 e.preventDefault(); 15385 }); 15386 } 15387 15388 this.subLinks.mouseenter(function() { 15389 if($this.activeitem && !$this.isRootLink($this.activeitem)) { 15390 $this.deactivate($this.activeitem); 15391 } 15392 $this.highlight($(this).parent()); 15393 }) 15394 .mouseleave(function() { 15395 if($this.activeitem && !$this.isRootLink($this.activeitem)) { 15396 $this.deactivate($this.activeitem); 15397 } 15398 $(this).removeClass('ui-state-hover'); 15399 }); 15400 15401 this.rootList.mouseleave(function(e) { 15402 var activeitem = $this.rootList.children('.ui-menuitem-active'); 15403 if(activeitem.length === 1) { 15404 $this.deactivate(activeitem, false); 15405 } 15406 }); 15407 15408 this.rootList.find('> li.ui-menuitem > ul.ui-menu-child').mouseleave(function(e) { 15409 e.stopPropagation(); 15410 }); 15411 15412 $(document.body).click(function(e) { 15413 var target = $(e.target); 15414 if(target.data('primefaces-megamenu') === $this.id) { 15415 return; 15416 } 15417 15418 $this.active = false; 15419 $this.deactivate($this.rootList.children('li.ui-menuitem-active'), true); 15420 }); 15421 }, 15422 15423 bindKeyEvents: function() { 15424 var $this = this; 15425 15426 this.keyboardTarget.on('focus.megamenu', function(e) { 15427 $this.highlight($this.rootLinks.eq(0).parent()); 15428 }) 15429 .on('blur.megamenu', function() { 15430 $this.reset(); 15431 }) 15432 .on('keydown.megamenu', function(e) { 15433 var currentitem = $this.activeitem; 15434 if(!currentitem) { 15435 return; 15436 } 15437 15438 var isRootLink = $this.isRootLink(currentitem), 15439 keyCode = $.ui.keyCode; 15440 15441 switch(e.which) { 15442 case keyCode.LEFT: 15443 if(isRootLink && !$this.cfg.vertical) { 15444 var prevItem = currentitem.prevAll('.ui-menuitem:first'); 15445 if(prevItem.length) { 15446 $this.deactivate(currentitem); 15447 $this.highlight(prevItem); 15448 } 15449 15450 e.preventDefault(); 15451 } 15452 else { 15453 if(currentitem.hasClass('ui-menu-parent') && currentitem.children('.ui-menu-child').is(':visible')) { 15454 $this.deactivate(currentitem); 15455 $this.highlight(currentitem); 15456 } 15457 else { 15458 var parentItem = currentitem.closest('ul.ui-menu-child').parent(); 15459 if(parentItem.length) { 15460 $this.deactivate(currentitem); 15461 $this.deactivate(parentItem); 15462 $this.highlight(parentItem); 15463 } 15464 } 15465 } 15466 break; 15467 15468 case keyCode.RIGHT: 15469 if(isRootLink && !$this.cfg.vertical) { 15470 var nextItem = currentitem.nextAll('.ui-menuitem:visible:first'); 15471 if(nextItem.length) { 15472 $this.deactivate(currentitem); 15473 $this.highlight(nextItem); 15474 } 15475 15476 e.preventDefault(); 15477 } 15478 else { 15479 15480 if(currentitem.hasClass('ui-menu-parent')) { 15481 var submenu = currentitem.children('.ui-menu-child'); 15482 if(submenu.is(':visible')) { 15483 $this.highlight(submenu.find('ul.ui-menu-list:visible > .ui-menuitem:visible:first')); 15484 } 15485 else { 15486 $this.activate(currentitem); 15487 } 15488 } 15489 } 15490 break; 15491 15492 case keyCode.UP: 15493 if(!isRootLink || $this.cfg.vertical) { 15494 var prevItem = $this.findPrevItem(currentitem); 15495 if(prevItem.length) { 15496 $this.deactivate(currentitem); 15497 $this.highlight(prevItem); 15498 } 15499 } 15500 15501 e.preventDefault(); 15502 break; 15503 15504 case keyCode.DOWN: 15505 if(isRootLink && !$this.cfg.vertical) { 15506 var submenu = currentitem.children('ul.ui-menu-child'); 15507 if(submenu.is(':visible')) { 15508 var firstMenulist = $this.getFirstMenuList(submenu); 15509 $this.highlight(firstMenulist.children('.ui-menuitem:visible:first')); 15510 } 15511 else { 15512 $this.activate(currentitem); 15513 } 15514 } 15515 else { 15516 var nextItem = $this.findNextItem(currentitem); 15517 if(nextItem.length) { 15518 $this.deactivate(currentitem); 15519 $this.highlight(nextItem); 15520 } 15521 } 15522 15523 e.preventDefault(); 15524 break; 15525 15526 case keyCode.ENTER: 15527 var currentLink = currentitem.children('.ui-menuitem-link'); 15528 currentLink.trigger('click'); 15529 $this.jq.blur(); 15530 var href = currentLink.attr('href'); 15531 if(href && href !== '#') { 15532 window.location.href = href; 15533 } 15534 $this.deactivate(currentitem); 15535 e.preventDefault(); 15536 break; 15537 15538 case keyCode.ESCAPE: 15539 if(currentitem.hasClass('ui-menu-parent')) { 15540 var submenu = currentitem.children('ul.ui-menu-list:visible'); 15541 if(submenu.length > 0) { 15542 submenu.hide(); 15543 } 15544 } 15545 else { 15546 var parentItem = currentitem.closest('ul.ui-menu-child').parent(); 15547 if(parentItem.length) { 15548 $this.deactivate(currentitem); 15549 $this.deactivate(parentItem); 15550 $this.highlight(parentItem); 15551 } 15552 } 15553 e.preventDefault(); 15554 break; 15555 } 15556 }); 15557 }, 15558 15559 findPrevItem: function(menuitem) { 15560 var previtem = menuitem.prev('.ui-menuitem'); 15561 15562 if(!previtem.length) { 15563 var prevSubmenu = menuitem.closest('ul.ui-menu-list').prev('.ui-menu-list'); 15564 15565 if(!prevSubmenu.length) { 15566 prevSubmenu = menuitem.closest('td').prev('td').children('.ui-menu-list:visible:last'); 15567 } 15568 15569 if(prevSubmenu.length) { 15570 previtem = prevSubmenu.find('li.ui-menuitem:visible:last'); 15571 } 15572 } 15573 return previtem; 15574 }, 15575 15576 findNextItem: function(menuitem) { 15577 var nextitem = menuitem.next('.ui-menuitem'); 15578 15579 if(!nextitem.length) { 15580 var nextSubmenu = menuitem.closest('ul.ui-menu-list').next('.ui-menu-list'); 15581 if(!nextSubmenu.length) { 15582 nextSubmenu = menuitem.closest('td').next('td').children('.ui-menu-list:visible:first'); 15583 } 15584 15585 if(nextSubmenu.length) { 15586 nextitem = nextSubmenu.find('li.ui-menuitem:visible:first'); 15587 } 15588 } 15589 return nextitem; 15590 }, 15591 15592 getFirstMenuList: function(submenu) { 15593 return submenu.find('.ui-menu-list:not(.ui-state-disabled):first'); 15594 }, 15595 15596 isRootLink: function(menuitem) { 15597 var submenu = menuitem.closest('ul'); 15598 return submenu.parent().hasClass('ui-menu'); 15599 }, 15600 15601 reset: function() { 15602 var $this = this; 15603 this.active = false;
15604 15605 this.jq.find('li.ui-menuitem-active').each(function() { 15606 $this.deactivate($(this), true); 15607 }); 15608 }, 15609 15610 deactivate: function(menuitem, animate) { 15611 var link = menuitem.children('a.ui-menuitem-link'), 15612 submenu = link.next(); 15613 15614 menuitem.removeClass('ui-menuitem-active'); 15615 link.removeClass('ui-state-hover'); 15616 this.activeitem = null; 15617 15618 if(submenu.length > 0) { 15619 if(animate) 15620 submenu.fadeOut('fast'); 15621 else 15622 submenu.hide(); 15623 } 15624 }, 15625 15626 highlight: function(menuitem) { 15627 var link = menuitem.children('a.ui-menuitem-link'); 15628 15629 menuitem.addClass('ui-menuitem-active'); 15630 link.addClass('ui-state-hover'); 15631 this.activeitem = menuitem; 15632 }, 15633 15634 activate: function(menuitem) { 15635 var submenu = menuitem.children('.ui-menu-child'), 15636 $this = this; 15637 15638 $this.highlight(menuitem); 15639 15640 if(submenu.length > 0) { 15641 $this.showSubmenu(menuitem, submenu); 15642 } 15643 }, 15644 15645 showSubmenu: function(menuitem, submenu) { 15646 var pos = null; 15647 15648 if(this.cfg.vertical) { 15649 pos = { 15650 my: 'left top', 15651 at: 'right top', 15652 of: menuitem, 15653 collision: 'flipfit' 15654 }; 15655 } 15656 else { 15657 pos = { 15658 my: 'left top', 15659 at: 'left bottom', 15660 of: menuitem, 15661 collision: 'flipfit' 15662 }; 15663 } 15664 15665 //avoid queuing multiple runs 15666 if(this.timeoutId) { 15667 clearTimeout(this.timeoutId); 15668 } 15669 15670 this.timeoutId = setTimeout(function () { 15671 submenu.css('z-index', ++PrimeFaces.zindex) 15672 .show() 15673 .position(pos) 15674 }, this.cfg.delay); 15675 } 15676 15677}); 15678 15679PrimeFaces.widget.PanelMenu = PrimeFaces.widget.BaseWidget.extend({ 15680 15681 init: function(cfg) { 15682 this._super(cfg); 15683 this.headers = this.jq.find('> .ui-panelmenu-panel > h3.ui-panelmenu-header:not(.ui-state-disabled)'); 15684 this.menuContent = this.jq.find('> .ui-panelmenu-panel > .ui-panelmenu-content'); 15685 this.menuitemLinks = this.menuContent.find('.ui-menuitem-link:not(.ui-state-disabled)'); 15686 this.menuText = this.menuitemLinks.find('.ui-menuitem-text'); 15687 this.treeLinks = this.menuContent.find('.ui-menu-parent > .ui-menuitem-link:not(.ui-state-disabled)'); 15688 15689 //keyboard support 15690 this.focusedItem = null; 15691 this.menuText.attr('tabindex', -1); 15692 15693 //ScreenReader support 15694 this.menuText.attr('role', 'menuitem'); 15695 this.treeLinks.find('> .ui-menuitem-text').attr('aria-expanded', false); 15696 15697 this.bindEvents(); 15698 15699 if(this.cfg.stateful) { 15700 this.stateKey = 'panelMenu-' + this.id; 15701 } 15702 15703 this.restoreState(); 15704 }, 15705 15706 bindEvents: function() { 15707 var $this = this; 15708 15709 this.headers.mouseover(function() { 15710 var element = $(this); 15711 if(!element.hasClass('ui-state-active')) { 15712 element.addClass('ui-state-hover'); 15713 } 15714 }).mouseout(function() { 15715 var element = $(this); 15716 if(!element.hasClass('ui-state-active')) { 15717 element.removeClass('ui-state-hover'); 15718 } 15719 }).click(function(e) { 15720 var header = $(this); 15721 15722 if (!$this.cfg.multiple) { 15723 $this.collapseActiveSibling(header); 15724 } 15725 15726 if (header.hasClass('ui-state-active')) 15727 $this.collapseRootSubmenu($(this)); 15728 else 15729 $this.expandRootSubmenu($(this), false); 15730 15731 $this.removeFocusedItem(); 15732 header.focus(); 15733 e.preventDefault(); 15734 }); 15735 15736 this.menuitemLinks.mouseover(function() { 15737 $(this).addClass('ui-state-hover'); 15738 }).mouseout(function() { 15739 $(this).removeClass('ui-state-hover'); 15740 }).click(function(e) { 15741 var currentLink = $(this); 15742 $this.focusItem(currentLink.closest('.ui-menuitem')); 15743 PrimeFaces.utils.openLink(e, currentLink); 15744 }); 15745 15746 this.treeLinks.click(function(e) { 15747 var link = $(this), 15748 submenu = link.parent(), 15749 submenuList = link.next(); 15750 15751 if(submenuList.is(':visible')) 15752 $this.collapseTreeItem(submenu); 15753 else 15754 $this.expandTreeItem(submenu, false); 15755 15756 e.preventDefault(); 15757 }); 15758 15759 this.bindKeyEvents(); 15760 }, 15761 15762 bindKeyEvents: function() { 15763 var $this = this; 15764 15765 if(PrimeFaces.env.isIE()) { 15766 this.focusCheck = false;
15767 } 15768 15769 this.headers.on('focus.panelmenu', function(){ 15770 $(this).addClass('ui-menuitem-outline'); 15771 }) 15772 .on('blur.panelmenu', function(){ 15773 $(this).removeClass('ui-menuitem-outline ui-state-hover'); 15774 }) 15775 .on('keydown.panelmenu', function(e) { 15776 var keyCode = $.ui.keyCode, 15777 key = e.which; 15778 15779 if(key === keyCode.SPACE || key === keyCode.ENTER) { 15780 $(this).trigger('click'); 15781 e.preventDefault(); 15782 } 15783 }); 15784 15785 this.menuContent.on('mousedown.panelmenu', function(e) { 15786 if($(e.target).is(':not(:input:enabled)')) { 15787 e.preventDefault(); 15788 } 15789 }).on('focus.panelmenu', function(){ 15790 if(!$this.focusedItem) { 15791 $this.focusItem($this.getFirstItemOfContent($(this))); 15792 if(PrimeFaces.env.isIE()) { 15793 $this.focusCheck = false; 15794 } 15795 } 15796 }); 15797 15798 this.menuContent.off('keydown.panelmenu blur.panelmenu').on('keydown.panelmenu', function(e) { 15799 if(!$this.focusedItem) { 15800 return; 15801 } 15802 15803 var keyCode = $.ui.keyCode; 15804 15805 switch(e.which) { 15806 case keyCode.LEFT: 15807 if($this.isExpanded($this.focusedItem)) { 15808 $this.focusedItem.children('.ui-menuitem-link').trigger('click'); 15809 } 15810 else { 15811 var parentListOfItem = $this.focusedItem.closest('ul.ui-menu-list'); 15812 15813 if(parentListOfItem.parent().is(':not(.ui-panelmenu-content)')) { 15814 $this.focusItem(parentListOfItem.closest('li.ui-menuitem')); 15815 } 15816 } 15817 15818 e.preventDefault(); 15819 break; 15820 15821 case keyCode.RIGHT: 15822 if($this.focusedItem.hasClass('ui-menu-parent') && !$this.isExpanded($this.focusedItem)) { 15823 $this.focusedItem.children('.ui-menuitem-link').trigger('click'); 15824 } 15825 e.preventDefault(); 15826 break; 15827 15828 case keyCode.UP: 15829 var itemToFocus = null, 15830 prevItem = $this.focusedItem.prev(); 15831 15832 if(prevItem.length) { 15833 itemToFocus = prevItem.find('li.ui-menuitem:visible:last'); 15834 if(!itemToFocus.length) { 15835 itemToFocus = prevItem; 15836 } 15837 } 15838 else { 15839 itemToFocus = $this.focusedItem.closest('ul').parent('li'); 15840 } 15841 15842 if(itemToFocus.length) { 15843 $this.focusItem(itemToFocus); 15844 } 15845 15846 e.preventDefault(); 15847 break; 15848 15849 case keyCode.DOWN: 15850 var itemToFocus = null, 15851 firstVisibleChildItem = $this.focusedItem.find('> ul > li:visible:first'); 15852 15853 if(firstVisibleChildItem.length) { 15854 itemToFocus = firstVisibleChildItem; 15855 } 15856 else if($this.focusedItem.next().length) { 15857 itemToFocus = $this.focusedItem.next(); 15858 } 15859 else { 15860 if($this.focusedItem.next().length === 0) { 15861 itemToFocus = $this.searchDown($this.focusedItem); 15862 } 15863 } 15864 15865 if(itemToFocus && itemToFocus.length) { 15866 $this.focusItem(itemToFocus); 15867 } 15868 15869 e.preventDefault(); 15870 break; 15871 15872 case keyCode.ENTER: 15873 case keyCode.SPACE: 15874 var currentLink = $this.focusedItem.children('.ui-menuitem-link'); 15875 //IE fix 15876 setTimeout(function(){ 15877 currentLink.trigger('click'); 15878 },1); 15879 $this.jq.blur(); 15880 15881 var href = currentLink.attr('href'); 15882 if(href && href !== '#') { 15883 window.location.href = href; 15884 } 15885 e.preventDefault(); 15886 break; 15887 15888 case keyCode.TAB: 15889 if($this.focusedItem) { 15890 if(PrimeFaces.env.isIE()) { 15891 $this.focusCheck = true; 15892 } 15893 $(this).focus(); 15894 } 15895 break; 15896 } 15897 }).on('blur.panelmenu', function(e) { 15898 if(PrimeFaces.env.isIE() && !$this.focusCheck) { 15899 return; 15900 } 15901 15902 $this.removeFocusedItem(); 15903 }); 15904 15905 var clickNS = 'click.' + this.id; 15906 //remove focusedItem when document is clicked 15907 $(document.body).off(clickNS).on(clickNS, function(event) { 15908 if(!$(event.target).closest('.ui-panelmenu').length) { 15909 $this.removeFocusedItem(); 15910 } 15911 }); 15912 }, 15913 15914 collapseActiveSibling: function(header) { 15915 this.collapseRootSubmenu(header.parent().siblings().children('.ui-panelmenu-header.ui-state-active').eq(0)); 15916 }, 15917 15918 searchDown: function(item) { 15919 var nextOfParent = item.closest('ul').parent('li').next(), 15920 itemToFocus = null; 15921 15922 if(nextOfParent.length) { 15923 itemToFocus = nextOfParent; 15924 } 15925 else if(item.closest('ul').parent('li').length === 0){ 15926 itemToFocus = item; 15927 } 15928 else { 15929 itemToFocus = this.searchDown(item.closest('ul').parent('li')); 15930 } 15931 15932 return itemToFocus; 15933 }, 15934 15935 getFirstItemOfContent: function(content) { 15936 return content.find('> .ui-menu-list > .ui-menuitem:visible:first-child'); 15937 }, 15938 15939 getItemText: function(item) { 15940 return item.find('> .ui-menuitem-link > span.ui-menuitem-text'); 15941 }, 15942 15943 focusItem: function(item) { 15944 this.removeFocusedItem(); 15945 this.getItemText(item).addClass('ui-menuitem-outline').focus(); 15946 this.focusedItem = item; 15947 }, 15948 15949 removeFocusedItem: function() { 15950 if(this.focusedItem) { 15951 this.getItemText(this.focusedItem).removeClass('ui-menuitem-outline'); 15952 this.focusedItem = null; 15953 } 15954 }, 15955 15956 isExpanded: function(item) { 15957 return item.children('ul.ui-menu-list').is(':visible'); 15958 }, 15959 15960 collapseRootSubmenu: function(header) { 15961 var panel = header.next(); 15962 15963 header.attr('aria-expanded', false).removeClass('ui-state-active ui-corner-top').addClass('ui-state-hover ui-corner-all') 15964 .children('.ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e'); 15965
15966 panel.attr('aria-hidden', true).slideUp('normal', 'easeInOutCirc'); 15967 15968 this.removeAsExpanded(panel); 15969 }, 15970 15971 expandRootSubmenu: function(header, restoring) { 15972 var panel = header.next(); 15973 15974 header.attr('aria-expanded', true).addClass('ui-state-active ui-corner-top').removeClass('ui-state-hover ui-corner-all') 15975 .children('.ui-icon').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s'); 15976 15977 if(restoring) { 15978 panel.attr('aria-hidden', false).show(); 15979 } 15980 else { 15981 panel.attr('aria-hidden', false).slideDown('normal', 'easeInOutCirc'); 15982 15983 this.addAsExpanded(panel); 15984 } 15985 }, 15986 15987 expandTreeItem: function(submenu, restoring) { 15988 var submenuLink = submenu.find('> .ui-menuitem-link'); 15989 15990 submenuLink.find('> .ui-menuitem-text').attr('aria-expanded', true); 15991 submenuLink.find('> .ui-panelmenu-icon').addClass('ui-icon-triangle-1-s'); 15992 submenu.children('.ui-menu-list').show(); 15993 15994 if(!restoring) { 15995 this.addAsExpanded(submenu); 15996 } 15997 }, 15998 15999 collapseTreeItem: function(submenu) { 16000 var submenuLink = submenu.find('> .ui-menuitem-link'); 16001 16002 submenuLink.find('> .ui-menuitem-text').attr('aria-expanded', false); 16003 submenuLink.find('> .ui-panelmenu-icon').removeClass('ui-icon-triangle-1-s'); 16004 submenu.children('.ui-menu-list').hide(); 16005 16006 this.removeAsExpanded(submenu); 16007 }, 16008 16009 saveState: function() { 16010 if(this.cfg.stateful) { 16011 var expandedNodeIds = this.expandedNodes.join(','); 16012 16013 PrimeFaces.setCookie(this.stateKey, expandedNodeIds, {path:'/'}); 16014 } 16015 }, 16016 16017 restoreState: function() { 16018 var expandedNodeIds = null; 16019 16020 if(this.cfg.stateful) { 16021 expandedNodeIds = PrimeFaces.getCookie(this.stateKey); 16022 } 16023 16024 if(expandedNodeIds) { 16025 this.collapseAll(); 16026 this.expandedNodes = expandedNodeIds.split(','); 16027 16028 for(var i = 0 ; i < this.expandedNodes.length; i++) { 16029 var element = $(PrimeFaces.escapeClientId(this.expandedNodes[i])); 16030 if(element.is('div.ui-panelmenu-content')) 16031 this.expandRootSubmenu(element.prev(), true); 16032 else if(element.is('li.ui-menu-parent')) 16033 this.expandTreeItem(element, true); 16034 } 16035 } 16036 else { 16037 this.expandedNodes = []; 16038 var activeHeaders = this.headers.filter('.ui-state-active'), 16039 activeTreeSubmenus = this.jq.find('.ui-menu-parent > .ui-menu-list:not(.ui-helper-hidden)'); 16040 16041 for(var i = 0; i < activeHeaders.length; i++) { 16042 this.expandedNodes.push(activeHeaders.eq(i).next().attr('id')); 16043 } 16044 16045 for(var i = 0; i < activeTreeSubmenus.length; i++) { 16046 this.expandedNodes.push(activeTreeSubmenus.eq(i).parent().attr('id')); 16047 } 16048 } 16049 }, 16050 16051 removeAsExpanded: function(element) { 16052 var id = element.attr('id'); 16053 16054 this.expandedNodes = $.grep(this.expandedNodes, function(value) { 16055 return value != id; 16056 }); 16057 16058 this.saveState(); 16059 }, 16060 16061 addAsExpanded: function(element) { 16062 this.expandedNodes.push(element.attr('id')); 16063 16064 this.saveState(); 16065 }, 16066 16067 clearState: function() { 16068 if(this.cfg.stateful) { 16069 PrimeFaces.deleteCookie(this.stateKey, {path:'/'}); 16070 } 16071 }, 16072 16073 collapseAll: function() { 16074 this.headers.filter('.ui-state-active').each(function() { 16075 var header = $(this); 16076 header.removeClass('ui-state-active').children('.ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e').removeClass('ui-icon-triangle-1-s'); 16077 header.next().addClass('ui-helper-hidden'); 16078 }); 16079 16080 this.jq.find('.ui-menu-parent > .ui-menu-list:not(.ui-helper-hidden)').each(function() { 16081 $(this).addClass('ui-helper-hidden').prev().children('.ui-panelmenu-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e'); 16082 }); 16083 } 16084 16085}); 16086
16087PrimeFaces.widget.TabMenu = PrimeFaces.widget.Menu.extend({ 16088 16089 init: function(cfg) { 16090 this._super(cfg); 16091 16092 this.items = this.jq.find('> .ui-tabmenu-nav > li:not(.ui-state-disabled)'); 16093 16094 this.bindEvents(); 16095 this.bindKeyEvents(); 16096 }, 16097 16098 bindEvents: function() { 16099 this.items.on('mouseover.tabmenu', function(e) { 16100 var element = $(this); 16101 if(!element.hasClass('ui-state-active')) { 16102 element.addClass('ui-state-hover'); 16103 } 16104 }) 16105 .on('mouseout.tabmenu', function(e) { 16106 $(this).removeClass('ui-state-hover'); 16107 }); 16108 }, 16109 16110 bindKeyEvents: function() { 16111 /* For Keyboard accessibility and Screen Readers */ 16112 this.items.attr('tabindex', 0); 16113 16114 this.items.on('focus.tabmenu', function(e) { 16115 $(this).addClass('ui-menuitem-outline'); 16116 }) 16117 .on('blur.tabmenu', function(){ 16118 $(this).removeClass('ui-menuitem-outline'); 16119 }) 16120 .on('keydown.tabmenu', function(e) { 16121 var keyCode = $.ui.keyCode, 16122 key = e.which; 16123 16124 if(key === keyCode.SPACE || key === keyCode.ENTER) { 16125 var currentLink = $(this).children('a'); 16126 currentLink.trigger('click'); 16127 PrimeFaces.utils.openLink(e, currentLink); 16128 } 16129 }); 16130 } 16131}); 16132 16133/** 16134 * PrimeFaces Message Widget 16135 */ 16136PrimeFaces.widget.Message = PrimeFaces.widget.BaseWidget.extend({ 16137 16138 init: function(cfg) { 16139 this._super(cfg); 16140 16141 var text = this.jq.children('.ui-message-error-detail').text(); 16142 16143 if(text) { 16144 var target = $(PrimeFaces.escapeClientId(this.cfg.target)); 16145 16146 if (this.cfg.tooltip) { 16147 target.data('tooltip', text); 16148 } 16149 16150 target.attr('aria-describedby', this.id + '_error-detail'); 16151 } 16152 } 16153}); 16154/** 16155 * PrimeFaces NotificationBar Widget 16156 */ 16157PrimeFaces.widget.NotificationBar = PrimeFaces.widget.BaseWidget.extend({ 16158 16159 init: function(cfg) { 16160 this._super(cfg); 16161 16162 var _self = this; 16163 16164 //relocate 16165 this.jq.css(this.cfg.position, '0').appendTo($('body')); 16166 16167 //display initially 16168 if(this.cfg.autoDisplay) { 16169 $(this.jq).css('display','block') 16170 } 16171 16172 //bind events 16173 this.jq.children('.ui-notificationbar-close').click(function() { 16174 _self.hide(); 16175 }); 16176 }, 16177 16178 /** 16179 * The up-to-three arguments will be routed to jQuery as it is. 16180 * @see: http://api.jquery.com/slidedown/ 16181 * @see: http://api.jquery.com/fadein/ 16182 * @see: http://api.jquery.com/show/ 16183 */ 16184 show: function(a1, a2, a3) { 16185 if(this.cfg.effect === 'slide') 16186 $(this.jq).slideDown(a1, a2, a3); 16187 else if(this.cfg.effect === 'fade') 16188 $(this.jq).fadeIn(a1, a2, a3); 16189 else if(this.cfg.effect === 'none') 16190 $(this.jq).show(a1, a2, a3); 16191 }, 16192 16193 hide: function() { 16194 if(this.cfg.effect === 'slide') 16195 $(this.jq).slideUp(this.cfg.effect); 16196 else if(this.cfg.effect === 'fade') 16197 $(this.jq).fadeOut(this.cfg.effect); 16198 else if(this.cfg.effect === 'none') 16199 $(this.jq).hide(); 16200 }, 16201 16202 isVisible: function() { 16203 return this.jq.is(':visible'); 16204 }, 16205 16206 toggle: function() { 16207 if(this.isVisible()) 16208 this.hide(); 16209 else 16210 this.show(); 16211 } 16212 16213}); 16214 16215/** 16216 * PrimeFaces Panel Widget 16217 */ 16218PrimeFaces.widget.Panel = PrimeFaces.widget.BaseWidget.extend({ 16219 16220 init: function(cfg) { 16221 this._super(cfg); 16222 this.header = this.jq.children('div.ui-panel-titlebar'); 16223 this.title = this.header.children('span.ui-panel-title'); 16224 this.content = $(this.jqId + '_content'); 16225 16226 this.bindEvents(); 16227 }, 16228 16229 bindEvents: function() { 16230 var $this = this; 16231 16232 if(this.cfg.toggleable) { 16233 this.bindToggler(); 16234 16235 if(this.cfg.toggleableHeader) { 16236 this.header.on('click', function() { 16237 if(!$this.isTitlebarClicked) { 16238 $this.toggle(); 16239 } 16240 16241 $this.isTitlebarClicked = false;
16242 }); 16243 } 16244 } 16245 16246 if(this.cfg.closable) { 16247 this.bindCloser(); 16248 } 16249 16250 if(this.cfg.hasMenu) { 16251 $(this.jqId + '_menu').on('click.panel', function(e) { 16252 e.preventDefault(); 16253 }); 16254 } 16255 16256 //visuals for action items 16257 this.header.find('.ui-panel-titlebar-icon').on('mouseover.panel',function() { 16258 $(this).addClass('ui-state-hover'); 16259 }).on('mouseout.panel',function() { 16260 $(this).removeClass('ui-state-hover'); 16261 }).on('click.panel', function(e) { 16262 var href = $(this).attr('href'); 16263 if(!href || href == '#') { 16264 e.preventDefault(); 16265 } 16266 16267 $this.isTitlebarClicked = true; 16268 }); 16269 }, 16270 16271 toggle: function() { 16272 if(this.cfg.collapsed) { 16273 this.expand(); 16274 PrimeFaces.invokeDeferredRenders(this.id); 16275 } 16276 else { 16277 this.collapse(); 16278 } 16279 }, 16280 16281 expand: function() { 16282 this.toggleState(false, 'ui-icon-plusthick', 'ui-icon-minusthick'); 16283 16284 if(this.cfg.toggleOrientation === 'vertical') 16285 this.slideDown(); 16286 else if(this.cfg.toggleOrientation === 'horizontal') 16287 this.slideRight(); 16288 }, 16289 16290 collapse: function() { 16291 this.toggleState(true, 'ui-icon-minusthick', 'ui-icon-plusthick'); 16292 16293 if(this.cfg.toggleOrientation === 'vertical') 16294 this.slideUp(); 16295 else if(this.cfg.toggleOrientation === 'horizontal') 16296 this.slideLeft(); 16297 }, 16298 16299 slideUp: function() { 16300 this.content.slideUp(this.cfg.toggleSpeed, 'easeInOutCirc'); 16301 }, 16302 16303 slideDown: function() { 16304 this.content.slideDown(this.cfg.toggleSpeed, 'easeInOutCirc'); 16305 }, 16306 16307 slideLeft: function() { 16308 var $this = this; 16309 16310 this.originalWidth = this.jq.width(); 16311 16312 this.title.hide(); 16313 this.toggler.hide(); 16314 this.content.hide(); 16315 16316 this.jq.animate({ 16317 width: '42px' 16318 }, this.cfg.toggleSpeed, 'easeInOutCirc', function() { 16319 $this.toggler.show(); 16320 $this.jq.addClass('ui-panel-collapsed-h'); 16321 }); 16322 }, 16323 16324 slideRight: function() { 16325 var $this = this, 16326 expandWidth = this.originalWidth||'100%'; 16327 16328 this.toggler.hide(); 16329 16330 this.jq.animate({ 16331 width: expandWidth 16332 }, this.cfg.toggleSpeed, 'easeInOutCirc', function() { 16333 $this.jq.removeClass('ui-panel-collapsed-h'); 16334 $this.title.show(); 16335 $this.toggler.show(); 16336 16337 $this.content.css({ 16338 'visibility': 'visible' 16339 ,'display': 'block' 16340 ,'height': 'auto' 16341 }); 16342 }); 16343 }, 16344 16345 toggleState: function(collapsed, removeIcon, addIcon) { 16346 this.toggler.children('span.ui-icon').removeClass(removeIcon).addClass(addIcon); 16347 this.cfg.collapsed = collapsed; 16348 this.toggleStateHolder.val(collapsed); 16349 16350 this.callBehavior('toggle'); 16351 }, 16352 16353 close: function() { 16354 if(this.visibleStateHolder) { 16355 this.visibleStateHolder.val(false); 16356 } 16357 16358 var $this = this; 16359 this.jq.fadeOut(this.cfg.closeSpeed, function(e) { 16360 if($this.hasBehavior('close')) { 16361 $this.callBehavior('close'); 16362 } 16363 }); 16364 }, 16365 16366 show: function() { 16367 var $this = this; 16368 $(this.jqId).fadeIn(this.cfg.closeSpeed, function() { 16369 PrimeFaces.invokeDeferredRenders($this.id); 16370 }); 16371 16372 this.visibleStateHolder.val(true); 16373 }, 16374 16375 bindToggler: function() { 16376 var $this = this; 16377 16378 this.toggler = $(this.jqId + '_toggler'); 16379 this.toggleStateHolder = $(this.jqId + '_collapsed'); 16380 16381 this.toggler.click(function() { 16382 $this.toggle(); 16383 16384 return false; 16385 }); 16386 }, 16387 16388 bindCloser: function() { 16389 var $this = this; 16390 16391 this.closer = $(this.jqId + '_closer'); 16392 this.visibleStateHolder = $(this.jqId + "_visible"); 16393 16394 this.closer.click(function(e) { 16395 $this.close(); 16396 e.preventDefault(); 16397 16398 return false;
16399 }); 16400 } 16401 16402}); 16403/** 16404 * PrimeFaces OrderList Widget 16405 */ 16406PrimeFaces.widget.OrderList = PrimeFaces.widget.BaseWidget.extend({ 16407 16408 init: function(cfg) { 16409 this._super(cfg); 16410 16411 this.list = this.jq.find('.ui-orderlist-list'), 16412 this.items = this.list.children('.ui-orderlist-item'); 16413 this.input = $(this.jqId + '_values'); 16414 this.cfg.effect = this.cfg.effect||'fade'; 16415 this.cfg.disabled = this.jq.hasClass('ui-state-disabled'); 16416 var $this = this; 16417 16418 if(!this.cfg.disabled) { 16419 this.generateItems(); 16420 16421 this.setupButtons(); 16422 16423 //Enable dnd 16424 this.list.sortable({ 16425 revert: 1, 16426 start: function(event, ui) { 16427 PrimeFaces.clearSelection(); 16428 } 16429 ,update: function(event, ui) { 16430 $this.onDragDrop(event, ui); 16431 } 16432 }); 16433 16434 this.bindEvents(); 16435 } 16436 }, 16437 16438 generateItems: function() { 16439 var $this = this; 16440 16441 this.list.children('.ui-orderlist-item').each(function() { 16442 var item = $(this), 16443 itemValue = item.data('item-value'), 16444 option = $('<option selected="selected"></option>'); 16445 16446 option.prop('value', itemValue).text(itemValue); 16447 $this.input.append(option); 16448 }); 16449 }, 16450 16451 bindEvents: function() { 16452 var $this = this; 16453 16454 if (PrimeFaces.env.browser.mobile) { 16455 var disabledSortable = function() { 16456 $this.list.sortable('disable'); 16457 $this.items.css('touch-action', 'auto'); 16458 }; 16459 16460 disabledSortable(); 16461 16462 this.items.on('touchend.orderList-mobile', function() { 16463 disabledSortable(); 16464 }) 16465 .on('click.orderList-mobile', function() { 16466 $this.list.sortable('enable'); 16467 }); 16468 } 16469 16470 this.items.on('mouseover.orderList', function(e) { 16471 var element = $(this); 16472 16473 if(!element.hasClass('ui-state-highlight')) 16474 $(this).addClass('ui-state-hover'); 16475 }) 16476 .on('mouseout.orderList', function(e) { 16477 var element = $(this); 16478 16479 if(!element.hasClass('ui-state-highlight')) 16480 $(this).removeClass('ui-state-hover'); 16481 }) 16482 .on('mousedown.orderList', function(e) { 16483 var element = $(this), 16484 metaKey = (e.metaKey||e.ctrlKey); 16485 16486 if(!metaKey) { 16487 element.removeClass('ui-state-hover').addClass('ui-state-highlight') 16488 .siblings('.ui-state-highlight').removeClass('ui-state-highlight'); 16489 16490 $this.fireItemSelectEvent(element, e); 16491 } 16492 else { 16493 if(element.hasClass('ui-state-highlight')) { 16494 element.removeClass('ui-state-highlight'); 16495 $this.fireItemUnselectEvent(element); 16496 } 16497 else { 16498 element.removeClass('ui-state-hover').addClass('ui-state-highlight'); 16499 $this.fireItemSelectEvent(element, e); 16500 } 16501 } 16502 }); 16503 }, 16504 16505 setupButtons: function() { 16506 var $this = this; 16507 16508 PrimeFaces.skinButton(this.jq.find('.ui-button')); 16509 16510 this.jq.find(' .ui-orderlist-controls .ui-orderlist-button-move-up').click(function() {$this.moveUp($this.sourceList);}); 16511 this.jq.find(' .ui-orderlist-controls .ui-orderlist-button-move-top').click(function() {$this.moveTop($this.sourceList);}); 16512 this.jq.find(' .ui-orderlist-controls .ui-orderlist-button-move-down').click(function() {$this.moveDown($this.sourceList);}); 16513 this.jq.find(' .ui-orderlist-controls .ui-orderlist-button-move-bottom').click(function() {$this.moveBottom($this.sourceList);}); 16514 }, 16515 16516 onDragDrop: function(event, ui) { 16517 ui.item.removeClass('ui-state-highlight'); 16518 this.saveState(); 16519 this.fireReorderEvent(); 16520 }, 16521 16522 saveState: function() { 16523 this.input.children().remove(); 16524 16525 this.generateItems(); 16526 }, 16527 16528 moveUp: function() { 16529 var $this = this, 16530 selectedItems = $this.list.children('.ui-orderlist-item.ui-state-highlight'), 16531 itemsToMoveCount = selectedItems.length, 16532 movedItemsCount = 0, 16533 hasFirstChild = selectedItems.is(':first-child'); 16534 16535 if(hasFirstChild) { 16536 return; 16537 } 16538 16539 selectedItems.each(function() { 16540 var item = $(this); 16541 16542 if(!item.is(':first-child')) { 16543 item.hide($this.cfg.effect, {}, 'fast', function() { 16544 item.insertBefore(item.prev()).show($this.cfg.effect, {}, 'fast', function() { 16545 movedItemsCount++; 16546 16547 if(itemsToMoveCount === movedItemsCount) { 16548 $this.saveState(); 16549 $this.fireReorderEvent(); 16550 } 16551 }); 16552 }); 16553 } 16554 else { 16555 itemsToMoveCount--; 16556 } 16557 }); 16558 }, 16559 16560 moveTop: function() { 16561 var $this = this, 16562 selectedItems = $this.list.children('.ui-orderlist-item.ui-state-highlight'), 16563 itemsToMoveCount = selectedItems.length, 16564 movedItemsCount = 0, 16565 hasFirstChild = selectedItems.is(':first-child'), 16566 firstSelectedItemIndex = selectedItems.eq(0).index(); 16567 16568 if(hasFirstChild) { 16569 return; 16570 } 16571 16572 selectedItems.each(function(index) { 16573 var item = $(this), 16574 currentIndex = (index === 0) ? 0 : (item.index() - firstSelectedItemIndex); 16575 16576 if(!item.is(':first-child')) { 16577 item.hide($this.cfg.effect, {}, 'fast', function() { 16578 item.insertBefore($this.list.children('.ui-orderlist-item').eq(currentIndex)).show($this.cfg.effect, {}, 'fast', function(){ 16579 movedItemsCount++; 16580 16581 if(itemsToMoveCount === movedItemsCount) { 16582 $this.saveState(); 16583 $this.fireReorderEvent(); 16584 } 16585 }); 16586 }); 16587 } 16588 else { 16589 itemsToMoveCount--; 16590 } 16591 }); 16592 }, 16593 16594 moveDown: function() { 16595 var $this = this, 16596 selectedItems = $($this.list.children('.ui-orderlist-item.ui-state-highlight').get().reverse()), 16597 itemsToMoveCount = selectedItems.length, 16598 movedItemsCount = 0, 16599 hasFirstChild = selectedItems.is(':last-child'); 16600 16601 if(hasFirstChild) { 16602 return; 16603 } 16604 16605 selectedItems.each(function() { 16606 var item = $(this); 16607 16608 if(!item.is(':last-child')) { 16609 item.hide($this.cfg.effect, {}, 'fast', function() { 16610 item.insertAfter(item.next()).show($this.cfg.effect, {}, 'fast', function() { 16611 movedItemsCount++; 16612 16613 if(itemsToMoveCount === movedItemsCount) { 16614 $this.saveState(); 16615 $this.fireReorderEvent(); 16616 } 16617 }); 16618 }); 16619 } 16620 else { 16621 itemsToMoveCount--; 16622 } 16623 }); 16624 }, 16625 16626 moveBottom: function() { 16627 var $this = this, 16628 selectedItems = $($this.list.children('.ui-orderlist-item.ui-state-highlight').get().reverse()), 16629 itemsToMoveCount = selectedItems.length, 16630 movedItemsCount = 0, 16631 hasFirstChild = selectedItems.is(':last-child'), 16632 lastSelectedItemIndex = selectedItems.eq(0).index(), 16633 itemsLength = this.items.length; 16634 16635 if(hasFirstChild) { 16636 return; 16637 } 16638 16639 selectedItems.each(function(index) { 16640 var item = $(this), 16641 currentIndex = (index === 0) ? itemsLength - 1 : (item.index() - lastSelectedItemIndex) - 1; 16642 16643 if(!item.is(':last-child')) { 16644 item.hide($this.cfg.effect, {}, 'fast', function() { 16645 item.insertAfter($this.list.children('.ui-orderlist-item').eq(currentIndex)).show($this.cfg.effect, {}, 'fast', function() { 16646 movedItemsCount++; 16647 16648 if(itemsToMoveCount === movedItemsCount) { 16649 $this.saveState(); 16650 $this.fireReorderEvent(); 16651 } 16652 }); 16653 }); 16654 } 16655 else { 16656 itemsToMoveCount--; 16657 } 16658 }); 16659 }, 16660 16661 fireItemSelectEvent: function(item, e) { 16662 if(this.hasBehavior('select')) { 16663 var ext = { 16664 params: [ 16665 {name: this.id + '_itemIndex', value: item.index()}, 16666 {name: this.id + '_metaKey', value: e.metaKey}, 16667 {name: this.id + '_ctrlKey', value: e.ctrlKey} 16668 ] 16669 }; 16670 16671 this.callBehavior('select', ext); 16672 } 16673 }, 16674 16675 fireItemUnselectEvent: function(item) { 16676 if(this.hasBehavior('unselect')) { 16677 var ext = { 16678 params: [ 16679 {name: this.id + '_itemIndex', value: item.index()} 16680 ] 16681 }; 16682 16683 this.callBehavior('unselect', ext); 16684 } 16685 }, 16686 16687 fireReorderEvent: function() { 16688 if(this.hasBehavior('reorder')) { 16689 this.callBehavior('reorder'); 16690 } 16691 } 16692 16693}); 16694/** 16695 * PrimeFaces OutputPanel Widget 16696 */ 16697PrimeFaces.widget.OutputPanel = PrimeFaces.widget.BaseWidget.extend({ 16698 16699 init: function(cfg) { 16700 this._super(cfg); 16701 this.cfg.global = this.cfg.global||false; 16702 16703 if(this.cfg.deferred) { 16704 if(this.cfg.deferredMode === 'load') { 16705 this.loadContent(); 16706 } 16707 else if(this.cfg.deferredMode === 'visible') { 16708 if(this.visible()) 16709 this.loadContent(); 16710 else 16711 this.bindScrollMonitor(); 16712 } 16713 } 16714 }, 16715 16716 loadContent: function() { 16717 var $this = this, 16718 options = { 16719 source: this.id, 16720 process: this.id, 16721 update: this.id, 16722 async: true,
16723 ignoreAutoUpdate: true, 16724 global: false, 16725 params: [ 16726 {name: this.id + '_load', value: true} 16727 ], 16728 onsuccess: function(responseXML, status, xhr) { 16729 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 16730 widget: $this, 16731 handle: function(content) { 16732 $this.jq.html(content); 16733 } 16734 }); 16735 16736 return true; 16737 }, 16738 onerror: function(xhr, status, errorThrown) { 16739 $this.jq.html(''); 16740 } 16741 }; 16742 16743 if(this.hasBehavior('load')) { 16744 this.callBehavior('load', options); 16745 } 16746 else { 16747 PrimeFaces.ajax.Request.handle(options); 16748 } 16749 }, 16750 16751 bindScrollMonitor: function() { 16752 var $this = this; 16753 16754 PrimeFaces.utils.registerScrollHandler(this, 'scroll.' + this.id + '_align', function() { 16755 if ($this.visible()) { 16756 PrimeFaces.utils.unbindScrollHandler($this, 'scroll.' + $this.id + '_align'); 16757 $this.loadContent(); 16758 } 16759 }); 16760 }, 16761 16762 visible: function() { 16763 var win = $(window), 16764 scrollTop = win.scrollTop(), 16765 height = win.height(), 16766 top = this.jq.offset().top, 16767 bottom = top + this.jq.innerHeight(); 16768 16769 if((top >= scrollTop && top <= (scrollTop + height)) || (bottom >= scrollTop && bottom <= (scrollTop + height))) { 16770 return true; 16771 } 16772 } 16773}); 16774/** 16775 * PrimeFaces OverlayPanel Widget 16776 */ 16777PrimeFaces.widget.OverlayPanel = PrimeFaces.widget.DynamicOverlayWidget.extend({ 16778 16779 init: function(cfg) { 16780 this._super(cfg); 16781 16782 this.content = this.jq.children('div.ui-overlaypanel-content'); 16783 16784 //configuration 16785 this.cfg.my = this.cfg.my||'left top'; 16786 this.cfg.at = this.cfg.at||'left bottom'; 16787 this.cfg.collision = this.cfg.collision||'flip'; 16788 this.cfg.showEvent = this.cfg.showEvent||'click.ui-overlaypanel'; 16789 this.cfg.hideEvent = this.cfg.hideEvent||'click.ui-overlaypanel'; 16790 this.cfg.dismissable = (this.cfg.dismissable === false) ? false : true; 16791 this.cfg.showDelay = this.cfg.showDelay || 0; 16792 16793 if(this.cfg.showCloseIcon) { 16794 this.closerIcon = $('<a href="#" class="ui-overlaypanel-close ui-state-default"><span class="ui-icon ui-icon-closethick"></span></a>') 16795 .attr('aria-label', PrimeFaces.getAriaLabel('overlaypanel.CLOSE')).appendTo(this.jq); 16796 } 16797 16798 this.bindCommonEvents(); 16799 16800 if(this.cfg.target) { 16801 this.target = PrimeFaces.expressions.SearchExpressionFacade.resolveComponentsAsSelector(this.cfg.target); 16802 this.bindTargetEvents(); 16803 16804 // set aria attributes 16805 this.target.attr({ 16806 'aria-expanded': false, 16807 'aria-controls': this.id 16808 }); 16809 16810 //dialog support 16811 this.setupDialogSupport(); 16812 } 16813 }, 16814 16815 //@Override 16816 refresh: function(cfg) { 16817 this._super(cfg); 16818 16819 // fix #4307 16820 this.loaded = false; 16821 16822 // see #setupDialogSupport 16823 if (!this.cfg.appendTo) { 16824 PrimeFaces.utils.removeDynamicOverlay(this, this.jq, this.id, $(document.body)); 16825 } 16826 }, 16827 16828 //@Override 16829 destroy: function() { 16830 this._super(); 16831 16832 // see #setupDialogSupport 16833 if (!this.cfg.appendTo) { 16834 PrimeFaces.utils.removeDynamicOverlay(this, this.jq, this.id, $(document.body)); 16835 } 16836 }, 16837 16838 bindTargetEvents: function() { 16839 var $this = this; 16840 16841 //mark target and descandants of target as a trigger for a primefaces overlay 16842 this.target.data('primefaces-overlay-target', this.id).find('*').data('primefaces-overlay-target', this.id); 16843 16844 //show and hide events for target 16845 if(this.cfg.showEvent === this.cfg.hideEvent) { 16846 var event = this.cfg.showEvent; 16847 16848 this.target.on(event, function(e) { 16849 $this.toggle(); 16850 }); 16851 } 16852 else { 16853 var showEvent = this.cfg.showEvent + '.ui-overlaypanel', 16854 hideEvent = this.cfg.hideEvent + '.ui-overlaypanel'; 16855 16856 this.target.off(showEvent + ' ' + hideEvent).on(showEvent, function(e) { 16857 if(!$this.isVisible()) { 16858 $this.show(); 16859 if(showEvent === 'contextmenu.ui-overlaypanel') { 16860 e.preventDefault(); 16861 } 16862 } 16863 }) 16864 .on(hideEvent, function(e) { 16865 clearTimeout($this.showTimeout); 16866 if($this.isVisible()) { 16867 $this.hide(); 16868 } 16869 }); 16870 } 16871 16872 $this.target.off('keydown.ui-overlaypanel keyup.ui-overlaypanel') 16873 .on('keydown.ui-overlaypanel', PrimeFaces.utils.blockEnterKey) 16874 .on('keyup.ui-overlaypanel', function(e) { 16875 var keyCode = $.ui.keyCode, key = e.which; 16876 16877 if(key === keyCode.ENTER) { 16878 $this.toggle(); 16879 e.preventDefault(); 16880 } 16881 }); 16882 16883 }, 16884 16885 bindCommonEvents: function() { 16886 var $this = this; 16887 16888 if(this.cfg.showCloseIcon) { 16889 this.closerIcon.on('mouseover.ui-overlaypanel', function() { 16890 $(this).addClass('ui-state-hover'); 16891 }) 16892 .on('mouseout.ui-overlaypanel', function() { 16893 $(this).removeClass('ui-state-hover'); 16894 }) 16895 .on('click.ui-overlaypanel', function(e) { 16896 $this.hide(); 16897 e.preventDefault(); 16898 }) 16899 .on('focus.ui-overlaypanel', function() { 16900 $(this).addClass('ui-state-focus'); 16901 }) 16902 .on('blur.ui-overlaypanel', function() { 16903 $(this).removeClass('ui-state-focus'); 16904 }); 16905 } 16906 16907 //hide overlay when mousedown is at outside of overlay 16908 if(this.cfg.dismissable && !this.cfg.modal) { 16909 PrimeFaces.utils.registerHideOverlayHandler(this, 'mousedown.' + this.id + '_hide', $this.jq, 16910 function() { return $this.target; }, 16911 function(e, eventTarget) { 16912 if(!($this.jq.is(eventTarget) || $this.jq.has(eventTarget).length > 0 || eventTarget.closest('.ui-input-overlay').length > 0)) { 16913 $this.hide(); 16914 } 16915 }); 16916 } 16917 16918 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 16919 $this.align(); 16920 }); 16921 }, 16922 16923 toggle: function() { 16924 if(!this.isVisible()) { 16925 this.show(); 16926 } 16927 else { 16928 clearTimeout(this.showTimeout); 16929 this.hide(); 16930 } 16931 }, 16932 16933 show: function(target) { 16934 var thisPanel = this; 16935 this.showTimeout = setTimeout(function() { 16936 if (!thisPanel.loaded && thisPanel.cfg.dynamic) { 16937 thisPanel.loadContents(target); 16938 } 16939 else { 16940 thisPanel._show(target); 16941 } 16942 }, this.cfg.showDelay); 16943 }, 16944 16945 _show: function(target) { 16946 var $this = this; 16947 16948 this.align(target); 16949 16950 //replace visibility hidden with display none for effect support, toggle marker class 16951 this.jq.removeClass('ui-overlay-hidden').addClass('ui-overlay-visible').css({ 16952 'display':'none' 16953 }); 16954 16955 if(this.cfg.showEffect) { 16956 this.jq.show(this.cfg.showEffect, {}, 200, function() { 16957 $this.postShow(); 16958 }); 16959 } 16960 else { 16961 this.jq.show(); 16962 this.postShow(); 16963 } 16964 16965 if(this.cfg.modal) { 16966 this.enableModality(); 16967 } 16968 }, 16969 16970 align: function(target) { 16971 var win = $(window); 16972 16973 if (target) { 16974 if (typeof target === 'string') { 16975 this.targetElement = $(document.getElementById(target)); 16976 } 16977 else if (target instanceof $) { 16978 this.targetElement = target; 16979 } 16980 } 16981 else if (this.target) { 16982 this.targetElement = this.target; 16983 } 16984 16985 if (this.targetElement) { 16986 this.targetZindex = this.targetElement.zIndex(); 16987 } 16988 16989 this.jq.css({'left':'', 'top':'', 'z-index': ++PrimeFaces.zindex}) 16990 .position({ 16991 my: this.cfg.my 16992 ,at: this.cfg.at 16993 ,of: this.targetElement 16994 ,collision: this.cfg.collision 16995 }); 16996 16997 var widthOffset = this.jq.width() - this.content.width(); 16998 this.jq.css('max-width', win.width() - widthOffset + 'px'); 16999 }, 17000 17001 hide: function() { 17002 var $this = this; 17003 17004 if(this.cfg.hideEffect) { 17005 this.jq.hide(this.cfg.hideEffect, {}, 200, function() { 17006 if($this.cfg.modal) { 17007 $this.disableModality(); 17008 } 17009 $this.postHide(); 17010 }); 17011 } 17012 else { 17013 this.jq.hide(); 17014 if($this.cfg.modal) { 17015 $this.disableModality(); 17016 } 17017 this.postHide(); 17018 } 17019 }, 17020 17021 postShow: function() { 17022 17023 this.callBehavior('show'); 17024 17025 if(this.cfg.onShow) { 17026 this.cfg.onShow.call(this); 17027 } 17028 17029 this.applyFocus(); 17030 17031 if (this.target) { 17032 this.target.attr('aria-expanded', true); 17033 } 17034 }, 17035 17036 postHide: function() { 17037 //replace display block with visibility hidden for hidden container support, toggle marker class 17038 this.jq.removeClass('ui-overlay-visible').addClass('ui-overlay-hidden').css({ 17039 'display':'block' 17040 }); 17041 17042 this.callBehavior('hide'); 17043 17044 if(this.cfg.onHide) { 17045 this.cfg.onHide.call(this); 17046 } 17047 17048 if (this.target) { 17049 this.target.attr('aria-expanded', false); 17050 } 17051 }, 17052 17053 setupDialogSupport: function() { 17054 var dialog = this.target[0].closest('.ui-dialog'); 17055 if (dialog) { 17056 var $dialog = $(dialog); 17057 if ($dialog.length == 1) { 17058 //set position as fixed to scroll with dialog 17059 if($dialog.css('position') === 'fixed') { 17060 this.jq.css('position', 'fixed'); 17061 } 17062 17063 //append to body if not already appended by user choice 17064 if(!this.cfg.appendTo) { 17065 this.jq.appendTo(document.body); 17066 } 17067 } 17068 } 17069 }, 17070 17071 loadContents: function(target) { 17072 var $this = this, 17073 options = { 17074 source: this.id, 17075 process: this.id, 17076 update: this.id, 17077 params: [ 17078 {name: this.id + '_contentLoad', value: true} 17079 ], 17080 onsuccess: function(responseXML, status, xhr) { 17081 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 17082 widget: $this, 17083 handle: function(content) { 17084 this.content.html(content); 17085 this.loaded = true; 17086 } 17087 }); 17088 17089 return true; 17090 }, 17091 oncomplete: function() { 17092 $this._show(target); 17093 } 17094 }; 17095 17096 PrimeFaces.ajax.Request.handle(options); 17097 }, 17098 17099 isVisible: function() { 17100 return this.jq.hasClass('ui-overlay-visible'); 17101 }, 17102 17103 applyFocus: function() { 17104 this.jq.find(':not(:submit):not(:button):input:visible:enabled:first').focus(); 17105 }, 17106 17107 //@override 17108 enableModality: function() { 17109 this._super(); 17110 17111 if(this.targetElement) { 17112 this.targetElement.css('z-index', this.jq.css('z-index')); 17113 } 17114 }, 17115 17116 //@override 17117 disableModality: function(){ 17118 this._super(); 17119 17120 if(this.targetElement) { 17121 this.targetElement.css('z-index', this.targetZindex); 17122 } 17123 }, 17124 17125 //@override 17126 getModalTabbables: function(){ 17127 var tabbables = this.jq.find(':tabbable'); 17128 17129 if (this.targetElement && this.targetElement.is(':tabbable')) { 17130 tabbables = tabbables.add(this.targetElement); 17131 } 17132 17133 return tabbables; 17134 } 17135}); 17136 17137PrimeFaces.widget.Paginator = PrimeFaces.widget.BaseWidget.extend({ 17138 17139 init: function(cfg) { 17140 this.cfg = cfg; 17141 this.jq = $(); 17142 17143 var _self = this; 17144 $.each(this.cfg.id, function(index, id){ 17145 _self.jq = _self.jq.add($(PrimeFaces.escapeClientId(id))); 17146 }); 17147 17148 //elements 17149 this.pagesContainer = this.jq.children('.ui-paginator-pages'); 17150 this.pageLinks = this.pagesContainer.children('.ui-paginator-page'); 17151 this.rppSelect = this.jq.children('.ui-paginator-rpp-options'); 17152 this.jtpSelect = this.jq.children('.ui-paginator-jtp-select');
17153 this.jtpInput = this.jq.children('.ui-paginator-jtp-input'); 17154 this.firstLink = this.jq.children('.ui-paginator-first'); 17155 this.prevLink = this.jq.children('.ui-paginator-prev'); 17156 this.nextLink = this.jq.children('.ui-paginator-next'); 17157 this.endLink = this.jq.children('.ui-paginator-last'); 17158 this.currentReport = this.jq.children('.ui-paginator-current'); 17159 17160 //metadata 17161 this.cfg.rows = this.cfg.rows == 0 ? this.cfg.rowCount : this.cfg.rows; 17162 this.cfg.prevRows = this.cfg.rows; 17163 this.cfg.pageCount = Math.ceil(this.cfg.rowCount / this.cfg.rows)||1; 17164 this.cfg.pageLinks = this.cfg.pageLinks||10; 17165 this.cfg.currentPageTemplate = this.cfg.currentPageTemplate||'({currentPage} of {totalPages})'; 17166 17167 //aria message 17168 this.cfg.ariaPageLabel = PrimeFaces.getAriaLabel('paginator.PAGE'); 17169 17170 //event bindings 17171 this.bindEvents(); 17172 }, 17173 17174 bindEvents: function(){ 17175 var $this = this; 17176 17177 //visuals for first,prev,next,last buttons 17178 this.jq.children('a.ui-state-default').on('mouseover.paginator', function(){ 17179 var item = $(this); 17180 if(!item.hasClass('ui-state-disabled')) { 17181 item.addClass('ui-state-hover'); 17182 } 17183 }) 17184 .on('mouseout.paginator', function() { 17185 $(this).removeClass('ui-state-hover'); 17186 }) 17187 .on('focus.paginator', function() { 17188 var item = $(this); 17189 if(!item.hasClass('ui-state-disabled')) { 17190 item.addClass('ui-state-focus'); 17191 } 17192 }) 17193 .on('blur.paginator', function() { 17194 $(this).removeClass('ui-state-focus'); 17195 }) 17196 .on('keydown.paginator', function(e) { 17197 var key = e.which, 17198 keyCode = $.ui.keyCode; 17199 17200 if((key === keyCode.ENTER)) { 17201 $(this).trigger('click'); 17202 e.preventDefault(); 17203 } 17204 }); 17205 17206 //page links 17207 this.bindPageLinkEvents(); 17208 17209 //records per page selection 17210 PrimeFaces.skinSelect(this.rppSelect); 17211 this.rppSelect.change(function(e) { 17212 if(!$(this).hasClass("ui-state-disabled")){ 17213 $this.setRowsPerPage($(this).val()); 17214 } 17215 }); 17216 17217 //jump to page dropdown 17218 PrimeFaces.skinSelect(this.jtpSelect); 17219 this.jtpSelect.change(function(e) { 17220 if(!$(this).hasClass("ui-state-disabled")){ 17221 $this.setPage(parseInt($(this).val())); 17222 } 17223 }); 17224 17225 //jump to page input 17226 PrimeFaces.skinInput(this.jtpInput); 17227 this.jtpInput.change(function(e) { 17228 if(!$(this).hasClass("ui-state-disabled")){ 17229 var page = parseInt($(this).val()); 17230 if (isNaN(page) || page > $this.cfg.pageCount || page < 1) { 17231 // restore old value if invalid 17232 $(this).val($this.cfg.page + 1); 17233 } 17234 else { 17235 $this.setPage(page - 1); 17236 } 17237 } 17238 }); 17239 17240 //First page link 17241 this.firstLink.click(function(e) { 17242 PrimeFaces.clearSelection(); 17243 17244 if(!$(this).hasClass("ui-state-disabled")){ 17245 $this.setPage(0); 17246 } 17247 17248 e.preventDefault(); 17249 }); 17250 17251 //Prev page link 17252 this.prevLink.click(function(e) { 17253 PrimeFaces.clearSelection(); 17254 17255 if(!$(this).hasClass("ui-state-disabled")){ 17256 $this.setPage($this.cfg.page - 1); 17257 } 17258 17259 e.preventDefault(); 17260 }); 17261 17262 //Next page link 17263 this.nextLink.click(function(e) { 17264 PrimeFaces.clearSelection(); 17265 17266 if(!$(this).hasClass("ui-state-disabled")){ 17267 $this.setPage($this.cfg.page + 1); 17268 } 17269 17270 e.preventDefault(); 17271 }); 17272 17273 //Last page link 17274 this.endLink.click(function(e) { 17275 PrimeFaces.clearSelection(); 17276 17277 if(!$(this).hasClass("ui-state-disabled")){ 17278 $this.setPage($this.cfg.pageCount - 1); 17279 } 17280 17281 e.preventDefault(); 17282 }); 17283 }, 17284 17285 bindPageLinkEvents: function(){ 17286 var $this = this, 17287 pageLinks = this.pagesContainer.children('.ui-paginator-page'); 17288 17289 pageLinks.each(function() { 17290 var link = $(this), 17291 pageNumber = parseInt(link.text()); 17292 17293 link.attr('aria-label', $this.cfg.ariaPageLabel.replace('{0}', (pageNumber))); 17294 }); 17295 17296 pageLinks.on('click.paginator', function(e) { 17297 var link = $(this), 17298 pageNumber = parseInt(link.text()); 17299 17300 if(!link.hasClass('ui-state-disabled')&&!link.hasClass('ui-state-active')) { 17301 $this.setPage(pageNumber - 1); 17302 } 17303 17304 e.preventDefault(); 17305 }) 17306 .on('mouseover.paginator', function() { 17307 var item = $(this); 17308 if(!item.hasClass('ui-state-disabled')&&!item.hasClass('ui-state-active')) { 17309 item.addClass('ui-state-hover'); 17310 } 17311 }) 17312 .on('mouseout.paginator', function() { 17313 $(this).removeClass('ui-state-hover'); 17314 }) 17315 .on('focus.paginator', function() { 17316 $(this).addClass('ui-state-focus'); 17317 }) 17318 .on('blur.paginator', function() { 17319 $(this).removeClass('ui-state-focus'); 17320 }) 17321 .on('keydown.paginator', function(e) { 17322 var key = e.which, 17323 keyCode = $.ui.keyCode; 17324 17325 if((key === keyCode.ENTER)) { 17326 $(this).trigger('click'); 17327 e.preventDefault(); 17328 } 17329 }); 17330 }, 17331 17332 /** 17333 * Binds swipe events to this paginator to the JQ element passed in. 17334 * 17335 * @param owner the owner of the paginator 17336 */ 17337 bindSwipeEvents: function(owner) { 17338 if (!PrimeFaces.env.touch) { 17339 return; 17340 } 17341 var $this = this; 17342 owner.swipe({ 17343 swipeLeft:function(event) { 17344 $this.prev(); 17345 }, 17346 swipeRight: function(event) { 17347 $this.next(); 17348 }, 17349 excludedElements: PrimeFaces.utils.excludedSwipeElements() 17350 }); 17351 }, 17352 17353 unbindEvents: function() { 17354 var buttons = this.jq.children('a.ui-state-default'); 17355 if (buttons.length > 0) { 17356 buttons.off(); 17357 } 17358 var pageLinks = this.pagesContainer.children('.ui-paginator-page'); 17359 if (pageLinks.length > 0) { 17360 pageLinks.off(); 17361 } 17362 }, 17363 17364 updateUI: function() { 17365 //boundaries 17366 if(this.cfg.page === 0) { 17367 this.disableElement(this.firstLink); 17368 this.disableElement(this.prevLink); 17369 } 17370 else { 17371 this.enableElement(this.firstLink); 17372 this.enableElement(this.prevLink); 17373 } 17374 17375 if(this.cfg.page === (this.cfg.pageCount - 1)) { 17376 this.disableElement(this.nextLink); 17377 this.disableElement(this.endLink); 17378 } 17379 else { 17380 this.enableElement(this.nextLink); 17381 this.enableElement(this.endLink); 17382 } 17383 17384 //current page report 17385 var startRecord = (this.cfg.rowCount === 0) ? 0 : (this.cfg.page * this.cfg.rows) + 1, 17386 endRecord = (this.cfg.page * this.cfg.rows) + this.cfg.rows; 17387 if(endRecord > this.cfg.rowCount) { 17388 endRecord = this.cfg.rowCount; 17389 } 17390 17391 var text = this.cfg.currentPageTemplate 17392 .replace("{currentPage}", this.cfg.page + 1) 17393 .replace("{totalPages}", this.cfg.pageCount) 17394 .replace("{totalRecords}", this.cfg.rowCount) 17395 .replace("{startRecord}", startRecord) 17396 .replace("{endRecord}", endRecord); 17397 this.currentReport.text(text); 17398 17399 //rows per page dropdown 17400 if(this.cfg.prevRows !== this.cfg.rows) { 17401 this.rppSelect.filter(':not(.ui-state-focus)').children('option').filter('option[value="' + $.escapeSelector(this.cfg.rows) + '"]').prop('selected', true); 17402 this.cfg.prevRows = this.cfg.rows; 17403 } 17404 17405 //jump to page dropdown 17406 if(this.jtpSelect.length > 0) { 17407 if(this.jtpSelect[0].options.length != this.cfg.pageCount){ 17408 var jtpOptions = ''; 17409 for(var i = 0; i < this.cfg.pageCount; i++) { 17410 jtpOptions += '<option value="' + i + '">' + (i + 1) + '</option>'; 17411 } 17412 17413 this.jtpSelect.html(jtpOptions); 17414 } 17415 this.jtpSelect.children('option[value=' + this.cfg.page + ']').prop('selected','selected'); 17416 } 17417 17418 //jump to page input 17419 if(this.jtpInput.length > 0) { 17420 this.jtpInput.val(this.cfg.page + 1); 17421 } 17422 17423 //page links 17424 this.updatePageLinks(); 17425 }, 17426 17427 updatePageLinks: function() { 17428 var start, end, delta, 17429 focusedElement = $(document.activeElement), 17430 focusContainer; 17431 17432 if(focusedElement.hasClass('ui-paginator-page')) { 17433 var pagesContainerIndex = this.pagesContainer.index(focusedElement.parent()); 17434 if(pagesContainerIndex >= 0) { 17435 focusContainer = this.pagesContainer.eq(pagesContainerIndex); 17436 } 17437 } 17438 17439 //calculate visible page links
17440 this.cfg.pageCount = Math.ceil(this.cfg.rowCount / this.cfg.rows)||1; 17441 var visiblePages = Math.min(this.cfg.pageLinks, this.cfg.pageCount); 17442 17443 //calculate range, keep current in middle if necessary 17444 start = Math.max(0, Math.ceil(this.cfg.page - ((visiblePages) / 2))); 17445 end = Math.min(this.cfg.pageCount - 1, start + visiblePages - 1); 17446 17447 //check when approaching to last page 17448 delta = this.cfg.pageLinks - (end - start + 1); 17449 start = Math.max(0, start - delta); 17450 17451 //update dom 17452 this.pagesContainer.children().remove(); 17453 for(var i = start; i <= end; i++) { 17454 var styleClass = 'ui-paginator-page ui-state-default ui-corner-all', 17455 ariaLabel = this.cfg.ariaPageLabel.replace('{0}', (i+1)); 17456 17457 if(this.cfg.page == i) { 17458 styleClass += " ui-state-active"; 17459 } 17460 17461 this.pagesContainer.append('<a class="' + styleClass + '" aria-label="' + ariaLabel + '" tabindex="0" href="#">' + (i + 1) + '</a>'); 17462 } 17463 17464 if(focusContainer) { 17465 focusContainer.children().filter('.ui-state-active').trigger('focus'); 17466 } 17467 17468 this.bindPageLinkEvents(); 17469 }, 17470 17471 setPage: function(p, silent) { 17472 if(p >= 0 && p < this.cfg.pageCount && this.cfg.page != p){ 17473 var newState = { 17474 first: this.cfg.rows * p, 17475 rows: this.cfg.rows, 17476 page: p 17477 }; 17478 17479 if(silent) { 17480 this.cfg.page = p; 17481 this.updateUI(); 17482 } 17483 else { 17484 this.cfg.paginate.call(this, newState); 17485 } 17486 } 17487 }, 17488 17489 setRowsPerPage: function(rpp) { 17490 if (rpp === '*') { 17491 this.cfg.rows = this.cfg.rowCount; 17492 this.cfg.pageCount = 1; 17493 this.cfg.page = 0; 17494 17495 var newState = { 17496 first: 0, 17497 rows: rpp, 17498 page: this.cfg.page 17499 }; 17500 17501 this.cfg.paginate.call(this, newState); 17502 } 17503 else { 17504 var first = this.cfg.rows * this.cfg.page; 17505 this.cfg.rows = parseInt(rpp); 17506 var page = parseInt(first / this.cfg.rows); 17507 17508 this.cfg.pageCount = Math.ceil(this.cfg.rowCount / this.cfg.rows); 17509 this.cfg.page = -1; 17510 17511 this.setPage(page); 17512 } 17513 }, 17514 17515 setTotalRecords: function(value) { 17516 this.cfg.rowCount = value; 17517 this.cfg.pageCount = Math.ceil(value / this.cfg.rows)||1; 17518 this.cfg.page = 0; 17519 this.updateUI(); 17520 }, 17521 17522 updateTotalRecords: function(value) { 17523 this.cfg.rowCount = value; 17524 this.cfg.pageCount = Math.ceil(value / this.cfg.rows)||1; 17525 this.updateUI(); 17526 }, 17527 17528 getCurrentPage: function() { 17529 return this.cfg.page; 17530 }, 17531 17532 getFirst: function() { 17533 return (this.cfg.rows * this.cfg.page); 17534 }, 17535 17536 getRows: function() { 17537 return this.cfg.rows; 17538 }, 17539 17540 getContainerHeight: function(margin) { 17541 var height = 0; 17542 17543 for(var i = 0; i < this.jq.length; i++) { 17544 height += this.jq.eq(i).outerHeight(margin); 17545 } 17546 17547 return height; 17548 }, 17549 17550 disableElement: function(element) { 17551 element.removeClass('ui-state-hover ui-state-focus ui-state-active').addClass('ui-state-disabled').attr('tabindex', -1); 17552 element.removeClass('ui-state-hover ui-state-focus ui-state-active').addClass('ui-state-disabled').attr('tabindex', -1); 17553 }, 17554 17555 enableElement: function(element) { 17556 element.removeClass('ui-state-disabled').attr('tabindex', 0); 17557 }, 17558 17559 next: function() { 17560 this.setPage(this.cfg.page + 1); 17561 }, 17562 17563 prev: function() { 17564 this.setPage(this.cfg.page - 1); 17565 } 17566}); 17567 17568/** 17569 * PrimeFaces PickList Widget 17570 */ 17571PrimeFaces.widget.PickList = PrimeFaces.widget.BaseWidget.extend({ 17572 17573 init: function(cfg) { 17574 this._super(cfg); 17575 17576 this.sourceList = this.jq.find('ul.ui-picklist-source'); 17577 this.targetList = this.jq.find('ul.ui-picklist-target'); 17578 this.sourceInput = $(this.jqId + '_source'); 17579 this.targetInput = $(this.jqId + '_target'); 17580 this.items = this.jq.find('.ui-picklist-item:not(.ui-state-disabled)'); 17581 if(this.cfg.showCheckbox) { 17582 this.checkboxes = this.items.find('div.ui-chkbox > div.ui-chkbox-box'); 17583 } 17584 this.focusedItem = null; 17585 this.ariaRegion = $(this.jqId + '_ariaRegion'); 17586 17587 var sourceCaption = this.sourceList.prev('.ui-picklist-caption'), 17588 targetCaption = this.targetList.prev('.ui-picklist-caption'); 17589 17590 if(sourceCaption.length) { 17591 var captionText = sourceCaption.text(); 17592 17593 this.sourceList.attr('aria-label', captionText);
17594 this.sourceInput.attr('title', captionText); 17595 } 17596 17597 if(targetCaption.length) { 17598 var captionText = targetCaption.text(); 17599 17600 this.targetList.attr('aria-label', captionText); 17601 this.targetInput.attr('title', captionText); 17602 } 17603 17604 this.setTabIndex(); 17605 17606 //generate input options 17607 this.generateItems(this.sourceList, this.sourceInput); 17608 this.generateItems(this.targetList, this.targetInput); 17609 17610 if(this.cfg.disabled) { 17611 $(this.jqId + ' li.ui-picklist-item').addClass('ui-state-disabled'); 17612 $(this.jqId + ' button').attr('disabled', 'disabled').addClass('ui-state-disabled'); 17613 $(this.jqId + ' .ui-picklist-filter-container').addClass('ui-state-disabled').children('input').attr('disabled', 'disabled'); 17614 } 17615 else { 17616 var $this = this, 17617 reordered = true; 17618 17619 //Sortable lists 17620 $(this.jqId + ' ul').sortable({ 17621 cancel: '.ui-state-disabled,.ui-chkbox-box', 17622 connectWith: this.jqId + ' .ui-picklist-list', 17623 revert: 1, 17624 helper: 'clone', 17625 update: function(event, ui) { 17626 $this.unselectItem(ui.item); 17627 17628 $this.saveState(); 17629 if(reordered) { 17630 $this.fireReorderEvent(); 17631 reordered = false; 17632 } 17633 }, 17634 receive: function(event, ui) { 17635 $this.fireTransferEvent(ui.item, ui.sender, ui.item.parents('ul.ui-picklist-list:first'), 'dragdrop'); 17636 }, 17637 17638 start: function(event, ui) { 17639 $this.itemListName = $this.getListName(ui.item); 17640 $this.dragging = true; 17641 }, 17642 17643 stop: function(event, ui) { 17644 $this.dragging = false; 17645 }, 17646 17647 beforeStop:function(event, ui) { 17648 if($this.itemListName !== $this.getListName(ui.item)) { 17649 reordered = false; 17650 } 17651 else { 17652 reordered = true; 17653 } 17654 } 17655 }); 17656 17657 this.bindItemEvents(); 17658 17659 this.bindButtonEvents(); 17660 17661 this.bindFilterEvents(); 17662 17663 this.bindKeyEvents(); 17664 17665 this.updateButtonsState(); 17666 17667 this.updateListRole(); 17668 } 17669 }, 17670 17671 bindItemEvents: function() { 17672 var $this = this; 17673 17674 this.items.on('mouseover.pickList', function(e) { 17675 var element = $(this); 17676 17677 if(!element.hasClass('ui-state-highlight')) { 17678 $(this).addClass('ui-state-hover'); 17679 } 17680 }) 17681 .on('mouseout.pickList', function(e) { 17682 $(this).removeClass('ui-state-hover'); 17683 }) 17684 .on('click.pickList', function(e) { 17685 //stop propagation 17686 if($this.checkboxClick||$this.dragging) { 17687 $this.checkboxClick = false; 17688 return; 17689 } 17690 17691 var item = $(this), 17692 parentList = item.parent(), 17693 metaKey = (e.metaKey||e.ctrlKey); 17694 17695 if(!e.shiftKey) { 17696 if(!metaKey) { 17697 $this.unselectAll(); 17698 } 17699 17700 if(metaKey && item.hasClass('ui-state-highlight')) { 17701 $this.unselectItem(item, true); 17702 } 17703 else { 17704 $this.selectItem(item, true); 17705 $this.cursorItem = item; 17706 } 17707 } 17708 else { 17709 $this.unselectAll(); 17710 17711 if($this.cursorItem && ($this.cursorItem.parent().is(item.parent()))) { 17712 var currentItemIndex = item.index(), 17713 cursorItemIndex = $this.cursorItem.index(), 17714 startIndex = (currentItemIndex > cursorItemIndex) ? cursorItemIndex : currentItemIndex, 17715 endIndex = (currentItemIndex > cursorItemIndex) ? (currentItemIndex + 1) : (cursorItemIndex + 1); 17716 17717 for(var i = startIndex ; i < endIndex; i++) { 17718 var it = parentList.children('li.ui-picklist-item').eq(i); 17719 17720 if(it.is(':visible')) { 17721 if(i === (endIndex - 1)) 17722 $this.selectItem(it, true); 17723 else 17724 $this.selectItem(it); 17725 } 17726 } 17727 } 17728 else { 17729 $this.selectItem(item, true); 17730 $this.cursorItem = item; 17731 } 17732 } 17733 17734 /* For keyboard navigation */ 17735 $this.removeOutline(); 17736 $this.focusedItem = item; 17737 parentList.trigger('focus.pickList'); 17738 }) 17739 .on('dblclick.pickList', function() { 17740 var item = $(this); 17741 17742 if($(this).parent().hasClass('ui-picklist-source')) 17743 $this.transfer(item, $this.sourceList, $this.targetList, 'dblclick'); 17744 else 17745 $this.transfer(item, $this.targetList, $this.sourceList, 'dblclick'); 17746 17747 /* For keyboard navigation */ 17748 $this.removeOutline(); 17749 $this.focusedItem = null; 17750 17751 PrimeFaces.clearSelection(); 17752 }); 17753 17754 if(this.cfg.showCheckbox) { 17755 this.checkboxes.on('mouseover.pickList', function(e) { 17756 var chkbox = $(this); 17757 17758 if(!chkbox.hasClass('ui-state-active')) 17759 chkbox.addClass('ui-state-hover'); 17760 }) 17761 .on('mouseout.pickList', function(e) { 17762 $(this).removeClass('ui-state-hover'); 17763 }) 17764 .on('click.pickList', function(e) { 17765 $this.checkboxClick = true; 17766 17767 var item = $(this).closest('li.ui-picklist-item'); 17768 if(item.hasClass('ui-state-highlight')) { 17769 $this.unselectItem(item, true); 17770 } 17771 else { 17772 $this.selectItem(item, true); 17773 } 17774 $this.focusedItem = item; 17775 }); 17776 } 17777 }, 17778 17779 bindKeyEvents: function() { 17780 var $this = this, 17781 listSelector = 'ul.ui-picklist-source, ul.ui-picklist-target'; 17782 17783 this.jq.off('focus.pickList blur.pickList keydown.pickList', listSelector).on('focus.pickList', listSelector, null, function(e) { 17784 var list = $(this), 17785 activeItem = $this.focusedItem||list.children('.ui-state-highlight:visible:first'); 17786 if(activeItem.length) { 17787 $this.focusedItem = activeItem; 17788 } 17789 else { 17790 $this.focusedItem = list.children('.ui-picklist-item:visible:first'); 17791 } 17792 17793 setTimeout(function() { 17794 if ($this.focusedItem) { 17795 PrimeFaces.scrollInView(list, $this.focusedItem); 17796 $this.focusedItem.addClass('ui-picklist-outline'); 17797 $this.ariaRegion.text($this.focusedItem.data('item-label')); 17798 } 17799 }, 100); 17800 }) 17801 .on('blur.pickList', listSelector, null, function() { 17802 $this.removeOutline(); 17803 $this.focusedItem = null; 17804 }) 17805 .on('keydown.pickList', listSelector, null, function(e) { 17806 17807 if(!$this.focusedItem) { 17808 return; 17809 } 17810 17811 var list = $(this), 17812 keyCode = $.ui.keyCode, 17813 key = e.which; 17814 17815 switch(key) { 17816 case keyCode.UP: 17817 $this.removeOutline(); 17818 17819 if(!$this.focusedItem.hasClass('ui-state-highlight')) { 17820 $this.selectItem($this.focusedItem); 17821 } 17822 else { 17823 var prevItem = $this.focusedItem.prevAll('.ui-picklist-item:visible:first'); 17824 if(prevItem.length) { 17825 $this.unselectAll(); 17826 $this.selectItem(prevItem); 17827 $this.focusedItem = prevItem; 17828 17829 PrimeFaces.scrollInView(list, $this.focusedItem); 17830 } 17831 } 17832 $this.ariaRegion.text($this.focusedItem.data('item-label')); 17833 e.preventDefault(); 17834 break; 17835 17836 case keyCode.DOWN: 17837 $this.removeOutline(); 17838 17839 if(!$this.focusedItem.hasClass('ui-state-highlight')) { 17840 $this.selectItem($this.focusedItem); 17841 } 17842 else { 17843 var nextItem = $this.focusedItem.nextAll('.ui-picklist-item:visible:first'); 17844 if(nextItem.length) { 17845 $this.unselectAll(); 17846 $this.selectItem(nextItem); 17847 $this.focusedItem = nextItem; 17848 17849 PrimeFaces.scrollInView(list, $this.focusedItem); 17850 } 17851 } 17852 $this.ariaRegion.text($this.focusedItem.data('item-label')); 17853 e.preventDefault(); 17854 break; 17855 17856 case keyCode.ENTER: 17857 case keyCode.SPACE: 17858 if($this.focusedItem && $this.focusedItem.hasClass('ui-state-highlight')) { 17859 $this.focusedItem.trigger('dblclick.pickList'); 17860 $this.focusedItem = null; 17861 } 17862 e.preventDefault(); 17863 break; 17864 default: 17865 // #3304 find first item matching the character typed 17866 var keyChar = String.fromCharCode(key).toLowerCase(); 17867 list.children('.ui-picklist-item').each(function() { 17868 var item = $(this), 17869 itemLabel = item.attr('data-item-label'); 17870 if (itemLabel.toLowerCase().indexOf(keyChar) === 0) { 17871 $this.removeOutline(); 17872 $this.unselectAll(); 17873 $this.selectItem(item); 17874 $this.focusedItem = item; 17875 PrimeFaces.scrollInView(list, $this.focusedItem); 17876 $this.ariaRegion.text($this.focusedItem.data('item-label')); 17877 e.preventDefault(); 17878 return false;
17879 } 17880 }); 17881 break; 17882 }; 17883 }); 17884 17885 }, 17886 17887 removeOutline: function() { 17888 if(this.focusedItem && this.focusedItem.hasClass('ui-picklist-outline')) { 17889 this.focusedItem.removeClass('ui-picklist-outline'); 17890 } 17891 }, 17892 17893 selectItem: function(item, silent) { 17894 item.removeClass('ui-state-hover').addClass('ui-state-highlight'); 17895 17896 if(this.cfg.showCheckbox) { 17897 this.selectCheckbox(item.find('div.ui-chkbox-box')); 17898 } 17899 17900 if(silent) { 17901 this.fireItemSelectEvent(item); 17902 } 17903 17904 this.updateButtonsState(); 17905 }, 17906 17907 unselectItem: function(item, silent) { 17908 item.removeClass('ui-state-hover ui-state-highlight'); 17909 17910 if(this.cfg.showCheckbox) { 17911 this.unselectCheckbox(item.find('div.ui-chkbox-box')); 17912 } 17913 17914 if(silent) { 17915 this.fireItemUnselectEvent(item); 17916 } 17917 17918 this.updateButtonsState(); 17919 }, 17920 17921 unselectAll: function() { 17922 var selectedItems = this.items.filter('.ui-state-highlight'); 17923 for(var i = 0; i < selectedItems.length; i++) { 17924 this.unselectItem(selectedItems.eq(i)); 17925 } 17926 }, 17927 17928 selectCheckbox: function(chkbox) { 17929 chkbox.removeClass('ui-state-hover').addClass('ui-state-active').children('span.ui-chkbox-icon').removeClass('ui-icon-blank').addClass('ui-icon-check'); 17930 }, 17931 17932 unselectCheckbox: function(chkbox) { 17933 chkbox.removeClass('ui-state-active').children('span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check'); 17934 }, 17935 17936 generateItems: function(list, input) { 17937 var $this = this; 17938 list.children('.ui-picklist-item').each(function() { 17939 var item = $(this), 17940 itemValue = item.attr('data-item-value'), 17941 itemLabel = item.attr('data-item-label') ? PrimeFaces.escapeHTML(item.attr('data-item-label')) : '', 17942 option = $('<option selected="selected"></option>'); 17943 17944 if ($this.cfg.escapeValue) { 17945 itemValue = PrimeFaces.escapeHTML(itemValue); 17946 } 17947 option.prop('value', itemValue).text(itemLabel); 17948 input.append(option); 17949 }); 17950 }, 17951 17952 bindButtonEvents: function() { 17953 var _self = this; 17954 17955 //visuals 17956 PrimeFaces.skinButton(this.jq.find('.ui-button')); 17957 17958 //events 17959 $(this.jqId + ' .ui-picklist-button-add').click(function() {_self.add();}); 17960 $(this.jqId + ' .ui-picklist-button-add-all').click(function() {_self.addAll();}); 17961 $(this.jqId + ' .ui-picklist-button-remove').click(function() {_self.remove();}); 17962 $(this.jqId + ' .ui-picklist-button-remove-all').click(function() {_self.removeAll();}); 17963 17964 if(this.cfg.showSourceControls) { 17965 $(this.jqId + ' .ui-picklist-source-controls .ui-picklist-button-move-up').click(function() {_self.moveUp(_self.sourceList);}); 17966 $(this.jqId + ' .ui-picklist-source-controls .ui-picklist-button-move-top').click(function() {_self.moveTop(_self.sourceList);}); 17967 $(this.jqId + ' .ui-picklist-source-controls .ui-picklist-button-move-down').click(function() {_self.moveDown(_self.sourceList);}); 17968 $(this.jqId + ' .ui-picklist-source-controls .ui-picklist-button-move-bottom').click(function() {_self.moveBottom(_self.sourceList);}); 17969 } 17970 17971 if(this.cfg.showTargetControls) { 17972 $(this.jqId + ' .ui-picklist-target-controls .ui-picklist-button-move-up').click(function() {_self.moveUp(_self.targetList);}); 17973 $(this.jqId + ' .ui-picklist-target-controls .ui-picklist-button-move-top').click(function() {_self.moveTop(_self.targetList);}); 17974 $(this.jqId + ' .ui-picklist-target-controls .ui-picklist-button-move-down').click(function() {_self.moveDown(_self.targetList);}); 17975 $(this.jqId + ' .ui-picklist-target-controls .ui-picklist-button-move-bottom').click(function() {_self.moveBottom(_self.targetList);}); 17976 } 17977 }, 17978 17979 bindFilterEvents: function() { 17980 this.cfg.filterEvent = this.cfg.filterEvent||'keyup'; 17981 this.cfg.filterDelay = this.cfg.filterDelay||300; 17982 this.setupFilterMatcher(); 17983 17984 this.sourceFilter = $(this.jqId + '_source_filter'); 17985 this.targetFilter = $(this.jqId + '_target_filter'); 17986 17987 PrimeFaces.skinInput(this.sourceFilter); 17988 this.bindTextFilter(this.sourceFilter); 17989 17990 PrimeFaces.skinInput(this.targetFilter); 17991 this.bindTextFilter(this.targetFilter); 17992 }, 17993 17994 bindTextFilter: function(filter) { 17995 if(this.cfg.filterEvent === 'enter') 17996 this.bindEnterKeyFilter(filter); 17997 else 17998 this.bindFilterEvent(filter); 17999 }, 18000 18001 bindEnterKeyFilter: function(filter) { 18002 var $this = this; 18003 18004 filter.on('keydown', PrimeFaces.utils.blockEnterKey) 18005 .on('keyup', function(e) { 18006 var key = e.which, 18007 keyCode = $.ui.keyCode; 18008 18009 if((key === keyCode.ENTER)) { 18010 $this.filter(this.value, $this.getFilteredList($(this))); 18011 18012 e.preventDefault(); 18013 } 18014 }); 18015 }, 18016 18017 bindFilterEvent: function(filter) { 18018 var $this = this; 18019 18020 //prevent form submit on enter key 18021 filter.on(this.cfg.filterEvent, function(e) { 18022 if (PrimeFaces.utils.ignoreFilterKey(e)) { 18023 return; 18024 } 18025 18026 var input = $(this); 18027 18028 if($this.filterTimeout) { 18029 clearTimeout($this.filterTimeout); 18030 } 18031 18032 $this.filterTimeout = setTimeout(function() { 18033 $this.filter(input.val(), $this.getFilteredList(input)); 18034 $this.filterTimeout = null; 18035 }, 18036 $this.cfg.filterDelay); 18037 }) 18038 .on('keydown', PrimeFaces.utils.blockEnterKey); 18039 }, 18040 18041 setupFilterMatcher: function() { 18042 this.cfg.filterMatchMode = this.cfg.filterMatchMode||'startsWith'; 18043 this.filterMatchers = { 18044 'startsWith': this.startsWithFilter 18045 ,'contains': this.containsFilter 18046 ,'endsWith': this.endsWithFilter 18047 ,'custom': this.cfg.filterFunction 18048 }; 18049 18050 this.filterMatcher = this.filterMatchers[this.cfg.filterMatchMode]; 18051 }, 18052 18053 filter: function(value, list) { 18054 var filterValue = $.trim(value).toLowerCase(), 18055 items = list.children('li.ui-picklist-item'), 18056 animated = this.isAnimated(); 18057 18058 list.removeAttr('role'); 18059 18060 if(filterValue === '') { 18061 items.filter(':hidden').show(); 18062 list.attr('role', 'menu'); 18063 } 18064 else { 18065 for(var i = 0; i < items.length; i++) { 18066 var item = items.eq(i), 18067 itemLabel = item.attr('data-item-label'), 18068 matches = this.filterMatcher(itemLabel, filterValue); 18069 18070 if(matches) { 18071 var hasRole = list[0].hasAttribute('role'); 18072 if(animated) { 18073 item.fadeIn('fast', function() { 18074 if(!hasRole) { 18075 list.attr('role', 'menu'); 18076 } 18077 }); 18078 } 18079 else { 18080 item.show(); 18081 if(!hasRole) { 18082 list.attr('role', 'menu'); 18083 } 18084 } 18085 } 18086 else { 18087 if(animated) { 18088 item.fadeOut('fast'); 18089 } 18090 else { 18091 item.hide(); 18092 } 18093 } 18094 } 18095 } 18096 18097 }, 18098 18099 startsWithFilter: function(value, filter) { 18100 return value.toLowerCase().indexOf(filter) === 0; 18101 }, 18102 18103 containsFilter: function(value, filter) { 18104 return value.toLowerCase().indexOf(filter) !== -1; 18105 }, 18106 18107 endsWithFilter: function(value, filter) { 18108 return value.indexOf(filter, value.length - filter.length) !== -1; 18109 }, 18110 18111 getFilteredList: function(filter) { 18112 return filter.hasClass('ui-source-filter-input') ? this.sourceList : this.targetList; 18113 }, 18114 18115 add: function() { 18116 var items = this.sourceList.children('li.ui-picklist-item.ui-state-highlight') 18117 18118 this.transfer(items, this.sourceList, this.targetList, 'command'); 18119 }, 18120 18121 addAll: function() { 18122 var items = this.sourceList.children('li.ui-picklist-item:visible:not(.ui-state-disabled)'); 18123 18124 this.transfer(items, this.sourceList, this.targetList, 'command'); 18125 }, 18126 18127 remove: function() { 18128 var items = this.targetList.children('li.ui-picklist-item.ui-state-highlight'); 18129 18130 this.transfer(items, this.targetList, this.sourceList, 'command'); 18131 }, 18132 18133 removeAll: function() { 18134 var items = this.targetList.children('li.ui-picklist-item:visible:not(.ui-state-disabled)'); 18135 18136 this.transfer(items, this.targetList, this.sourceList, 'command'); 18137 }, 18138 18139 moveUp: function(list) { 18140 var _self = this, 18141 animated = _self.isAnimated(), 18142 items = list.children('.ui-state-highlight'), 18143 itemsCount = items.length, 18144 movedCount = 0; 18145 18146 if(itemsCount) { 18147 items.each(function() { 18148 var item = $(this); 18149 18150 if(!item.is(':first-child')) { 18151 18152 if(animated) { 18153 item.hide(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18154 item.insertBefore(item.prev()).show(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18155 movedCount++; 18156 18157 if(movedCount === itemsCount) { 18158 _self.saveState(); 18159 _self.fireReorderEvent(); 18160 } 18161 }); 18162 }); 18163 } 18164 else { 18165 item.hide().insertBefore(item.prev()).show(); 18166 } 18167 18168 } 18169 }); 18170 18171 if(!animated) { 18172 this.saveState(); 18173 this.fireReorderEvent(); 18174 } 18175 } 18176 18177 }, 18178 18179 moveTop: function(list) { 18180 var _self = this, 18181 animated = _self.isAnimated(), 18182 items = list.children('.ui-state-highlight'), 18183 itemsCount = items.length, 18184 movedCount = 0; 18185 18186 if(itemsCount) { 18187 items.each(function() { 18188 var item = $(this); 18189 18190 if(!item.is(':first-child')) { 18191 18192 if(animated) { 18193 item.hide(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18194 item.prependTo(item.parent()).show(_self.cfg.effect, {}, _self.cfg.effectSpeed, function(){ 18195 movedCount++; 18196 18197 if(movedCount === itemsCount) { 18198 _self.saveState(); 18199 _self.fireReorderEvent(); 18200 } 18201 }); 18202 }); 18203 } 18204 else { 18205 item.hide().prependTo(item.parent()).show(); 18206 } 18207 } 18208 }); 18209 18210 if(!animated) { 18211 this.saveState(); 18212 this.fireReorderEvent(); 18213 } 18214 } 18215 }, 18216 18217 moveDown: function(list) { 18218 var _self = this, 18219 animated = _self.isAnimated(), 18220 items = list.children('.ui-state-highlight'), 18221 itemsCount = items.length, 18222 movedCount = 0; 18223 18224 if(itemsCount) { 18225 $(items.get().reverse()).each(function() { 18226 var item = $(this); 18227 18228 if(!item.is(':last-child')) { 18229 if(animated) { 18230 item.hide(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18231 item.insertAfter(item.next()).show(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18232 movedCount++; 18233 18234 if(movedCount === itemsCount) { 18235 _self.saveState(); 18236 _self.fireReorderEvent(); 18237 } 18238 }); 18239 }); 18240 } 18241 else { 18242 item.hide().insertAfter(item.next()).show(); 18243 } 18244 } 18245 18246 }); 18247 18248 if(!animated) { 18249 this.saveState(); 18250 this.fireReorderEvent(); 18251 } 18252 } 18253 }, 18254 18255 moveBottom: function(list) { 18256 var _self = this, 18257 animated = _self.isAnimated(), 18258 items = list.children('.ui-state-highlight'), 18259 itemsCount = items.length, 18260 movedCount = 0; 18261 18262 if(itemsCount) { 18263 items.each(function() { 18264 var item = $(this); 18265 18266 if(!item.is(':last-child')) { 18267 18268 if(animated) { 18269 item.hide(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18270 item.appendTo(item.parent()).show(_self.cfg.effect, {}, _self.cfg.effectSpeed, function() { 18271 movedCount++; 18272 18273 if(movedCount === itemsCount) { 18274 _self.saveState(); 18275 _self.fireReorderEvent(); 18276 } 18277 }); 18278 }); 18279 } 18280 else { 18281 item.hide().appendTo(item.parent()).show(); 18282 } 18283 } 18284 18285 }); 18286 18287 if(!animated) { 18288 this.saveState(); 18289 this.fireReorderEvent(); 18290 } 18291 } 18292 }, 18293 18294 /** 18295 * Clear inputs and repopulate them from the list states 18296 */ 18297 saveState: function() {
18298 this.sourceInput.children().remove(); 18299 this.targetInput.children().remove(); 18300 18301 this.generateItems(this.sourceList, this.sourceInput); 18302 this.generateItems(this.targetList, this.targetInput); 18303 this.cursorItem = null; 18304 }, 18305 18306 transfer: function(items, from, to, type) { 18307 $(this.jqId + ' ul').sortable('disable'); 18308 var $this = this; 18309 var itemsCount = items.length; 18310 var transferCount = 0; 18311 18312 if(this.isAnimated()) { 18313 items.hide(this.cfg.effect, {}, this.cfg.effectSpeed, function() { 18314 var item = $(this); 18315 $this.unselectItem(item); 18316 18317 item.appendTo(to).show($this.cfg.effect, {}, $this.cfg.effectSpeed, function() { 18318 transferCount++; 18319 18320 //fire transfer when all items are transferred 18321 if(transferCount == itemsCount) { 18322 $this.saveState(); 18323 $this.fireTransferEvent(items, from, to, type); 18324 } 18325 }); 18326 18327 $this.updateListRole(); 18328 }); 18329 } 18330 else { 18331 items.hide(); 18332 18333 if(this.cfg.showCheckbox) { 18334 items.each(function() { 18335 $this.unselectItem($(this)); 18336 }); 18337 } 18338 18339 items.appendTo(to).show(); 18340 18341 this.saveState(); 18342 this.fireTransferEvent(items, from, to, type); 18343 this.updateListRole(); 18344 } 18345 }, 18346 18347 /** 18348 * Fire transfer ajax behavior event 18349 */ 18350 fireTransferEvent: function(items, from, to, type) { 18351 if(this.cfg.onTransfer) { 18352 var obj = {}; 18353 obj.items = items; 18354 obj.from = from; 18355 obj.to = to; 18356 obj.type = type; 18357 18358 this.cfg.onTransfer.call(this, obj); 18359 } 18360 18361 if(this.hasBehavior('transfer')) { 18362 var ext = { 18363 params: [] 18364 }, 18365 paramName = this.id + '_transferred', 18366 isAdd = from.hasClass('ui-picklist-source'); 18367 18368 items.each(function(index, item) { 18369 ext.params.push({name:paramName, value:$(item).attr('data-item-value')}); 18370 }); 18371 18372 ext.params.push({name:this.id + '_add', value:isAdd}); 18373 18374 this.callBehavior('transfer', ext); 18375 } 18376 $(this.jqId + ' ul').sortable('enable'); 18377 18378 this.updateButtonsState(); 18379 }, 18380 18381 getListName: function(element){ 18382 return element.parent().hasClass("ui-picklist-source") ? "source" : "target"; 18383 }, 18384 18385 fireItemSelectEvent: function(item) { 18386 if(this.hasBehavior('select')) { 18387 var listName = this.getListName(item), 18388 inputContainer = (listName === "source") ? this.sourceInput : this.targetInput, 18389 ext = { 18390 params: [ 18391 {name: this.id + '_itemIndex', value: item.index()}, 18392 {name: this.id + '_listName', value: listName} 18393 ], 18394 onstart: function() { 18395 if(!inputContainer.children().length) { 18396 return false; 18397 } 18398 } 18399 }; 18400 18401 this.callBehavior('select', ext); 18402 } 18403 }, 18404 18405 fireItemUnselectEvent: function(item) { 18406 if(this.hasBehavior('unselect')) { 18407 var ext = { 18408 params: [ 18409 {name: this.id + '_itemIndex', value: item.index()}, 18410 {name: this.id + '_listName', value: this.getListName(item)} 18411 ] 18412 }; 18413 18414 this.callBehavior('unselect', ext); 18415 } 18416 }, 18417 18418 fireReorderEvent: function() { 18419 this.callBehavior('reorder'); 18420 }, 18421 18422 isAnimated: function() { 18423 return (this.cfg.effect && this.cfg.effect != 'none'); 18424 }, 18425 18426 setTabIndex: function() { 18427 var tabindex = (this.cfg.disabled) ? '-1' : this.getTabIndex(); 18428 this.sourceList.attr('tabindex', tabindex); 18429 this.targetList.attr('tabindex', tabindex); 18430 $(this.jqId + ' button').attr('tabindex', tabindex); 18431 $(this.jqId + ' .ui-picklist-filter-container > input').attr('tabindex', tabindex); 18432 }, 18433 18434 getTabIndex: function() { 18435 return this.cfg.tabindex||'0'; 18436 }, 18437 18438 updateButtonsState: function () { 18439 var addButton = $(this.jqId + ' .ui-picklist-button-add'); 18440 var sourceListButtons = $(this.jqId + ' .ui-picklist-source-control
18440s .ui-button'); 18441 if (this.sourceList.find('li.ui-state-highlight').length) { 18442 this.enableButton(addButton); 18443 this.enableButton(sourceListButtons); 18444 } 18445 else { 18446 this.disableButton(addButton); 18447 this.disableButton(sourceListButtons); 18448 } 18449 18450 var removeButton = $(this.jqId + ' .ui-picklist-button-remove'); 18451 var targetListButtons = $(this.jqId + ' .ui-picklist-target-controls .ui-button'); 18452 if (this.targetList.find('li.ui-state-highlight').length) { 18453 this.enableButton(removeButton); 18454 this.enableButton(targetListButtons); 18455 } 18456 else { 18457 this.disableButton(removeButton); 18458 this.disableButton(targetListButtons); 18459 } 18460 18461 var addAllButton = $(this.jqId + ' .ui-picklist-button-add-all'); 18462 if (this.sourceList.find('li.ui-picklist-item:not(.ui-state-disabled)').length) { 18463 this.enableButton(addAllButton); 18464 this.sourceList.attr('tabindex', this.getTabIndex()); 18465 } 18466 else { 18467 this.disableButton(addAllButton); 18468 this.sourceList.attr('tabindex', '-1'); 18469 } 18470 18471 var removeAllButton = $(this.jqId + ' .ui-picklist-button-remove-all'); 18472 if (this.targetList.find('li.ui-picklist-item:not(.ui-state-disabled)').length) { 18473 this.enableButton(removeAllButton); 18474 this.targetList.attr('tabindex', this.getTabIndex()); 18475 } 18476 else { 18477 this.disableButton(removeAllButton); 18478 this.targetList.attr('tabindex', '-1'); 18479 } 18480 }, 18481 18482 disableButton: function (button) { 18483 if (button.hasClass('ui-state-focus')) { 18484 button.blur(); 18485 } 18486 18487 button.attr('disabled', 'disabled').addClass('ui-state-disabled'); 18488 button.attr('tabindex', '-1'); 18489 }, 18490 18491 enableButton: function (button) { 18492 button.removeAttr('disabled').removeClass('ui-state-disabled'); 18493 button.attr('tabindex', this.getTabIndex()); 18494 }, 18495 18496 updateListRole: function() { 18497 this.sourceList.children('li:visible').length > 0 ? this.sourceList.attr('role', 'menu') : this.sourceList.removeAttr('role'); 18498 this.targetList.children('li:visible').length > 0 ? this.targetList.attr('role', 'menu') : this.targetList.removeAttr('role'); 18499 } 18500 18501}); 18502/** 18503 * PrimeFaces ProgressBar widget 18504 */ 18505PrimeFaces.widget.ProgressBar = PrimeFaces.widget.BaseWidget.extend({ 18506 18507 init: function(cfg) { 18508 this._super(cfg); 18509 18510 this.jqValue = this.jq.children('.ui-progressbar-value'); 18511 this.jqLabel = this.jq.children('.ui-progressbar-label'); 18512 this.value = this.cfg.initialValue; 18513 this.cfg.global = (this.cfg.global === false) ? false : true; 18514 18515 if(this.cfg.ajax) { 18516 this.cfg.formId = this.jq.closest('form').attr('id'); 18517 } 18518 18519 this.enableARIA(); 18520 }, 18521 18522 setValue: function(value) { 18523 if(value >= 0 && value<=100) { 18524 if(value == 0) { 18525 this.jqValue.hide().css('width', '0%').removeClass('ui-corner-right'); 18526 18527 this.jqLabel.hide(); 18528 } 18529 else { 18530 this.jqValue.show().animate({ 18531 'width': value + '%' 18532 }, this.cfg.animationDuration, 'easeInOutCirc'); 18533 18534 if(this.cfg.labelTemplate) { 18535 var formattedLabel = this.cfg.labelTemplate.replace(/{value}/gi, value); 18536 this.jqLabel.text(formattedLabel).show(); 18537 } 18538 } 18539 18540 this.value = value; 18541 this.jq.attr('aria-valuenow', value); 18542 } 18543 }, 18544 18545 getValue: function() { 18546 return this.value; 18547 }, 18548 18549 start: function() { 18550 var $this = this; 18551 18552 if(this.cfg.ajax) { 18553 18554 this.progressPoll = setInterval(function() { 18555 var options = { 18556 source: $this.id, 18557 process: $this.id, 18558 formId: $this.cfg.formId, 18559 global: $this.cfg.global, 18560 async: true, 18561 oncomplete: function(xhr, status, args, data) { 18562 var value = args[$this.id + '_value']; 18563 $this.setValue(value); 18564 18565 //trigger complete listener 18566 if(value === 100) { 18567 $this.fireCompleteEvent(); 18568 } 18569 } 18570 }; 18571 18572 PrimeFaces.ajax.Request.handle(options); 18573 18574 }, this.cfg.interval); 18575 } 18576 }, 18577 18578 fireCompleteEvent: function() { 18579 clearInterval(this.progressPoll); 18580 18581 this.callBehavior('complete'); 18582 }, 18583 18584 cancel: function() { 18585 clearInterval(this.progressPoll); 18586 this.setValue(0); 18587 }, 18588 18589 enableARIA: function() { 18590 this.jq.attr('role', 'progressbar') 18591 .attr('aria-valuemin', 0) 18592 .attr('aria-valuenow', this.value) 18593 .attr('aria-valuemax', 100); 18594 } 18595 18596}); 18597/** 18598 * PrimeFaces Rating Widget 18599 */ 18600PrimeFaces.widget.Rating = PrimeFaces.widget.BaseWidget.extend({ 18601 18602 init: function(cfg) { 18603 this._super(cfg); 18604 this.jqInput = $(this.jqId + '_input'); 18605 this.value = this.getValue(); 18606 this.stars = this.jq.children('.ui-rating-star'); 18607 this.cancel = this.jq.children('.ui-rating-cancel'); 18608 18609 if(!this.cfg.disabled && !this.cfg.readonly) { 18610 this.bindEvents(); 18611 } 18612 18613 if(this.cfg.readonly) { 18614 this.jq.children().css('cursor', 'default'); 18615 } 18616 }, 18617 18618 bindEvents: function() { 18619 var _self = this; 18620 18621 this.stars.click(function() { 18622 var value = _self.stars.index(this) + 1; //index starts from zero 18623 18624 _self.setValue(value); 18625 }); 18626 18627 this.cancel.hover(function() { 18628 $(this).toggleClass('ui-rating-cancel-hover'); 18629 }) 18630 .click(function() { 18631 _self.reset(); 18632 }); 18633 }, 18634 18635 unbindEvents: function() { 18636 this.stars.unbind('click'); 18637 18638 this.cancel.unbind('hover click'); 18639 }, 18640 18641 getValue: function() { 18642 var inputVal = this.jqInput.val(); 18643 18644 return inputVal == '' ? null : parseInt(inputVal); 18645 }, 18646 18647 setValue: function(value) { 18648 //set hidden value 18649 this.jqInput.val(value); 18650 18651 //update visuals 18652 this.stars.removeClass('ui-rating-star-on'); 18653 for(var i = 0; i < value; i++) { 18654 this.stars.eq(i).addClass('ui-rating-star-on'); 18655 } 18656 18657 //invoke callback 18658 if(this.cfg.onRate) { 18659 this.cfg.onRate.call(this, value); 18660 } 18661 18662 this.callBehavior('rate'); 18663 }, 18664 18665 enable: function() { 18666 this.cfg.disabled = false;
18667 18668 this.bindEvents(); 18669 18670 this.jq.removeClass('ui-state-disabled'); 18671 }, 18672 18673 disable: function() { 18674 this.cfg.disabled = true; 18675 18676 this.unbindEvents(); 18677 18678 this.jq.addClass('ui-state-disabled'); 18679 }, 18680 18681 reset: function() { 18682 this.jqInput.val(''); 18683 18684 this.stars.filter('.ui-rating-star-on').removeClass('ui-rating-star-on'); 18685 18686 this.callBehavior('cancel'); 18687 } 18688}); 18689/** 18690 * PrimeFaces Resizable Widget 18691 */ 18692PrimeFaces.widget.Resizable = PrimeFaces.widget.BaseWidget.extend({ 18693 18694 init: function(cfg) { 18695 this.cfg = cfg; 18696 this.id = this.cfg.id; 18697 this.jqId = PrimeFaces.escapeClientId(this.id); 18698 this.jqTarget = $(PrimeFaces.escapeClientId(this.cfg.target)); 18699 18700 this.renderDeferred(); 18701 }, 18702 18703 //@Override 18704 renderDeferred: function() { 18705 if(this.jqTarget.is(':visible')) { 18706 this._render(); 18707 } 18708 else { 18709 var container = this.jqTarget.parent()[0].closest('.ui-hidden-container'); 18710 if (container) { 18711 var $container = $(container); 18712 if ($container.length) { 18713 var $this = this; 18714 PrimeFaces.addDeferredRender(this.id, $container.attr('id'), function() { 18715 return $this.render(); 18716 }); 18717 } 18718 } 18719 } 18720 }, 18721 18722 render: function() { 18723 if(this.jqTarget.is(':visible')) { 18724 this._render(); 18725 return true; 18726 } 18727 18728 return false; 18729 }, 18730 18731 _render: function() { 18732 if(this.cfg.ajaxResize) { 18733 this.cfg.formId = $(this.target).parents('form:first').attr('id'); 18734 } 18735 18736 if (this.cfg.isContainment) { 18737 this.cfg.containment = PrimeFaces.escapeClientId(this.cfg.parentComponentId); 18738 } 18739 18740 var _self = this; 18741 18742 this.cfg.stop = function(event, ui) { 18743 if(_self.cfg.onStop) { 18744 _self.cfg.onStop.call(_self, event, ui); 18745 } 18746 18747 _self.fireAjaxResizeEvent(event, ui); 18748 }; 18749 18750 this.cfg.start = function(event, ui) { 18751 if(_self.cfg.onStart) { 18752 _self.cfg.onStart.call(_self, event, ui); 18753 } 18754 }; 18755 18756 this.cfg.resize = function(event, ui) { 18757 if(_self.cfg.onResize) { 18758 _self.cfg.onResize.call(_self, event, ui); 18759 } 18760 }; 18761 18762 this.jqTarget.resizable(this.cfg); 18763 18764 this.removeScriptElement(this.id); 18765 }, 18766 18767 fireAjaxResizeEvent: function(event, ui) { 18768 if(this.hasBehavior('resize')) { 18769 var ext = { 18770 params: [ 18771 {name: this.id + '_width', value: parseInt(ui.helper.width())}, 18772 {name: this.id + '_height', value: parseInt(ui.helper.height())} 18773 ] 18774 }; 18775 18776 this.callBehavior('resize', ext); 18777 } 18778 } 18779 18780}); 18781/** 18782 * PrimeFaces Slider Widget 18783 */ 18784PrimeFaces.widget.Slider = PrimeFaces.widget.BaseWidget.extend({ 18785 18786 init: function(cfg) { 18787 this._super(cfg); 18788 18789 this.cfg.displayTemplate = this.cfg.displayTemplate||(this.cfg.range ? '{min} - {max}' : '{value}'); 18790 18791 if(this.cfg.range) { 18792 var inputIds = this.cfg.input.split(','); 18793 this.input = $(PrimeFaces.escapeClientId(inputIds[0]) + ',' + PrimeFaces.escapeClientId(inputIds[1])); 18794 } 18795 else { 18796 this.input = $(PrimeFaces.escapeClientId(this.cfg.input)); 18797 } 18798 18799 if(this.cfg.display) { 18800 this.output = $(PrimeFaces.escapeClientId(this.cfg.display)); 18801 } 18802 18803 this.jq.slider(this.cfg); 18804 18805 this.decimalStep = !(this.cfg.step % 1 === 0); 18806 18807 this.bindEvents(); 18808 18809 if (PrimeFaces.env.touch) { 18810 this.bindTouchEvents(); 18811 } 18812 }, 18813 18814 bindEvents: function() { 18815 var $this = this; 18816 18817 this.jq.on('slide', function(event, ui) { 18818 $this.onSlide(event, ui); 18819 }); 18820 18821 if(this.cfg.onSlideStart) { 18822 this.jq.on('slidestart', function(event, ui) { 18823 $this.cfg.onSlideStart.call(this, event, ui); 18824 }); 18825 } 18826 18827 this.jq.on('slidestop', function(event, ui) { 18828 $this.onSlideEnd(event, ui); 18829 }); 18830 18831 if (this.input.parent().hasClass('ui-inputnumber')) {
18832 this.input.parent().find('input:hidden').on('change', function () { 18833 $this.setValue($(this).val()); 18834 }); 18835 } 18836 else { 18837 this.input.on('keydown.slider', function (e) { 18838 var keyCode = $.ui.keyCode, 18839 key = e.which; 18840 18841 switch(key) { 18842 case keyCode.UP: 18843 case keyCode.DOWN: 18844 case keyCode.LEFT: 18845 case keyCode.RIGHT: 18846 case keyCode.BACKSPACE: 18847 case keyCode.DELETE: 18848 case keyCode.END: 18849 case keyCode.HOME: 18850 case keyCode.TAB: 18851 break; 18852 18853 default: 18854 var metaKey = e.metaKey||e.ctrlKey, 18855 isNumber = (key >= 48 && key <= 57) || (key >= 96 && key <= 105) || (key === 190); 18856 18857 //prevent special characters with alt and shift 18858 if(e.altKey || (e.shiftKey && !(key === keyCode.UP || key === keyCode.DOWN || key === keyCode.LEFT || key === keyCode.RIGHT))) { 18859 e.preventDefault(); 18860 } 18861 18862 //prevent letters and allow letters with meta key such as ctrl+c 18863 //also allow '.' when the step is defined as decimal 18864 if(!isNumber && !metaKey && !($this.decimalStep && key === 190)) { 18865 e.preventDefault(); 18866 } 18867 break; 18868 } 18869 }).on('keyup.slider', function (e) { 18870 $this.setValue($this.input.val()); 18871 }); 18872 } 18873 }, 18874 18875 bindTouchEvents: function() { 18876 var eventMapping = { 18877 touchstart: 'mousedown', 18878 touchmove: 'mousemove', 18879 touchend: 'mouseup' 18880 }; 18881 18882 this.jq.children('.ui-slider-handle').on('touchstart touchmove touchend', function(e) { 18883 var touch = e.originalEvent.changedTouches[0]; 18884 var targetEvent = document.createEvent('MouseEvent'); 18885 18886 targetEvent.initMouseEvent( 18887 eventMapping[e.originalEvent.type], 18888 true, // canBubble 18889 true, // cancelable 18890 window, // view 18891 1, // detail 18892 touch.screenX, 18893 touch.screenY, 18894 touch.clientX, 18895 touch.clientY, 18896 false, // ctrlKey 18897 false, // altKey 18898 false, // shiftKey 18899 false, // metaKey 18900 0, // button 18901 null // relatedTarget 18902 ); 18903 18904 touch.target.dispatchEvent(targetEvent); 18905 e.preventDefault(); 18906 }); 18907 }, 18908 18909 onSlide: function(event, ui) { 18910 if(this.cfg.onSlide) { 18911 this.cfg.onSlide.call(this, event, ui); 18912 } 18913 18914 if(this.cfg.range) { 18915 this.setInputValue(this.input.eq(0), ui.values[0]); 18916 this.setInputValue(this.input.eq(1), ui.values[1]); 18917 18918 if(this.output) { 18919 this.output.text(this.cfg.displayTemplate.replace('{min}', ui.values[0]).replace('{max}', ui.values[1])); 18920 } 18921 } 18922 else { 18923 this.setInputValue(this.input, ui.value); 18924 18925 if(this.output) { 18926 this.output.text(this.cfg.displayTemplate.replace('{value}', ui.value)); 18927 } 18928 } 18929 }, 18930 18931 setInputValue: function(input, inputValue) { 18932 if (input.parent().hasClass('ui-inputnumber')) { 18933 var inputNumberId = input.closest('.ui-inputnumber').attr('id'); 18934 var inputNumberWidget = PrimeFaces.getWidgetById(inputNumberId); 18935 inputNumberWidget.autonumeric.set(inputValue); 18936 } 18937 else if (input.hasClass('ui-spinner-input')) { 18938 var spinnerId = input.closest('.ui-spinner').attr('id'); 18939 var spinnerWidget = PrimeFaces.getWidgetById(spinnerId); 18940 spinnerWidget.setValue(inputValue); 18941 } 18942 else { 18943 input.val(inputValue); 18944 } 18945 }, 18946 18947 triggerOnchange: function(input) { 18948 if (input.parent().hasClass('ui-inputnumber')) { 18949 input.change(); 18950 } 18951 else if (input.hasClass('ui-spinner-input')) { 18952 input.change(); 18953 } 18954 }, 18955 18956 onSlideEnd: function(event, ui) { 18957 if(this.cfg.onSlideEnd) { 18958 this.cfg.onSlideEnd.call(this, event, ui); 18959 } 18960 18961 if(this.cfg.range) { 18962 this.triggerOnchange(this.input.eq(0)); 18963 this.triggerOnchange(this.input.eq(1)); 18964 } 18965 else { 18966 this.triggerOnchange(this.input); 18967 } 18968 18969 if(this.hasBehavior('slideEnd')) { 18970 var ext = { 18971 params: [ 18972 {name: this.id + '_slideValue', value: ui.value} 18973 ] 18974 }; 18975 18976 this.callBehavior('slideEnd', ext); 18977 } 18978 }, 18979 18980 getValue: function() { 18981 return this.jq.slider('value'); 18982 }, 18983 18984 setValue: function(value) { 18985 this.jq.slider('value', value); 18986 }, 18987 18988 getValues: function() { 18989 return this.jq.slider('values'); 18990 }, 18991 18992 setValues: function(values) { 18993 this.jq.slider('values', values); 18994 }, 18995 18996 enable: function() { 18997 this.jq.slider('enable'); 18998 }, 18999 19000 disable: function() { 19001 this.jq.slider('disable'); 19002 } 19003}); 19004/** 19005 * PrimeFaces Spinner Widget 19006 */ 19007PrimeFaces.widget.Spinner = PrimeFaces.widget.BaseWidget.extend({ 19008 19009 init: function(cfg) { 19010 this._super(cfg); 19011 19012 this.input = this.jq.children('.ui-spinner-input'); 19013 this.upButton = this.jq.children('a.ui-spinner-up'); 19014 this.downButton = this.jq.children('a.ui-spinner-down'); 19015 this.cfg.step = this.cfg.step || 1; 19016 if (this.cfg.thousandSeparator == undefined) { 19017 this.cfg.thousandSeparator = ''; 19018 } 19019 if (!this.cfg.decimalSeparator) { 19020 this.cfg.decimalSeparator = '.'; 19021 } 19022 this.cursorOffset = this.cfg.prefix ? this.cfg.prefix.length: 0; 19023 19024 var inputValue = this.input.val(); 19025 19026 if(this.cfg.decimalPlaces > 0) { 19027 this.cfg.precision = this.cfg.decimalPlaces; 19028 } 19029 else if(!(typeof this.cfg.step === 'number' && this.cfg.step % 1 === 0)) { 19030 this.cfg.precision = this.cfg.step.toString().split(/[,]|[.]/)[1].length; 19031 } 19032 19033 var maxlength = this.input.attr('maxlength'); 19034 if(maxlength) { 19035 this.cfg.maxlength = parseInt(maxlength); 19036 } 19037 19038 this.value = this.parseValue(inputValue); 19039 19040 this.format(); 19041 19042 this.addARIA(); 19043 19044 if(this.input.prop('disabled')||this.input.prop('readonly')) { 19045 return; 19046 } 19047 19048 this.bindEvents(); 19049 19050 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 19051 19052 PrimeFaces.skinInput(this.input); 19053 }, 19054 19055 bindEvents: function() { 19056 var $this = this; 19057 19058 this.jq.children('.ui-spinner-button') 19059 .on('mouseover.spinner', function() { 19060 $(this).addClass('ui-state-hover'); 19061 }) 19062 .on('mouseout.spinner', function() { 19063 $(this).removeClass('ui-state-hover ui-state-active'); 19064 19065 if($this.timer) { 19066 clearInterval($this.timer); 19067 } 19068 }) 19069 .on('mouseup.spinner', function() { 19070 clearInterval($this.timer); 19071 $(this).removeClass('ui-state-active').addClass('ui-state-hover'); 19072 $this.input.trigger('change'); 19073 }) 19074 .on('mousedown.spinner', function(e) { 19075 var element = $(this), 19076 dir = element.hasClass('ui-spinner-up') ? 1 : -1; 19077 19078 element.removeClass('ui-state-hover').addClass('ui-state-active'); 19079 19080 if($this.input.is(':not(:focus)')) { 19081 $this.input.focus(); 19082 } 19083 19084 $this.repeat(null, dir); 19085 19086 //keep focused 19087 e.preventDefault(); 19088 }); 19089 19090 this.input.on('keydown.spinner', function (e) { 19091 var keyCode = $.ui.keyCode; 19092 19093 switch(e.which) { 19094 case keyCode.UP: 19095 $this.spin(1); 19096 break; 19097 19098 case keyCode.DOWN: 19099 $this.spin(-1); 19100 break; 19101 19102 case keyCode.ENTER:
19103 $this.updateValue(); 19104 $this.format(); 19105 break; 19106 19107 default: 19108 //do nothing 19109 break; 19110 } 19111 19112 /* Github #1964 do not allow minus */ 19113 if ($this.cfg.min >= 0 && event.key === "-") { 19114 e.preventDefault(); 19115 } 19116 }) 19117 .on('keyup.spinner', function (e) { 19118 $this.updateValue(); 19119 19120 var keyCode = $.ui.keyCode; 19121 19122 /* Github #2636 */ 19123 var checkForIE = (PrimeFaces.env.isIE(11) || PrimeFaces.env.isLtIE(11)) && (e.which === keyCode.ENTER); 19124 19125 if(e.which === keyCode.UP||e.which === keyCode.DOWN||checkForIE) { 19126 $this.input.trigger('change'); 19127 $this.format(); 19128 } 19129 }) 19130 .on('blur.spinner', function(e) { 19131 $this.format(); 19132 }) 19133 .on('mousewheel.spinner', function(event, delta) { 19134 if($this.input.is(':focus')) { 19135 if(delta > 0) 19136 $this.spin(1); 19137 else 19138 $this.spin(-1); 19139 19140 $this.input.trigger('change'); 19141 19142 return false; 19143 } 19144 }); 19145 }, 19146 19147 repeat: function(interval, dir) { 19148 var $this = this, 19149 i = interval||500; 19150 19151 clearTimeout(this.timer); 19152 this.timer = setTimeout(function() { 19153 $this.repeat(40, dir); 19154 }, i); 19155 19156 this.spin(dir); 19157 }, 19158 19159 spin: function(dir) { 19160 var step = this.cfg.step * dir, 19161 currentValue = this.value ? this.value : 0, 19162 newValue = this.parseValue(currentValue + step); 19163 19164 if(this.cfg.maxlength !== undefined && newValue.toString().length > this.cfg.maxlength) { 19165 newValue = currentValue; 19166 } 19167 19168 this.value = newValue; 19169 this.format(); 19170 this.input.attr('aria-valuenow', this.getValue()); 19171 }, 19172 19173 updateValue: function() { 19174 var value = this.input.val(); 19175 19176 if(this.cfg.prefix && value.indexOf(this.cfg.prefix) === 0) { 19177 value = value.substring(this.cfg.prefix.length, value.length); 19178 } else { 19179 var ix = value.indexOf(this.cfg.suffix); 19180 if(this.cfg.suffix && ix > -1 && ix === (value.length - this.cfg.suffix.length)) { 19181 value = value.substring(0, value.length - this.cfg.suffix.length); 19182 } 19183 } 19184 19185 value = value.replace(new RegExp(PrimeFaces.escapeRegExp(this.cfg.thousandSeparator), 'g'), ''); 19186 value = value.replace(new RegExp(PrimeFaces.escapeRegExp(this.cfg.decimalSeparator), 'g'), '\.'); 19187 this.value = this.parseValue(value); 19188 }, 19189 19190 parseValue: function(value) { 19191 var parsedValue; 19192 if(this.cfg.precision) { 19193 parsedValue = parseFloat(value); 19194 } else { 19195 parsedValue = parseInt(value); 19196 } 19197 if(isNaN(parsedValue)) { 19198 if($.trim(value) === '' && this.cfg.min !== undefined && this.cfg.required) { 19199 parsedValue = this.cfg.min; 19200 } else { 19201 parsedValue = null; 19202 } 19203 } else { 19204 var minimum = this.cfg.min; 19205 var maximum = this.cfg.max; 19206 19207 if (this.cfg.rotate) { 19208 if(parsedValue < minimum) { 19209 parsedValue = maximum; 19210 } 19211 if(parsedValue > maximum) { 19212 parsedValue = minimum; 19213 } 19214 } else { 19215 if(parsedValue > maximum) { 19216 parsedValue = maximum; 19217 } 19218 if(parsedValue < minimum) { 19219 parsedValue = minimum; 19220 } 19221 } 19222 } 19223 return parsedValue; 19224 }, 19225 19226 format: function() { 19227 if(this.value !== null) { 19228 var value = this.getValue(); 19229 var numAndFract = value.toString().split('.'); 19230 value = numAndFract[0].replace(/(\d)(?=(?:\d{3})+\b)/g, '$1' + this.cfg.thousandSeparator); 19231 if (numAndFract.length === 2) { 19232 value += this.cfg.decimalSeparator + numAndFract[1]; 19233 } 19234 if(this.cfg.prefix) 19235 value = this.cfg.prefix + value; 19236 19237 if(this.cfg.suffix) 19238 value = value + this.cfg.suffix; 19239 19240 this.input.val(value); 19241 } 19242 }, 19243 19244 19245 addARIA: function() { 19246 this.input.attr('role', 'spinbutton'); 19247 this.input.attr('aria-multiline', false); 19248 this.input.attr('aria-valuenow', this.getValue()); 19249 19250 if(this.cfg.min !== undefined) 19251 this.input.attr('aria-valuemin', this.cfg.min); 19252 19253 if(this.cfg.max !== undefined) 19254 this.input.attr('aria-valuemax', this.cfg.max); 19255 19256 if(this.input.prop('disabled')) 19257 this.input.attr('aria-disabled', true); 19258 19259 if(this.input.prop('readonly')) 19260 this.input.attr('aria-readonly', true); 19261 }, 19262 19263 getValue: function() { 19264 if(this.cfg.precision) { 19265 return parseFloat(this.value).toFixed(this.cfg.precision); 19266 } 19267 else { 19268 return this.value; 19269 } 19270 }, 19271 19272 setValue: function(value) { 19273 this.value = value; 19274 this.format(); 19275 } 19276}); 19277 19278/** 19279 * PrimeFaces Spotlight Widget 19280 */ 19281PrimeFaces.widget.Spotlight = PrimeFaces.widget.BaseWidget.extend({ 19282 19283 init: function(cfg) { 19284 this._super(cfg); 19285 this.target = PrimeFaces.expressions.SearchExpressionFacade.resolve
19285ComponentsAsSelector(this.cfg.target); 19286 19287 if(!$(document.body).children('.ui-spotlight').length) { 19288 this.createMasks(); 19289 } 19290 19291 if(this.cfg.active) { 19292 this.show(); 19293 } 19294 }, 19295 19296 createMasks: function() { 19297 var documentBody = $(document.body); 19298 documentBody.append('<div class="ui-widget-overlay ui-spotlight ui-spotlight-top ui-helper-hidden"></div><div class="ui-widget-overlay ui-spotlight ui-spotlight-bottom ui-helper-hidden"></div>' + 19299 '<div class="ui-widget-overlay ui-spotlight ui-spotlight-left ui-helper-hidden"></div><div class="ui-widget-overlay ui-spotlight ui-spotlight-right ui-helper-hidden"></div>'); 19300 }, 19301 19302 show: function() { 19303 this.calculatePositions(); 19304 19305 $(document.body).children('div.ui-spotlight').show(); 19306 19307 this.bindEvents(); 19308 }, 19309 19310 calculatePositions: function() { 19311 var doc = $(document), 19312 documentBody = $(document.body), 19313 offset = PrimeFaces.utils.calculateRelativeOffset(this.target), 19314 zindex = ++PrimeFaces.zindex; 19315 19316 documentBody.children('div.ui-spotlight-top').css({ 19317 'left': 0, 19318 'top': 0, 19319 'width': documentBody.width(), 19320 'height': offset.top, 19321 'z-index': zindex 19322 }); 19323 19324 var bottomTop = offset.top + this.target.outerHeight(); 19325 documentBody.children('div.ui-spotlight-bottom').css({ 19326 'left': 0, 19327 'top': bottomTop, 19328 'width': documentBody.width(), 19329 'height': doc.height() - bottomTop, 19330 'z-index': zindex 19331 }); 19332 19333 documentBody.children('div.ui-spotlight-left').css({ 19334 'left': 0, 19335 'top': offset.top, 19336 'width': offset.left, 19337 'height': this.target.outerHeight(), 19338 'z-index': zindex 19339 }); 19340 19341 var rightLeft = offset.left + this.target.outerWidth(); 19342 documentBody.children('div.ui-spotlight-right').css({ 19343 'left': rightLeft, 19344 'top': offset.top, 19345 'width': documentBody.width() - rightLeft, 19346 'height': this.target.outerHeight(), 19347 'z-index': zindex 19348 }); 19349 }, 19350 19351 bindEvents: function() { 19352 var $this = this; 19353 19354 this.target.data('zindex',this.target.zIndex()).css('z-index', ++PrimeFaces.zindex); 19355 19356 if (this.cfg.blockScroll) { 19357 PrimeFaces.utils.preventScrolling(); 19358 } 19359 PrimeFaces.utils.preventTabbing(this.id, $this.target.zIndex(), function() { 19360 return $this.target.find(':tabbable'); 19361 }); 19362
19363 $(window).on('resize.spotlight scroll.spotlight', function() { 19364 $this.calculatePositions(); 19365 }); 19366 }, 19367 19368 unbindEvents: function() { 19369 PrimeFaces.utils.enableTabbing(this.id); 19370 if (this.cfg.blockScroll) { 19371 PrimeFaces.utils.enableScrolling(); 19372 } 19373 $(window).off('resize.spotlight scroll.spotlight'); 19374 }, 19375 19376 hide: function() { 19377 $(document.body).children('.ui-spotlight').hide(); 19378 this.unbindEvents(); 19379 this.target.css('z-index', this.target.zIndex()); 19380 } 19381 19382}); 19383/** 19384 * PrimeFaces Sticky Widget 19385 */ 19386PrimeFaces.widget.Sticky = PrimeFaces.widget.BaseWidget.extend({ 19387 19388 init: function(cfg) { 19389 this._super(cfg); 19390 this.target = $(PrimeFaces.escapeClientId(this.cfg.target)); 19391 this.cfg.margin = this.cfg.margin||0; 19392 19393 this.initialState = { 19394 top: this.target.offset().top, 19395 height: this.target.height() 19396 }; 19397 19398 this.bindEvents(); 19399 }, 19400 19401 refresh: function(cfg) { 19402 this.target = $(PrimeFaces.escapeClientId(this.cfg.target)); 19403 19404 if(this.fixed) { 19405 this.ghost.remove(); 19406 this.fix(true); 19407 } 19408 }, 19409 19410 bindEvents: function() { 19411 var $this = this, 19412 win = $(window); 19413 19414 PrimeFaces.utils.registerScrollHandler(this, 'scroll.' + this.id + '_align', function() { 19415 if(win.scrollTop() > $this.initialState.top - $this.cfg.margin) 19416 $this.fix(); 19417 else 19418 $this.restore(); 19419 }); 19420 19421 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', null, function() { 19422 if ($this.fixed) { 19423 $this.target.width($this.ghost.outerWidth() - ($this.target.outerWidth() - $this.target.width())); 19424 } 19425 }); 19426 }, 19427 19428 fix: function(force) { 19429 if(!this.fixed || force) { 19430 var win = $(window), 19431 winScrollTop = win.scrollTop(); 19432 19433 this.target.css({ 19434 'position': 'fixed', 19435 'top': this.cfg.margin, 19436 'z-index': ++PrimeFaces.zindex 19437 }) 19438 .addClass('ui-shadow ui-sticky'); 19439 19440 this.ghost = $('<div class="ui-sticky-ghost"></div>').height(this.target.outerHeight()).insertBefore(this.target); 19441 this.target.width(this.ghost.outerWidth() - (this.target.outerWidth() - this.target.width())); 19442 this.fixed = true; 19443 win.scrollTop(winScrollTop); 19444 } 19445 }, 19446 19447 restore: function() { 19448 if(this.fixed) { 19449 this.target.css({ 19450 position: 'static', 19451 top: 'auto', 19452 width: 'auto' 19453 }) 19454 .removeClass('ui-shadow ui-sticky'); 19455 19456 this.ghost.remove(); 19457 this.fixed = false; 19458 } 19459 } 19460 19461}); 19462 19463/** 19464 * PrimeFaces TabView Widget 19465 */ 19466PrimeFaces.widget.TabView = PrimeFaces.widget.DeferredWidget.extend({ 19467 19468 init: function(cfg) { 19469 this._super(cfg); 19470 19471 this.panelContainer = this.jq.children('.ui-tabs-panels'); 19472 this.stateHolder = $(this.jqId + '_activeIndex'); 19473 this.cfg.selected = parseInt(this.stateHolder.val()); 19474 this.focusedTabHeader = null; 19475 this.tabindex = this.cfg.tabindex||0; 19476 19477 if(this.cfg.scrollable) { 19478 this.navscroller = this.jq.children('.ui-tabs-navscroller'); 19479 this.navcrollerLeft = this.navscroller.children('.ui-tabs-navscroller-btn-left'); 19480 this.navcrollerRight = this.navscroller.children('.ui-tabs-navscroller-btn-right'); 19481 this.navContainer = this.navscroller.children('.ui-tabs-nav'); 19482 this.firstTab = this.navContainer.children('li.ui-tabs-header:first-child'); 19483 this.lastTab = this.navContainer.children('li.ui-tabs-header:last-child'); 19484 this.scrollStateHolder = $(this.jqId + '_scrollState'); 19485 } 19486 else { 19487 this.navContainer = this.jq.children('.ui-tabs-nav'); 19488 } 19489 19490 this.headerContainer = this.navContainer.children('li.ui-tabs-header'); 19491 19492 this.bindEvents(); 19493 19494 //Cache initial active tab
19495 if(this.cfg.dynamic && this.cfg.cache) { 19496 this.markAsLoaded(this.panelContainer.children().eq(this.cfg.selected)); 19497 } 19498 19499 this.renderDeferred(); 19500 }, 19501 19502 //@Override 19503 renderDeferred: function() { 19504 if(this.jq.is(':visible')) { 19505 this._render(); 19506 } 19507 else { 19508 var container = this.jq.parent()[0].closest('.ui-hidden-container'); 19509 if (container) { 19510 var $container = $(container); 19511 if ($container.length) { 19512 var $this = this; 19513 this.addDeferredRender(this.id, $container, function() { 19514 return $this.render(); 19515 }); 19516 } 19517 } 19518 } 19519 }, 19520 19521 _render: function() { 19522 if(this.cfg.scrollable) { 19523 this.initScrolling(); 19524 19525 var $this = this; 19526 19527 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', null, function() { 19528 $this.initScrolling(); 19529 }); 19530 } 19531 }, 19532 19533 bindEvents: function() { 19534 var $this = this; 19535 19536 //Tab header events 19537 this.headerContainer 19538 .on('mouseover.tabview', function(e) { 19539 var element = $(this); 19540 if(!element.hasClass('ui-state-disabled')) { 19541 element.addClass('ui-state-hover'); 19542 } 19543 }) 19544 .on('mouseout.tabview', function(e) { 19545 var element = $(this); 19546 if(!element.hasClass('ui-state-disabled')) { 19547 element.removeClass('ui-state-hover'); 19548 } 19549 }) 19550 .on('click.tabview', function(e) { 19551 var element = $(this); 19552 19553 if($(e.target).is(':not(.ui-icon-close)')) { 19554 var index = $this.headerContainer.index(element); 19555 19556 if(!element.hasClass('ui-state-disabled') && index !== $this.cfg.selected) { 19557 $this.select(index); 19558 } 19559 } 19560 19561 e.preventDefault(); 19562 }); 19563 19564 //Closable tabs 19565 this.navContainer.find('li .ui-icon-close') 19566 .on('click.tabview', function(e) { 19567 var index = $(this).parent().index(); 19568 19569 if($this.cfg.onTabClose) { 19570 var retVal = $this.cfg.onTabClose.call($this, index); 19571 19572 if(retVal !== false) { 19573 $this.remove(index); 19574 } 19575 } 19576 else { 19577 $this.remove(index); 19578 } 19579 19580 e.preventDefault(); 19581 }); 19582 19583 //Scrolling 19584 if(this.cfg.scrollable) { 19585 this.navscroller.children('.ui-tabs-navscroller-btn') 19586 .on('mouseover.tabview', function() { 19587 var el = $(this); 19588 if(!el.hasClass('ui-state-disabled')) 19589 $(this).addClass('ui-state-hover'); 19590 }) 19591 .on('mouseout.tabview', function() { 19592 var el = $(this); 19593 if(!el.hasClass('ui-state-disabled')) 19594 $(this).removeClass('ui-state-hover ui-state-active'); 19595 }) 19596 .on('mousedown.tabview', function() { 19597 var el = $(this); 19598 if(!el.hasClass('ui-state-disabled')) 19599 $(this).removeClass('ui-state-hover').addClass('ui-state-active'); 19600 }) 19601 .on('mouseup.tabview', function() { 19602 var el = $(this); 19603 if(!el.hasClass('ui-state-disabled')) 19604 $(this).addClass('ui-state-hover').removeClass('ui-state-active'); 19605 }) 19606 .on('focus.tabview', function() { 19607 $(this).addClass('ui-state-focus'); 19608 }) 19609 .on('blur.tabview', function() { 19610 $(this).removeClass('ui-state-focus'); 19611 }); 19612 19613 19614 this.navcrollerLeft.on('click.tabview', function(e) { 19615 $this.scroll(100); 19616 e.preventDefault(); 19617 }); 19618 19619 this.navcrollerRight.on('click.tabview', function(e) { 19620 $this.scroll(-100); 19621 e.preventDefault(); 19622 }); 19623 } 19624 19625 this.bindSwipeEvents(); 19626 this.bindKeyEvents(); 19627 }, 19628 19629 /** 19630 * Binds swipe events to this tabview. 19631 */ 19632 bindSwipeEvents: function() { 19633 if (!PrimeFaces.env.touch) { 19634 return; 19635 } 19636 var $this = this; 19637 this.jq.swipe({ 19638 swipeLeft:function(event) { 19639 var activeIndex = $this.getActiveIndex(); 19640 if (activeIndex < $this.getLength() - 1) { 19641 $this.select(activeIndex + 1); 19642 } 19643 }, 19644 swipeRight: function(event) { 19645 var activeIndex = $this.getActiveIndex(); 19646 if (activeIndex > 0) { 19647 $this.select(activeIndex - 1); 19648 } 19649 }, 19650 excludedElements: PrimeFaces.utils.excludedSwipeElements() 19651 }); 19652 }, 19653 19654 bindKeyEvents: function() { 19655 var $this = this, 19656 tabs = this.headerContainer; 19657 19658 /* For Screen Reader and Keyboard accessibility */ 19659 tabs.attr('tabindex', this.tabindex); 19660 19661 tabs.on('focus.tabview', function(e) { 19662 var focusedTab = $(this); 19663 19664 if(!focusedTab.hasClass('ui-state-disabled')) { 19665 focusedTab.addClass('ui-tabs-outline'); 19666 19667 if($this.cfg.scrollable) {
19668 if(focusedTab.position().left + focusedTab.width() > $this.navcrollerRight.position().left) { 19669 $this.navcrollerRight.trigger('click.tabview'); 19670 } 19671 else if(focusedTab.position().left < $this.navcrollerLeft.position().left) { 19672 $this.navcrollerLeft.trigger('click.tabview'); 19673 } 19674 } 19675 } 19676 }) 19677 .on('blur.tabview', function(){ 19678 $(this).removeClass('ui-tabs-outline'); 19679 }) 19680 .on('keydown.tabview', function(e) { 19681 var keyCode = $.ui.keyCode, 19682 key = e.which, 19683 element = $(this); 19684 19685 if((key === keyCode.SPACE || key === keyCode.ENTER) && !element.hasClass('ui-state-disabled')) { 19686 $this.select(element.index()); 19687 e.preventDefault(); 19688 } 19689 }); 19690 19691 //Scrolling 19692 if(this.cfg.scrollable) { 19693 this.navcrollerLeft.on('keydown.tabview', function(e) { 19694 var keyCode = $.ui.keyCode, 19695 key = e.which; 19696 19697 if(key === keyCode.SPACE || key === keyCode.ENTER) { 19698 $this.scroll(100); 19699 e.preventDefault(); 19700 } 19701 }); 19702 19703 this.navcrollerRight.on('keydown.tabview', function(e) { 19704 var keyCode = $.ui.keyCode, 19705 key = e.which; 19706 19707 if(key === keyCode.SPACE || key === keyCode.ENTER) { 19708 $this.scroll(-100); 19709 e.preventDefault(); 19710 } 19711 }); 19712 } 19713 }, 19714 19715 initScrolling: function() { 19716 if(this.headerContainer.length) { 19717 var overflown = ((this.lastTab.position().left + this.lastTab.width())
19717- this.firstTab.position().left) > this.navscroller.innerWidth(); 19718 if (overflown) { 19719 this.navscroller.removeClass('ui-tabs-navscroller-btn-hidden'); 19720 this.navcrollerLeft.attr('tabindex', this.tabindex); 19721 this.navcrollerRight.attr('tabindex', this.tabindex); 19722 this.restoreScrollState(); 19723 } 19724 else { 19725 this.navscroller.addClass('ui-tabs-navscroller-btn-hidden'); 19726 this.navcrollerLeft.attr('tabindex', this.tabindex); 19727 this.navcrollerRight.attr('tabindex', this.tabindex); 19728 } 19729 } 19730 }, 19731 19732 scroll: function(step) { 19733 if(this.navContainer.is(':animated')) { 19734 return; 19735 } 19736 19737 var oldMarginLeft = parseInt(this.navContainer.css('margin-left')), 19738 newMarginLeft = oldMarginLeft + step, 19739 viewportWidth = this.navscroller.innerWidth(), 19740 $this = this; 19741 19742 if(step < 0) { 19743 var lastTabBoundry = this.lastTab.position().left + parseInt(this.lastTab.innerWidth()); 19744 19745 if(lastTabBoundry > viewportWidth) 19746 this.navContainer.animate({'margin-left': newMarginLeft + 'px'}, 'fast', 'easeInOutCirc', function() { 19747 $this.saveScrollState(newMarginLeft); 19748 19749 if((lastTabBoundry + step) < viewportWidth) 19750 $this.disableScrollerButton($this.navcrollerRight); 19751 if($this.navcrollerLeft.hasClass('ui-state-disabled')) 19752 $this.enableScrollerButton($this.navcrollerLeft); 19753 }); 19754 } 19755 else { 19756 if(newMarginLeft <= 0) { 19757 this.navContainer.animate({'margin-left': newMarginLeft + 'px'}, 'fast', 'easeInOutCirc', function() { 19758 $this.saveScrollState(newMarginLeft); 19759 19760 if(newMarginLeft === 0) 19761 $this.disableScrollerButton($this.navcrollerLeft); 19762 if($this.navcrollerRight.hasClass('ui-state-disabled')) 19763 $this.enableScrollerButton($this.navcrollerRight); 19764 }); 19765 } 19766 } 19767 }, 19768 19769 disableScrollerButton: function(btn) { 19770 btn.addClass('ui-state-disabled').removeClass('ui-state-hover ui-state-active ui-state-focus').attr('tabindex', -1); 19771 }, 19772 19773 enableScrollerButton: function(btn) { 19774 btn.removeClass('ui-state-disabled').attr('tabindex', this.tabindex); 19775 }, 19776 19777 saveScrollState: function(value) { 19778 this.scrollStateHolder.val(value); 19779 }, 19780 19781 restoreScrollState: function() { 19782 var value = parseInt(this.scrollStateHolder.val()); 19783 if(value === 0) { 19784 this.disableScrollerButton(this.navcrollerLeft); 19785 } 19786 19787 this.navContainer.css('margin-left', this.scrollStateHolder.val() + 'px'); 19788 }, 19789 19790 /** 19791 * Selects an inactive tab given index 19792 */ 19793 select: function(index, silent) { 19794 //Call user onTabChange callback 19795 if(this.cfg.onTabChange && !silent) { 19796 var result = this.cfg.onTabChange.call(this, index); 19797 if(result === false) 19798 return false; 19799 } 19800 19801 var newPanel = this.panelContainer.children().eq(index), 19802 shouldLoad = this.cfg.dynamic && !this.isLoaded(newPanel); 19803 19804 //update state 19805 this.stateHolder.val(newPanel.data('index')); 19806 this.cfg.selected = index; 19807 19808 if(shouldLoad) { 19809 this.loadDynamicTab(newPanel); 19810 } 19811 else { 19812 this.show(newPanel); 19813 19814 if(this.hasBehavior('tabChange') && !silent) { 19815 this.fireTabChangeEvent(newPanel); 19816 } 19817 } 19818 19819 return true; 19820 }, 19821 19822 show: function(newPanel) { 19823 var headers = this.headerContainer, 19824 oldHeader = headers.filter('.ui-state-active'), 19825 oldActions = oldHeader.next('.ui-tabs-actions'), 19826 newHeader = headers.eq(newPanel.index()), 19827 newActions = newHeader.next('.ui-tabs-actions'), 19828 oldPanel = this.panelContainer.children('.ui-tabs-panel:visible'), 19829 _self = this; 19830 19831 //aria 19832 oldPanel.attr('aria-hidden', true); 19833 oldPanel.addClass('ui-helper-hidden'); 19834 oldHeader.attr('aria-expanded', false); 19835 oldHeader.attr('aria-selected', false); 19836 if(oldActions.length != 0) { 19837 oldActions.attr('aria-hidden', true); 19838 } 19839 19840 newPanel.attr('aria-hidden', false); 19841 newPanel.removeClass('ui-helper-hidden'); 19842 newHeader.attr('aria-expanded', true); 19843 newHeader.attr('aria-selected', true); 19844 if(newActions.length != 0) { 19845 newActions.attr('aria-hidden', false); 19846 } 19847 19848 if(this.cfg.effect) { 19849 oldPanel.hide(this.cfg.effect, null, this.cfg.effectDuration, function() { 19850 oldHeader.removeClass('ui-tabs-selected ui-state-active'); 19851 if(oldActions.length != 0) { 19852 oldActions.hide(_self.cfg.effect, null, _self.cfg.effectDuration); 19853 } 19854 19855 newHeader.addClass('ui-tabs-selected ui-state-active'); 19856 newPanel.show(_self.cfg.effect, null, _self.cfg.effectDuration, function() { 19857 _self.postTabShow(newPanel); 19858 }); 19859 if(newActions.length != 0) { 19860 newActions.show(_self.cfg.effect, null, _self.cfg.effectDuration); 19861 } 19862 }); 19863 } 19864 else { 19865 oldHeader.removeClass('ui-tabs-selected ui-state-active'); 19866 oldPanel.hide(); 19867 if(oldActions.length != 0) { 19868 oldActions.hide(); 19869 } 19870 19871 newHeader.addClass('ui-tabs-selected ui-state-active'); 19872 newPanel.show(); 19873 if(newActions.length != 0) { 19874 newActions.show(); 19875 } 19876 19877 this.postTabShow(newPanel); 19878 } 19879 }, 19880 19881 /** 19882 * Loads tab contents with ajax 19883 */ 19884 loadDynamicTab: function(newPanel) { 19885 var $this = this, 19886 options = { 19887 source: this.id, 19888 process: this.id, 19889 update: this.id, 19890 params: [ 19891 {name: this.id + '_contentLoad', value: true}, 19892 {name: this.id + '_newTab', value: newPanel.attr('id')}, 19893 {name: this.id + '_tabindex', value: newPanel.data('index')} 19894 ], 19895 onsuccess: function(responseXML, status, xhr) { 19896 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 19897 widget: $this, 19898 handle: function(content) { 19899 newPanel.html(content); 19900
19901 if(this.cfg.cache) { 19902 this.markAsLoaded(newPanel); 19903 } 19904 } 19905 }); 19906 19907 return true; 19908 }, 19909 oncomplete: function() { 19910 $this.show(newPanel); 19911 } 19912 }; 19913 19914 if(this.hasBehavior('tabChange')) { 19915 this.callBehavior('tabChange', options); 19916 } 19917 else { 19918 PrimeFaces.ajax.Request.handle(options); 19919 } 19920 }, 19921 19922 /** 19923 * Removes a tab with given index 19924 */ 19925 remove: function(index) { 19926 // remove old header and content 19927 var header = this.headerContainer.eq(index), 19928 panel = this.panelContainer.children().eq(index); 19929 19930 header.remove(); 19931 panel.remove(); 19932 19933 // refresh "chached" selectors 19934 this.headerContainer = this.navContainer.children('li.ui-tabs-header'); 19935 this.panelContainer = this.jq.children('.ui-tabs-panels'); 19936 19937 // select next tab 19938 var length = this.getLength(); 19939 if(length > 0) { 19940 if(index < this.cfg.selected) { 19941 this.cfg.selected--; 19942 } 19943 else if(index === this.cfg.selected) { 19944 var newIndex = (this.cfg.selected === (length)) ? (this.cfg.selected - 1): this.cfg.selected, 19945 newPanelHeader = this.headerContainer.eq(newIndex); 19946 19947 if(newPanelHeader.hasClass('ui-state-disabled')) { 19948 var newHeader = this.headerContainer.filter(':not(.ui-state-disabled):first'); 19949 if(newHeader.length) { 19950 this.select(newHeader.index(), true); 19951 } 19952 } 19953 else { 19954 this.select(newIndex, true); 19955 } 19956 } 19957 } 19958 else { 19959 this.cfg.selected = -1; 19960 } 19961 19962 this.fireTabCloseEvent(panel.attr('id'), index); 19963 }, 19964 19965 getLength: function() { 19966 return this.navContainer.children().length; 19967 }, 19968 19969 getActiveIndex: function() { 19970 return this.cfg.selected; 19971 }, 19972 19973 fireTabChangeEvent: function(panel) { 19974 var ext = { 19975 params: [ 19976 {name: this.id + '_newTab', value: panel.attr('id')}, 19977 {name: this.id + '_tabindex', value: panel.data('index')} 19978 ] 19979 }; 19980 19981 this.callBehavior('tabChange', ext); 19982 }, 19983 19984 fireTabCloseEvent: function(id, index) { 19985 if(this.hasBehavior('tabClose')) { 19986 var ext = { 19987 params: [ 19988 {name: this.id + '_closeTab', value: id}, 19989 {name: this.id + '_tabindex', value: index} 19990 ] 19991 }; 19992 19993 this.callBehavior('tabClose', ext); 19994 } 19995 }, 19996 19997 markAsLoaded: function(panel) { 19998 panel.data('loaded', true); 19999 }, 20000 20001 isLoaded: function(panel) { 20002 return panel.data('loaded') === true; 20003 }, 20004 20005 disable: function(index) { 20006 this.headerContainer.eq(index).addClass('ui-state-disabled'); 20007 }, 20008 20009 enable: function(index) { 20010 this.headerContainer.eq(index).removeClass('ui-state-disabled'); 20011 }, 20012 20013 postTabShow: function(newPanel) { 20014 //execute user defined callback 20015 if(this.cfg.onTabShow) { 20016 this.cfg.onTabShow.call(this, newPanel.index()); 20017 } 20018 20019 PrimeFaces.invokeDeferredRenders(this.id); 20020 } 20021 20022}); 20023 20024/**
20025 * PrimeFaces TagCloud Widget 20026 */ 20027PrimeFaces.widget.TagCloud = PrimeFaces.widget.BaseWidget.extend({ 20028 20029 init: function(cfg) { 20030 this._super(cfg); 20031 var _self = this; 20032 20033 this.jq.find('a').mouseover(function() { 20034 $(this).addClass('ui-state-hover'); 20035 }) 20036 .mouseout(function() { 20037 $(this).removeClass('ui-state-hover'); 20038 }) 20039 .click(function(e) { 20040 var link = $(this); 20041 20042 if(link.attr('href') === '#') { 20043 _self.fireSelectEvent(link); 20044 e.preventDefault(); 20045 } 20046 }); 20047 }, 20048 20049 fireSelectEvent: function(link) { 20050 if(this.hasBehavior('select')) { 20051 var ext = { 20052 params: [ 20053 {name: this.id + '_itemIndex', value: link.parent().index()} 20054 ] 20055 }; 20056 20057 this.callBehavior('select', ext); 20058 } 20059 } 20060 20061}); 20062/** 20063 * PrimeFaces Tooltip Widget 20064 */ 20065PrimeFaces.widget.Tooltip = PrimeFaces.widget.BaseWidget.extend({ 20066 20067 init: function(cfg) { 20068 this.cfg = cfg; 20069 this.id = this.cfg.id; 20070 this.cfg.showEvent = this.cfg.showEvent ? this.cfg.showEvent + '.tooltip' : 'mouseover.tooltip'; 20071 this.cfg.hideEvent = this.cfg.hideEvent ? this.cfg.hideEvent + '.tooltip' : 'mouseout.tooltip'; 20072 this.cfg.showEffect = this.cfg.showEffect ? this.cfg.showEffect : 'fade'; 20073 this.cfg.hideEffect = this.cfg.hideEffect ? this.cfg.hideEffect : 'fade'; 20074 this.cfg.showDelay = this.cfg.showDelay||150; 20075 this.cfg.hideDelay = this.cfg.hideDelay||0; 20076 this.cfg.hideEffectDuration = this.cfg.target ? 250 : 1; 20077 this.cfg.position = this.cfg.position||'right'; 20078 this.cfg.escape = (this.cfg.escape === undefined) ? true : this.cfg.escape; 20079 20080 if(this.cfg.target) 20081 this.bindTarget(); 20082 else 20083 this.bindGlobal(); 20084 20085 this.removeScriptElement(this.id); 20086 }, 20087 20088 //@override 20089 refresh: function(cfg) { 20090 if(cfg.target) { 20091 var targetTooltip = $(document.body).children(PrimeFaces.escapeClientId(cfg.id)); 20092 if(targetTooltip.length) 20093 targetTooltip.remove(); 20094 } 20095 else { 20096 $(document.body).children('.ui-tooltip-global').remove(); 20097 } 20098 20099 this._super(cfg); 20100 }, 20101 20102 bindGlobal: function() { 20103 this.jq = $('<div class="ui-tooltip ui-tooltip-global ui-widget ui-tooltip-' + this.cfg.position + '" role="tooltip"></div>') 20104 .appendTo('body'); 20105 this.jq.append('<div class="ui-tooltip-arrow"></div><div class="ui-tooltip-text ui-shadow ui-corner-all"></div>'); 20106 20107 this.jq.addClass(this.cfg.styleClass); 20108 20109 this.cfg.globalSelector = this.cfg.globalSelector||'a,:input,:button'; 20110 var $this = this; 20111 20112 $(document).off(this.cfg.showEvent + ' ' + this.cfg.hideEvent, this.cfg.globalSelector) 20113 .on(this.cfg.showEvent, this.cfg.globalSelector, function(e) { 20114 var element = $(this); 20115 if(element.prop('disabled')) { 20116 return; 20117 } 20118 20119 if($this.cfg.trackMouse) { 20120 $this.mouseEvent = e; 20121 } 20122 20123 var title = element.attr('title'); 20124 if(title) { 20125 element.data('tooltip', title).removeAttr('title'); 20126 } 20127 20128 var arrow = $this.jq.children('.ui-tooltip-arrow'); 20129 20130 if(element.hasClass('ui-state-error')) { 20131 $this.jq.children('.ui-tooltip-text').addClass('ui-state-error'); 20132 arrow.addClass('ui-state-error'); 20133 } 20134 else { 20135 arrow.removeClass('ui-state-error'); 20136 } 20137 20138 var text = element.data('tooltip'); 20139 if(text) { 20140 if($this.cfg.escape) 20141 $this.jq.children('.ui-tooltip-text').text(text); 20142 else 20143 $this.jq.children('.ui-tooltip-text').html(text); 20144 20145 $this.globalTitle = text; 20146 $this.target = element; 20147 $this.show(); 20148 } 20149 }) 20150 .on(this.cfg.hideEvent + '.tooltip', this.cfg.globalSelector, function() { 20151 if($this.globalTitle) { 20152 $this.hide(); 20153 $this.globalTitle = null; 20154 $this.target = null; 20155 $this.jq.children('.ui-tooltip-text').removeClass('ui-state-error'); 20156 } 20157 }); 20158 20159 PrimeFaces.utils.registerResizeHandler(this, 'resize.tooltip' + '_align', $this.jq, function() { 20160 $this.align(); 20161 }); 20162 20163 }, 20164 20165 bindTarget: function() { 20166 this.id = this.cfg.id; 20167 this.jqId = PrimeFaces.escapeClientId(this.id); 20168 this.jq = $(this.jqId); 20169 this.target = PrimeFaces.expressions.SearchExpressionFacade.resolve
20169ComponentsAsSelector(this.cfg.target); 20170 20171 var describedBy = this.target.attr("aria-describedby"); 20172 if (!describedBy || 0 === describedBy.length) { 20173 describedBy = this.id; 20174 } else { 20175 describedBy += " " + this.id; 20176 } 20177 this.target.attr("aria-describedby", describedBy); 20178 20179 var $this = this; 20180 if(this.cfg.delegate) { 20181 var targetSelector = "*[id='" + this.target.attr('id') + "']"; 20182 20183 $(document).off(this.cfg.showEvent + ' ' + this.cfg.hideEvent, targetSelector) 20184 .on(this.cfg.showEvent, targetSelector, function(e) { 20185 if($this.cfg.trackMouse) { 20186 $this.mouseEvent = e; 20187 } 20188 20189 if($.trim($this.jq.children('.ui-tooltip-text').html()) !== '') { 20190 $this.show(); 20191 } 20192 }) 20193 .on(this.cfg.hideEvent + '.tooltip', function() { 20194 $this.hide(); 20195 }); 20196 } 20197 else { 20198 this.target.off(this.cfg.showEvent + ' ' + this.cfg.hideEvent) 20199 .on(this.cfg.showEvent, function(e) { 20200 if($this.cfg.trackMouse) { 20201 $this.mouseEvent = e; 20202 } 20203 20204 if($.trim($this.jq.children('.ui-tooltip-text').html()) !== '') { 20205 $this.show(); 20206 } 20207 }) 20208 .on(this.cfg.hideEvent + '.tooltip', function() { 20209 $this.hide(); 20210 }); 20211 } 20212 20213 this.jq.appendTo(document.body); 20214 20215 if($.trim(this.jq.children('.ui-tooltip-text').html()) === '') { 20216 var text = this.target.attr('title'); 20217 if(this.cfg.escape) 20218 this.jq.children('.ui-tooltip-text').text(text); 20219 else 20220 this.jq.children('.ui-tooltip-text').html(text); 20221 } 20222 20223 this.target.removeAttr('title'); 20224 20225 20226 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 20227 $this.align(); 20228 }); 20229 }, 20230 20231 alignUsing: function(position,feedback) { 20232 this.jq.removeClass('ui-tooltip-left ui-tooltip-right ui-tooltip-top ui-tooltip-bottom'); 20233 switch (this.cfg.position) { 20234 case "right": 20235 case "left": 20236 this.jq.addClass('ui-tooltip-'+ 20237 (feedback['horizontal']=='left'?'right':'left')); 20238 break; 20239 case "top": 20240 case "bottom": 20241 this.jq.addClass('ui-tooltip-'+ 20242 (feedback['vertical']=='top'?'bottom':'top')); 20243 break; 20244 } 20245 this.jq.css({ 20246 left: position['left'], 20247 top: position['top'] 20248 }); 20249 }, 20250 20251 align: function() { 20252 var $this = this; 20253 this.jq.css({ 20254 left:'', 20255 top:'', 20256 'z-index': ++PrimeFaces.zindex 20257 }); 20258 20259 if(this.cfg.trackMouse && this.mouseEvent) { 20260 this.jq.position({ 20261 my: 'left top+15', 20262 at: 'right bottom', 20263 of: this.mouseEvent, 20264 collision: 'flipfit', 20265 using: function(p,f) { 20266 $this.alignUsing.call($this,p,f); 20267 } 20268 }); 20269 20270 this.mouseEvent = null; 20271 } 20272 else { 20273 var _my, _at; 20274 20275 switch(this.cfg.position) { 20276 case 'right': 20277 _my = 'left center'; 20278 _at = 'right center'; 20279 break; 20280 20281 case 'left': 20282 _my = 'right center'; 20283 _at = 'left center'; 20284 break; 20285 20286 case 'top': 20287 _my = 'center bottom'; 20288 _at = 'center top'; 20289 break; 20290 20291 case 'bottom': 20292 _my = 'center top'; 20293 _at = 'center bottom'; 20294 break; 20295 } 20296 20297 this.jq.position({ 20298 my: _my, 20299 at: _at, 20300 of: this.getTarget(), 20301 collision: 'flipfit', 20302 using: function(p,f) { 20303 $this.alignUsing.call($this,p,f); 20304 } 20305 }); 20306 } 20307 }, 20308 20309 show: function() { 20310 if(this.getTarget()) { 20311 var $this = this; 20312 this.clearTimeout(); 20313 20314 this.timeout = setTimeout(function() { 20315 $this._show(); 20316 }, this.cfg.showDelay); 20317 } 20318 }, 20319 20320 _show: function() { 20321 var $this = this; 20322 20323 if(this.cfg.beforeShow) { 20324 var retVal = this.cfg.beforeShow.call(this); 20325 if(retVal === false) { 20326 return; 20327 } 20328 } 20329 20330 this.jq.css({'display':'block', 'opacity':0, 'pointer-events': 'none'}); 20331 20332 this.align(); 20333 20334 this.jq.css({'display':'none', 'opacity':'', 'pointer-events': ''}); 20335 20336 if(this.cfg.trackMouse) { 20337 this.followMouse(); 20338 } 20339 this.jq.show(this.cfg.showEffect, {}, 250, function() { 20340 if($this.cfg.onShow) { 20341 $this.cfg.onShow.call(); 20342 } 20343 }); 20344 }, 20345 20346 hide: function() { 20347 var $this = this; 20348 this.clearTimeout(); 20349 20350 if(this.cfg.hideDelay) { 20351 this.timeout = setTimeout(function() { 20352 $this._hide(); 20353 }, this.cfg.hideDelay); 20354 } 20355 else { 20356 this._hide(); 20357 } 20358 }, 20359 20360 _hide: function() { 20361 var $this = this; 20362 20363 if(this.isVisible()) { 20364 this.jq.hide(this.cfg.hideEffect, {}, this.cfg.hideEffectDuration, function() { 20365 $(this).css('z-index', ''); 20366 if($this.cfg.trackMouse) { 20367 $this.unfollowMouse(); 20368 } 20369 20370 if($this.cfg.onHide) { 20371 $this.cfg.onHide.call(); 20372 } 20373 }); 20374 } 20375 }, 20376 20377 clearTimeout: function() { 20378 if(this.timeout) { 20379 clearTimeout(this.timeout); 20380 } 20381 }, 20382 20383 followMouse: function() { 20384 var $this = this; 20385 20386 this.getTarget().on('mousemove.tooltip-track', function(e) { 20387 $this.jq.position({ 20388 my: 'left top+15', 20389 at: 'right bottom', 20390 of: e, 20391 collision: 'flipfit' 20392 }); 20393 }); 20394 }, 20395 20396 unfollowMouse: function() { 20397 var target = this.getTarget(); 20398 if(target) { 20399 target.off('mousemove.tooltip-track'); 20400 } 20401 }, 20402 20403 isVisible: function() { 20404 return this.jq.is(':visible'); 20405 }, 20406 20407 getTarget: function() { 20408 if(this.cfg.delegate) 20409 return PrimeFaces.expressions.SearchExpressionFacade.resolve
20409ComponentsAsSelector(this.cfg.target); 20410 else 20411 return this.target; 20412 } 20413 20414}); 20415 20416/** 20417 * PrimeFaces Base Tree Widget 20418 */ 20419PrimeFaces.widget.BaseTree = PrimeFaces.widget.BaseWidget.extend({ 20420 20421 init: function(cfg) { 20422 this._super(cfg); 20423 this.cfg.highlight = (this.cfg.highlight === false) ? false : true; 20424 this.focusedNode = null; 20425 20426 if(!this.cfg.disabled) { 20427 if(this.cfg.selectionMode) { 20428 this.initSelection(); 20429 } 20430 20431 this.bindEvents(); 20432 20433 this.jq.data('widget', cfg.widgetVar); 20434 } 20435 }, 20436 20437 initSelection: function() { 20438 this.selectionHolder = $(this.jqId + '_selection'); 20439 var selectionsValue = this.selectionHolder.val(); 20440 this.selections = selectionsValue === '' ? [] : selectionsValue.split(','); 20441 20442 if(this.cursorNode) { 20443 this.cursorNode = this.jq.find('.ui-treenode[data-rowkey="' + $.escapeSelector(this.cursorNode.data('rowkey')) + '"]'); 20444 } 20445 20446 if(this.isCheckboxSelection() && this.cfg.propagateUp) { 20447 this.preselectCheckbox(); 20448 } 20449 }, 20450 20451 bindContextMenu : function(menuWidget, targetWidget, targetId, cfg) { 20452 var nodeContentSelector = targetId + ' .ui-tree-selectable', 20453 nodeEvent = cfg.nodeType ? cfg.event + '.treenode.' + cfg.nodeType : cfg.event + '.treenode', 20454 containerEvent = cfg.event + '.tree'; 20455 20456 $(document).off(nodeEvent, nodeContentSelector).on(nodeEvent, nodeContentSelector, null, function(e) { 20457 var nodeContent = $(this); 20458 20459 if($(e.target).is(':not(.ui-tree-toggler)') && (cfg.nodeType === undefined || nodeContent.parent().data('nodetype') === cfg.nodeType)) { 20460 var isContextMenuDelayed = targetWidget.nodeRightClick(e, nodeContent, function(){ 20461 menuWidget.show(e); 20462 }); 20463 20464 if(isContextMenuDelayed) { 20465 e.preventDefault(); 20466 e.stopPropagation(); 20467 } 20468 } 20469 }); 20470 20471 $(document).off(containerEvent, this.jqTargetId).on(containerEvent, this.jqTargetId, null, function(e) { 20472 if(targetWidget.isEmpty()) { 20473 menuWidget.show(e); 20474 } 20475 }); 20476 }, 20477 20478 expandNode: function(node) { 20479 var $this = this; 20480 20481 if(this.cfg.dynamic) { 20482 if(this.cfg.cache && $this.getNodeChildrenContainer(node).children().length > 0) { 20483 this.showNodeChildren(node); 20484 20485 return; 20486 } 20487 20488 if(node.data('processing')) { 20489 PrimeFaces.debug('Node is already being expanded, ignoring expand event.'); 20490 return; 20491 } 20492 20493 node.data('processing', true); 20494 20495 var options = { 20496 source: this.id, 20497 process: this.id, 20498 update: this.id, 20499 formId: this.cfg.formId, 20500 params: [ 20501 {name: this.id + '_expandNode', value: $this.getRowKey(node)} 20502 ], 20503 onsuccess: function(responseXML, status, xhr) { 20504 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 20505 widget: $this, 20506 handle: function(content) { 20507 var nodeChildrenContainer = this.getNodeChildrenContainer(node); 20508 nodeChildrenContainer.append(content); 20509 20510 this.showNodeChildren(node); 20511 20512 if(this.cfg.draggable) { 20513 this.makeDraggable(nodeChildrenContainer.find('span.ui-treenode-content')); 20514 } 20515 20516 if(this.cfg.droppable) { 20517 this.makeDropPoints(nodeChildrenContainer.find('li.ui-tree-droppoint')); 20518 this.makeDropNodes(nodeChildrenContainer.find('span.ui-treenode-droppable')); 20519 } 20520 } 20521 }); 20522 20523 return true; 20524 }, 20525 oncomplete: function() { 20526 node.removeData('processing'); 20527 } 20528 }; 20529 20530 if(this.hasBehavior('expand')) { 20531 this.callBehavior('expand', options); 20532 } 20533 else { 20534 PrimeFaces.ajax.Request.handle(options); 20535 } 20536 } 20537 else { 20538 this.showNodeChildren(node); 20539 this.fireExpandEvent(node); 20540 } 20541 }, 20542 20543 fireExpandEvent: function(node) { 20544 if(this.hasBehavior('expand')) { 20545 var ext = { 20546 params: [ 20547 {name: this.id + '_expandNode', value: this.getRowKey(node)} 20548 ] 20549 }; 20550 20551 this.callBehavior('expand', ext); 20552 } 20553 }, 20554 20555 fireCollapseEvent: function(node) { 20556 if(this.hasBehavior('collapse')) { 20557 var ext = { 20558 params: [ 20559 {name: this.id + '_collapseNode', value: this.getRowKey(node)} 20560 ] 20561 }; 20562 20563 this.callBehavior('collapse', ext); 20564 } 20565 }, 20566 20567 getNodeChildrenContainer: function(node) { 20568 throw "Unsupported Operation"; 20569 }, 20570 20571 showNodeChildren: function(node) { 20572 throw "Unsupported Operation"; 20573 }, 20574 20575 writeSelections: function() { 20576 this.selectionHolder.val(this.selections.join(',')); 20577 }, 20578 20579 fireNodeSelectEvent: function(node) { 20580 if(this.isCheckboxSelection() && this.cfg.dynamic) { 20581 var $this = this, 20582 options = { 20583 source: this.id, 20584 process: this.id 20585 }; 20586 20587 options.params = [ 20588 {name: this.id + '_instantSelection', value: this.getRowKey(node)} 20589 ]; 20590 20591 options.oncomplete = function(xhr, status, args, data) { 20592 if(args.descendantRowKeys && args.descendantRowKeys !== '') { 20593 var rowKeys = args.descendantRowKeys.split(','); 20594 for(var i = 0; i < rowKeys.length; i++) { 20595 $this.addToSelection(rowKeys[i]); 20596 } 20597 $this.writeSelections(); 20598 } 20599 }; 20600 20601 if(this.hasBehavior('select')) { 20602 this.callBehavior('select', options); 20603 } 20604 else { 20605 PrimeFaces.ajax.Request.handle(options); 20606 } 20607 } 20608 else { 20609 if(this.hasBehavior('select')) { 20610 var ext = { 20611 params: [ 20612 {name: this.id + '_instantSelection', value: this.getRowKey(node)} 20613 ] 20614 }; 20615 20616 this.callBehavior('select', ext); 20617 } 20618 } 20619 }, 20620 20621 fireNodeUnselectEvent: function(node) { 20622 if(this.hasBehavior('unselect')) { 20623 var ext = { 20624 params: [ 20625 {name: this.id + '_instantUnselection', value: this.getRowKey(node)} 20626 ] 20627 }; 20628 20629 this.callBehavior('unselect', ext); 20630 } 20631 }, 20632 20633 fireContextMenuEvent: function(node, fnShowMenu) { 20634 if(this.hasBehavior('contextMenu')) { 20635 var ext = { 20636 params: [ 20637 {name: this.id + '_contextMenuNode', value: this.getRowKey(node)} 20638 ], 20639 oncomplete: function() { 20640 fnShowMenu(); 20641 } 20642 }; 20643 20644 this.callBehavior('contextMenu', ext); 20645 } else { 20646 fnShowMenu(); 20647 } 20648 }, 20649 20650 getRowKey: function(node) { 20651 return node.attr('data-rowkey'); 20652 }, 20653 20654 isNodeSelected: function(node) { 20655 return $.inArray(this.getRowKey(node), this.selections) != -1; 20656 }, 20657 20658 isSingleSelection: function() { 20659 return this.cfg.selectionMode == 'single'; 20660 }, 20661 20662 isMultipleSelection: function() { 20663 return this.cfg.selectionMode == 'multiple'; 20664 }, 20665 20666 isCheckboxSelection: function() { 20667 return this.cfg.selectionMode == 'checkbox'; 20668 }, 20669 20670 addToSelection: function(rowKey) { 20671 if(!PrimeFaces.inArray(this.selections, rowKey)) { 20672 this.selections.push(rowKey); 20673 } 20674 }, 20675 20676 removeFromSelection: function(rowKey) { 20677 this.selections = $.grep(this.selections, function(r) { 20678 return r !== rowKey; 20679 }); 20680 }, 20681 20682 removeDescendantsFromSelection: function(rowKey) { 20683 var newSelections = []; 20684 for(var i = 0; i < this.selections.length; i++) { 20685 if(this.selections[i].indexOf(rowKey + '_') !== 0) 20686 newSelections.push(this.selections[i]); 20687 } 20688 this.selections = newSelections; 20689 }, 20690 20691 nodeClick: function(event, nodeContent) { 20692 if($(event.target).is(':not(.ui-tree-toggler)')) { 20693 var node = nodeContent.parent(), 20694 selectable = nodeContent.hasClass('ui-tree-selectable'); 20695 20696 if(this.cfg.onNodeClick) { 20697 var retVal = this.cfg.onNodeClick.call(this, node, event); 20698 if (retVal === false) { 20699 return; 20700 } 20701 } 20702 20703 if(selectable && this.cfg.selectionMode) { 20704 var selected = this.isNodeSelected(node), 20705 metaKey = event.metaKey||event.ctrlKey,
20706 shiftKey = event.shiftKey; 20707 20708 if(this.isCheckboxSelection()) { 20709 this.toggleCheckboxNode(node); 20710 } 20711 else { 20712 if(selected && (metaKey)) { 20713 this.unselectNode(node); 20714 } 20715 else { 20716 if(this.isSingleSelection()||(this.isMultipleSelection() && !metaKey)) { 20717 this.unselectAllNodes(); 20718 } 20719 20720 if(this.isMultipleSelection() && shiftKey && this.cursorNode && (this.cursorNode.parent().is(node.parent()))) { 20721 var parentList = node.parent(), 20722 treenodes = parentList.children('li.ui-treenode'), 20723 currentNodeIndex = treenodes.index(node), 20724 cursorNodeIndex = treenodes.index(this.cursorNode), 20725 startIndex = (currentNodeIndex > cursorNodeIndex) ? cursorNodeIndex : currentNodeIndex, 20726 endIndex = (currentNodeIndex > cursorNodeIndex) ? (currentNodeIndex + 1) : (cursorNodeIndex + 1); 20727 20728 for(var i = startIndex; i < endIndex; i++) { 20729 var treenode = treenodes.eq(i); 20730 if(treenode.is(':visible')) { 20731 if(i === (endIndex - 1)) 20732 this.selectNode(treenode); 20733 else 20734 this.selectNode(treenode, true); 20735 } 20736 } 20737 } 20738 else { 20739 this.selectNode(node); 20740 this.cursorNode = node; 20741 } 20742 } 20743 } 20744 20745 if($(event.target).is(':not(:input:enabled)')) { 20746 PrimeFaces.clearSelection(); 20747 this.focusNode(node); 20748 } 20749 } 20750 } 20751 }, 20752 20753 nodeRightClick: function(event, nodeContent, fnShowMenu) { 20754 PrimeFaces.clearSelection(); 20755 20756 if($(event.target).is(':not(.ui-tree-toggler)')) { 20757 var node = nodeContent.parent(), 20758 selectable = nodeContent.hasClass('ui-tree-selectable'); 20759 20760 if(selectable && this.cfg.selectionMode) { 20761 var selected = this.isNodeSelected(node); 20762 if(!selected) { 20763 if(this.isCheckboxSelection()) { 20764 this.toggleCheckboxNode(node); 20765 } 20766 else { 20767 this.unselectAllNodes(); 20768 this.selectNode(node, true); 20769 this.cursorNode = node; 20770 } 20771 } 20772 20773 this.fireContextMenuEvent(node, fnShowMenu); 20774 return true; 20775 } 20776 } 20777 return false; 20778 }, 20779 20780 bindEvents: function() { 20781 throw "Unsupported Operation"; 20782 }, 20783 20784 selectNode: function(node, silent) { 20785 throw "Unsupported Operation"; 20786 }, 20787 20788 unselectNode: function(node, silent) { 20789 throw "Unsupported Operation"; 20790 }, 20791 20792 unselectAllNodes: function() { 20793 throw "Unsupported Operation"; 20794 }, 20795 20796 preselectCheckbox: function() { 20797 throw "Unsupported Operation"; 20798 }, 20799 20800 toggleCheckboxNode: function(node) { 20801 throw "Unsupported Operation"; 20802 }, 20803 20804 isEmpty: function() { 20805 throw "Unsupported Operation"; 20806 }, 20807 20808 toggleCheckboxState: function(checkbox, checked) { 20809 if(checked) 20810 this.uncheck(checkbox); 20811 else 20812 this.check(checkbox); 20813 }, 20814 20815 partialCheck: function(checkbox) { 20816 var box = checkbox.children('.ui-chkbox-box'), 20817 icon = box.children('.ui-chkbox-icon'), 20818 treeNode = checkbox.closest('.ui-treenode'), 20819 rowKey = this.getRowKey(treeNode); 20820 20821 treeNode.find('> .ui-treenode-content > .ui-treenode-label').removeClass('ui-state-highlight'); 20822 icon.removeClass('ui-icon-blank ui-icon-check').addClass('ui-icon-minus'); 20823 treeNode.removeClass('ui-treenode-selected ui-treenode-unselected').addClass('ui-treenode-hasselected').attr('aria-checked', false).attr('aria-selected', false); 20824 20825 this.removeFromSelection(rowKey); 20826 }, 20827 20828 check: function(checkbox) { 20829 var box = checkbox.children('.ui-chkbox-box'), 20830 icon = box.children('.ui-chkbox-icon'), 20831 treeNode = checkbox.closest('.ui-treenode'), 20832 rowKey = this.getRowKey(treeNode); 20833 20834 box.removeClass('ui-state-hover'); 20835 icon.removeClass('ui-icon-blank ui-icon-minus').addClass('ui-icon-check'); 20836 treeNode.removeClass('ui-treenode-hasselected ui-treenode-unselected').addClass('ui-treenode-selected').attr('aria-checked', true).attr('aria-selected', true); 20837 20838 this.addToSelection(rowKey); 20839 }, 20840 20841 uncheck: function(checkbox) { 20842 var box = checkbox.children('.ui-chkbox-box'), 20843 icon = box.children('.ui-chkbox-icon'), 20844 treeNode = checkbox.closest('.ui-treenode'), 20845 rowKey = this.getRowKey(treeNode); 20846 20847 box.removeClass('ui-state-hover'); 20848 icon.removeClass('ui-icon-minus ui-icon-check').addClass('ui-icon-blank'); 20849 treeNode.removeClass('ui-treenode-hasselected ui-treenode-selected').addClass('ui-treenode-unselected').attr('aria-checked', false).attr('aria-selected', false); 20850 20851 this.removeFromSelection(rowKey); 20852 }, 20853 20854 isExpanded: function(node) { 20855 return this.getNodeChildrenContainer(node).is(':visible'); 20856 }, 20857 20858 focusNode: function() { 20859 throw "Unsupported Operation"; 20860 } 20861 20862}); 20863 20864/** 20865 * PrimeFaces Vertical Tree Widget 20866 */ 20867PrimeFaces.widget.VerticalTree = PrimeFaces.widget.BaseTree.extend({ 20868 20869 init: function(cfg) { 20870 this._super(cfg); 20871 20872 this.container = this.jq.children('.ui-tree-container'); 20873 this.cfg.rtl = this.jq.hasClass('ui-tree-rtl'); 20874 this.cfg.collapsedIcon = this.cfg.rtl ? 'ui-icon-triangle-1-w' : 'ui-icon-triangle-1-e'; 20875 this.scrollStateHolder = $(this.jqId + '_scrollState'); 20876 20877 if(!this.cfg.disabled) { 20878 if(this.cfg.draggable) { 20879 this.initDraggable(); 20880 } 20881 20882 if(this.cfg.droppable) { 20883 this.initDroppable(); 20884 } 20885 } 20886 20887 this.restoreScrollState(); 20888 }, 20889 20890 bindEvents: function() { 20891 var $this = this, 20892 togglerSelector = '.ui-tree-toggler', 20893 nodeLabelSelector = '.ui-tree-selectable .ui-treenode-label', 20894 nodeContentSelector = '.ui-treenode-content'; 20895 20896 this.jq.off('click.tree-toggle', togglerSelector) 20897 .on('click.tree-toggle', togglerSelector, null, function(e) { 20898 var toggleIcon = $(this), 20899 node = toggleIcon.closest('li'); 20900 20901 if(toggleIcon.hasClass($this.cfg.collapsedIcon)) 20902 $this.expandNode(node); 20903 else 20904 $this.collapseNode(node); 20905 }); 20906 20907 if(this.cfg.highlight && this.cfg.selectionMode) { 20908 this.jq.off('mouseout.tree mouseover.tree', nodeLabelSelector) 20909 .on('mouseout.tree', nodeLabelSelector, null, function() { 20910 var label = $(this); 20911 20912 label.removeClass('ui-state-hover'); 20913 20914 if($this.isCheckboxSelection()) { 20915 label.siblings('div.ui-chkbox').children('div.ui-chkbox-box').removeClass('ui-state-hover'); 20916 } 20917 }) 20918 .on('mouseover.tree', nodeLabelSelector, null, function() { 20919 var label = $(this); 20920 20921 $(this).addClass('ui-state-hover'); 20922 20923 if($this.isCheckboxSelection()) { 20924 label.siblings('div.ui-chkbox').children('div.ui-chkbox-box').addClass('ui-state-hover'); 20925 } 20926 }); 20927 } 20928 20929 if(this.isCheckboxSelection()) { 20930 var checkboxSelector = '.ui-chkbox-box:not(.ui-state-disabled)'; 20931 20932 this.jq.off('mouseout.tree-checkbox mouseover.tree-checkbox click.tree-checkbox', checkboxSelector) 20933 .on('mouseout.tree-checkbox', checkboxSelector, null, function() { 20934 $(this).removeClass('ui-state-hover').parent().siblings('span.ui-treenode-label').removeClass('ui-state-hover'); 20935 }) 20936 .on('mouseover.tree-checkbox', checkboxSelector, null, function() { 20937 $(this).addClass('ui-state-hover').parent().siblings('span.ui-treenode-label').addClass('ui-state-hover'); 20938 }); 20939 } 20940 20941 this.jq.off('click.tree-content', nodeContentSelector) 20942 .on('click.tree-content', nodeContentSelector, null, function(e) { 20943 $this.nodeClick(e, $(this)); 20944 }); 20945 20946 if(this.cfg.filter) { 20947 this.filterInput = this.jq.find('.ui-tree-filter'); 20948 PrimeFaces.skinInput(this.filterInput); 20949 20950 this.filterInput.on('keydown.tree-filter', PrimeFaces.utils.blockEnterKey) 20951 .on('keyup.tree-filter', function(e) { 20952 if (PrimeFaces.utils.ignoreFilterKey(e)) { 20953 return; 20954 } 20955 20956 if($this.filterTimeout) { 20957 clearTimeout($this.filterTimeout); 20958 } 20959 20960 $this.filterTimeout = setTimeout(function() { 20961 $this.filter(); 20962 $this.filterTimeout = null; 20963 }, 300); 20964 }); 20965 } 20966 20967 this.jq.on('scroll.tree', function(e) { 20968 $this.saveScrollState(); 20969 }); 20970 20971 this.bindKeyEvents(); 20972 }, 20973 20974 bindKeyEvents: function() { 20975 var $this = this, 20976 pressTab = false;
20977 20978 this.jq.on('mousedown.tree', function(e) { 20979 if($(e.target).is(':not(:input:enabled)')) { 20980 e.preventDefault(); 20981 } 20982 }) 20983 .on('focus.tree', function() { 20984 if(!$this.focusedNode && !pressTab) { 20985 $this.focusNode($this.getFirstNode()); 20986 } 20987 }); 20988 20989 this.jq.off('keydown.tree blur.tree', '.ui-treenode-label').on('keydown.tree', '.ui-treenode-label', null, function(e) { 20990 if(!$this.focusedNode) { 20991 return; 20992 } 20993 20994 var searchRowkey = "", 20995 keyCode = $.ui.keyCode; 20996 20997 switch(e.which) { 20998 case keyCode.LEFT: 20999 var rowkey = $this.focusedNode.data('rowkey').toString(), 21000 keyLength = rowkey.length; 21001 21002 if($this.isExpanded($this.focusedNode)) { 21003 $this.collapseNode($this.focusedNode); 21004 } 21005 else { 21006 var nodeToFocus = null; 21007 for(var i = 1; i < parseInt(keyLength / 2) + 1; i++){ 21008 searchRowkey = rowkey.substring(0, keyLength - 2 * i); 21009 nodeToFocus = $this.container.find("li:visible[data-rowkey = '" + searchRowkey + "']"); 21010 if(nodeToFocus.length) { 21011 $this.focusNode(nodeToFocus); 21012 break; 21013 } 21014 } 21015 } 21016 21017 e.preventDefault(); 21018 break; 21019 21020 case keyCode.RIGHT: 21021 if(!$this.focusedNode.hasClass('ui-treenode-leaf')) { 21022 var rowkey = $this.focusedNode.data('rowkey').toString(), 21023 keyLength = rowkey.length; 21024 21025 if(!$this.isExpanded($this.focusedNode)) { 21026 $this.expandNode($this.focusedNode); 21027 } 21028 21029 if(!$this.isExpanded($this.focusedNode) && !$this.cfg.dynamic) { 21030 searchRowkey = rowkey + '_0'; 21031 var nodeToFocus = $this.container.find("li:visible[data-rowkey = '" + searchRowkey + "']"); 21032 21033 if(nodeToFocus.length) { 21034 $this.focusNode(nodeToFocus); 21035 } 21036 } 21037 } 21038 21039 e.preventDefault(); 21040 break; 21041 21042 case keyCode.UP: 21043 var nodeToFocus = null, 21044 prevNode = $this.focusedNode.prev(); 21045 21046 if(prevNode.length) { 21047 nodeToFocus = prevNode.find('li.ui-treenode:visible:last'); 21048 if(!nodeToFocus.length) { 21049 nodeToFocus = prevNode; 21050 } 21051 } 21052 else { 21053 nodeToFocus = $this.focusedNode.closest('ul').parent('li'); 21054 } 21055 21056 if(nodeToFocus.length) { 21057 $this.focusNode(nodeToFocus); 21058 } 21059 21060 e.preventDefault(); 21061 break; 21062 21063 case keyCode.DOWN: 21064 var nodeToFocus = null, 21065 firstVisibleChildNode = $this.focusedNode.find("> ul > li:visible:first"); 21066 21067 if(firstVisibleChildNode.length) { 21068 nodeToFocus = firstVisibleChildNode; 21069 } 21070 else if($this.focusedNode.next().length) { 21071 nodeToFocus = $this.focusedNode.next(); 21072 } 21073 else { 21074 var rowkey = $this.focusedNode.data('rowkey').toString(); 21075 21076 if(rowkey.length !== 1) { 21077 nodeToFocus = $this.searchDown($this.focusedNode); 21078 } 21079 } 21080 21081 if(nodeToFocus && nodeToFocus.length) { 21082 $this.focusNode(nodeToFocus); 21083 } 21084 21085 e.preventDefault(); 21086 break; 21087 21088 case keyCode.ENTER: 21089 case keyCode.SPACE: 21090 if($this.cfg.selectionMode) { 21091 var selectable = $this.focusedNode.children('.ui-treenode-content').hasClass('ui-tree-selectable'); 21092 21093 if($this.cfg.onNodeClick) { 21094 var retVal = $this.cfg.onNodeClick.call($this, $this.focusedNode, e); 21095 if (retVal === false) { 21096 return; 21097 } 21098 } 21099 21100 if(selectable) { 21101 var selected = $this.isNodeSelected($this.focusedNode); 21102 21103 if($this.isCheckboxSelection()) { 21104 $this.toggleCheckboxNode($this.focusedNode); 21105 } 21106 else { 21107 if(selected) { 21108 $this.unselectNode($this.focusedNode); 21109 } 21110 else { 21111 if($this.isSingleSelection()) { 21112 $this.unselectAllNodes(); 21113 } 21114 21115 $this.selectNode($this.focusedNode); 21116 $this.cursorNode = $this.focusedNode; 21117 } 21118 } 21119 } 21120 } 21121 21122 e.preventDefault(); 21123 break; 21124 21125 case keyCode.TAB: 21126 pressTab = true; 21127 $this.jq.focus(); 21128 setTimeout(function() { 21129 pressTab = false;
21130 }, 2); 21131 21132 break; 21133 } 21134 }) 21135 .on('blur.tree', '.ui-treenode-label', null, function(e) { 21136 if($this.focusedNode) { 21137 $this.getNodeLabel($this.focusedNode).removeClass('ui-treenode-outline'); 21138 $this.focusedNode = null; 21139 } 21140 }); 21141 21142 /* For copy/paste operation on drag and drop */ 21143 $(document.body).on('keydown.tree', function(e) { 21144 $this.shiftKey = e.shiftKey; 21145 }) 21146 .on('keyup.tree', function() { 21147 $this.shiftKey = false; 21148 }); 21149 }, 21150 21151 searchDown: function(node) { 21152 var nextOfParent = node.closest('ul').parent('li').next(), 21153 nodeToFocus = null; 21154 21155 if(nextOfParent.length) { 21156 nodeToFocus = nextOfParent; 21157 } 21158 else if(node.hasClass('ui-treenode-leaf') && node.closest('ul').parent('li').length == 0){ 21159 nodeToFocus = node; 21160 } 21161 else { 21162 var rowkey = node.data('rowkey').toString(); 21163 21164 if(rowkey.length !== 1) { 21165 nodeToFocus = this.searchDown(node.closest('ul').parent('li')); 21166 } 21167 } 21168 21169 return nodeToFocus; 21170 }, 21171 21172 collapseNode: function(node) { 21173 var _self = this, 21174 nodeContent = node.find('> .ui-treenode-content'), 21175 toggleIcon = nodeContent.find('> .ui-tree-toggler'), 21176 nodeType = node.data('nodetype'), 21177 nodeIcon = toggleIcon.nextAll('span.ui-treenode-icon'), 21178 iconState = this.cfg.iconStates[nodeType], 21179 childrenContainer = node.children('.ui-treenode-children'); 21180 21181 //aria 21182 nodeContent.find('> .ui-treenode-label').attr('aria-expanded', false); 21183 21184 toggleIcon.removeClass('ui-icon-triangle-1-s').addClass(_self.cfg.collapsedIcon); 21185 21186 if(iconState) { 21187 nodeIcon.removeClass(iconState.expandedIcon).addClass(iconState.collapsedIcon); 21188 } 21189 21190 if(this.cfg.animate) { 21191 childrenContainer.slideUp('fast', function() { 21192 _self.postCollapse(node, childrenContainer); 21193 }); 21194 } 21195 else { 21196 childrenContainer.hide(); 21197 this.postCollapse(node, childrenContainer); 21198 } 21199 }, 21200 21201 postCollapse: function(node, childrenContainer) { 21202 if(this.cfg.dynamic && !this.cfg.cache) { 21203 childrenContainer.empty(); 21204 } 21205 21206 if(!this.cfg.cache) { 21207 this.fireCollapseEvent(node); 21208 } 21209 }, 21210 21211 //@Override 21212 getNodeChildrenContainer: function(node) { 21213 return node.children('.ui-treenode-children'); 21214 }, 21215 21216 //@Override 21217 showNodeChildren: function(node) { 21218 var nodeContent = node.find('> .ui-treenode-content'), 21219 toggleIcon = nodeContent.find('> .ui-tree-toggler'), 21220 nodeType = node.data('nodetype'), 21221 nodeIcon = toggleIcon.nextAll('span.ui-treenode-icon'), 21222 iconState = this.cfg.iconStates[nodeType]; 21223 21224 //aria 21225 nodeContent.find('> .ui-treenode-label').attr('aria-expanded', true); 21226 21227 toggleIcon.removeClass(this.cfg.collapsedIcon).addClass('ui-icon-triangle-1-s'); 21228 21229 if(iconState) { 21230 nodeIcon.removeClass(iconState.collapsedIcon).addClass(iconState.expandedIcon); 21231 } 21232 21233 if(this.cfg.animate) { 21234 node.children('.ui-treenode-children').slideDown('fast'); 21235 } 21236 else { 21237 node.children('.ui-treenode-children').show(); 21238 } 21239 }, 21240 21241 unselectAllNodes: function() { 21242 this.selections = []; 21243 this.jq.find('.ui-treenode-label.ui-state-highlight').each(function() { 21244 $(this).removeClass('ui-state-highlight').closest('.ui-treenode').attr('aria-selected', false); 21245 }); 21246 }, 21247 21248 selectNode: function(node, silent) { 21249 node.attr('aria-selected', true) 21250 .find('> .ui-treenode-content > .ui-treenode-label').removeClass('ui-state-hover').addClass('ui-state-highlight'); 21251 21252 this.addToSelection(this.getRowKey(node)); 21253 this.writeSelections(); 21254 21255 if(!silent) 21256 this.fireNodeSelectEvent(node); 21257 }, 21258 21259 unselectNode: function(node, silent) { 21260 var rowKey = this.getRowKey(node); 21261 21262 node.attr('aria-selected', false). 21263 find('> .ui-treenode-content > .ui-treenode-label').removeClass('ui-state-highlight ui-state-hover'); 21264 21265 this.removeFromSelection(rowKey); 21266 this.writeSelections(); 21267 21268 if(!silent) 21269 this.fireNodeUnselectEvent(node); 21270 }, 21271 21272 toggleCheckboxNode: function(node) { 21273 var $this = this, 21274 checkbox = node.find('> .ui-treenode-content > .ui-chkbox'), 21275 checked = checkbox.find('> .ui-chkbox-box > .ui-chkbox-icon').hasClass('ui-icon-check'); 21276 21277 this.toggleCheckboxState(checkbox, checked); 21278 21279 if(this.cfg.propagateDown) { 21280 node.children('.ui-treenode-children').find('.ui-chkbox').each(function() { 21281 $this.toggleCheckboxState($(this), checked); 21282 }); 21283 21284 if(this.cfg.dynamic) { 21285 this.removeDescendantsFromSelection(node.data('rowkey')); 21286 } 21287 } 21288 21289 if(this.cfg.propagateUp) { 21290 node.parents('li.ui-treenode-parent').each(function() { 21291 var parentNode = $(this), 21292 parentsCheckbox = parentNode.find('> .ui-treenode-content > .ui-chkbox'), 21293 children = parentNode.find('> .ui-treenode-children > .ui-treenode'); 21294 21295 if(checked) { 21296 if(children.filter('.ui-treenode-unselected').length === children.length)
21297 $this.uncheck(parentsCheckbox); 21298 else 21299 $this.partialCheck(parentsCheckbox); 21300 } 21301 else { 21302 if(children.filter('.ui-treenode-selected').length === children.length) 21303 $this.check(parentsCheckbox); 21304 else 21305 $this.partialCheck(parentsCheckbox); 21306 } 21307 }); 21308 } 21309 21310 this.writeSelections(); 21311 21312 if(checked) 21313 this.fireNodeUnselectEvent(node); 21314 else 21315 this.fireNodeSelectEvent(node); 21316 }, 21317 21318 preselectCheckbox: function() { 21319 this.jq.find('.ui-chkbox-icon').not('.ui-icon-check').each(function() { 21320 var icon = $(this), 21321 node = icon.closest('li'); 21322 21323 if(node.children('.ui-treenode-children').find('.ui-chkbox-icon.ui-icon-check').length > 0) { 21324 node.addClass('ui-treenode-hasselected'); 21325 icon.removeClass('ui-icon-blank').addClass('ui-icon-minus'); 21326 } 21327 }); 21328 }, 21329 21330 check: function(checkbox) { 21331 this._super(checkbox); 21332 checkbox.siblings('span.ui-treenode-label').addClass('ui-state-highlight').removeClass('ui-state-hover'); 21333 }, 21334 21335 uncheck: function(checkbox) { 21336 this._super(checkbox); 21337 checkbox.siblings('span.ui-treenode-label').removeClass('ui-state-highlight'); 21338 }, 21339 21340 initDraggable: function() { 21341 this.makeDraggable(this.jq.find('span.ui-treenode-content')); 21342 }, 21343 21344 initDroppable: function() { 21345 this.makeDropPoints(this.jq.find('li.ui-tree-droppoint')); 21346 this.makeDropNodes(this.jq.find('span.ui-treenode-droppable')); 21347 this.initDropScrollers(); 21348 }, 21349 21350 makeDraggable: function(elements) { 21351 var $this = this, 21352 dragdropScope = this.cfg.dragdropScope||this.id; 21353 21354 elements.draggable({ 21355 start: function(event, ui) { 21356 if(ui.helper) { 21357 var element = $(event.target), 21358 source = PF($(element.data('dragsourceid')).data('widget')), 21359 height = 20; 21360 21361 if(source.cfg.multipleDrag && element.find('.ui-treenode-label').hasClass('ui-state-highlight')) { 21362 source.draggedSourceKeys = $this.findSelectedParentKeys(source.selections.slice()); 21363 height = 20 * (source.draggedSourceKeys.length || 1); 21364 } 21365 21366 $(ui.helper).height(height); 21367 } 21368 }, 21369 helper: function() { 21370 var el = $('<div class="ui-tree-draghelper ui-state-highlight"></div>'); 21371 el.width($this.jq.width()); 21372 return el; 21373 }, 21374 appendTo: document.body, 21375 zIndex: ++PrimeFaces.zindex, 21376 revert: true, 21377 scope: dragdropScope, 21378 containment: 'document' 21379 }) 21380 .data({ 21381 'dragsourceid': this.jqId, 21382 'dragmode': this.cfg.dragMode 21383 }); 21384 }, 21385 21386 makeDropPoints: function(elements) { 21387 var $this = this, 21388 dragdropScope = this.cfg.dragdropScope||this.id; 21389 21390 elements.droppable({ 21391 hoverClass: 'ui-state-hover', 21392 accept: 'span.ui-treenode-content', 21393 tolerance: 'pointer', 21394 scope: dragdropScope, 21395 drop: function(event, ui) { 21396 var dragSource = PF($(ui.draggable.data('dragsourceid')).data('widget')), 21397 dropSource = $this, 21398 dropPoint = $(this), 21399 dropNode = dropPoint.closest('li.ui-treenode-parent'), 21400 dropNodeKey = $this.getRowKey(dropNode), 21401 transfer = (dragSource.id !== dropSource.id), 21402 draggedSourceKeys = dragSource.draggedSourceKeys, 21403 isDroppedNodeCopy = ($this.cfg.dropCopyNode && $this.shiftKey), 21404 draggedNodes, 21405 dragNodeKey; 21406 21407 if(draggedSourceKeys) { 21408 draggedNodes = dragSource.findNodes(draggedSourceKeys); 21409 } 21410 else { 21411 draggedNodes = [ui.draggable]; 21412 } 21413 21414 if($this.cfg.controlled) { 21415 $this.droppedNodeParams = []; 21416 } 21417 21418 $this.invalidSourceKeys = []; 21419 21420 for(var i = (draggedNodes.length - 1); i >= 0; i--) { 21421 var draggedNode = $(draggedNodes[i]), 21422 dragMode = ui.draggable.data('dragmode'), 21423 dragNode = draggedNode.is('li.ui-treenode') ? draggedNode : draggedNode.closest('li.ui-treenode'), 21424 dragNode = (isDroppedNodeCopy) ? dragNode.clone() : dragNode, 21425 targetDragNode = $this.findTargetDragNode(dragNode, dragMode); 21426 21427 dragNodeKey = $this.getRowKey(targetDragNode); 21428 21429 if(!transfer && dropNodeKey && dropNodeKey.indexOf(dragNodeKey) === 0) { 21430 return; 21431 } 21432 21433 if($this.cfg.controlled) { 21434 $this.droppedNodeParams.push({ 21435 'ui': ui, 21436 'dragSource': dragSource, 21437 'dragNode': dragNode, 21438 'targetDragNode': targetDragNode, 21439 'dropPoint': dropPoint, 21440 'dropNode': dropNode, 21441 'transfer': transfer 21442 }); 21443 } 21444 else { 21445 $this.onDropPoint(ui, dragSource, dragNode, targetDragNode, dropPoint, dropNode, transfer); 21446 } 21447 } 21448 21449 if (!draggedSourceKeys) { 21450 draggedSourceKeys = [dragNodeKey]; 21451 } 21452 draggedSourceKeys = draggedSourceKeys.filter(function(key) { 21453 return $.inArray(key, $this.invalidSourceKeys) === -1; 21454 }); 21455 21456 if (draggedSourceKeys && draggedSourceKeys.length) { 21457 draggedSourceKeys = draggedSourceKeys.reverse().join(','); 21458 $this.fireDragDropEvent({ 21459 'dragNodeKey': draggedSourceKeys, 21460 'dropNodeKey': dropNodeKey, 21461 'dragSource': dragSource.id, 21462 'dndIndex': dropPoint.prevAll('li.ui-treenode').length, 21463 'transfer': transfer, 21464 'isDroppedNodeCopy': isDroppedNodeCopy 21465 }); 21466 } 21467 21468 dragSource.draggedSourceKeys = null; 21469 $this.invalidSourceKeys = null; 21470 21471 if(isDroppedNodeCopy) { 21472 $this.initDraggable(); 21473 } 21474 } 21475 }); 21476 }, 21477 21478 onDropPoint: function(ui, dragSource, dragNode, targetDragNode, dropPoint, dropNode, transfer) { 21479 var dragNodeDropPoint = targetDragNode.next('li.ui-tree-droppoint'), 21480 oldParentNode = targetDragNode.parent().closest('li.ui-treenode-parent'); 21481 21482 ui.helper.remove(); 21483 dropPoint.removeClass('ui-state-hover'); 21484
21485 var validDrop = this.validateDropPoint(dragNode, dropPoint); 21486 if(!validDrop) { 21487 if (this.invalidSourceKeys) { 21488 var dragNodeKey = this.getRowKey(targetDragNode); 21489 this.invalidSourceKeys.push(dragNodeKey); 21490 } 21491 return; 21492 } 21493 21494 targetDragNode.hide().insertAfter(dropPoint); 21495 21496 if(transfer) { 21497 if(dragSource.cfg.selectionMode) { 21498 dragSource.unselectSubtree(targetDragNode); 21499 } 21500 21501 dragNodeDropPoint.remove(); 21502 this.updateDragDropBindings(targetDragNode); 21503 } 21504 else { 21505 dragNodeDropPoint.insertAfter(targetDragNode); 21506 } 21507 21508 if(oldParentNode.length && (oldParentNode.find('> ul.ui-treenode-children > li.ui-treenode').length === 0)) { 21509 this.makeLeaf(oldParentNode); 21510 } 21511 21512 targetDragNode.fadeIn(); 21513 21514 if(this.isCheckboxSelection()) { 21515 this.syncDNDCheckboxes(dragSource, oldParentNode, dropNode); 21516 } 21517 21518 this.syncDragDrop(); 21519 if(transfer) { 21520 dragSource.syncDragDrop(); 21521 } 21522 }, 21523 21524 makeDropNodes: function(elements) { 21525 var $this = this, 21526 dragdropScope = this.cfg.dragdropScope||this.id; 21527 21528 elements.droppable({ 21529 accept: '.ui-treenode-content', 21530 tolerance: 'pointer', 21531 scope: dragdropScope, 21532 over: function(event, ui) { 21533 $(this).children('.ui-treenode-label').addClass('ui-state-hover'); 21534 }, 21535 out: function(event, ui) { 21536 $(this).children('.ui-treenode-label').removeClass('ui-state-hover'); 21537 }, 21538 drop: function(event, ui) { 21539 var dragSource = PF($(ui.draggable.data('dragsourceid')).data('widget')), 21540 dropSource = $this, 21541 droppable = $(this), 21542 dropNode = droppable.closest('li.ui-treenode'), 21543 dropNodeKey = $this.getRowKey(dropNode), 21544 transfer = (dragSource.id !== dropSource.id), 21545 draggedSourceKeys = dragSource.draggedSourceKeys, 21546 isDroppedNodeCopy = ($this.cfg.dropCopyNode && $this.shiftKey), 21547 draggedNodes, 21548 dragNodeKey, 21549 dndIndex; 21550 21551 if(draggedSourceKeys) { 21552 draggedNodes = dragSource.findNodes(draggedSourceKeys); 21553 } 21554 else { 21555 draggedNodes = [ui.draggable]; 21556 } 21557 21558 if($this.cfg.controlled) { 21559 $this.droppedNodeParams = []; 21560 } 21561 21562 $this.invalidSourceKeys = []; 21563 21564 for(var i = 0; i < draggedNodes.length; i++) { 21565 var draggedNode = $(draggedNodes[i]), 21566 dragMode = ui.draggable.data('dragmode'), 21567 dragNode = draggedNode.is('li.ui-treenode') ? draggedNode : draggedNode.closest('li.ui-treenode'), 21568 dragNode = (isDroppedNodeCopy) ? dragNode.clone() : dragNode, 21569 targetDragNode = $this.findTargetDragNode(dragNode, dragMode); 21570 21571 if(i === 0) { 21572 dndIndex = dropNode.find('>.ui-treenode-children>li.ui-treenode').length; 21573 } 21574 21575 dragNodeKey = $this.getRowKey(targetDragNode); 21576 21577 if(!transfer && dropNodeKey && dropNodeKey.indexOf(dragNodeKey) === 0) { 21578 return; 21579 } 21580 21581 if($this.cfg.controlled) { 21582 $this.droppedNodeParams.push({ 21583 'ui': ui, 21584 'dragSource': dragSource, 21585 'dragNode': dragNode, 21586 'targetDragNode': targetDragNode, 21587 'droppable': droppable, 21588 'dropNode': dropNode, 21589 'transfer': transfer 21590 }); 21591 } 21592 else { 21593 $this.onDropNode(ui, dragSource, dragNode, targetDragNode, droppable, dropNode, transfer); 21594 } 21595 } 21596 21597 if (!draggedSourceKeys) { 21598 draggedSourceKeys = [dragNodeKey]; 21599 } 21600 draggedSourceKeys = draggedSourceKeys.filter(function(key) { 21601 return $.inArray(key, $this.invalidSourceKeys) === -1; 21602 }); 21603 21604 if (draggedSourceKeys && draggedSourceKeys.length) { 21605 draggedSourceKeys = draggedSourceKeys.reverse().join(','); 21606 $this.fireDragDropEvent({ 21607 'dragNodeKey': draggedSourceKeys, 21608 'dropNodeKey': dropNodeKey, 21609 'dragSource': dragSource.id, 21610 'dndIndex': dndIndex, 21611 'transfer': transfer, 21612 'isDroppedNodeCopy': isDroppedNodeCopy 21613 }); 21614 } 21615 21616 dragSource.draggedSourceKeys = null; 21617 $this.invalidSourceKeys = null; 21618 21619 if(isDroppedNodeCopy) { 21620 $this.initDraggable(); 21621 } 21622 } 21623 }); 21624 }, 21625 21626 onDropNode: function(ui, dragSource, dragNode, targetDragNode, droppable, dropNode, transfer) { 21627 var dragNodeDropPoint = targetDragNode.next('li.ui-tree-droppoint'), 21628 oldParentNode = targetDragNode.parent().closest('li.ui-treenode-parent'), 21629 childrenContainer = dropNode.children('.ui-treenode-children'); 21630 21631 ui.helper.remove(); 21632 droppable.children('.ui-treenode-label').removeClass('ui-state-hover'); 21633
21634 var validDrop = this.validateDropNode(dragNode, dropNode, oldParentNode); 21635 if(!validDrop) { 21636 if (this.invalidSourceKeys) { 21637 var dragNodeKey = this.getRowKey(targetDragNode); 21638 this.invalidSourceKeys.push(dragNodeKey); 21639 } 21640 return; 21641 } 21642 21643 if(childrenContainer.children('li.ui-treenode').length === 0) { 21644 this.makeParent(dropNode); 21645 } 21646 21647 targetDragNode.hide(); 21648 childrenContainer.append(targetDragNode); 21649 21650 if(oldParentNode.length && (oldParentNode.find('> ul.ui-treenode-children > li.ui-treenode').length === 0)) { 21651 this.makeLeaf(oldParentNode); 21652 } 21653 21654 if(transfer) { 21655 if(dragSource.cfg.selectionMode) { 21656 dragSource.unselectSubtree(targetDragNode); 21657 } 21658 21659 dragNodeDropPoint.remove(); 21660 this.updateDragDropBindings(targetDragNode); 21661 } 21662 else { 21663 childrenContainer.append(dragNodeDropPoint); 21664 } 21665 21666 targetDragNode.fadeIn(); 21667 21668 if(this.isCheckboxSelection()) { 21669 this.syncDNDCheckboxes(dragSource, oldParentNode, dropNode); 21670 } 21671 21672 this.syncDragDrop(); 21673 if(transfer) { 21674 dragSource.syncDragDrop(); 21675 } 21676 }, 21677 21678 findSelectedParentKeys: function(arr) { 21679 for(var i = 0; i < arr.length; i++) { 21680 var key = arr[i]; 21681 for(var j = 0; j < arr.length && key !== -1; j++) { 21682 var tempKey = arr[j]; 21683 if(tempKey !== -1 && key.length > tempKey.length && key.indexOf(tempKey) === 0) { 21684 arr[i] = -1; 21685 } 21686 } 21687 } 21688 21689 return arr.filter(function(item) { 21690 return item !== -1; 21691 }); 21692 }, 21693 21694 initDropScrollers: function() { 21695 var $this = this, 21696 dragdropScope = this.cfg.dragdropScope||this.id; 21697 21698 this.jq.prepend('<div class="ui-tree-scroller ui-tree-scrollertop"></div>').append('<div class="ui-tree-scroller ui-tree-scrollerbottom"></div>'); 21699 21700 this.jq.children('div.ui-tree-scroller').droppable({ 21701 accept: '.ui-treenode-content', 21702 tolerance: 'pointer', 21703 scope: dragdropScope, 21704 over: function() { 21705 var step = $(this).hasClass('ui-tree-scrollertop') ? -10 : 10; 21706 21707 $this.scrollInterval = setInterval(function() { 21708 $this.scroll(step); 21709 }, 100); 21710 }, 21711 out: function() { 21712 clearInterval($this.scrollInterval); 21713 } 21714 }); 21715 }, 21716 21717 scroll: function(step) { 21718 this.container.scrollTop(this.container.scrollTop() + step); 21719 }, 21720 21721 updateDragDropBindings: function(node) { 21722 //self droppoint 21723 node.after('<li class="ui-tree-droppoint ui-droppable"></li>'); 21724 this.makeDropPoints(node.next('li.ui-tree-droppoint')); 21725 21726 //descendant droppoints 21727 var subtreeDropPoints = node.find('li.ui-tree-droppoint'); 21728 if(subtreeDropPoints.hasClass('ui-droppable') && !this.shiftKey && !this.cfg.dropCopyNode) { 21729 subtreeDropPoints.droppable('destroy'); 21730 } 21731 this.makeDropPoints(subtreeDropPoints); 21732 21733 //descendant drop node contents 21734 var subtreeDropNodeContents = node.find('span.ui-treenode-content'); 21735 if(subtreeDropNodeContents.hasClass('ui-droppable') && !this.shiftKey && !this.cfg.dropCopyNode) { 21736 subtreeDropNodeContents.droppable('destroy'); 21737 } 21738 this.makeDropNodes(subtreeDropNodeContents); 21739 21740 if(this.cfg.draggable) { 21741 subtreeDropNodeContents.data({ 21742 'dragsourceid': this.jqId, 21743 'dragmode': this.cfg.dragMode 21744 }); 21745 } 21746 }, 21747 21748 findTargetDragNode: function(dragNode, dragMode) { 21749 var targetDragNode = null; 21750 21751 if(dragMode === 'self') { 21752 targetDragNode = dragNode; 21753 } else if(dragMode === 'parent') { 21754 targetDragNode = dragNode.parent().closest('li.ui-treenode'); 21755 } else if(dragMode === 'ancestor') { 21756 targetDragNode = dragNode.parent().parents('li.ui-treenode:last'); 21757 } 21758 21759 if(targetDragNode.length === 0) { 21760 targetDragNode = dragNode; 21761 } 21762 21763 return targetDragNode; 21764 }, 21765 21766 findNodes: function(rowkeys) { 21767 var nodes = []; 21768 for(var i = 0; i < rowkeys.length; i++) { 21769 nodes.push($(this.jqId + '\\:' + rowkeys[i])); 21770 } 21771 21772 return nodes; 21773 }, 21774 21775 updateRowKeys: function() { 21776 var children = this.jq.find('> ul.ui-tree-container > li.ui-treenode'); 21777 this.updateChildrenRowKeys(children, null); 21778 }, 21779 21780 updateChildrenRowKeys: function(children, rowkey) { 21781 var $this = this; 21782 21783 children.each(function(i) { 21784 var childNode = $(this), 21785 oldRowKey = childNode.attr('data-rowkey'), 21786 newRowKey = (rowkey === null) ? i.toString() : rowkey + '_' + i; 21787 21788 childNode.attr({ 21789 'id': $this.id + ':' + newRowKey, 21790 'data-rowkey' : newRowKey 21791 }); 21792 21793 if(childNode.hasClass('ui-treenode-parent')) { 21794 $this.updateChildrenRowKeys(childNode.find('> ul.ui-treenode-children > li.ui-treenode'), newRowKey); 21795 } 21796 }); 21797 }, 21798 21799 validateDropPoint: function(dragNode, dropPoint) { 21800 //dropped before or after 21801 if(dragNode.next().get(0) === dropPoint.get(0)||dragNode.prev().get(0) === dropPoint.get(0)) { 21802 return false;
21803 } 21804 21805 //descendant of dropnode 21806 if(dragNode.has(dropPoint.get(0)).length) { 21807 return false; 21808 } 21809 21810 //drop restriction 21811 if(this.cfg.dropRestrict) { 21812 if(this.cfg.dropRestrict === 'sibling' && dragNode.parent().get(0) !== dropPoint.parent().get(0)) { 21813 return false; 21814 } 21815 } 21816 21817 return true; 21818 }, 21819 21820 validateDropNode: function(dragNode, dropNode, oldParentNode) { 21821 //dropped on parent 21822 if(oldParentNode.get(0) === dropNode.get(0)) 21823 return false; 21824 21825 //descendant of dropnode 21826 if(dragNode.has(dropNode.get(0)).length) { 21827 return false; 21828 } 21829 21830 //drop restriction 21831 if(this.cfg.dropRestrict) { 21832 if(this.cfg.dropRestrict === 'sibling') { 21833 return false; 21834 } 21835 } 21836 21837 return true; 21838 }, 21839 21840 makeLeaf: function(node) { 21841 node.removeClass('ui-treenode-parent').addClass('ui-treenode-leaf'); 21842 node.find('> .ui-treenode-content > .ui-tree-toggler').addClass('ui-treenode-leaf-icon').removeClass('ui-tree-toggler ui-icon ui-icon-triangle-1-s'); 21843 node.children('.ui-treenode-children').hide().children().remove(); 21844 }, 21845 21846 makeParent: function(node) { 21847 node.removeClass('ui-treenode-leaf').addClass('ui-treenode-parent'); 21848 node.find('> span.ui-treenode-content > span.ui-treenode-leaf-icon').removeClass('ui-treenode-leaf-icon').addClass('ui-tree-toggler ui-icon ui-icon-triangle-1-e'); 21849 node.children('.ui-treenode-children').append('<li class="ui-tree-droppoint ui-droppable"></li>'); 21850 21851 this.makeDropPoints(node.find('> ul.ui-treenode-children > li.ui-tree-droppoint')); 21852 }, 21853 21854 syncDragDrop: function() { 21855 var $this = this; 21856 21857 if(this.cfg.selectionMode) { 21858 var selectedNodes = this.findNodes(this.selections); 21859 21860 this.updateRowKeys(); 21861 this.selections = []; 21862 $.each(selectedNodes, function(i, item) { 21863 $this.selections.push(item.attr('data-rowkey')); 21864 }); 21865 this.writeSelections(); 21866 } 21867 else { 21868 this.updateRowKeys(); 21869 } 21870 }, 21871 21872 syncDNDCheckboxes: function(dragSource, oldParentNode, newParentNode) { 21873 if(oldParentNode.length) { 21874 dragSource.propagateDNDCheckbox(oldParentNode); 21875 } 21876 21877 if(newParentNode.length) { 21878 this.propagateDNDCheckbox(newParentNode); 21879 } 21880 }, 21881 21882 unselectSubtree: function(node) { 21883 var $this = this; 21884 21885 if(this.isCheckboxSelection()) { 21886 var checkbox = node.find('> .ui-treenode-content > .ui-chkbox'); 21887 21888 this.toggleCheckboxState(checkbox, true); 21889 21890 node.children('.ui-treenode-children').find('.ui-chkbox').each(function() { 21891 $this.toggleCheckboxState($(this), true); 21892 }); 21893 } 21894 else { 21895 node.find('.ui-treenode-label.ui-state-highlight').each(function() { 21896 $(this).removeClass('ui-state-highlight').closest('li.ui-treenode').attr('aria-selected', false); 21897 }); 21898 } 21899 }, 21900 21901 propagateDNDCheckbox: function(node) { 21902 var checkbox = node.find('> .ui-treenode-content > .ui-chkbox'), 21903 children = node.find('> .ui-treenode-children > .ui-treenode'); 21904 21905 if(children.length) { 21906 if(children.filter('.ui-treenode-unselected').length === children.length) 21907 this.uncheck(checkbox); 21908 else if(children.filter('.ui-treenode-selected').length === children.length) 21909 this.check(checkbox); 21910 else 21911 this.partialCheck(checkbox); 21912 } 21913 21914 var parent = node.parent().closest('.ui-treenode-parent'); 21915 if(parent.length) { 21916 this.propagateDNDCheckbox(parent); 21917 } 21918 }, 21919 21920 fireDragDropEvent: function(event) { 21921 var $this = this, 21922 options = { 21923 source: this.id, 21924 process: event.transfer ? this.id + ' ' + event.dragSource : this.id 21925 }; 21926 21927 options.params = [ 21928 {name: this.id + '_dragdrop', value: true}, 21929 {name: this.id + '_dragNode', value: event.dragNodeKey}, 21930 {name: this.id + '_dragSource', value: event.dragSource}, 21931 {name: this.id + '_dropNode', value: event.dropNodeKey}, 21932 {name: this.id + '_dndIndex', value: event.dndIndex}, 21933 {name: this.id + '_isDroppedNodeCopy', value: event.isDroppedNodeCopy} 21934 ]; 21935 21936 if(this.cfg.controlled) { 21937 options.oncomplete = function(xhr, status, args, data) { 21938 if(args.access) { 21939 for(var i = 0; i < $this.droppedNodeParams.length; i++) { 21940 var params = $this.droppedNodeParams[i]; 21941 if(params.dropPoint) 21942 $this.onDropPoint(params.ui, params.dragSource, params.dragNode, params.targetDragNode, params.dropPoint, params.dropNode, params.transfer); 21943 else 21944 $this.onDropNode(params.ui, params.dragSource, params.dragNode, params.targetDragNode, params.droppable, params.dropNode, params.transfer); 21945 } 21946 } 21947 }; 21948 } 21949 21950 if(this.hasBehavior('dragdrop')) { 21951 this.callBehavior('dragdrop', options); 21952 } 21953 else { 21954 PrimeFaces.ajax.Request.handle(options); 21955 } 21956 }, 21957 21958 isEmpty: function() { 21959 return (this.container.children().length === 0); 21960 }, 21961 21962 getFirstNode: function() { 21963 return this.jq.find('> ul.ui-tree-container > li:first-child'); 21964 }, 21965 21966 getNodeLabel: function(node) { 21967 return node.find('> span.ui-treenode-content > span.ui-treenode-label'); 21968 }, 21969 21970 focusNode: function(node) { 21971 if(this.focusedNode) { 21972 this.getNodeLabel(this.focusedNode).removeClass('ui-treenode-outline'); 21973 } 21974 21975 this.getNodeLabel(node).addClass('ui-treenode-outline').focus(); 21976 this.focusedNode = node; 21977 }, 21978 21979 /** 21980 * Ajax filter 21981 */ 21982 filter: function() { 21983 var $this = this, 21984 options = { 21985 source: this.id, 21986 update: this.id, 21987 process: this.id, 21988 global: false, 21989 formId: this.cfg.formId, 21990 params: [{name: this.id + '_filtering', value: true}, 21991 {name: this.id + '_encodeFeature', value: true}], 21992 onsuccess: function(responseXML, status, xhr) { 21993 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 21994 widget: $this, 21995 handle: function(content) { 21996 $this.container.html(content); 21997 } 21998 }); 21999 22000 return true; 22001 }, 22002 oncomplete: function() { 22003 if ($this.cfg.filterMode === 'contains') { 22004 var notLeafNodes = $this.container.find('li.ui-treenode:not(.ui-treenode-leaf):visible'); 22005 for(var i = 0; i < notLeafNodes.length; i++) { 22006 var node = notLeafNodes.eq(i), 22007 hasChildNodes = node.children('.ui-treenode-children:empty').length; 22008 22009 if(hasChildNodes) { 22010 node.removeClass('ui-treenode-parent').addClass('ui-treenode-leaf') 22011 .find('> .ui-treenode-content > .ui-tree-toggler').removeClass('ui-tree-toggler ui-icon ui-icon-triangle-1-e').addClass('ui-treenode-leaf-icon'); 22012 } 22013 } 22014 } 22015 } 22016 }; 22017 22018 if(this.hasBehavior('filter')) { 22019 this.callBehavior('filter', options); 22020 } 22021 else { 22022 PrimeFaces.ajax.Request.handle(options); 22023 } 22024 22025 }, 22026 22027 restoreScrollState: function() { 22028 var scrollState = this.scrollStateHolder.val(), 22029 scrollValues = scrollState.split(','); 22030 22031 this.jq.scrollLeft(scrollValues[0]); 22032 this.jq.scrollTop(scrollValues[1]); 22033 }, 22034 22035 saveScrollState: function() { 22036 var scrollState = this.jq.scrollLeft() + ',' + this.jq.scrollTop(); 22037 22038 this.scrollStateHolder.val(scrollState); 22039 }, 22040 22041 clearScrollState: function() { 22042 this.scrollStateHolder.val('0,0'); 22043 } 22044 22045}); 22046 22047/** 22048 * PrimeFaces Horizontal Tree Widget 22049 */ 22050PrimeFaces.widget.HorizontalTree = PrimeFaces.widget.BaseTree.extend({ 22051 22052 init: function(cfg) { 22053 this._super(cfg); 22054 22055 if(PrimeFaces.env.isIE() && !this.cfg.disabled) { 22056 this.drawConnectors(); 22057 } 22058 }, 22059 22060 //@Override 22061 bindEvents: function() { 22062 var $this = this, 22063 selectionMode = this.cfg.selectionMode, 22064 togglerSelector = '.ui-tree-toggler', 22065 nodeContentSelector = '.ui-treenode-content.ui-tree-selectable'; 22066 22067 this.jq.off('click.tree-toggle', togglerSelector) 22068 .on('click.tree-toggle', togglerSelector, null, function() { 22069 var icon = $(this), 22070 node = icon.closest('td.ui-treenode'); 22071 22072 if(node.hasClass('ui-treenode-collapsed')) 22073 $this.expandNode(node); 22074 else 22075 $this.collapseNode(node); 22076 }); 22077 22078 if(selectionMode && this.cfg.highlight) { 22079 this.jq.off('mouseout.tree mouseover.tree', nodeContentSelector) 22080 .on('mouseover.tree', nodeContentSelector, null, function() { 22081 var nodeContent = $(this); 22082 if(!nodeContent.hasClass('ui-state-highlight')) { 22083 nodeContent.addClass('ui-state-hover'); 22084 22085 if($this.isCheckboxSelection()) { 22086 nodeContent.children('div.ui-chkbox').children('div.ui-chkbox-box').addClass('ui-state-hover'); 22087 } 22088 } 22089 }) 22090 .on('mouseout.tree', nodeContentSelector, null, function() { 22091 var nodeContent = $(this); 22092 if(!nodeContent.hasClass('ui-state-highlight')) { 22093 nodeContent.removeClass('ui-state-hover'); 22094 22095 if($this.isCheckboxSelection()) { 22096 nodeContent.children('div.ui-chkbox').children('div.ui-chkbox-box').removeClass('ui-state-hover'); 22097 } 22098 } 22099 }); 22100 } 22101 22102 this.jq.off('click.tree-content', nodeContentSelector) 22103 .on('click.tree-content', nodeContentSelector, null, function(e) { 22104 $this.nodeClick(e, $(this)); 22105 }); 22106 22107 }, 22108 22109 //@Override 22110 showNodeChildren: function(node) { 22111 node.attr('aria-expanded', true); 22112 22113 var childrenContainer = node.next(), 22114 toggleIcon = node.find('> .ui-treenode-content > .ui-tree-toggler'), 22115 nodeType = node.data('nodetype'), 22116 iconState = this.cfg.iconStates[nodeType]; 22117 22118 if(iconState) { 22119 toggleIcon.nextAll('span.ui-treenode-icon').removeClass(iconState.collapsedIcon).addClass(iconState.expandedIcon); 22120 } 22121 22122 toggleIcon.addClass('ui-icon-minus').removeClass('ui-icon-plus'); 22123 node.removeClass('ui-treenode-collapsed'); 22124 childrenContainer.show(); 22125 22126 if($.browser.msie) { 22127 this.drawConnectors(); 22128 } 22129 }, 22130 22131 collapseNode: function(node) { 22132 var childrenContainer = node.next(), 22133 toggleIcon = node.find('> .ui-treenode-content > .ui-tree-toggler'), 22134 nodeType = node.data('nodetype'), 22135 iconState = this.cfg.iconStates[nodeType]; 22136 22137 if(iconState) { 22138 toggleIcon.nextAll('span.ui-treenode-icon').removeClass(iconState.expandedIcon).addClass(iconState.collapsedIcon); 22139 } 22140 22141 toggleIcon.removeClass('ui-icon-minus').addClass('ui-icon-plus'); 22142 node.addClass('ui-treenode-collapsed'); 22143 childrenContainer.hide(); 22144
22145 if(this.cfg.dynamic && !this.cfg.cache) { 22146 childrenContainer.children('.ui-treenode-children').empty(); 22147 } 22148 22149 if(!this.cfg.cache) { 22150 this.fireCollapseEvent(node); 22151 } 22152 22153 if($.browser.msie) { 22154 this.drawConnectors(); 22155 } 22156 }, 22157 22158 //@Override 22159 getNodeChildrenContainer: function(node) { 22160 return node.next('.ui-treenode-children-container').children('.ui-treenode-children'); 22161 }, 22162 22163 selectNode: function(node, silent) { 22164 node.removeClass('ui-treenode-unselected').addClass('ui-treenode-selected').children('.ui-treenode-content').removeClass('ui-state-hover').addClass('ui-state-highlight'); 22165 22166 this.addToSelection(this.getRowKey(node)); 22167 this.writeSelections(); 22168 22169 if(!silent) 22170 this.fireNodeSelectEvent(node); 22171 }, 22172 22173 unselectNode: function(node, silent) { 22174 var rowKey = this.getRowKey(node); 22175 22176 node.removeClass('ui-treenode-selected').addClass('ui-treenode-unselected').children('.ui-treenode-content').removeClass('ui-state-highlight'); 22177 22178 this.removeFromSelection(rowKey); 22179 this.writeSelections(); 22180 22181 if(!silent) 22182 this.fireNodeUnselectEvent(node); 22183 }, 22184 22185 unselectAllNodes: function() { 22186 this.selections = []; 22187 this.jq.find('.ui-treenode-content.ui-state-highlight').each(function() { 22188 $(this).removeClass('ui-state-highlight').closest('.ui-treenode').attr('aria-selected', false); 22189 }); 22190 }, 22191 22192 preselectCheckbox: function() { 22193 var _self = this; 22194 22195 this.jq.find('.ui-chkbox-icon').not('.ui-icon-check').each(function() { 22196 var icon = $(this), 22197 node = icon.closest('.ui-treenode'), 22198 childrenContainer = _self.getNodeChildrenContainer(node); 22199 22200 if(childrenContainer.find('.ui-chkbox-icon.ui-icon-check').length > 0) { 22201 icon.removeClass('ui-icon-blank').addClass('ui-icon-minus'); 22202 } 22203 }); 22204 }, 22205 22206 toggleCheckboxNode: function(node) { 22207 var $this = this, 22208 checkbox = node.find('> .ui-treenode-content > .ui-chkbox'), 22209 checked = checkbox.find('> .ui-chkbox-box > .ui-chkbox-icon').hasClass('ui-icon-check'); 22210 22211 this.toggleCheckboxState(checkbox, checked); 22212 22213 if(this.cfg.propagateDown) { 22214 node.next('.ui-treenode-children-container').find('.ui-chkbox').each(function() { 22215 $this.toggleCheckboxState($(this), checked); 22216 }); 22217 22218 if(this.cfg.dynamic) { 22219 this.removeDescendantsFromSelection(node.data('rowkey')); 22220 } 22221 } 22222 22223 if(this.cfg.propagateUp) { 22224 node.parents('td.ui-treenode-children-container').each(function() { 22225 var childrenContainer = $(this), 22226 parentNode = childrenContainer.prev('.ui-treenode-parent'), 22227 parentsCheckbox = parentNode.find('> .ui-treenode-content > .ui-chkbox'), 22228 children = childrenContainer.find('> .ui-treenode-children > table > tbody > tr > td.ui-treenode'); 22229 22230 if(checked) { 22231 if(children.filter('.ui-treenode-unselected').length === children.length) 22232 $this.uncheck(parentsCheckbox); 22233 else 22234 $this.partialCheck(parentsCheckbox); 22235 } 22236 else { 22237 if(children.filter('.ui-treenode-selected').length === children.length) 22238 $this.check(parentsCheckbox); 22239 else 22240 $this.partialCheck(parentsCheckbox); 22241 } 22242 }); 22243 } 22244 22245 this.writeSelections(); 22246 22247 if(checked) 22248 this.fireNodeUnselectEvent(node); 22249 else 22250 this.fireNodeSelectEvent(node); 22251 }, 22252 22253 check: function(checkbox) { 22254 this._super(checkbox); 22255 checkbox.parent('.ui-treenode-content').addClass('ui-state-highlight').removeClass('ui-state-hover'); 22256 }, 22257 22258 uncheck: function(checkbox) { 22259 this._super(checkbox); 22260 checkbox.parent('.ui-treenode-content').removeClass('ui-state-highlight'); 22261 }, 22262 22263 drawConnectors: function() { 22264 this.jq.find('table.ui-treenode-connector-table').each(function() { 22265 var table = $(this), 22266 row = table.closest('tr'); 22267 22268 table.height(0).height(row.height()); 22269 }); 22270 }, 22271 22272 isEmpty: function() { 22273 return this.jq.children('table').length === 0; 22274 }, 22275 22276 focusNode: function(node) { 22277 //focus not supported in horizontal mode 22278 }, 22279 22280 //@Override 22281 partialCheck: function(checkbox) { 22282 var box = checkbox.children('.ui-chkbox-box'), 22283 icon = box.children('.ui-chkbox-icon'), 22284 treeNode = checkbox.closest('.ui-treenode'), 22285 rowKey = this.getRowKey(treeNode); 22286 22287 treeNode.find('> .ui-treenode-content').removeClass('ui-state-highlight'); 22288 icon.removeClass('ui-icon-blank ui-icon-check').addClass('ui-icon-minus'); 22289 treeNode.removeClass('ui-treenode-selected ui-treenode-unselected').addClass('ui-treenode-hasselected').attr('aria-checked', false).attr('aria-selected', false); 22290 22291 this.removeFromSelection(rowKey); 22292 } 22293 22294}); 22295/** 22296 * PrimeFaces TreeTable Widget 22297 */ 22298PrimeFaces.widget.TreeTable = PrimeFaces.widget.DeferredWidget.extend({ 22299 22300 init: function(cfg) { 22301 this._super(cfg); 22302 this.thead = $(this.jqId + '_head'); 22303 this.tbody = $(this.jqId + '_data'); 22304 this.cfg.expandMode = this.cfg.expandMode||"children"; 22305 22306 this.renderDeferred(); 22307 }, 22308 22309 _render: function() { 22310 if(this.cfg.scrollable) { 22311 this.setupScrolling(); 22312 } 22313 22314 if(this.cfg.filter) { 22315 this.setupFiltering(); 22316 } 22317 22318 if(this.cfg.resizableColumns) { 22319 this.setupResizableColumns(); 22320 } 22321 22322 if(this.cfg.stickyHeader) { 22323 this.setupStickyHeader(); 22324 } 22325 22326 if(this.cfg.editable) { 22327 this.bindEditEvents(); 22328 } 22329 22330 this.bindEvents(); 22331 }, 22332 22333 //@override 22334 refresh: function(cfg) { 22335 this.columnWidthsFixed = false;
22336 this.scrollStateVal = this.scrollStateHolder ? this.scrollStateHolder.val() : null; 22337 22338 this._super(cfg); 22339 }, 22340 22341 bindEvents: function() { 22342 var $this = this, 22343 togglerSelector = '> tr > td:first-child > .ui-treetable-toggler'; 22344 22345 //expand and collapse 22346 this.tbody.off('click.treeTable-toggle', togglerSelector) 22347 .on('click.treeTable-toggle', togglerSelector, null, function(e) { 22348 var toggler = $(this), 22349 node = toggler.closest('tr'); 22350 22351 if(!node.data('processing')) { 22352 node.data('processing', true); 22353 22354 if(toggler.hasClass('ui-icon-triangle-1-e')) 22355 $this.expandNode(node); 22356 else 22357 $this.collapseNode(node); 22358 } 22359 }); 22360 22361 //selection 22362 if(this.cfg.selectionMode) { 22363 this.jqSelection = $(this.jqId + '_selection'); 22364 var selectionValue = this.jqSelection.val(); 22365 this.selections = selectionValue === "" ? [] : selectionValue.split(','); 22366 this.cfg.disabledTextSelection = this.cfg.disabledTextSelection === false ? false : true; 22367 22368 this.bindSelectionEvents(); 22369 } 22370 22371 //sorting 22372 this.bindSortEvents(); 22373 22374 if(this.cfg.paginator) { 22375 this.cfg.paginator.paginate = function(newState) { 22376 $this.handlePagination(newState); 22377 }; 22378 22379 this.paginator = new PrimeFaces.widget.Paginator(this.cfg.paginator); 22380 } 22381 }, 22382 22383 /** 22384 * Binds filter events to standard filters 22385 */ 22386 setupFiltering: function() { 22387 var $this = this, 22388 filterColumns = this.thead.find('> tr > th.ui-filter-column'); 22389 this.cfg.filterEvent = this.cfg.filterEvent||'keyup'; 22390 this.cfg.filterDelay = this.cfg.filterDelay||300; 22391 22392 filterColumns.children('.ui-column-filter').each(function() { 22393 var filter = $(this); 22394 22395 if(filter.is('input:text')) { 22396 PrimeFaces.skinInput(filter); 22397 $this.bindTextFilter(filter); 22398 } 22399 else { 22400 PrimeFaces.skinSelect(filter); 22401 $this.bindChangeFilter(filter); 22402 } 22403 }); 22404 }, 22405 22406 /** 22407 * Clears table filters 22408 */ 22409 clearFilters: function() { 22410 columnFilters = this.thead.find('> tr > th.ui-filter-column > .ui-column-filter').val(''); 22411 $(this.jqId + '\\:globalFilter').val(''); 22412 this.filter(); 22413 }, 22414 22415 bindTextFilter: function(filter) { 22416 if(this.cfg.filterEvent === 'enter') 22417 this.bindEnterKeyFilter(filter); 22418 else 22419 this.bindFilterEvent(filter); 22420 }, 22421 22422 bindChangeFilter: function(filter) { 22423 var $this = this; 22424 22425 filter.change(function() { 22426 $this.filter(); 22427 }); 22428 }, 22429 22430 bindEnterKeyFilter: function(filter) { 22431 var $this = this; 22432 22433 filter.on('keydown', PrimeFaces.utils.blockEnterKey) 22434 .on('keyup', function(e) { 22435 var key = e.which, 22436 keyCode = $.ui.keyCode; 22437 22438 if(key === keyCode.ENTER) { 22439 $this.filter(); 22440 22441 e.preventDefault(); 22442 } 22443 }); 22444 }, 22445 22446 bindFilterEvent: function(filter) { 22447 var $this = this; 22448 22449 //prevent form submit on enter key 22450 filter.on('keydown.treeTable-blockenter', PrimeFaces.utils.blockEnterKey) 22451 .on(this.cfg.filterEvent + '.treeTable', function(e) { 22452 if($this.filterTimeout) { 22453 clearTimeout($this.filterTimeout); 22454 } 22455 22456 $this.filterTimeout = setTimeout(function() { 22457 $this.filter(); 22458 $this.filterTimeout = null; 22459 }, 22460 $this.cfg.filterDelay); 22461 }); 22462 }, 22463 22464 /** 22465 * Ajax filter 22466 */ 22467 filter: function() { 22468 var $this = this, 22469 options = { 22470 source: this.id, 22471 update: this.id, 22472 process: this.id, 22473 formId: this.cfg.formId, 22474 params: [{name: this.id + '_filtering', value: true}, 22475 {name: this.id + '_encodeFeature', value: true}], 22476 onsuccess: function(responseXML, status, xhr) { 22477 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 22478 widget: $this, 22479 handle: function(content) { 22480 this.tbody.html(content); 22481 } 22482 }); 22483 22484 return true; 22485 }, 22486 oncomplete: function(xhr, status, args, data) { 22487 var paginator = $this.getPaginator(); 22488 if(args && args.totalRecords) { 22489 if(paginator) { 22490 paginator.setTotalRecords(args.totalRecords); 22491 } 22492 } 22493 } 22494 }; 22495 22496 if(this.hasBehavior('filter')) { 22497 this.callBehavior('filter', options); 22498 } 22499 else { 22500 PrimeFaces.ajax.Request.handle(options); 22501 } 22502 }, 22503 22504 handlePagination: function(newState) { 22505 var $this = this, 22506 options = { 22507 source: this.id, 22508 update: this.id, 22509 process: this.id, 22510 params: [ 22511 {name: this.id + '_pagination', value: true}, 22512 {name: this.id + '_first', value: newState.first}, 22513 {name: this.id + '_rows', value: newState.rows} 22514 ], 22515 onsuccess: function(responseXML, status, xhr) { 22516 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 22517 widget: $this, 22518 handle: function(content) { 22519 this.tbody.html(content); 22520 } 22521 }); 22522 22523 return true; 22524 }, 22525 oncomplete: function() { 22526 $this.paginator.cfg.page = newState.page; 22527 $this.paginator.updateUI(); 22528 } 22529 }; 22530 22531 if(this.hasBehavior('page')) { 22532 this.callBehavior('page', options); 22533 } 22534 else { 22535 PrimeFaces.ajax.Request.handle(options); 22536 } 22537 }, 22538 22539 getPaginator: function() { 22540 return this.paginator; 22541 }, 22542 22543 bindSelectionEvents: function() { 22544 var $this = this, 22545 rowSelector = '> tr.ui-treetable-selectable-node'; 22546 22547 this.tbody.off('mouseover.treeTable mouseout.treeTable click.treeTable', rowSelector) 22548 .on('mouseover.treeTable', rowSelector, null, function(e) { 22549 var element = $(this); 22550 if(!element.hasClass('ui-state-highlight')) { 22551 element.addClass('ui-state-hover'); 22552 22553 if($this.isCheckboxSelection() && !$this.cfg.nativeElements) { 22554 element.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box').addClass('ui-state-hover'); 22555 } 22556 } 22557 }) 22558 .on('mouseout.treeTable', rowSelector, null, function(e) { 22559 var element = $(this); 22560 if(!element.hasClass('ui-state-highlight')) { 22561 element.removeClass('ui-state-hover'); 22562 22563 if($this.isCheckboxSelection() && !$this.cfg.nativeElements) { 22564 element.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box').removeClass('ui-state-hover'); 22565 } 22566 } 22567 }) 22568 .on('click.treeTable', rowSelector, null, function(e) { 22569 $this.onRowClick(e, $(this)); 22570 }); 22571 22572 if(this.isCheckboxSelection()) { 22573 var checkboxSelector = this.cfg.nativeElements ? '> tr.ui-treetable-selectable-node > td:first-child :checkbox': 22574 '> tr.ui-treetable-selectable-node > td:first-child div.ui-chkbox-box'; 22575 22576 this.tbody.off('click.treeTable-checkbox', checkboxSelector) 22577 .on('click.treeTable-checkbox', checkboxSelector, null, function(e) { 22578 var node = $(this).closest('tr.ui-treetable-selectable-node'); 22579 $this.toggleCheckboxNode(node); 22580 }); 22581 22582 22583 //initial partial selected visuals 22584 if(this.cfg.nativeElements) { 22585 this.indeterminateNodes(this.tbody.children('tr.ui-treetable-partialselected')); 22586 } 22587 } 22588 }, 22589 22590 bindSortEvents: function() { 22591 var $this = this; 22592 this.sortableColumns = this.thead.find('> tr > th.ui-sortable-column'); 22593 22594 this.sortableColumns.filter('.ui-state-active').each(function() { 22595 var columnHeader = $(this), 22596 sortIcon = columnHeader.children('span.ui-sortable-column-icon'), 22597 sortOrder = null; 22598 22599 if(sortIcon.hasClass('ui-icon-triangle-1-n')) 22600 sortOrder = 'ASCENDING'; 22601 else 22602 sortOrder = 'DESCENDING'; 22603 22604 columnHeader.data('sortorder', sortOrder); 22605 }); 22606 22607 this.sortableColumns.on('mouseenter.treeTable', function() { 22608 var column = $(this); 22609 22610 if(!column.hasClass('ui-state-active')) 22611 column.addClass('ui-state-hover'); 22612 }) 22613 .on('mouseleave.treeTable', function() { 22614 var column = $(this); 22615 22616 if(!column.hasClass('ui-state-active')) 22617 column.removeClass('ui-state-hover'); 22618 }) 22619 .on('click.treeTable', function(e) { 22620 if(!$this.shouldSort(e, this)) { 22621 return; 22622 } 22623 22624 PrimeFaces.clearSelection(); 22625 22626 var columnHeader = $(this), 22627 sortOrder = columnHeader.data('sortorder')||'DESCENDING'; 22628 22629 if(sortOrder === 'ASCENDING') 22630 sortOrder = 'DESCENDING'; 22631 else if(sortOrder === 'DESCENDING') 22632 sortOrder = 'ASCENDING'; 22633 22634 $this.sort(columnHeader, sortOrder); 22635 }); 22636 }, 22637 22638 bindContextMenu : function(menuWidget, targetWidget, targetId, cfg) { 22639 var targetSelector = targetId + ' .ui-treetable-data > ' + (cfg.nodeType ? 'tr.ui-treetable-selectable-node.' + cfg.nodeType : 'tr.ui-treetable-selectable-node'); 22640 var targetEvent = cfg.event + '.treetable'; 22641 22642 $(document).off(targetEvent, targetSelector).on(targetEvent, targetSelector, null, function(e) { 22643 targetWidget.onRowRightClick(e, $(this)); 22644 menuWidget.show(e); 22645 }); 22646 }, 22647 22648 setupStickyHeader: function() { 22649 var table = this.thead.parent(), 22650 offset = table.offset(), 22651 win = $(window), 22652 $this = this; 22653
22654 this.stickyContainer = $('<div class="ui-treetable ui-treetable-sticky ui-widget"><table></table></div>'); 22655 this.clone = this.thead.clone(false); 22656 this.stickyContainer.children('table').append(this.thead); 22657 table.append(this.clone); 22658 22659 this.stickyContainer.css({ 22660 position: 'absolute', 22661 width: table.outerWidth(), 22662 top: offset.top, 22663 left: offset.left, 22664 'z-index': ++PrimeFaces.zindex 22665 }); 22666 22667 this.jq.prepend(this.stickyContainer); 22668 22669 if(this.cfg.resizableColumns) { 22670 this.relativeHeight = 0; 22671 } 22672 22673 PrimeFaces.utils.registerScrollHandler(this, 'scroll.' + this.id + '_align', function() { 22674 var scrollTop = win.scrollTop(), 22675 tableOffset = table.offset(); 22676 22677 if(scrollTop > tableOffset.top) { 22678 $this.stickyContainer.css({ 22679 'position': 'fixed', 22680 'top': '0px' 22681 }) 22682 .addClass('ui-shadow ui-sticky'); 22683 22684 if($this.cfg.resizableColumns) { 22685 $this.relativeHeight = scrollTop - tableOffset.top; 22686 } 22687 22688 if(scrollTop >= (tableOffset.top + $this.tbody.height())) 22689 $this.stickyContainer.hide(); 22690 else 22691 $this.stickyContainer.show(); 22692 } 22693 else { 22694 $this.stickyContainer.css({ 22695 'position': 'absolute', 22696 'top': tableOffset.top 22697 }) 22698 .removeClass('ui-shadow ui-sticky'); 22699 22700 if($this.stickyContainer.is(':hidden')) { 22701 $this.stickyContainer.show(); 22702 } 22703 22704 if($this.cfg.resizableColumns) { 22705 $this.relativeHeight = 0; 22706 } 22707 } 22708 }); 22709 22710 PrimeFaces.utils.registerResizeHandler(this, 'resize.sticky-' + this.id + '_align', null, function() { 22711 $this.stickyContainer.width(table.outerWidth()); 22712 }); 22713 }, 22714 22715 bindEditEvents: function() { 22716 var $this = this; 22717 this.cfg.cellSeparator = this.cfg.cellSeparator||' '; 22718 22719 if(this.cfg.editMode === 'row') { 22720 var rowEditorSelector = '> tr > td > div.ui-row-editor'; 22721 this.tbody.off('click.treetable', rowEditorSelector) 22722 .on('click.treetable', rowEditorSelector, null, function(e) { 22723 var element = $(e.target), 22724 row = element.closest('tr'); 22725 22726 if(element.hasClass('ui-icon-pencil')) { 22727 $this.switchToRowEdit(row); 22728 element.hide().siblings().show(); 22729 } 22730 else if(element.hasClass('ui-icon-check')) { 22731 $this.saveRowEdit(row); 22732 } 22733 else if(element.hasClass('ui-icon-close')) { 22734 $this.cancelRowEdit(row); 22735 } 22736 22737 e.preventDefault(); 22738 }); 22739 } 22740 else if(this.cfg.editMode === 'cell') { 22741 var cellSelector = '> tr > td.ui-editable-column'; 22742 22743 this.tbody.off('click.treetable-cell', cellSelector) 22744 .on('click.treetable-cell', cellSelector, null, function(e) { 22745 if(!$(e.target).is('span.ui-treetable-toggler.ui-c')) { 22746 $this.incellClick = true; 22747 22748 var cell = $(this); 22749 if(!cell.hasClass('ui-cell-editing')) { 22750 $this.showCellEditor($(this)); 22751 } 22752 } 22753 }); 22754 22755 $(document).off('click.treetable-cell-blur' + this.id) 22756 .on('click.treetable-cell-blur' + this.id, function(e) { 22757 if((!$this.incellClick && $this.currentCell && !$this.contextMenuClick)) { 22758 $this.saveCell($this.currentCell); 22759 } 22760 22761 $this.incellClick = false;
22762 $this.contextMenuClick = false; 22763 }); 22764 } 22765 }, 22766 22767 sort: function(columnHeader, order) { 22768 var $this = this, 22769 options = { 22770 source: this.id, 22771 update: this.id, 22772 process: this.id, 22773 params: [ 22774 {name: this.id + '_sorting', value: true}, 22775 {name: this.id + '_sortKey', value: columnHeader.attr('id')}, 22776 {name: this.id + '_sortDir', value: order} 22777 ], 22778 onsuccess: function(responseXML, status, xhr) { 22779 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 22780 widget: $this, 22781 handle: function(content) { 22782 this.tbody.html(content); 22783 22784 columnHeader.siblings().filter('.ui-state-active').removeData('sortorder').removeClass('ui-state-active') 22785 .find('.ui-sortable-column-icon').removeClass('ui-icon-triangle-1-n ui-icon-triangle-1-s'); 22786 22787 columnHeader.removeClass('ui-state-hover').addClass('ui-state-active').data('sortorder', order); 22788 var sortIcon = columnHeader.find('.ui-sortable-column-icon'); 22789 22790 if(order === 'DESCENDING') 22791 sortIcon.removeClass('ui-icon-triangle-1-n').addClass('ui-icon-triangle-1-s'); 22792 else if(order === 'ASCENDING') 22793 sortIcon.removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-n'); 22794 } 22795 }); 22796 22797 return true; 22798 }, 22799 oncomplete: function(xhr, status, args, data) { 22800 if($this.cfg.selectionMode && args.selection) { 22801 $this.selections = args.selection.split(','); 22802 $this.writeSelections(); 22803 } 22804 } 22805 }; 22806 22807 if(this.hasBehavior('sort')) { 22808 this.callBehavior('sort', options); 22809 } 22810 else { 22811 PrimeFaces.ajax.Request.handle(options); 22812 } 22813 }, 22814 22815 expandNode: function(node) { 22816 var $this = this, 22817 nodeKey = node.attr('data-rk'), 22818 options = { 22819 source: this.id, 22820 process: this.id, 22821 update: this.id, 22822 params: [ 22823 {name: this.id + '_expand', value: nodeKey} 22824 ], 22825 onsuccess: function(responseXML, status, xhr) { 22826 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 22827 widget: $this, 22828 handle: function(content) { 22829 if($this.cfg.expandMode === "self") 22830 node.replaceWith(content); 22831 else 22832 node.after(content); 22833 22834 node.find('.ui-treetable-toggler:first').addClass('ui-icon-triangle-1-s').removeClass('ui-icon-triangle-1-e'); 22835 node.attr('aria-expanded', true); 22836 $this.indeterminateNodes($this.tbody.children('tr.ui-treetable-partialselected')); 22837 22838 if(this.cfg.scrollable) { 22839 this.alignScrollBody(); 22840 } 22841 } 22842 }); 22843 22844 return true; 22845 }, 22846 oncomplete: function() { 22847 node.data('processing', false); 22848 $this.updateVerticalScroll(); 22849 } 22850 }; 22851 22852 if(this.hasBehavior('expand')) { 22853 this.callBehavior('expand', options); 22854 } 22855 else { 22856 PrimeFaces.ajax.Request.handle(options); 22857 } 22858 }, 22859 22860 collapseNode: function(node) { 22861 var nodeKey = node.attr('data-rk'), 22862 nextNodes = node.nextAll(); 22863 22864 for(var i = 0; i < nextNodes.length; i++) { 22865 var nextNode = nextNodes.eq(i), 22866 nextNodeRowKey = nextNode.attr('data-rk'); 22867 22868 if(nextNodeRowKey.indexOf(nodeKey) !== -1) { 22869 nextNode.remove(); 22870 } 22871 else { 22872 break; 22873 } 22874 } 22875 22876 node.attr('aria-expanded', false).find('.ui-treetable-toggler:first').addClass('ui-icon-triangle-1-e').removeClass('ui-icon-triangle-1-s'); 22877 node.data('processing', false); 22878 22879 if(this.cfg.scrollable) { 22880 this.alignScrollBody(); 22881 } 22882 22883 if(this.hasBehavior('collapse')) { 22884 var $this = this, 22885 nodeKey = node.attr('data-rk'), 22886 options = { 22887 source: this.id, 22888 process: this.id, 22889 update: this.id, 22890 params: [
22891 {name: this.id + '_collapse', value: nodeKey} 22892 ], 22893 onsuccess: function(responseXML, status, xhr) { 22894 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 22895 widget: $this, 22896 handle: function(content) { 22897 // do nothing 22898 } 22899 }); 22900 22901 return true; 22902 }, 22903 oncomplete: function() { 22904 $this.updateVerticalScroll(); 22905 } 22906 }; 22907 22908 this.callBehavior('collapse', options); 22909 } 22910 else { 22911 this.updateVerticalScroll(); 22912 } 22913 }, 22914 22915 onRowClick: function(event, node) { 22916 if($(event.target).is('td,span:not(.ui-c)')) { 22917 var selected = node.hasClass('ui-state-highlight'), 22918 metaKey = event.metaKey||event.ctrlKey, 22919 shiftKey = event.shiftKey; 22920 22921 if(this.isCheckboxSelection()) { 22922 this.toggleCheckboxNode(node); 22923 } 22924 else { 22925 if(selected && metaKey) { 22926 this.unselectNode(node); 22927 } 22928 else { 22929 if(this.isSingleSelection()||(this.isMultipleSelection() && !metaKey)) { 22930 this.unselectAllNodes(); 22931 } 22932 22933 if(this.isMultipleSelection() && shiftKey) { 22934 this.selectNodesInRange(node); 22935 } 22936 else { 22937 this.selectNode(node); 22938 this.cursorNode = node; 22939 } 22940 } 22941 } 22942 22943 if(this.cfg.disabledTextSelection) { 22944 PrimeFaces.clearSelection(); 22945 } 22946 } 22947 }, 22948 22949 onRowRightClick: function(event, node) { 22950 var selected = node.hasClass('ui-state-highlight'); 22951 22952 if(this.isCheckboxSelection()) { 22953 if(!selected) { 22954 this.toggleCheckboxNode(node); 22955 } 22956 } 22957 else { 22958 if(this.isSingleSelection() || !selected ) { 22959 this.unselectAllNodes(); 22960 } 22961 this.selectNode(node); 22962 } 22963 22964 if(this.cfg.disabledTextSelection) { 22965 PrimeFaces.clearSelection(); 22966 } 22967 }, 22968 22969 selectNode: function(node, silent) { 22970 var nodeKey = node.attr('data-rk'); 22971 22972 node.removeClass('ui-state-hover ui-treetable-partialselected').addClass('ui-state-highlight').attr('aria-selected', true); 22973 this.addToSelection(nodeKey); 22974 this.writeSelections(); 22975 22976 if(this.isCheckboxSelection()) { 22977 if(this.cfg.nativeElements) 22978 node.find('> td:first-child > :checkbox').prop('checked', true).prop('indeterminate', false); 22979 else 22980 node.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box').removeClass('ui-state-hover').children('span.ui-chkbox-icon').removeClass('ui-icon-blank ui-icon-minus').addClass('ui-icon-check'); 22981 } 22982 22983 if(!silent) { 22984 this.fireSelectNodeEvent(nodeKey); 22985 } 22986 }, 22987 22988 unselectNode: function(node, silent) { 22989 var nodeKey = node.attr('data-rk'); 22990 22991 node.removeClass('ui-state-highlight ui-treetable-partialselected').attr('aria-selected', false); 22992 this.removeSelection(nodeKey); 22993 this.writeSelections(); 22994 22995 if(this.isCheckboxSelection()) { 22996 if(this.cfg.nativeElements) 22997 node.find('> td:first-child > :checkbox').prop('checked', false).prop('indeterminate', false); 22998 else 22999 node.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box > span.ui-chkbox-icon').addClass('ui-icon-blank').removeClass('ui-icon-check ui-icon-minus'); 23000 } 23001 23002 if(!silent) { 23003 this.fireUnselectNodeEvent(nodeKey); 23004 } 23005 }, 23006 23007 unselectAllNodes: function() { 23008 var selectedNodes = this.tbody.children('tr.ui-state-highlight'); 23009 for(var i = 0; i < selectedNodes.length; i++) { 23010 this.unselectNode(selectedNodes.eq(i), true); 23011 } 23012 23013 this.selections = []; 23014 this.writeSelections(); 23015 }, 23016 23017 selectNodesInRange: function(node) { 23018 if(this.cursorNode) { 23019 this.unselectAllNodes(); 23020 23021 var currentNodeIndex = node.index(), 23022 cursorNodeIndex = this.cursorNode.index(), 23023 startIndex = (currentNodeIndex > cursorNodeIndex) ? cursorNodeIndex : currentNodeIndex, 23024 endIndex = (currentNodeIndex > cursorNodeIndex) ? (currentNodeIndex + 1) : (cursorNodeIndex + 1), 23025 nodes = this.tbody.children(); 23026 23027 for(var i = startIndex ; i < endIndex; i++) { 23028 this.selectNode(nodes.eq(i), true); 23029 } 23030 } 23031 else { 23032 this.selectNode(node); 23033 } 23034 }, 23035 23036 indeterminateNodes: function(nodes) { 23037 for(var i = 0; i < nodes.length; i++) { 23038 nodes.eq(i).find('> td:first-child > :checkbox').prop('indeterminate', true); 23039 } 23040 }, 23041 23042 toggleCheckboxNode: function(node) { 23043 var selected = node.hasClass('ui-state-highlight'), 23044 rowKey = node.data('rk'); 23045 23046 //toggle itself 23047 if(selected) 23048 this.unselectNode(node, true); 23049 else 23050 this.selectNode(node, true); 23051 23052 //propagate down 23053 var descendants = this.getDescendants(node); 23054 for(var i = 0;
23054 i < descendants.length; i++) { 23055 var descendant = descendants[i]; 23056 if(selected) 23057 this.unselectNode(descendant, true); 23058 else 23059 this.selectNode(descendant, true); 23060 } 23061 23062 if(selected) { 23063 this.removeDescendantsFromSelection(node.data('rk')); 23064 } 23065 23066 //propagate up 23067 var parentNode = this.getParent(node); 23068 if(parentNode) { 23069 this.propagateUp(parentNode); 23070 } 23071 23072 this.writeSelections(); 23073 23074 if(selected) 23075 this.fireUnselectNodeEvent(rowKey); 23076 else 23077 this.fireSelectNodeEvent(rowKey); 23078 }, 23079 23080 getDescendants: function(node) { 23081 var nodeKey = node.attr('data-rk'), 23082 nextNodes = node.nextAll(), 23083 descendants = []; 23084 23085 for(var i = 0; i < nextNodes.length; i++) { 23086 var nextNode = nextNodes.eq(i), 23087 nextNodeRowKey = nextNode.attr('data-rk'); 23088 23089 if(nextNodeRowKey.indexOf(nodeKey) != -1) { 23090 descendants.push(nextNode); 23091 } 23092 else { 23093 break; 23094 } 23095 } 23096 23097 return descendants; 23098 }, 23099 23100 getChildren: function(node) { 23101 var nodeKey = node.attr('data-rk'), 23102 nextNodes = node.nextAll(), 23103 children = []; 23104 23105 for(var i = 0; i < nextNodes.length; i++) { 23106 var nextNode = nextNodes.eq(i), 23107 nextNodeParentKey = nextNode.attr('data-prk'); 23108 23109 if(nextNodeParentKey === nodeKey) { 23110 children.push(nextNode); 23111 } 23112 } 23113 23114 return children; 23115 }, 23116 23117 propagateUp: function(node) { 23118 var children = this.getChildren(node), 23119 allSelected = true, 23120 partialSelected = false, 23121 checkbox = this.cfg.nativeElements ? node.find('> td:first-child > :checkbox') : 23122 node.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box > span.ui-chkbox-icon'); 23123 23124 for(var i = 0; i < children.length; i++) { 23125 var child = children[i], 23126 childSelected = child.hasClass('ui-state-highlight'); 23127 23128 allSelected = allSelected&&childSelected; 23129 partialSelected = partialSelected||childSelected||child.hasClass('ui-treetable-partialselected'); 23130 } 23131 23132 if(allSelected) { 23133 node.removeClass('ui-treetable-partialselected'); 23134 this.selectNode(node, true); 23135 } 23136 else if(partialSelected) { 23137 node.removeClass('ui-state-highlight').addClass('ui-treetable-partialselected'); 23138 23139 if(this.cfg.nativeElements) 23140 checkbox.prop('indeterminate', true); 23141 else 23142 checkbox.removeClass('ui-icon-blank ui-icon-check').addClass('ui-icon-minus'); 23143 23144 this.removeSelection(node.attr('data-rk')); 23145 } 23146 else { 23147 node.removeClass('ui-state-highlight ui-treetable-partialselected'); 23148 23149 if(this.cfg.nativeElements) 23150 checkbox.prop('indeterminate', false).prop('checked', false); 23151 else 23152 checkbox.addClass('ui-icon-blank').removeClass('ui-icon-check ui-icon-minus'); 23153 23154 this.removeSelection(node.attr('data-rk')); 23155 } 23156 23157 var parent = this.getParent(node); 23158 if(parent) { 23159 this.propagateUp(parent); 23160 } 23161 }, 23162 23163 getParent: function(node) { 23164 var parent = $(this.jqId + '_node_' + node.attr('data-prk')); 23165 23166 return parent.length === 1 ? parent : null; 23167 }, 23168 23169 removeDescendantsFromSelection: function(rowKey) { 23170 this.selections = $.grep(this.selections, function(value) { 23171 return value.indexOf(rowKey + '_') !== 0; 23172 }); 23173 }, 23174 23175 removeSelection: function(nodeKey) { 23176 this.selections = $.grep(this.selections, function(value) { 23177 return value !== nodeKey; 23178 }); 23179 }, 23180 23181 addToSelection: function(rowKey) { 23182 if(!this.isSelected(rowKey)) { 23183 this.selections.push(rowKey); 23184 } 23185 }, 23186 23187 isSelected: function(nodeKey) { 23188 return PrimeFaces.inArray(this.selections, nodeKey); 23189 }, 23190 23191 isSingleSelection: function() { 23192 return this.cfg.selectionMode == 'single'; 23193 }, 23194 23195 isMultipleSelection: function() { 23196 return this.cfg.selectionMode == 'multiple'; 23197 }, 23198 23199 isCheckboxSelection: function() { 23200 return this.cfg.selectionMode == 'checkbox'; 23201 }, 23202 23203 writeSelections: function() { 23204 this.jqSelection.val(this.selections.join(',')); 23205 }, 23206 23207 fireSelectNodeEvent: function(nodeKey) { 23208 if(this.isCheckboxSelection()) { 23209 var $this = this, 23210 options = { 23211 source: this.id, 23212 process: this.id 23213 }; 23214 23215 options.params = [
23216 {name: this.id + '_instantSelection', value: nodeKey} 23217 ]; 23218 23219 options.oncomplete = function(xhr, status, args, data) { 23220 if(args.descendantRowKeys && args.descendantRowKeys !== '') { 23221 var rowKeys = args.descendantRowKeys.split(','); 23222 for(var i = 0; i < rowKeys.length; i++) { 23223 $this.addToSelection(rowKeys[i]); 23224 } 23225 $this.writeSelections(); 23226 } 23227 } 23228 23229 if(this.hasBehavior('select')) { 23230 this.callBehavior('select', options); 23231 } 23232 else { 23233 PrimeFaces.ajax.Request.handle(options); 23234 } 23235 } 23236 else { 23237 if(this.hasBehavior('select')) { 23238 var ext = { 23239 params: [ 23240 {name: this.id + '_instantSelection', value: nodeKey} 23241 ] 23242 }; 23243 23244 this.callBehavior('select', ext); 23245 } 23246 } 23247 }, 23248 23249 fireUnselectNodeEvent: function(nodeKey) { 23250 if(this.hasBehavior('unselect')) { 23251 var ext = { 23252 params: [ 23253 {name: this.id + '_instantUnselection', value: nodeKey} 23254 ] 23255 }; 23256 23257 this.callBehavior('unselect', ext); 23258 } 23259 }, 23260 23261 setupScrolling: function() { 23262 this.scrollHeader = this.jq.children('div.ui-treetable-scrollable-header'); 23263 this.scrollBody = this.jq.children('div.ui-treetable-scrollable-body'); 23264 this.scrollFooter = this.jq.children('div.ui-treetable-scrollable-footer'); 23265 this.scrollStateHolder = $(this.jqId + '_scrollState'); 23266 this.scrollHeaderBox = this.scrollHeader.children('div.ui-treetable-scrollable-header-box'); 23267 this.scrollFooterBox = this.scrollFooter.children('div.ui-treetable-scrollable-footer-box'); 23268 this.headerTable = this.scrollHeaderBox.children('table'); 23269 this.bodyTable = this.scrollBody.children('table'); 23270 this.footerTable = this.scrollFooterBox.children('table'); 23271 this.headerCols = this.headerTable.find('> thead > tr > th'); 23272 this.footerCols = this.footerTable.find('> tfoot > tr > td'); 23273 this.percentageScrollHeight = this.cfg.scrollHeight && (this.cfg.scrollHeight.indexOf('%') !== -1); 23274 this.percentageScrollWidth = this.cfg.scrollWidth && (this.cfg.scrollWidth.indexOf('%') !== -1); 23275 var $this = this; 23276 23277 if(this.cfg.scrollHeight) { 23278 if(this.cfg.scrollHeight.indexOf('%') !== -1) { 23279 this.adjustScrollHeight(); 23280 } 23281 23282 if(this.cfg.scrollHeight.indexOf('vh') !== -1) { 23283 this.applyViewPortScrollHeight(); 23284 } 23285 23286 this.marginRight = this.getScrollbarWidth() + 'px'; 23287 this.scrollHeaderBox.css('margin-right', this.marginRight); 23288 this.scrollFooterBox.css('margin-right', this.marginRight); 23289 this.alignScrollBody(); 23290 } 23291 23292 this.fixColumnWidths(); 23293 23294 if(this.cfg.scrollWidth) { 23295 if(this.cfg.scrollWidth.indexOf('%') !== -1) { 23296 this.adjustScrollWidth(); 23297 } 23298 else { 23299 this.setScrollWidth(parseInt(this.cfg.scrollWidth)); 23300 } 23301 } 23302 23303 this.cloneHead(); 23304 23305 this.restoreScrollState(); 23306 23307 this.updateVerticalScroll(); 23308 23309 this.scrollBody.scroll(function() { 23310 var scrollLeft = $this.scrollBody.scrollLeft(); 23311 $this.scrollHeaderBox.css('margin-left', -scrollLeft); 23312 $this.scrollFooterBox.css('margin-left', -scrollLeft); 23313 23314 $this.saveScrollState(); 23315 }); 23316 23317 this.scrollHeader.on('scroll.treeTable', function() { 23318 $this.scrollHeader.scrollLeft(0); 23319 }); 23320 23321 this.scrollFooter.on('scroll.treeTable', function() { 23322 $this.scrollFooter.scrollLeft(0); 23323 }); 23324 23325 PrimeFaces.utils.registerResizeHandler(this, 'resize.' + this.id + '_align', $this.jq, function() { 23326 if ($this.percentageScrollHeight) { 23327 $this.adjustScrollHeight(); 23328 } 23329 if ($this.percentageScrollWidth) { 23330 $this.adjustScrollWidth(); 23331 } 23332 }); 23333 }, 23334 23335 cloneHead: function() { 23336 this.theadClone = this.headerTable.children('thead').clone(); 23337 this.theadClone.find('th').each(function() { 23338 var header = $(this); 23339 header.attr('id', header.attr('id') + '_clone'); 23340 }); 23341 this.theadClone.removeAttr('id').addClass('ui-treetable-scrollable-theadclone').height(0).prependTo(this.bodyTable); 23342 }, 23343 23344 fixColumnWidths: function() { 23345 var $this = this; 23346 23347 if(!this.columnWidthsFixed) { 23348 if(this.cfg.scrollable) { 23349 this.headerCols.each(function() { 23350 var headerCol = $(this), 23351 colIndex = headerCol.index(), 23352 width = headerCol.width(); 23353 23354 headerCol.width(width); 23355 23356 if($this.footerCols.length > 0) { 23357 var footerCol = $this.footerCols.eq(colIndex); 23358 footerCol.width(width); 23359 } 23360 }); 23361 } 23362 else { 23363 this.jq.find('> table > thead > tr > th').each(function() { 23364 var col = $(this); 23365 col.width(col.width()); 23366 }); 23367 } 23368 23369 this.columnWidthsFixed = true; 23370 } 23371 }, 23372 23373 updateColumnWidths: function() { 23374 this.columnWidthsFixed = false;
23375 this.jq.find('> table > thead > tr > th').each(function() { 23376 var col = $(this); 23377 col.css('width', ''); 23378 }); 23379 this.fixColumnWidths(); 23380 }, 23381 23382 adjustScrollHeight: function() { 23383 var relativeHeight = this.jq.parent().innerHeight() * (parseInt(this.cfg.scrollHeight) / 100), 23384 tableHeaderHeight = this.jq.children('.ui-treetable-header').outerHeight(true), 23385 tableFooterHeight = this.jq.children('.ui-treetable-footer').outerHeight(true), 23386 scrollersHeight = (this.scrollHeader.outerHeight(true) + this.scrollFooter.outerHeight(true)), 23387 height = (relativeHeight - (scrollersHeight + tableHeaderHeight + tableFooterHeight)); 23388 23389 this.scrollBody.height(height); 23390 }, 23391 23392 applyViewPortScrollHeight: function() { 23393 this.scrollBody.height(this.cfg.scrollHeight); 23394 }, 23395 23396 adjustScrollWidth: function() { 23397 var width = parseInt((this.jq.parent().innerWidth() * (parseInt(this.cfg.scrollWidth) / 100))); 23398 this.setScrollWidth(width); 23399 }, 23400 23401 setOuterWidth: function(element, width) { 23402 var diff = element.outerWidth() - element.width(); 23403 element.width(width - diff); 23404 }, 23405 23406 hasVerticalOverflow: function() { 23407 return (this.cfg.scrollHeight && this.bodyTable.outerHeight() > this.scrollBody.outerHeight()); 23408 }, 23409 23410 setScrollWidth: function(width) { 23411 var $this = this; 23412 this.jq.children('.ui-widget-header').each(function() { 23413 $this.setOuterWidth($(this), width); 23414 }); 23415 this.scrollHeader.width(width); 23416 this.scrollBody.css('padding-right', 0).width(width); 23417 this.scrollFooter.width(width); 23418 }, 23419 23420 alignScrollBody: function() { 23421 if(!this.cfg.scrollWidth) { 23422 if(this.hasVerticalOverflow()) 23423 this.scrollBody.css('padding-right', 0); 23424 else 23425 this.scrollBody.css('padding-right', this.getScrollbarWidth()); 23426 } 23427 }, 23428 23429 getScrollbarWidth: function() { 23430 return $.browser.webkit ? '15' : PrimeFaces.calculateScrollbarWidth(); 23431 }, 23432 23433 restoreScrollState: function() { 23434 var scrollState = this.scrollStateVal||this.scrollStateHolder.val(), 23435 scrollValues = scrollState.split(','); 23436 23437 this.scrollBody.scrollLeft(scrollValues[0]); 23438 this.scrollBody.scrollTop(scrollValues[1]); 23439 this.scrollStateVal = null; 23440 }, 23441 23442 saveScrollState: function() { 23443 var scrollState = this.scrollBody.scrollLeft() + ',' + this.scrollBody.scrollTop(); 23444 23445 this.scrollStateHolder.val(scrollState); 23446 }, 23447 23448 setupResizableColumns: function() { 23449 this.fixColumnWidths(); 23450 23451 if(!this.cfg.liveResize) { 23452 this.resizerHelper = $('<div class="ui-column-resizer-helper ui-state-highlight"></div>').appendTo(this.jq); 23453 } 23454 23455 this.thead.find('> tr > th.ui-resizable-column:not(:last-child)').prepend('<span class="ui-column-resizer"> </span>'); 23456 var resizers = this.thead.find('> tr > th > span.ui-column-resizer'), 23457 $this = this; 23458 23459 resizers.draggable({ 23460 axis: 'x', 23461 start: function() { 23462 if($this.cfg.liveResize) { 23463 $this.jq.css('cursor', 'col-resize'); 23464 } 23465 else { 23466 var header = $this.cfg.stickyHeader ? $this.clone : $this.thead, 23467 height = $this.cfg.scrollable ? $this.scrollBody.height() : header.parent().height() - header.height() - 1; 23468 23469 if($this.cfg.stickyHeader) { 23470 height = height - $this.relativeHeight; 23471 } 23472 23473 $this.resizerHelper.height(height); 23474 $this.resizerHelper.show(); 23475 } 23476 }, 23477 drag: function(event, ui) { 23478 if($this.cfg.liveResize) { 23479 $this.resize(event, ui); 23480 } 23481 else { 23482 $this.resizerHelper.offset({ 23483 left: ui.helper.offset().left + ui.helper.width() / 2, 23484 top: $this.thead.offset().top + $this.thead.height() 23485 }); 23486 } 23487 }, 23488 stop: function(event, ui) { 23489 var columnHeader = ui.helper.parent(); 23490 ui.helper.css('left',''); 23491 23492 if($this.cfg.liveResize) { 23493 $this.jq.css('cursor', 'default'); 23494 } else { 23495 $this.resize(event, ui); 23496 $this.resizerHelper.hide(); 23497 } 23498 23499 var options = { 23500 source: $this.id, 23501 process: $this.id, 23502 params: [ 23503 {name: $this.id + '_colResize', value: true}, 23504 {name: $this.id + '_columnId', value: columnHeader.attr('id')}, 23505 {name: $this.id + '_width', value: parseInt(columnHeader.width())}, 23506 {name: $this.id + '_height', value: parseInt(columnHeader.height())} 23507 ] 23508 }; 23509 23510 if($this.hasBehavior('colResize')) { 23511 $this.callBehavior('colResize', options); 23512 } 23513 23514 if($this.cfg.stickyHeader) { 23515 $this.reclone(); 23516 } 23517 }, 23518 containment: this.jq 23519 }); 23520 }, 23521 23522 resize: function(event, ui) { 23523 var columnHeader = ui.helper.parent(), 23524 nextColumnHeader = columnHeader.next(), 23525 change = null, newWidth = null, nextColumnWidth = null; 23526 23527 if(this.cfg.liveResize) { 23528 change = columnHeader.outerWidth() - (event.pageX - columnHeader.offset().left), 23529 newWidth = (columnHeader.width() - change), 23530 nextColumnWidth = (nextColumnHeader.width() + change); 23531 } 23532 else { 23533 change = (ui.position.left - ui.originalPosition.left), 23534 newWidth = (columnHeader.width() + change), 23535 nextColumnWidth = (nextColumnHeader.width() - change); 23536 } 23537 23538 if(newWidth > 15 && nextColumnWidth > 15) { 23539 columnHeader.width(newWidth); 23540 nextColumnHeader.width(nextColumnWidth); 23541 var colIndex = columnHeader.index(); 23542 23543 if(this.cfg.scrollable) { 23544 this.theadClone.find(PrimeFaces.escapeClientId(columnHeader.attr('id') + '_clone')).width(newWidth); 23545 this.theadClone.find(PrimeFaces.escapeClientId(nextColumnHeader.attr('id') + '_clone')).width(nextColumnWidth); 23546 23547 if(this.footerCols.length > 0) { 23548 var footerCol = this.footerCols.eq(colIndex), 23549 nextFooterCol = footerCol.next(); 23550 23551 footerCol.width(newWidth); 23552 nextFooterCol.width(nextColumnWidth); 23553 } 23554 } 23555 } 23556 }, 23557 23558 reclone: function() { 23559 this.clone.remove(); 23560 this.clone = this.thead.clone(false); 23561 this.jq.children('table').append(this.clone); 23562 }, 23563 23564 switchToRowEdit: function(row) { 23565 this.showRowEditors(row); 23566 23567 if(this.hasBehavior('rowEditInit')) { 23568 var rowIndex = row.data('rk'); 23569 23570 var ext = { 23571 params: [{name: this.id + '_rowEditIndex', value: rowIndex}] 23572 }; 23573 23574 this.callBehavior('rowEditInit', ext); 23575 } 23576 }, 23577 23578 showRowEditors: function(row) { 23579 row.addClass('ui-state-highlight ui-row-editing').children('td.ui-editable-column').each(function() { 23580 var column = $(this); 23581 23582 column.find('.ui-cell-editor-output').hide(); 23583 column.find('.ui-cell-editor-input').show(); 23584 }); 23585 }, 23586 23587 /** 23588 * Saves the edited row 23589 */ 23590 saveRowEdit: function(rowEditor) { 23591 this.doRowEditRequest(rowEditor, 'save'); 23592 }, 23593 23594 /** 23595 * Cancels row editing 23596 */ 23597 cancelRowEdit: function(rowEditor) { 23598 this.doRowEditRequest(rowEditor, 'cancel'); 23599 }, 23600 23601 /** 23602 * Sends an ajax request to handle row save or cancel 23603 */ 23604 doRowEditRequest: function(rowEditor, action) { 23605 var row = rowEditor.closest('tr'), 23606 rowIndex = row.data('rk'), 23607 expanded = row.hasClass('ui-expanded-row'), 23608 $this = this, 23609 options = { 23610 source: this.id, 23611 process: this.id, 23612 update: this.id, 23613 formId: this.cfg.formId, 23614 params: [{name: this.id + '_rowEditIndex', value: rowIndex}, 23615 {name: this.id + '_rowEditAction', value: action}], 23616 onsuccess: function(responseXML, status, xhr) { 23617 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 23618 widget: $this, 23619 handle: function(content) { 23620 if(expanded) { 23621 this.collapseRow(row); 23622 } 23623 23624 this.updateRows(row, content); 23625 } 23626 }); 23627 23628 return true; 23629 }, 23630 oncomplete: function(xhr, status, args, data) { 23631 if(args && args.validationFailed) { 23632 $this.invalidateRow(rowIndex); 23633 } 23634 } 23635 }; 23636 23637 if(action === 'save') { 23638 this.getRowEditors(row).each(function() { 23639 options.params.push({name: this.id, value: this.id}); 23640 }); 23641 } 23642 23643 if(action === 'save' && this.hasBehavior('rowEdit')) { 23644 this.callBehavior('rowEdit', options); 23645 } 23646 else if(action === 'cancel' && this.hasBehavior('rowEditCancel')) { 23647 this.callBehavior('rowEditCancel', options); 23648 } 23649 else { 23650 PrimeFaces.ajax.Request.handle(options); 23651 } 23652 }, 23653 23654 /* 23655 * Updates rows with given content 23656 */ 23657 updateRows: function(row, content) { 23658 this.tbody.children('tr').filter('[data-prk^="'+ row.data('rk') +'"]').remove(); 23659 row.replaceWith(content); 23660 }, 23661 23662 /**
23663 * Displays row editors in invalid format 23664 */ 23665 invalidateRow: function(index) { 23666 this.tbody.children('tr').eq(index).addClass('ui-widget-content ui-row-editing ui-state-error'); 23667 }, 23668 23669 /** 23670 * Finds all editors of a row 23671 */ 23672 getRowEditors: function(row) { 23673 return row.find('div.ui-cell-editor'); 23674 }, 23675 23676 collapseRow: function(row) { 23677 row.removeClass('ui-expanded-row').next('.ui-expanded-row-content').remove(); 23678 }, 23679 23680 showCellEditor: function(c) { 23681 this.incellClick = true; 23682 23683 var cell = null; 23684 23685 if(c) { 23686 cell = c; 23687 23688 //remove contextmenu selection highlight 23689 if(this.contextMenuCell) { 23690 this.contextMenuCell.parent().removeClass('ui-state-highlight'); 23691 } 23692 } 23693 else { 23694 cell = this.contextMenuCell; 23695 } 23696 23697 var editorInput = cell.find('> .ui-cell-editor > .ui-cell-editor-input'); 23698 if(editorInput.length !== 0 && editorInput.children().length === 0 && this.cfg.editMode === 'cell') { 23699 // for lazy cellEditMode 23700 this.cellEditInit(cell); 23701 } 23702 else { 23703 this.showCurrentCell(cell); 23704 23705 if(this.hasBehavior('cellEditInit')) { 23706 var cellInfo = this.getCellMeta(cell); 23707 var ext = { 23708 params: [{name: this.id + '_cellInfo', value: cellInfo}] 23709 }; 23710 this.callBehavior('cellEditInit', ext); 23711 } 23712 } 23713 }, 23714 23715 showCurrentCell: function(cell) { 23716 var $this = this; 23717 23718 if(this.currentCell) { 23719 $this.saveCell(this.currentCell); 23720 } 23721 23722 this.currentCell = cell; 23723 23724 var cellEditor = cell.children('div.ui-cell-editor'), 23725 displayContainer = cellEditor.children('div.ui-cell-editor-output'), 23726 inputContainer = cellEditor.children('div.ui-cell-editor-input'), 23727 inputs = inputContainer.find(':input:enabled'), 23728 multi = inputs.length > 1; 23729 23730 cell.addClass('ui-state-highlight ui-cell-editing'); 23731 displayContainer.hide(); 23732 inputContainer.show(); 23733 inputs.eq(0).focus().select(); 23734 23735 //metadata 23736 if(multi) { 23737 var oldValues = []; 23738 for(var i = 0; i < inputs.length; i++) { 23739 oldValues.push(inputs.eq(i).val()); 23740 } 23741 23742 cell.data('multi-edit', true); 23743 cell.data('old-value', oldValues); 23744 } 23745 else { 23746 cell.data('multi-edit', false); 23747 cell.data('old-value', inputs.eq(0).val()); 23748 } 23749 23750 //bind events on demand 23751 if(!cell.data('edit-events-bound')) { 23752 cell.data('edit-events-bound', true); 23753 23754 inputs.on('keydown.treetable-cell', function(e) { 23755 var keyCode = $.ui.keyCode, 23756 shiftKey = e.shiftKey, 23757 key = e.which, 23758 input = $(this); 23759 23760 if(key === keyCode.ENTER) { 23761 $this.saveCell(cell); 23762 23763 e.preventDefault(); 23764 } 23765 else if(key === keyCode.TAB) { 23766 if(multi) { 23767 var focusIndex = shiftKey ? input.index() - 1 : input.index() + 1; 23768 23769 if(focusIndex < 0 || (focusIndex === inputs.length)) { 23770 $this.tabCell(cell, !shiftKey); 23771 } else { 23772 inputs.eq(focusIndex).focus(); 23773 } 23774 } 23775 else { 23776 $this.tabCell(cell, !shiftKey); 23777 } 23778 23779 e.preventDefault(); 23780 } 23781 else if(key === keyCode.ESCAPE) { 23782 $this.doCellEditCancelRequest(cell); 23783 e.preventDefault(); 23784 } 23785 }) 23786 .on('focus.treetable-cell click.treetable-cell', function(e) { 23787 $this.currentCell = cell; 23788 }); 23789 } 23790 }, 23791 23792 tabCell: function(cell, forward) { 23793 var targetCell = forward ? cell.nextAll('td.ui-editable-column:first') : cell.prevAll('td.ui-editable-column:first'); 23794 if(targetCell.length == 0) { 23795 var tabRow = forward ? cell.parent().next() : cell.parent().prev(); 23796 targetCell = forward ? tabRow.children('td.ui-editable-column:first') : tabRow.children('td.ui-editable-column:last'); 23797 } 23798 23799 this.showCellEditor(targetCell); 23800 }, 23801 23802 saveCell: function(cell) { 23803 var inputs = cell.find('div.ui-cell-editor-input :input:enabled'), 23804 changed = false, 23805 $this = this; 23806 23807 if(cell.data('multi-edit')) { 23808 var oldValues = cell.data('old-value'); 23809 for(var i = 0; i < inputs.length; i++) { 23810 if(inputs.eq(i).val() != oldValues[i]) { 23811 changed = true; 23812 break; 23813 } 23814 } 23815 } 23816 else { 23817 changed = (inputs.eq(0).val() != cell.data('old-value')); 23818 } 23819 23820 if(changed) 23821 $this.doCellEditRequest(cell); 23822 else 23823 $this.viewMode(cell); 23824 23825 this.currentCell = null; 23826 }, 23827 23828 viewMode: function(cell) { 23829 var cellEditor = cell.children('div.ui-cell-editor'), 23830 editableContainer = cellEditor.children('div.ui-cell-editor-input'), 23831 displayContainer = cellEditor.children('div.ui-cell-editor-output'); 23832 23833 cell.removeClass('ui-cell-editing ui-state-error ui-state-highlight'); 23834 displayContainer.show(); 23835 editableContainer.hide(); 23836 cell.removeData('old-value').removeData('multi-edit'); 23837 23838 if(this.cfg.cellEditMode === "lazy") { 23839 editableContainer.children().remove(); 23840 } 23841 }, 23842 23843 doCellEditRequest: function(cell) { 23844 var cellEditor = cell.children('.ui-cell-editor'), 23845 cellEditorId = cellEditor.attr('id'), 23846 cellInfo = this.getCellMeta(cell), 23847 $this = this; 23848 23849 var options = { 23850 source: this.id, 23851 process: this.id, 23852 update: this.id, 23853 params: [{name: this.id + '_cellInfo', value: cellInfo}, 23854 {name: cellEditorId, value: cellEditorId}], 23855 onsuccess: function(responseXML, status, xhr) { 23856 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 23857 widget: $this, 23858 handle: function(content) { 23859 cellEditor.children('.ui-cell-editor-output').html(content); 23860 } 23861 }); 23862 23863 return true; 23864 }, 23865 oncomplete: function(xhr, status, args, data) { 23866 if(args.validationFailed) 23867 cell.addClass('ui-state-error'); 23868 else 23869 $this.viewMode(cell); 23870 } 23871 }; 23872 23873 if(this.hasBehavior('cellEdit')) { 23874 this.callBehavior('cellEdit', options); 23875 } 23876 else { 23877 PrimeFaces.ajax.Request.handle(options); 23878 } 23879 }, 23880 23881 doCellEditCancelRequest: function(cell) { 23882 var cellEditor = cell.children('.ui-cell-editor'), 23883 cellIndex = cell.index(), 23884 cellInfo = cell.closest('tr').data('rk') + ',' + cellIndex, 23885 $this = this; 23886 23887 this.currentCell = null; 23888 23889 var options = { 23890 source: this.id, 23891 process: this.id, 23892 update: this.id, 23893 params: [{name: this.id + '_cellEditCancel', value: true}, 23894 {name: this.id + '_cellInfo', value: cellInfo}], 23895 onsuccess: function(responseXML, status, xhr) { 23896 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 23897 widget: $this, 23898 handle: function(content) { 23899 cellEditor.children('.ui-cell-editor-input').html(content); 23900 } 23901 }); 23902 23903 return true; 23904 }, 23905 oncomplete: function(xhr, status, args, data) { 23906 $this.viewMode(cell);
23907 cell.data('edit-events-bound', false); 23908 } 23909 }; 23910 23911 if(this.hasBehavior('cellEditCancel')) { 23912 this.callBehavior('cellEditCancel', options); 23913 } 23914 else { 23915 PrimeFaces.ajax.Request.handle(options); 23916 } 23917 }, 23918 23919 cellEditInit: function(cell) { 23920 var cellEditor = cell.children('.ui-cell-editor'), 23921 cellInfo = this.getCellMeta(cell), 23922 $this = this; 23923 23924 var options = { 23925 source: this.id, 23926 process: this.id, 23927 update: this.id, 23928 global: false, 23929 params: [{name: this.id + '_cellEditInit', value: true}, 23930 {name: this.id + '_cellInfo', value: cellInfo}], 23931 onsuccess: function(responseXML, status, xhr) { 23932 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 23933 widget: $this, 23934 handle: function(content) { 23935 cellEditor.children('.ui-cell-editor-input').html(content); 23936 } 23937 }); 23938 23939 return true; 23940 }, 23941 oncomplete: function(xhr, status, args, data) { 23942 cell.data('edit-events-bound', false); 23943 $this.showCurrentCell(cell); 23944 } 23945 }; 23946 23947 if(this.hasBehavior('cellEditInit')) { 23948 this.callBehavior('cellEditInit', options); 23949 } 23950 else { 23951 PrimeFaces.ajax.Request.handle(options); 23952 } 23953 }, 23954 23955 getCellMeta: function(cell) { 23956 var cellIndex = cell.index(), 23957 cellInfo = cell.closest('tr').data('rk') + ',' + cellIndex; 23958 return cellInfo; 23959 }, 23960 23961 updateVerticalScroll: function() { 23962 if(this.cfg.scrollable && this.cfg.scrollHeight) { 23963 if(this.bodyTable.outerHeight() < this.scrollBody.outerHeight()) { 23964 this.scrollHeaderBox.css('margin-right', 0); 23965 this.scrollFooterBox.css('margin-right', 0); 23966 } 23967 else { 23968 this.scrollHeaderBox.css('margin-right', this.marginRight); 23969 this.scrollFooterBox.css('margin-right', this.marginRight); 23970 } 23971 } 23972 }, 23973 23974 shouldSort: function(event, column) { 23975 if(this.isEmpty()) { 23976 return false; 23977 } 23978 23979 var target = $(event.target); 23980 if(target.closest('.ui-column-customfilter', column).length) { 23981 return false; 23982 } 23983 23984 return target.is('th,span'); 23985 }, 23986 23987 /** 23988 * Returns if there is any data displayed 23989 */ 23990 isEmpty: function() { 23991 return this.tbody.children('tr.ui-treetable-empty-message').length === 1; 23992 } 23993}); 23994/** 23995 * PrimeFaces Wizard Component 23996 */ 23997PrimeFaces.widget.Wizard = PrimeFaces.widget.BaseWidget.extend({ 23998 23999 init: function(cfg) { 24000 this._super(cfg); 24001 24002 this.content = $(this.jqId + '_content'); 24003 this.backNav = $(this.jqId + '_back'); 24004 this.nextNav = $(this.jqId + '_next'); 24005 this.cfg.formId = this.jq.parents('form:first').attr('id'); 24006 this.currentStep = this.cfg.initialStep; 24007 24008 var _self = this; 24009 24010 //Step controls 24011 if(this.cfg.showStepStatus) { 24012 this.stepControls = $(this.jqId + ' .ui-wizard-step-titles li.ui-wizard-step-title'); 24013 } 24014 24015 //Navigation controls 24016 if(this.cfg.showNavBar) { 24017 var currentStepIndex = this.getStepIndex(this.currentStep); 24018 24019 //visuals 24020 PrimeFaces.skinButton(this.backNav); 24021 PrimeFaces.skinButton(this.nextNav); 24022 24023 //events 24024 this.backNav.click(function() {_self.back();}); 24025 this.nextNav.click(function() {_self.next();}); 24026 24027 if(currentStepIndex == 0) 24028 this.backNav.hide(); 24029 else if(currentStepIndex == this.cfg.steps.length - 1) 24030 this.nextNav.hide(); 24031 } 24032 }, 24033 24034 back: function() { 24035 if(this.cfg.onback) { 24036 var value = this.cfg.onback.call(this); 24037 if(value === false) { 24038 return; 24039 } 24040 } 24041
24042 var targetStepIndex = this.getStepIndex(this.currentStep) - 1; 24043 if(targetStepIndex >= 0) { 24044 var stepToGo = this.cfg.steps[targetStepIndex]; 24045 this.loadStep(stepToGo, "back"); 24046 } 24047 }, 24048 24049 next: function() { 24050 if(this.cfg.onnext) { 24051 var value = this.cfg.onnext.call(this); 24052 if(value === false) { 24053 return; 24054 } 24055 } 24056 24057 var targetStepIndex = this.getStepIndex(this.currentStep) + 1; 24058 if(targetStepIndex < this.cfg.steps.length) { 24059 var stepToGo = this.cfg.steps[targetStepIndex]; 24060 this.loadStep(stepToGo, "next"); 24061 } 24062 }, 24063 24064 loadStep: function(stepToGo, event) { 24065 var $this = this, 24066 options = { 24067 source: this.id, 24068 process: this.id, 24069 update: this.id, 24070 formId: this.cfg.formId, 24071 params: [ 24072 {name: this.id + '_direction', value: event}, 24073 {name: this.id + '_stepToGo', value: stepToGo} 24074 ], 24075 onsuccess: function(responseXML, status, xhr) { 24076 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 24077 widget: $this, 24078 handle: function(content) { 24079 this.content.html(content); 24080 } 24081 }); 24082 24083 return true; 24084 }, 24085 oncomplete: function(xhr, status, args, data) { 24086 $this.currentStep = args.currentStep; 24087 24088 if(!args.validationFailed) { 24089 var currentStepIndex = $this.getStepIndex($this.currentStep); 24090 24091 if($this.cfg.showNavBar) { 24092 if(currentStepIndex === $this.cfg.steps.length - 1) { 24093 $this.hideNextNav(); 24094 $this.showBackNav(); 24095 } else if(currentStepIndex === 0) { 24096 $this.hideBackNav(); 24097 $this.showNextNav(); 24098 } else { 24099 $this.showBackNav(); 24100 $this.showNextNav(); 24101 } 24102 } 24103 24104 //update step status 24105 if($this.cfg.showStepStatus) { 24106 $this.stepControls.removeClass('ui-state-highlight'); 24107 $($this.stepControls.get(currentStepIndex)).addClass('ui-state-highlight'); 24108 } 24109 } 24110 } 24111 }; 24112 24113 if(this.hasBehavior(event)) { 24114 this.callBehavior(event, options); 24115 } 24116 else { 24117 PrimeFaces.ajax.Request.handle(options); 24118 } 24119 }, 24120 24121 getStepIndex: function(step) { 24122 for(var i=0; i < this.cfg.steps.length; i++) { 24123 if(this.cfg.steps[i] == step) 24124 return i; 24125 } 24126 24127 return -1; 24128 }, 24129 24130 showNextNav: function() { 24131 this.nextNav.fadeIn(); 24132 }, 24133 24134 hideNextNav: function() { 24135 this.nextNav.fadeOut(); 24136 }, 24137 24138 showBackNav: function() { 24139 this.backNav.fadeIn(); 24140 }, 24141 24142 hideBackNav: function() { 24143 this.backNav.fadeOut(); 24144 } 24145 24146}); 24147 24148 24149PrimeFaces.widget.TriStateCheckbox = PrimeFaces.widget.BaseWidget.extend({ 24150 24151 init:function (cfg) { 24152 this._super(cfg); 24153 24154 this.input = $(this.jqId + '_input'); 24155 this.box = this.jq.find('.ui-chkbox-box'); 24156 this.icon = this.box.children('.ui-chkbox-icon'); 24157 this.itemLabel = this.jq.find('.ui-chkbox-label'); 24158 this.disabled = this.input.is(':disabled'); 24159 this.fixedMod = function(number, mod){ 24160 return ((number % mod) + mod) % mod; 24161 }; 24162 24163 var $this = this; 24164 24165 //bind events if not disabled 24166 if (!this.disabled) { 24167 this.box.on('mouseover.triStateCheckbox', function () { 24168 $this.box.addClass('ui-state-hover'); 24169 }) 24170 .on('mouseout.triStateCheckbox', function () { 24171 $this.box.removeClass('ui-state-hover'); 24172 }) 24173 .on('click.triStateCheckbox', function () { 24174 $this.toggle(1); 24175 $this.input.trigger('focus'); 24176 }); 24177 24178 this.input.on('focus.triStateCheckbox', function () { 24179 $this.box.addClass('ui-state-focus'); 24180 }) 24181 .on('blur.triStateCheckbox', function () { 24182 $this.box.removeClass('ui-state-focus'); 24183 }) 24184 .on('keydown.triStateCheckbox', function (e) { 24185 var keyCode = $.ui.keyCode; 24186 24187 switch (e.which) { 24188 case keyCode.SPACE: 24189 case keyCode.UP: 24190 case keyCode.RIGHT: 24191 case keyCode.LEFT: 24192 case keyCode.DOWN: 24193 e.preventDefault(); 24194 break; 24195 } 24196 }) 24197 .on('keyup.triStateCheckbox', function (e) { 24198 var keyCode = $.ui.keyCode; 24199 24200 switch(e.which) { 24201 case keyCode.SPACE: 24202 case keyCode.UP: 24203 case keyCode.RIGHT: 24204 $this.toggle(1); 24205 break; 24206 case keyCode.LEFT: 24207 case keyCode.DOWN: 24208 $this.toggle(-1); 24209 break; 24210 } 24211 }); 24212 24213 //toggle state on label click 24214 this.itemLabel.on('click.triStateCheckbox', function() { 24215 $this.toggle(1); 24216 $this.input.trigger('focus'); 24217 }); 24218 24219 // client behaviors 24220 if (this.cfg.behaviors) { 24221 PrimeFaces.attachBehaviors(this.input, this.cfg.behaviors); 24222 } 24223 } 24224 24225 // pfs metadata 24226 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 24227 }, 24228 24229 toggle:function (direction) { 24230 if (!this.disabled) { 24231 // default to switch to next state 24232 if (isNaN(direction)) { 24233 direction = 1; 24234 } 24235 24236 var oldValue = parseInt(this.input.val()); 24237 var newValue = this.fixedMod((oldValue + direction), 3); 24238 this.input.val(newValue); 24239 24240 // remove / add def. icon and active classes 24241 if (newValue == 0) { 24242 this.box.removeClass('ui-state-active'); 24243 } else { 24244 this.box.addClass('ui-state-active'); 24245 } 24246 24247 // remove old icon and add the new one
24248 var iconsClasses = this.box.data('iconstates'); 24249 this.icon.removeClass(iconsClasses[oldValue]).addClass(iconsClasses[newValue]); 24250 24251 // change title to the new one 24252 var iconTitles = this.box.data('titlestates'); 24253 if (iconTitles != null && iconTitles.titles != null && iconTitles.titles.length > 0) { 24254 this.box.attr('title', iconTitles.titles[newValue]); 24255 } 24256 24257 // fire change event 24258 this.input.change(); 24259 } 24260 } 24261}); 24262 24263 24264/** 24265 * PrimeFaces Chips Widget 24266 */ 24267PrimeFaces.widget.Chips = PrimeFaces.widget.BaseWidget.extend({ 24268 24269 init: function(cfg) { 24270 this._super(cfg); 24271 24272 this.input = $(this.jqId + '_input'); 24273 this.hinput = $(this.jqId + '_hinput'); 24274 this.itemContainer = this.jq.children('ul'); 24275 this.inputContainer = this.itemContainer.children('.ui-chips-input-token'); 24276 24277 //pfs metadata 24278 this.input.data(PrimeFaces.CLIENT_ID_DATA, this.id); 24279 this.hinput.data(PrimeFaces.CLIENT_ID_DATA, this.id); 24280 this.placeholder = this.input.attr('placeholder'); 24281 24282 this.bindEvents(); 24283 }, 24284 24285 bindEvents: function() { 24286 var $this = this; 24287 24288 this.itemContainer.hover(function() { 24289 $(this).addClass('ui-state-hover'); 24290 }, 24291 function() { 24292 $(this).removeClass('ui-state-hover'); 24293 } 24294 ).click(function() { 24295 $this.input.focus(); 24296 }); 24297 24298 24299 this.input.on('focus.chips', function() { 24300 $this.itemContainer.addClass('ui-state-focus'); 24301 }).on('blur.chips', function() { 24302 $this.itemContainer.removeClass('ui-state-focus'); 24303 24304 if ($this.cfg.addOnBlur) { 24305 $this.addItem($(this).val(), false); 24306 } 24307 }).on('keydown.chips', function(e) { 24308 var value = $(this).val(); 24309 24310 switch(e.which) { 24311 //backspace 24312 case 8: 24313 if(value.length === 0 && $this.hinput.children('option') && $this.hinput.children('option').length > 0) { 24314 var lastOption = $this.hinput.children('option:last'), 24315 index = lastOption.index(); 24316 $this.removeItem($($this.itemContainer.children('li.ui-chips-token').get(index))); 24317 } 24318 break; 24319 24320 //enter 24321 case 13: 24322 $this.addItem(value, true); 24323 e.preventDefault(); 24324 break; 24325 24326 default: 24327 if($this.cfg.max && $this.cfg.max === $this.hinput.children('option').length) { 24328 e.preventDefault(); 24329 } 24330 break; 24331 } 24332 }); 24333 24334 var closeSelector = '> li.ui-chips-token > .ui-chips-token-icon'; 24335 this.itemContainer.off('click', closeSelector).on('click', closeSelector, null, function(event) { 24336 $this.removeItem($(this).parent()); 24337 }); 24338 }, 24339 24340 addItem : function(value, refocus) { 24341 if(value && value.trim().length && (!this.cfg.max||this.cfg.max > this.hinput.children('option').length)) { 24342 var escapedValue = PrimeFaces.escapeHTML(value); 24343 var itemDisplayMarkup = '<li class="ui-chips-token ui-state-active ui-corner-all">'; 24344 itemDisplayMarkup += '<span class="ui-chips-token-icon ui-icon ui-icon-close"></span>'; 24345 itemDisplayMarkup += '<span class="ui-chips-token-label">' + escapedValue + '</span></li>'; 24346 24347 this.inputContainer.before(itemDisplayMarkup); 24348 this.input.val(''); 24349 this.input.removeAttr('placeholder'); 24350 24351 if (refocus) { 24352 this.input.focus(); 24353 } 24354 24355 this.hinput.append('<option value="' + escapedValue + '" selected="selected"></option>'); 24356 this.invokeItemSelectBehavior(escapedValue); 24357 } 24358 }, 24359 24360 removeItem: function(item) { 24361 var itemIndex = this.itemContainer.children('li.ui-chips-token').index(item); 24362 var itemValue = item.find('span.ui-chips-token-label').html() 24363 $this = this; 24364 24365 //remove from options 24366 this.hinput.children('option').eq(itemIndex).remove(); 24367 24368 item.fadeOut('fast', function() { 24369 var token = $(this); 24370 24371 token.remove(); 24372 24373 $this.invokeItemUnselectBehavior(itemValue); 24374 }); 24375 24376 // if empty return placeholder 24377 if (this.placeholder && this.hinput.children('option').length === 0) { 24378 this.input.attr('placeholder', this.placeholder); 24379 } 24380 }, 24381 24382 invokeItemSelectBehavior: function(itemValue) { 24383 if(this.hasBehavior('itemSelect')) { 24384 var ext = { 24385 params : [ 24386 {name: this.id + '_itemSelect', value: itemValue} 24387 ] 24388 }; 24389 24390 this.callBehavior('itemSelect', ext); 24391 } 24392 }, 24393 24394 invokeItemUnselectBehavior: function(itemValue) { 24395 if(this.hasBehavior('itemUnselect')) { 24396 var ext = { 24397 params : [ 24398 {name: this.id + '_itemUnselect', value: itemValue} 24399 ] 24400 }; 24401 24402 this.callBehavior('itemUnselect', ext); 24403 } 24404 } 24405}); 24406/** 24407 * PrimeFaces Sidebar Widget 24408 */ 24409PrimeFaces.widget.Sidebar = PrimeFaces.widget.DynamicOverlayWidget.extend({ 24410 24411 init: function(cfg) { 24412 this._super(cfg); 24413 24414 this.closeIcon = this.jq.children('.ui-sidebar-close'); 24415 this.cfg.baseZIndex = this.cfg.baseZIndex||0; 24416 24417 //aria 24418 this.applyARIA(); 24419 24420 if(this.cfg.visible){ 24421 this.show(); 24422 } 24423 24424 this.bindEvents(); 24425 }, 24426 24427 bindEvents: function() { 24428 var $this = this; 24429 24430 this.closeIcon.on('mouseover', function() { 24431 $(this).addClass('ui-state-hover'); 24432 }).on('mouseout', function() { 24433 $(this).removeClass('ui-state-hover'); 24434 }).on('focus', function() { 24435 $(this).addClass('ui-state-focus'); 24436 }).on('blur', function() { 24437 $(this).removeClass('ui-state-focus'); 24438 }).on('click', function(e) { 24439 $this.hide(); 24440 e.preventDefault(); 24441 }); 24442 }, 24443 24444 show: function() { 24445 if(this.isVisible()) { 24446 return; 24447 } 24448 24449 this.jq.addClass('ui-sidebar-active'); 24450 this.jq.css('z-index', this.cfg.baseZIndex + (++PrimeFaces.zindex)); 24451 24452 this.postShow(); 24453 this.enableModality(); 24454 }, 24455 24456 postShow: function() { 24457 PrimeFaces.invokeDeferredRenders(this.id); 24458 24459 //execute user defined callback 24460 if(this.cfg.onShow) { 24461 this.cfg.onShow.call(this); 24462 } 24463 24464 this.jq.attr({ 24465 'aria-hidden': false 24466 ,'aria-live': 'polite' 24467 }); 24468 }, 24469 24470 hide: function() { 24471 if(!this.isVisible()) { 24472 return; 24473 } 24474 24475 this.jq.removeClass('ui-sidebar-active'); 24476 this.onHide(); 24477 this.disableModality(); 24478 }, 24479 24480 isVisible: function() { 24481 return this.jq.hasClass('ui-sidebar-active'); 24482 }, 24483 24484 onHide: function(event, ui) { 24485 this.jq.attr({ 24486 'aria-hidden': true 24487 ,'aria-live': 'off' 24488 }); 24489 24490 if(this.cfg.onHide) { 24491 this.cfg.onHide.call(this, event, ui); 24492 } 24493 }, 24494 24495 toggle: function() { 24496 if(this.isVisible()) 24497 this.hide(); 24498 else 24499 this.show(); 24500 }, 24501 24502 //@override 24503 enableModality: function() { 24504 this._super(); 24505 24506 var $this = this; 24507 this.modalOverlay.on('click', function() { 24508 $this.hide(); 24509 }); 24510 }, 24511 24512 //@override 24513 getModalTabbables: function(){ 24514 return this.jq.find(':tabbable'); 24515 }, 24516 24517 applyARIA: function() { 24518 this.jq.attr({ 24519 'role': 'dialog' 24520 ,'aria-hidden': !this.cfg.visible 24521 }); 24522 24523 this.closeIcon.attr('role', 'button'); 24524 } 24525 24526}); 24527/* 24528 * PrimeFaces DataView Widget 24529 */ 24530PrimeFaces.widget.DataView = PrimeFaces.widget.BaseWidget.extend({ 24531 24532 init: function(cfg) { 24533 this._super(cfg); 24534 24535 this.header = this.jq.children('.ui-dataview-header'); 24536 this.content = this.jq.children('.ui-dataview-content'); 24537 this.layoutOptions = this.header.children('.ui-dataview-layout-options'); 24538 this.buttons = this.layoutOptions.children('div'); 24539 this.cfg.formId = $(this.jqId).closest('form').attr('id'); 24540 24541 if(this.cfg.paginator) { 24542 this.setupPaginator(); 24543 } 24544 24545 this.bindEvents(); 24546 }, 24547 24548 setupPaginator: function() { 24549 var $this = this; 24550 this.cfg.paginator.paginate = function(newState) { 24551 $this.handlePagination(newState); 24552 }; 24553 24554 this.paginator = new PrimeFaces.widget.Paginator(this.cfg.paginator); 24555 }, 24556 24557 bindEvents: function () { 24558 var $this = this; 24559 24560 this.buttons.on('mouseover', function() { 24561 var button = $(this); 24562 button.addClass('ui-state-hover'); 24563 }) 24564 .on('mouseout', function() { 24565 $(this).removeClass('ui-state-hover'); 24566 }) 24567 .on('click', function() { 24568 var button = $(this), 24569 radio = button.children(':radio'); 24570 24571 if(!radio.prop('checked')) { 24572 $this.select(button); 24573 } 24574 }); 24575 24576 /* For keyboard accessibility */ 24577 this.buttons.on('focus.dataview-button', function(){ 24578 var button = $(this); 24579 button.addClass('ui-state-focus'); 24580 }) 24581 .on('blur.dataview-button', function(){ 24582 var button = $(this); 24583 button.removeClass('ui-state-focus'); 24584 }) 24585 .on('keydown.dataview-button', function(e) { 24586 var keyCode = $.ui.keyCode, 24587 key = e.which; 24588 24589 if(key === keyCode.SPACE || key === keyCode.ENTER) { 24590 var button = $(this), 24591 radio = button.children(':radio'); 24592 24593 if(!radio.prop('checked')) { 24594 $this.select(button); 24595 } 24596 e.preventDefault(); 24597 } 24598 }); 24599 }, 24600 24601 select: function(button) { 24602 this.buttons.filter('.ui-state-active').removeClass('ui-state-active ui-state-hover').children(':radio').prop('checked', false); 24603 24604 button.addClass('ui-state-active').children(':radio').prop('checked', true); 24605 24606 this.loadLayoutContent(button.children(':radio').val()); 24607 }, 24608 24609 loadLayoutContent: function(layout) { 24610 var $this = this, 24611 options = { 24612 source: this.id, 24613 process: this.id, 24614 update: this.id, 24615 params: [ 24616 {name: this.id + '_layout', value: layout} 24617 ], 24618 onsuccess: function(responseXML, status, xhr) { 24619 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 24620 widget: $this, 24621 handle: function(content) { 24622 this.content.html(content); 24623 } 24624 }); 24625 24626 return true; 24627 }, 24628 oncomplete: function() { 24629 $this.jq.removeClass('ui-dataview-grid ui-dataview-list').addClass('ui-dataview-' + layout); 24630 } 24631 }; 24632 24633 PrimeFaces.ajax.Request.handle(options); 24634 }, 24635 24636 handlePagination: function(newState) { 24637 var $this = this, 24638 options = { 24639 source: this.id, 24640 update: this.id, 24641 process: this.id, 24642 formId: this.cfg.formId, 24643 params: [ 24644 {name: this.id + '_pagination', value: true}, 24645 {name: this.id + '_first', value: newState.first}, 24646 {name: this.id + '_rows', value: newState.rows} 24647 ], 24648 onsuccess: function(responseXML, status, xhr) { 24649 PrimeFaces.ajax.Response.handle(responseXML, status, xhr, { 24650 widget: $this, 24651 handle: function(content) { 24652 this.content.html(content); 24653 } 24654 }); 24655 24656 return true; 24657 }, 24658 oncomplete: function() { 24659 $this.paginator.cfg.page = newState.page; 24660 $this.paginator.updateUI(); 24661 } 24662 }; 24663 24664 if(this.hasBehavior('page')) { 24665 this.callBehavior('page', options); 24666 } 24667 else { 24668 PrimeFaces.ajax.Request.handle(options); 24669 } 24670 }, 24671 24672 getPaginator: function() { 24673 return this.paginator; 24674 } 24675});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.