1! function($) { 2 3 // Namespace 4 if (!$.jalios) { 5 $.jalios = {}; 6 } 7 8 // ------------------------------------------ 9 // PRIVATE 10 // ------------------------------------------ 11 12 var rJcmsId = /ID_([^ ]+)/; 13 var rUsage = /USAGE_([^ ]+)/; 14 15 var cbDelay = $.Callbacks(); 16 var registerTimer = function() { 17 18 $(document).idleTimer(8000, { 19 'name': 'Notifier' 20 }); 21 22 $(document).on("Notifier.idle", function() { 23 $.jalios.Common.idle = true; 24 }); 25 26 $(document).on("Notifier.active", function() { 27 $.jalios.Common.idle = false; 28 cbDelay.fire(); 29 cbDelay.empty(); 30 }); 31 }; 32 33 var registerFocus = function() { 34 $(document).on('focusin', function() { 35 $.jalios.DOM.hasFocus = true; 36 }); 37 $(document).on('focusout', function() { 38 $.jalios.DOM.hasFocus = false; 39 }); 40 }; 41 42 var baseUrl = false; 43 var contextPath = false; 44 45 46 var registerResponsive = function() { 47 48 if (typeof(elementQuery) === 'undefined') { 49 return; 50 } 51 52 $(document).on('jalios:refresh', function(event) { 53 var refresh = $.jalios.Event.match(event, 'refresh', 'after'); 54 if (!refresh) { 55 return; 56 } 57 if (!refresh.target) { 58 return; 59 } 60 61 elementQuery(); 62 }); 63 64 $(document).on('show.bs.collapse', function(event) { 65 setTimeout(elementQuery, 200); 66 }); 67 68 $(document).on('shown.bs.tab', function(event) { 69 setTimeout(elementQuery, 200); 70 }); 71 72 $(document).on('shown.bs.modal', function(event) { 73 setTimeout(elementQuery, 200); 74 }); 75 76 $(document).on('jalios:broker', function(event) { 77 var broker = $.jalios.Event.match(event, 'broker', /toggle/i, true); 78 if (!broker) { 79 return; 80 } 81 var elm = broker.source.currentTarget; 82 if ($(elm).is(':visible')) { 83 setTimeout(elementQuery, 200); 84 } 85 }); 86 87 elementQuery(); 88 }; 89 90 /** 91 * Do not follow links with only # at the end of href 92 */ 93 var registerBTFix = function() { 94 $(document).on('click', 'A', function(event) { 95 var $e = $(event.currentTarget); 96 var href = $e.attr('href'); // JsChecker.authorize(".attr('href')") 97 if (href && href.endsWith('#')) { 98 event.preventDefault(); 99 } 100 }); 101 }; 102 103 // ------------------------------------------ 104 // PUBLIC 105 // ------------------------------------------ 106 107 /** 108 * Creates an Object following the specified namespace identifier. 109 * 110 * @public 111 * @param String name The namespace string 112 * @param Object klasses (OPTIONAL) An object which properties will be added to the namespace 113 * @param String separator (OPTIONAL) Namespace segment separator. Default is '.'. 114 * @param Object container (OPTIONAL) object which contains the created Object. Default is 'window'. 115 * @return Object The most inner object 116 */ 117 window.namespace = function(name, klasses, separator, container) { 118 var ns = container || window; 119 name.split(separator || '.').forEach(function(x) { 120 // Handle the prototype/jQuery conflict 121 if (x === '$') { 122 x = 'jQuery'; 123 } 124 ns = ns[x] = ns[x] || {}; 125 }); 126 if (klasses) { 127 for (var klass in klasses) { 128 if (klasses.hasOwnProperty(klass)) { 129 ns[klass] = klasses[klass]; 130 } 131 } 132 } 133 return ns; 134 }; 135 136 /** 137 * Add convenient function to Function prototype 138 * 139 * @namespace Function 140 * @copyright Jalios SA 141 */ 142 143 /** 144 * Convennient delay function (inspired by Prototype) to defer execution. 145 * This fix many IE6+ thread issues 146 * 147 * @example 148 * var func = function(arg1, arg2){ ... } 149 * func.defer(arg1, arg2); 150 */ 151 Function.prototype.defer = function() { 152 var __method = this, 153 args = Array.prototype.slice.call(arguments, 0); 154 155 return window.setTimeout(function() { 156 return __method.apply(__method, args); 157 }, 0.01); 158 } 159 160 /** 161 * Convennient delay function (inspired by Prototype) 162 * 163 * @param {int} delay the delay in seconds 164 * 165 * @example 166 * var func = function(arg1, arg2){ ... } 167 * func.delay(5, arg1, arg2); 168 */ 169 Function.prototype.delay = function(delay) { 170 var __method = this, 171 args = Array.prototype.slice.call(arguments, 1); 172 var __func = function() { 173 return __method.apply(__method, args); 174 } 175 176 return window.setTimeout(__func, delay * 1000); 177 } 178 179 /** 180 * Same as delay function 181 * but If browser is not available, the event will be fired later 182 * 183 * @param {int} delay the delay in seconds 184 * 185 * @example 186 * var func = function(arg1, arg2){ ... } 187 * func.delay(5, arg1, arg2); 188 */ 189 Function.prototype.postpone = function(delay) { 190 var __method = this, 191 args = Array.prototype.slice.call(arguments, 1); 192 var __func = function() { 193 return __method.apply(__method, args); 194 } 195 196 if (!$.jalios.DOM.hasFocus) { 197 cbDelay.add(__func); 198 return; 199 } 200 201 if ($.jalios.Common.idle) { 202 cbDelay.add(__func); 203 return; 204 } 205 206 return window.setTimeout(__func, delay * 1000); 207 } 208 209 /** 210 * Add prototype endsWith() to String 211 */ 212 if (typeof String.prototype.endsWith !== 'function') { 213 String.prototype.endsWith = function(suffix) { 214 return this.indexOf(suffix, this.length - suffix.length) !== -1; 215 }; 216 } 217 218 /** 219 * <p>The navigator.sendBeacon() method can be used to asynchronously transfer a small amount of data over HTTP to a web server.</p> 220 * <p>This method addresses the needs of analytics and diagnostics code that typically attempts to send data to a web server prior to the unloading of the 221 * document. Sending the data any sooner may result in a missed opportunity to gather data. However, ensuring that the data has been sent during the 222 * unloading of a document is something that has traditionally been difficult for developers, because user agents typically ignore asynchronous 223 * XMLHttpRequests made in an unload handler.</p> 224 * 225 * @param {string} url The url parameter indicates the resolved URL to which the data is to be transmitted. 226 * @param {(ArrayBufferView|Blob|DOMString|FormData)} [data] Optional The data parameter is a ArrayBufferView, Blob, DOMString, or FormData object 227 * containing the data to be transmitted. 228 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon|Navigator.sendBeacon()} 229 * @see {@link http://usefulangle.com/post/62/javascript-send-data-to-server-on-page-exit-reload-redirect|Sending AJAX Data when User Moves Away / Exits from Page} 230 */ 231 navigator.sendBeacon = navigator.sendBeacon || function(url, data) { 232 var client = new XMLHttpRequest(); 233 client.open("POST", url, false); // third parameter indicates sync xhr 234 client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); 235 client.send(data); 236 }; 237 238 // ========================================== 239 // $.jalios.Commons 240 // ========================================== 241 242 /** 243 * Jalios Commons:<br/> 244 * Static funtion missing in core librairies to manipulate: String, Arrays, ... 245 * 246 * @namespace $.jalios.Common 247 * @copyright Jalios SA
248 */ 249 250 $.jalios.Common = { 251 252 idle: false, 253 254 /** 255 * Strip all spaces in a given string and merge all blank. 256 * 257 * @param {string} str the String to strip 258 * @param {boolean} lazy set true to not merge spaces 259 * @return {string} the stripped String 260 * @unittest js/tests/jalios/core/jalios-common.html 261 */ 262 strip: function(str, lazy) { 263 str = str.replace(/^\s+|\s+$/g, ''); 264 if (!lazy) { 265 str = str.replace(/(\s)\s*/g, '$1'); 266 } 267 return str; 268 }, 269 270 /** 271 * Check if a given String is blank 272 * 273 * @param {string} str the String to test 274 * @return {boolean} true if the String is blank 275 * @unittest js/tests/jalios/core/jalios-common.html 276 */ 277 blank: function(str) { 278 return !str || !/\S/.test(str); 279 }, 280 281 /** 282 * Inject object into memo using iterator 283 * @param {object} object to iterate 284 * @param {object} memo receive data 285 * @param {function} iterator to walkthrough 286 */ 287 inject: function(object, memo, iterator) { 288 $.each(object, function(idx, val) { 289 memo = iterator(memo, val, idx); 290 }); 291 return memo; 292 }, 293 294 /** 295 * Convert the given object in to a boolean value, or use 296 * default value if object cannot be converted 297 */ 298 toBoolean: function(object, defaultValue) { 299 if (typeof object == 'boolean') { 300 return object; 301 } 302 if (object == 'false' || object == 'no') { 303 return false; 304 } 305 if (object == 'true' || object == 'yes') { 306 return true; 307 } 308 return defaultValue; 309 }, 310 311 size: function(obj) { 312 var count = 0; 313 314 if (typeof obj == "object") { 315 if (Object.keys) { 316 count = Object.keys(obj).length; 317 } else if (jQuery) { 318 count = jQuery.map(obj, function() { 319 return 1; 320 }).length; 321 } else if (window._) { 322 count = _.keys(obj).length; 323 } else { 324 for (var key in obj) { 325 if (obj.hasOwnProperty(key)) { 326 count++; 327 } 328 } 329 } 330 } 331 332 return count; 333 }, 334 335 shakeIE: function() { 336 /* 337 if (!Prototype.Browser.IE) { return; } 338 $(document.body).toggleClassName("fixIERenderingBug"); 339 JcmsLogger.debug('ShakeIE','Warning slow IE6 ! Use instead CSS (position: relative; zoom:1)'); 340 */ 341 }, 342 343 /** 344 * Escape the given string to be treated as a literal string within a regular expression. 345 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Special_Characters 346 */ 347 escapeRegExp: function(str) { 348 return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 349 }, 350 351 /** 352 * Replace all occurrences of a string. 353 */ 354 replaceAll: function(str, find, replace) { 355 return str.replace(new RegExp(escapeRegExp(find), 'g'), replace); 356 } 357 }; 358 359 // ========================================== 360 // $.jalios.Properties 361 // ========================================== 362 363 /** 364 * Jalios Properties : 365 * Server side configuration framework for JavaScript 366 * 367 * @namespace $.jalios.Properties 368 * @copyright Jalios SA 369 */ 370 $.jalios.Properties = { 371 372 /** 373 * Retrieve the specified property value. 374 * 375 * Properties are retrieved from all server side properties prefixed with <code>js.</code> 376 * and declared in file such as <code>custom.prop</code>, <code>webapp.prop</code> and <code>plugin.prop</code> 377 * 378 * @example 379 * 380 * js.myplugin.some-feature.duration: 42 381 * $.jalios.Properties.get('myplugin.some-feature.duration'); 382 * => 42 383 * 384 * @example 385 * You can also declare real javascript code! 386 * 387 * js.myplugin.hello-world: function() { alert('Hello World!'); } 388 * 389 * $.jalios.Properties.get('myplugin.hello-world')() ; 390 * => retrieve function, execute it and display hello world message 391 * 392 * @param {string} prop the property to retrieve 393 * @return {string} the value of the property or null/undefined if properties could not be found 394 */ 395 get: function(prop) { 396 if (!JCMS_Properties) { 397 return null; 398 } 399 return JCMS_Properties[prop]; 400 } 401 }; 402 403 // ========================================== 404 // $.jalios.Event 405 // ========================================== 406 407 /** 408 * Jalios Event: 409 * Event helpers for JavaScript 410 * 411 * @namespace $.jalios.Event 412 * @copyright Jalios SA
413 */ 414 415 $.jalios.Event = { 416 417 /** 418 * Perform common tests on Event to check requirement. 419 * 420 * @param {object} event the Event to test 421 * @param {string} memo the Event's memo name (broker, refresh, ...) 422 * @param {pattern} (optional) pattern the Event's type (Some JCMS multipurpose events have a type) 423 * @param {boolean} (optional) stop Stop event propagation 424 * @param {boolean} (optional) stop Stop event propagation (if multiple action: modal > ajax-refresh) 425 * @return {object} the matching memo 426 */ 427 match: function(event, memo, pattern, stop, stopImmediate) { 428 429 // No event 430 if (!event || !event[memo]) { 431 return false; 432 } 433 434 // Data type 435 var data = event[memo]; 436 if (pattern) { 437 if (!data.type) { 438 return false; 439 } 440 if (!data.type.match(pattern)) { 441 return false; 442 } 443 } 444 445 // Prevent propagation 446 if (stop) { 447 event.stopPropagation(); 448 } 449 450 // Prevent other handlers 451 if (stopImmediate) { 452 event.stopImmediatePropagation(); 453 } 454 455 return data; 456 457 } 458 }; 459 460 // ========================================== 461 // $.jalios.Http 462 // ========================================== 463 464 465 466 /** 467 * Jalios Http:<br/> 468 * Static funtion missing in core librairies to manipulate: URL, QueryString, ... missing in core librairies. 469 * 470 * @namespace $.jalios.Http 471 * @copyright Jalios SA 472 */ 473 $.jalios.Http = { 474 475 buildUrl: function(url, params) { 476 var queryParams = $.jalios.Http.toQueryParams(url); 477 478 if (typeof params === 'string') { 479 params = params.length > 0 ? $.jalios.Http.toQueryParams(params) : null; 480 } 481 482 // Merge parameters (replace old values, add new parameters) 483 queryParams = $.extend({}, queryParams, params); 484 485 // Exclude query parameters without value 486 for (key in queryParams) { 487 var queryValue = queryParams[key]; 488 if (!queryValue) { // No value 489 delete queryParams[key]; 490 } 491 } 492 493 var originUrl = (url != null ? url : ""); 494 var buildUrl; 495 var hash; 496 497 var startParamsIndex = originUrl.indexOf("?"); 498 var startHashIndex = originUrl.indexOf("#"); 499 if (startHashIndex >= 0) { 500 hash = originUrl.substring(startHashIndex + 1); 501 } 502 if (startParamsIndex >= 0) { 503 buildUrl = originUrl.substring(0, startParamsIndex); 504 } else if (startHashIndex >= 0) { 505 buildUrl = originUrl.substring(0, startHashIndex); 506 } else { 507 buildUrl = originUrl; 508 } 509 510 var buildQueryParams = queryParams ? $.param(queryParams, true) : null; 511 if (buildQueryParams != null && buildQueryParams.length > 0) { 512 buildUrl += "?" + buildQueryParams; 513 } 514 515 if (hash != null) { 516 buildUrl += "#" + hash; 517 } 518 519 return buildUrl; 520 }, 521 522 /** 523 * Decode QueryString parameters<br/> 524 * Querystring parameters are always encoded and must be decoded before processed. 525 * 526 * @param {string} param the parameter or it's key 527 * @return {string} decoded parameter 528 * @unittest js/tests/jalios/core/jalios-common.html 529 */ 530 decode: function(param) { 531 return decodeURIComponent(param.replace(/\+/g, ' ')); 532 }, 533 534 /** 535 * Encode QueryString parameters 536 * 537 * @param {string} param the parameter or it's key 538 * @return {string} encoded parameter 539 * @unittest js/tests/jalios/core/jalios-common.html 540 */ 541 encode: function(param) { 542 return encodeURIComponent(param); 543 }, 544 545 /** 546 * Convert a QueryString to a JSON Object.<br/> 547 * The oposite is <a href="http://api.jquery.com/jQuery.param/">jQuery.param()</a> 548 * 549 * @param {string} str the url to parse 550 * @return {object} a JSON object 551 * 552 * @example 553 * $.jalios.Http.toQueryParams("http://my.server/webapp/my.jsp?param1=value1&param1=value3&param2=value2") 554 * => { param1: ['value1','value3'] , param2: 'value2' } 555 * 556 * @unittest js/tests/jalios/core/jalios-common.html 557 */ 558 toQueryParams: function(str, separator) { 559 if (!str) return {}; 560 str = $.jalios.Common.strip(str); 561 562 // MUST contains '=' aka a key/value pairs 563 if (str.indexOf('=') < 0) return {}; 564 565 var match = str.match(/([^?#]*)(#.*)?$/); 566 if (!match) return {}; 567 568 569 return $.jalios.Common.inject(match[1].split(separator || '&'), {}, function(hash, pair) { 570 if ((pair = pair.split('='))[0]) { 571 var key = decodeURIComponent(pair.shift()), 572 value = pair.length > 1 ? pair.join('=') : pair[0];
573 574 if (value != undefined) value = $.jalios.Http.decode(value); 575 576 if (key in hash) { 577 if (!$.isArray(hash[key])) hash[key] = [hash[key]]; 578 hash[key].push(value); 579 } else hash[key] = value; 580 } 581 return hash; 582 }); 583 }, 584 585 /** 586 * Return browser base baseURL computed from base tag 587 * 588 * @return {string} the base URL 589 * @unittest js/tests/jalios/core/jalios-common.html 590 */ 591 getBaseUrl: function() { 592 if (!baseUrl) { 593 baseUrl = $('BASE').prop('href'); 594 } 595 return baseUrl || ''; 596 }, 597 598 /** 599 * Return browser context path<br/> 600 * 601 * <strong>Implementation note:</strong> A JSP code (server side) set "document._contextPath" in document's head 602 * @return the context path 603 */ 604 getContextPath: function() { 605 if (!contextPath) { 606 contextPath = document._contextPath; 607 } 608 return contextPath || ''; 609 }, 610 611 /** 612 * Update given url with given params/value pairs replace or add (using regexp)<br/> 613 * Note: Develpers should use instead toQueryParams(), jQuery.param() and jQuery.extend() 614 * 615 * @param {string} url the url to start 616 * @param {string} param the param to update 617 * @param {string} value the value to update 618 * @return {string} the updated url 619 * @unittest js/tests/jalios/core/jalios-common.html 620 */ 621 getUrlWithUpdatedParam: function(url, param, value) { 622 var targeturl = url.toString(); 623 624 re1 = new RegExp("([^\?]*\\?.*)(" + param + "=[^&]*&?)(.*)", "i"); 625 re2 = new RegExp("([^\?]*\\?)(.*)", "i"); 626 re3 = new RegExp("([^\?]*)", "i"); 627 628 var v = value; 629 if (v) { 630 v = $.jalios.Http.encode(v); 631 } 632 633 if (targeturl.search(re1) != -1) { 634 if (value) { 635 targeturl = targeturl.replace(re1, "$1" + param + "=" + v + "&$3"); 636 } else { 637 targeturl = targeturl.replace(re1, "$1" + "$3"); 638 } 639 } else if (targeturl.search(re2) != -1) { 640 if (value) { 641 targeturl = targeturl.replace(re2, "$1" + param + "=" + v + "&$2"); 642 } else { 643 targeturl = targeturl.replace(re2, "$1" + "$2"); 644 } 645 } else { 646 if (value) { 647 targeturl = targeturl.replace(re3, "$1?" + param + "=" + v); 648 } else { 649 targeturl = targeturl.replace(re3, "$1"); 650 } 651 } 652 653 return targeturl; 654 } 655 } 656 657 // ========================================== 658 // $.jalios.Ajax 659 // ========================================== 660 661 /** 662 * Jalios Ajax: <br/> 663 * 664 * <ul> 665 * <li>Add hooks and filters to improve communication, security, ... between JCMS and Xhr</li> 666 * <li>Add convenient Ajax function </li> 667 * </ul> 668 * 669 * There is no wrapper on Ajax request. Developers should simply use <a href="http://api.jquery.com/jQuery.ajax/" />jQuery API</a>. 670 * 671 * 672 * @namespace $.jalios.Ajax 673 * @copyright Jalios SA 674 */ 675 676 $.jalios.Ajax = { 677 678 /** 679 * <strong>Internal</strong><br/> 680 * Callback of jQuery.ajaxPrefilter() to override all jQuery XHR parameter by custom headers. 681 * 682 * @param {object} options the XHR options 683 */ 684 _fixHeader: function(options) { 685 if (options.crossDomain) { 686 return; 687 } 688 options.headers = options.headers || {}; 689 // Handle AjaxId 690 var ajaxId = document.body.id; 691 if (ajaxId) { 692 options.headers['X-Jcms-Ajax-Id'] = ajaxId; 693 } 694 695 // Handle Ajax-Deflate : Keep Ajax request working even after session expiration 696 var ajaxCtxtDeflat = $('#AjaxCtxtDeflate'); 697 if (ajaxCtxtDeflat.exists() && !$.jalios.Browser.isMobileSafari()) { 698 options.headers['X-Jcms-Ajax-Deflate'] = ajaxCtxtDeflat.html(); 699 } 700 701 // Handle CSRF Prevention 702 var csrfTokenElm = $('#CSRFTokenElm'); 703 if (csrfTokenElm.exists()) { 704 options.headers['X-Jcms-CSRF-Token'] = csrfTokenElm.html(); // see: JCMS.Security.CSRF_TOKEN_HEADER_NAME 705 } 706 }, 707 708 /** 709 * <strong>Internal</strong><br/> 710 * Callback of jQuery.ajaxPrefilter() to display waiting area. 711 * 712 * @param {object} options the XHR options 713 */ 714 _fixWait: function(options, defaults, jqXHR) { 715 716 var before = options.beforeSend; 717 var after = options.complete; 718 719 options.beforeSend = function() { 720 $.jalios.Ajax.wait(true); 721 if (before) before.apply(this, arguments); 722 } 723 options.complete = function() { 724 $.jalios.Ajax.wait(false); 725 if (after) after.apply(this, arguments); 726 } 727 }, 728 729 /** 730 * Toggle the wait div according to given parameter 731 * 732 * @param {boolean} show to display wait state 733 * @param {element} (optional) trigger 734 */ 735 wait: function(show, trigger) { 736 737 // Setup window status 738 var wnd = parent ? parent : window; 739 var wndcursor = ''; 740 var wndstatus = ''; 741 var $body = $('BODY'); 742 743 744 // Get wait window 745 var $div = $('#ajax-wait'); 746 if (!$div.exists()) { 747 var glp = $("#ajaxWaitIconWrapper").html(); 748 $("#ajaxWaitIconWrapper").remove();
749 $div = $('<div id="ajax-wait" class="hide">' + glp + '</div>').appendTo($body); 750 } 751 752 // Toggle visibility 753 if (show) { 754 wndcursor = 'wait'; 755 wndstatus = I18N.glp('info.msg.loading'); 756 $div.removeClass("hide"); 757 } else { 758 $div.addClass("hide"); 759 } 760 761 // Set window status 762 try { 763 if (wnd.status) { 764 wnd.status = wndstatus; 765 } 766 } catch (e) { /* Security catch */ } 767 768 // Set window cursor 769 if (trigger) { 770 $(trigger).css('cursor', wndcursor); 771 } 772 $body.css('cursor', wndcursor); 773 }, 774 775 /** 776 * <strong>Internal</strong><br/> 777 * Initialise history management for Ajax requests.<br/> 778 * 779 * <ul> 780 * <li>Create HTML component based on Browser version in DIV#rshStorageDiv</li> 781 * <li>Trigger Event jalios:history on change</li> 782 * <li>Already bind to ajax-refresh events</li> 783 * </ul> 784 * 785 * @fires jalios:history 786 * @unittest js/tests/jalios/core/jalios-ajax-refresh.html 787 */ 788 _history: function() { 789 790 if (typeof(History) == 'undefined' || typeof(History.getState) == 'undefined') { 791 return; 792 } 793 794 // No advanced Ajax history for non HTML 5 browser, there'a limit in what we want to maintain without hassle ! 795 if (typeof(window.history) == 'undefined' || typeof(window.history.pushState) == 'undefined') { 796 $.console.debug("[Common] [History] No History. Stop using outdated browser without modern feature."); 797 return; 798 } 799 800 $.console.debug("[Common] [History] Initializing History"); 801 802 // History 803 $.jalios.Ajax._histIntercept = true; 804 $.jalios.Ajax._histIdx = 0; 805 806 // Function invoked when we want to revert to a specific state 807 var browseBack = function(state) { 808 if (!state) { 809 $.console.debug("[Common] [History] Skip statechange missing state data"); 810 return; 811 } 812 813 if (!$.jalios.Ajax._histIntercept) { 814 $.console.debug("[Common] [History] Skip statechange we triggered", state); 815 $.jalios.Ajax._histIntercept = true; 816 return; 817 } 818 819 if (!state.data || !state.data.url || !state.data.target) { 820 let initialState = History.getStateByIndex(0); 821 var $firstTarget = $(initialState.data.target); 822 if ($firstTarget.exists()) { 823 $.console.debug("[Common] [History] Revert to initial state, by refreshing target", $firstTarget, state); 824 825 // We must keep initial parameters of the url if any 826 let initialUrl = initialState.url; 827 let params = { historyRevertToInitialState: true }; 828 if (initialUrl) { 829 const queryParams = $.jalios.Http.toQueryParams(initialUrl); 830 params = $.extend({}, params, queryParams); 831 } 832 $firstTarget.refresh({ 833 params: params, 834 nohistory: true, 835 noscroll: true 836 }); 837 return; 838 } 839 $.console.debug("[Common] [History] Skip statechange without original first history target", state); 840 return; 841 } 842 843 // Send an Event 844 var event = jQuery.Event("jalios:history"); 845 event.history = {}; 846 //event.history.loc = loc; 847 event.history.data = state.data; 848 $(document).trigger(event); 849 850 // Handle Ajax-Refresh to revert to previous state 851 $.console.debug("[Common] [History] Revert to state by refreshing target", state.data.target, state); 852 $.jalios.AjaxRefresh.refresh(state.data.url, state.data.target, $.extend({}, state.data.options, { 853 nohistory: true, 854 noscroll: true 855 })) 856 } 857 858 // Revert to initial state when user come back from another page 859 var state = History.getState(); 860 if (state && state.data && state.data.target) { 861 $.console.debug("[Common] [History] Revert to last state in previous page", state); 862 browseBack(state); 863 } 864 865 // Add listener to StateChange Event 866 History.Adapter.bind(window, 'statechange', function() { // Note: We are using statechange instead of popstate 867 var state = History.getState(); // Note: We are using History.getState() instead of event.state 868 browseBack(state); 869 }); 870 871 // Add Ajax-Refresh listener 872 $(document).on('jalios:refresh', function(event) { 873 874 var refresh = $.jalios.Event.match(event, 'refresh', 'success') 875 if (!refresh) { 876 return; 877 } 878 879 // Check flag nohisotry 880 if (refresh.options.nohistory) { 881 return; 882 } 883 884 // Can't handle callbacks 885 if (refresh.callback) { 886 return 887 } 888
889 // Do not stack history 890 refresh.options.nohistory = true; 891 892 // Add an history entry 893 refresh.options.target = false; // because not a periodical 894 var historyEntryData = { 895 'url': refresh.url, 896 'target': refresh.target.identify().map(function() { 897 return '#' + $(this).attr('id'); 898 }).get().join(','), 899 'options': refresh.options 900 }; 901 902 // On first Ajax request, update the initial state with the portlet being modified to be able to refresh it when needed 903 var firstState = History.getStateByIndex(0); 904 if (firstState && firstState.data && !firstState.data.target) { 905 $.console.debug("[Common] [History] Update initial state with first portlet being modified", historyEntryData.target); 906 firstState.data.target = historyEntryData.target; 907 } 908 909 $.jalios.Ajax.addHistory(historyEntryData); 910 911 }); 912 }, 913 914 /** 915 * Add a new entry to Ajax History. 916 * 917 * @param data the object to store 918 */ 919 addHistory: function(data) { 920 if (typeof(History) == 'undefined' || typeof(History.getState) == 'undefined') { 921 return; 922 } 923 924 // Use of a URL parameter is required to provide working back button to the initial request 925 $.jalios.Ajax._histIdx++; 926 var currentUrlWithoutHash = document.location.href.replace(document.location.hash, ""); 927 var newUrl = $.jalios.Http.getUrlWithUpdatedParam(currentUrlWithoutHash, 'histstate', $.jalios.Ajax._histIdx); 928 929 // Set custom flag to skip this event in the statechange callback 930 $.jalios.Ajax._histIntercept = false; 931 932 $.console.debug("[Common] [History] Adding History Entry", data, newUrl); 933 934 // Prevent circular reference on select2 on brokerTrigger) 935 data && data.options && delete data.options.brokerTrigger; 936 937 History.pushState(data, document.title, newUrl); 938 } 939 } 940 941 // ========================================== 942 // $.jalios.DOM 943 // ========================================== 944 945 // Remove return false; 946 var regxpClick = /^\W*return\W*false\W*$/i; 947 948 var injectCssUrlInDocumentHead = function(url, media) { 949 media = media || 'all'; 950 $.console.info('Load CSS with DOM injection...', url, media); 951 952 // Fix bug DEVVDP-14 : CSS are not loaded properly in IE7 during/after Ajax request 953 // do not use the jQuery loading which does not work in IE7 : 954 // $('HEAD').append('<link rel="stylesheet" href="'+path+'" type="text/css" media="'+media+'" />'); 955 // instead use the classic old method which work fine : 956 var headID = document.getElementsByTagName("head")[0]; 957 var cssNode = document.createElement('link'); 958 cssNode.href = url; 959 if (media == 'prefetch') { // Chrome test: http://prerender-test.appspot.com/ 960 cssNode.rel = 'prerender prefetch'; 961 } else { 962 cssNode.type = 'text/css'; 963 cssNode.rel = 'stylesheet'; 964 cssNode.media = media; 965 } 966 headID.appendChild(cssNode); 967 }; 968 969 /** 970 * Jalios DOM:<br/> 971 * A set of DOM static function to fill the gap between JCMS, jQuery and Prototype. 972 * 973 * @namespace $.jalios.DOM 974 * @copyright Jalios SA 975 */ 976 977 $.jalios.DOM = { 978 979 _resources: {}, 980 981 /** 982 * Mark the given resource as "loaded". 983 * @param {string} path to resource 984 * @return {boolean} true if the resources is marked false if alread marked. 985 * 986 * @unittest js/tests/jalios/core/jalios-common.html 987 */ 988 markResource: function(path) { 989 990 // Already marked 991 if ($.jalios.DOM._resources[path]) { 992 return false; 993 } 994 995 // Mark resource 996 $.jalios.DOM._resources[path] = true; 997 return true; 998 }, 999 1000 /** 1001 * Mark the given resources as "loaded". 1002 * @param {string...} paths to resources 1003 */ 1004 markResources: function() { 1005 $.each(arguments, function(idx, path) { 1006 $.jalios.DOM.markResource(path); 1007 }); 1008 }, 1009 1010 /** 1011 * Load several StyleSheets files from their path, using CSS packer. 1012 * 1013 * @param {array} paths the CSS path (absolute or relative) 1014 * @param {array} medias the media of each css (length must be the same as paths argument) 1015 * @param {string} media an optionnal media for this CSS (default to all) 1016 * @param {string} version an optionnal version of this file, as defined through JCMS property channel.packer.version 1017 * @param {number} maxUrlLengthPerPack an optionnal maximum length of packer URL 1018 * @return {boolean} true if the stylesheet has been added 1019 * 1020 * @since jcms-10.0.2 / JCMS-6923 1021 */ 1022 loadStyleSheets: function(paths, medias, version, maxUrlLengthPerPack) { 1023 1024 // Build arrays of resources to load (distributed by media) 1025 var mediaToRelativePathsToLoad = { 1026 'all': [], 1027 'print': [], 1028 'screen': [], 1029 'speech': [] 1030 }; 1031 var mediaToAbsolutePathsToLoad = { 1032 'all': [], 1033 'print': [], 1034 'screen': [], 1035 'speech': [] 1036 }; 1037 for (var i = 0; i < paths.length; i++) { 1038 var path = paths[i]; 1039 var media = medias[i] || 'all'; 1040 // filter resources already loaded 1041 if (!$.jalios.DOM.markResource(path)) { 1042 $.console.debug('StyleSheet already imported: ', path); 1043 } else { 1044 var isAbsolute = (path.indexOf("http") == 0); 1045 (isAbsolute ? mediaToAbsolutePathsToLoad : mediaToRelativePathsToLoad)[media].push(path);
1046 } 1047 } 1048 1049 // CSS with absolute URL are loaded invidually 1050 for (media in mediaToAbsolutePathsToLoad) { 1051 var absolutePathsToLoad = mediaToAbsolutePathsToLoad[media]; 1052 if (absolutePathsToLoad.length != 0) { 1053 $.console.info('Import StyleSheets (absolute URL)', media, absolutePathsToLoad, version); 1054 for (var i = 0; i < absolutePathsToLoad.length; i++) { 1055 var absPath = absolutePathsToLoad[i]; 1056 jQuery.jalios.DOM.loadStyleSheet(absPath, media, version); 1057 } 1058 } 1059 } 1060 1061 var maxUrlLength = maxUrlLengthPerPack || 1800; 1062 var cssPackerPrefixUrl = JcmsJsContext.getBaseUrl() + "css/csspacker.jsp?v=" + version + "&css="; 1063 1064 // Method to add CSS in DOM 1065 var addLinkToHead = function(encodedPathsToLoad, media) { 1066 if (encodedPathsToLoad.length == 0) { 1067 return; 1068 } 1069 var url = cssPackerPrefixUrl + encodedPathsToLoad.join("&css="); 1070 injectCssUrlInDocumentHead(url, media); 1071 } 1072 1073 // CSS with relative path are loaded using CSS packer 1074 for (media in mediaToRelativePathsToLoad) { 1075 var relativePathsToLoad = mediaToRelativePathsToLoad[media]; 1076 if (relativePathsToLoad.length != 0) { 1077 $.console.info('Import StyleSheets', media, relativePathsToLoad, version); 1078 1079 // Build packer URL 1080 var encodedPathsToLoad = [] 1081 var encodedPathsToLoadLength = 0; 1082 while( (relativePath = relativePathsToLoad.shift()) !== undefined ) { 1083 var encodedPath = encodeURIComponent(relativePath); 1084 1085 // Add Packer URL with previous css, if current css would make the URL length exceed max length 1086 var wouldBeUrlLength = cssPackerPrefixUrl.length + encodedPathsToLoadLength + encodedPath.length + ((encodedPathsToLoad.length+1) * "&css=".length); 1087 if (wouldBeUrlLength >= maxUrlLength) { 1088 addLinkToHead(encodedPathsToLoad, media); 1089 encodedPathsToLoad = []; 1090 encodedPathsToLoadLength = 0; 1091 } 1092 1093 encodedPathsToLoad.push(encodedPath); 1094 encodedPathsToLoadLength += encodedPath.length; 1095 } 1096 1097 // Add last Packer URL 1098 addLinkToHead(encodedPathsToLoad, media); 1099 } 1100 } 1101 1102 return true; 1103 }, 1104 1105 /** 1106 * Load a StyleSheet file from its relative path. 1107 * @param {string} path the CSS path (absolute or relative) 1108 * @param {string} media an optionnal media for this CSS (default to all) 1109 * @param {string} version an optionnal version of this file, as defined through JCMS property channel.packer.version 1110 * @return {boolean} true if the stylesheet has been added 1111 * 1112 * @unittest js/tests/jalios/core/jalios-common.html 1113 */ 1114 loadStyleSheet: function(path, media, version) { 1115 1116 // Mark resource 1117 if (!$.jalios.DOM.markResource(path)) { 1118 $.console.info('StyleSheet already imported: ', path); 1119 return false; 1120 } 1121 1122 $.console.info('Import StyleSheet', path, version); 1123 1124 // Add LINK to HEAD 1125 path += version ? ('?v=' + version) : ''; 1126 injectCssUrlInDocumentHead(path, media); 1127 1128 return true; 1129 }, 1130 1131 /** 1132 * Load several JavaScript files from their path, using JS packer.<br/> 1133 * Fire Event jalios:ready when all the javascript files has been loaded<br/> 1134 * <br/> 1135 * 1136 * Trigger event jalios:ready when all javascript has been added. 1137 * @param {array} paths array of the JS path (absolute or relative) 1138 * @param {string} version an optionnal version of this file, as defined through JCMS property channel.packer.version 1139 * @param {number} maxUrlLengthPerPack an optionnal maximum length of packer URL 1140 * @return {boolean} true if the javascript has been added 1141 * @fires jalios:ready 1142 * 1143 * @since jcms-10.0.2 / JCMS-6923 1144 */ 1145 loadJavaScripts: function(paths, version, maxUrlLengthPerPack) { 1146 1147 // Indicate resource is being loaded 1148 // to ensure jalios:ready event is triggered on method end) 1149 $.jalios.DOM._loaded++; 1150 1151 // Build arrays of resources to load (and new one as loaded) 1152 var relativePathsToLoad = []; 1153 var absolutePathsToLoad = []; 1154 for (var i = 0; i < paths.length; i++) { 1155 var path = paths[i]; 1156 // filter resources already loaded 1157 if (!$.jalios.DOM.markResource(path)) { 1158 $.console.debug('JavaScript already imported: ', path); 1159 } else { 1160 var isAbsolute = (path.indexOf("http") == 0); 1161 (isAbsolute ? absolutePathsToLoad : relativePathsToLoad).push(path);
1162 } 1163 } 1164 1165 var retVal = false; 1166 1167 // JS with absolute URL are loaded invidually 1168 if (absolutePathsToLoad.length != 0) { 1169 $.console.info('Import JavaScripts (absolute URL)', absolutePathsToLoad, version); 1170 for (var i = 0; i < absolutePathsToLoad.length; i++) { 1171 var absPath = absolutePathsToLoad[i]; 1172 retVal |= jQuery.jalios.DOM.loadJavaScript(absPath, version); 1173 } 1174 } 1175 1176 var maxUrlLength = maxUrlLengthPerPack || 1800; 1177 var jsPackerPrefixUrl = JcmsJsContext.getBaseUrl() + "js/jspacker.jsp"; 1178 1179 // Method to load JS 1180 // Load JavaScript, using jQuery AjaxQueue to ensure sequential loading/execution (fix bug such as JCMS-4489) 1181 var loadJS = function(relativePathsToLoad) { 1182 $.console.info('Load JS with jQuery...', relativePathsToLoad); 1183 1184 $.ajaxQueue({ 1185 url: jsPackerPrefixUrl, 1186 traditional: true, // data handling : send each value array as one param 1187 data: { 1188 "v": version, 1189 "js": relativePathsToLoad 1190 }, 1191 dataType: "script", 1192 cache: true 1193 1194 }).always(function(data) { 1195 $.jalios.DOM._loadReady.defer(relativePathsToLoad); // trigger to synchronize 1196 }); 1197 } 1198 1199 1200 // JS with relative path are loaded using JS packer 1201 if (relativePathsToLoad.length != 0) { 1202 $.jalios.DOM._loaded++; 1203 1204 $.console.info('Import JavaScripts', relativePathsToLoad, version); 1205 1206 var currentJsToLoad = [] 1207 var currentJsToLoadLength = 0; 1208 while( (relativePath = relativePathsToLoad.shift()) !== undefined ) { 1209 var encodedPath = encodeURIComponent(relativePath); 1210 1211 // Add Packer URL with previous js, if current hs would make the URL length exceed max length 1212 var wouldBeUrlLength = jsPackerPrefixUrl.length + currentJsToLoadLength + encodedPath.length + ((currentJsToLoad.length+1) * "&js=".length); 1213 if (wouldBeUrlLength >= maxUrlLength) { 1214 loadJS(currentJsToLoad); 1215 currentJsToLoad = []; 1216 currentJsToLoadLength = 0; 1217 } 1218 1219 currentJsToLoad.push(relativePath); 1220 currentJsToLoadLength += encodedPath.length; 1221 } 1222 1223 // Add last Packer URL 1224 loadJS(currentJsToLoad); 1225 1226 retVal |= true; 1227 } 1228 1229 $.jalios.DOM._loadReady.defer(relativePathsToLoad); 1230 1231 return retVal; 1232 }, 1233 1234 /** 1235 * Load a JavaScript file from its relative path.<br/> 1236 * Fire Event jalios:ready when all the javascrip files has been loaded<br/> 1237 * <br/> 1238 * 1239 * Trigger event jalios:ready when all javascript has been added. 1240 * <ul> 1241 * <li><jalios:javascript> is already trigged on jalios:ready</li> 1242 * <li>Custom code that relies on javascript loaded MUST wait for this event</li> 1243 * <li>The event can be trigged multiple times</li> 1244 * </ul> 1245 * 1246 * <br/> 1247 * <strong>Implementation:</strong><br/> 1248 * Use jQuery magic that do not add script tag in the header 1249 * 1250 * @param {string} path the JS path (absolute or relative) 1251 * @param {string} version an optionnal version of this file, as defined through JCMS property channel.packer.version 1252 * @return {boolean} true if the javascript has been added 1253 * @fires jalios:ready 1254 * 1255 * @unittest js/tests/jalios/core/jalios-common.html 1256 */ 1257 loadJavaScript: function(path, version) { 1258 1259 // Push resource to load 1260 $.jalios.DOM._loaded++; 1261 1262 // Mark resource 1263 if (!$.jalios.DOM.markResource(path)) { 1264 $.console.info('JavaScript already imported: ', path); 1265 $.jalios.DOM._loadReady.defer(path); // trigger to synchronize 1266 return false; 1267 } 1268 1269 $.console.info('Import JavaScript', path, version); 1270 1271 // Load JavaScript, using jQuery AjaxQueue to ensure sequential loading/execution (fix bug such as JCMS-4489) 1272 $.ajaxQueue({ 1273 url: path, 1274 data: { 1275 "v": version 1276 }, 1277 dataType: "script", 1278 cache: true 1279 1280 }).always(function(data) { 1281 $.jalios.DOM._loadReady.defer(path); // trigger to synchronize 1282 }); 1283 1284 return true; 1285 }, 1286 1287 _loaded: 0, 1288 _loadTrigger: $.Callbacks(), 1289 _loadReady: function(path) { 1290 1291 $.jalios.DOM._loaded--; 1292 if ($.jalios.DOM._loaded > 0) { 1293 return; 1294 } 1295 1296 // Fire all callback 1297 $.jalios.DOM._loadTrigger.fire(); 1298 $.jalios.DOM._loadTrigger.empty(); 1299 1300 // Fire an event 1301 var event = jQuery.Event("jalios:ready"); 1302 $(document).trigger(event); 1303 }, 1304 1305 /** 1306 * <strong>Internal</strong><br/> 1307 * Called by <jalios:javascript> to trigger script at the end of javascript load 1308 * @param {function} cb the callback to call once 1309 */ 1310 _loadRegister: function(cb) { 1311 $.jalios.DOM._loadTrigger.add(cb); 1312 }, 1313 1314 /**
1315 * Displays information about browser state. 1316 * True indicate document is focused otherwise false 1317 */ 1318 hasFocus: true, 1319 1320 /** 1321 * Follow given element with updated key/value and skip given data:broker event 1322 * @param {element} elm the element to work with 1323 * @param {string} skip the component triggering the follow (avoid loop) 1324 * @param {string} key the key pair to update 1325 * @param {string} value the value pair to update 1326 * 1327 * FIXME: handle target = _blank (window.open(url,'_blank');) 1328 */ 1329 follow: function(elm, skip, key, value) { 1330 1331 if (!elm) { 1332 return; 1333 } 1334 var $elm = $(elm); 1335 if (!$elm.exists()) { 1336 return; 1337 } 1338 1339 // Build event 1340 var evt = $.Event('click'); 1341 evt.which = 1; 1342 evt.skip = skip; 1343 1344 // Clean return false; 1345 var hack = $elm.attr('onclick'); 1346 if (hack && regxpClick.test(hack)) { 1347 $elm.prop('onclick', null); 1348 } 1349 1350 if (!key || !value) { 1351 // Simulate click with a given skip info 1352 $elm.trigger(evt); 1353 if (evt.isDefaultPrevented()) { 1354 return; 1355 } 1356 } 1357 1358 // Update href value of the trigger 1359 var href = $elm.prop('href'); // fix bug DEVJCMS-5 : DO NOT use $elm.attr('href') 1360 if (href && key && value) { 1361 $elm.attr('href', $.jalios.Http.getUrlWithUpdatedParam(href, key, value)); 1362 } 1363 1364 // Update form value of the trigger 1365 var $form = $elm.closest('FORM'); 1366 if ($form.exists()) { 1367 // Should we add input name/value ? 1368 } 1369 1370 // Simulate click with a given skip info 1371 $elm.trigger(evt); 1372 if (evt.isDefaultPrevented()) { 1373 return; 1374 } 1375 1376 // Follow links 1377 var href = $elm.prop('href'); // fix bug DEVJCMS-5 : DO NOT use $elm.attr('href') 1378 if (href) { 1379 var target = $elm.attr('target'); 1380 if (target) { 1381 $.jalios.Browser.popup(href, $elm.attr('title')); 1382 } else { 1383 $.jalios.Browser.redirect(href); 1384 } 1385 return; 1386 } 1387 1388 // Follow Input Form 1389 if ($elm.attr('type') == 'submit') { 1390 var $form = $elm.closest('FORM'); 1391 $form.append('<input type="hidden" name="' + $elm.attr('name') + '" value="' + $elm.attr('value') + '" />'); 1392 $form.submit(); 1393 } 1394 }, 1395 1396 // ---------- 1397 // IFRAME 1398 // ---------- 1399 1400 /** 1401 * Check if current code is running in IFrame or main window 1402 */ 1403 isInIFrame: function() { 1404 return window != top; // DO NOT use "!==" as it would not work in IE 1405 }, 1406 1407 registerIFrame: function() { 1408 $.jalios.DOM.setupIFrame(); 1409 $(document).on('jalios:refresh', $.jalios.DOM.setupIFrame); 1410 }, 1411 1412 setupIFrame: function(event) { 1413 var $e = $(document); 1414 if (event) { 1415 var refresh = $.jalios.Event.match(event, 'refresh', 'after'); 1416 if (!refresh || !refresh.$target) { 1417 return; 1418 } 1419 $e = refresh.$target; 1420 } 1421 1422 $e.find('IFRAME[height="100%"]') 1423 .each(function() { 1424 $.jalios.DOM.resizeIframeToViewport.defer($(this)); 1425 }) 1426 .on("load", function() { 1427 $.jalios.DOM.resizeIframeToViewport.defer($(this)); 1428 }); 1429 }, 1430 1431 /** 1432 * Resize given jquery element to viewport with the given max height. 1433 * If no max height is providen, max height will be 400px. 1434 * Do not handle, but catch cross domain exceptions. Handle iFrame navigation. 1435 * @param {element} $e the IFrame 1436 * @param {int} max the max height to apply. Set -1 for no max. 1437 */ 1438 resizeIframeToViewport: function($e, max) { 1439 if (!$e || !$e.exists()) { 1440 return; 1441 } 1442 var maxHeight = max || 400; 1443 var height = maxHeight; 1444 try { 1445 height = $e.contents().find('BODY').css('height', 'auto').outerHeight() + 20; 1446 } catch (ex) {} 1447 height = maxHeight !== -1 ? Math.min(maxHeight, height) : height; 1448 $e.css('height', height + 'px'); 1449 } 1450 } 1451 1452 // ========================================== 1453 // $.fn 1454 // ========================================== 1455 1456 /** 1457 * Add convenient function to jQuery function $() 1458 * 1459 * @namespace $.fn 1460 * @copyright Jalios SA
1461 */ 1462 1463 /** 1464 * Check if a jQuery object has results 1465 * @unittest js/tests/jalios/core/jalios-common.html 1466 */ 1467 $.fn.exists = function() { 1468 return this.length > 0; 1469 } 1470 1471 1472 /** 1473 * Build and set unique id for the given element with given prefix 1474 * @param prefix {string} the to append (without '_') 1475 * @param force {boolean} force new random id 1476 * @unittest js/tests/jalios/core/jalios-common.html 1477 */ 1478 $.fn.identify = function(prefix, force) { 1479 var i = 0; 1480 prefix = prefix || 'jq'; 1481 return this.each(function() { 1482 if ($(this).attr('id')) { 1483 if (force) { 1484 var now = new Date().getTime(); 1485 $(this).attr('id', prefix + '_' + now); 1486 } 1487 return; 1488 }; 1489 do { 1490 i++; 1491 var id = prefix + '_' + i; 1492 } while ($('#' + id).length > 0); 1493 $(this).attr('id', id); 1494 }); 1495 }; 1496 1497 /** 1498 * Call the find() on each next() sibbling. Usefull with ToggleManager 1499 * @param selector the selector to match 1500 */ 1501 $.fn.findNext = function(selector) { 1502 return this.nextAll().find(selector); 1503 } 1504 1505 /** 1506 * Call the find() on each next() sibbling. Usefull with ToggleManager 1507 * @param selector the selector to match 1508 */ 1509 $.fn.findPrev = function(selector) { 1510 return this.prevAll().find(selector); 1511 } 1512 1513 /** 1514 * Returns the match for the given regexp on given element classes 1515 * @param regexp to match 1516 * @param group the regexp group to match (default = 1) 1517 * @return an array of match 1518 * @unittest js/tests/jalios/core/jalios-common.html 1519 */ 1520 $.fn.matchClass = function(regexp, group) { 1521 var group = group || 1; 1522 var value = []; 1523 1524 this.each(function() { 1525 var clazz = $(this).attr('class'); 1526 1527 if (!clazz) { 1528 return; 1529 } 1530 1531 var classes = clazz.split(/\s+/); 1532 for (var i = 0; i < classes.length; i++) { 1533 /* recompile the regex */ 1534 regexp.compile(regexp); 1535 var match = regexp.exec(classes[i]); 1536 if (match && match.length > group) { 1537 value.push(match[group]); 1538 } 1539 } 1540 }); 1541 1542 return value; 1543 }; 1544 1545 /** 1546 * Add all the given classes to the given Set. 1547 * And update all classes with the following pattern: te-xt-number 1548 * @param classes string classes separated by spaces 1549 */ 1550 $.fn.updateClass = function(classes) { 1551 if (!classes) { 1552 return; 1553 } 1554 var classes = classes.split(' '); 1555 return this.each(function() { 1556 var $this = $(this); 1557 var cname = $this.attr('class'); 1558 for (var i = 0; i < classes.length; i++) { 1559 if (rClassCpt.test(classes[i])) { 1560 var match = rClassCpt.exec(classes[i]); 1561 var rexp = new RegExp(match[1] + '\\d+'); 1562 var src = cname.match(rexp); 1563 $this.removeClass('' + src); 1564 }
1565 $this.addClass(classes[i]); 1566 } 1567 }); 1568 } 1569 1570 var rClassCpt = /(([\w_-])+(-+))(\d)+/; 1571 1572 // Form functions 1573 // ============== 1574 1575 /** 1576 * Serialize a Form to JSON using underlaying jQuery function and fill the gap. 1577 * @param filter a subset of keys to retrieve 1578 * @unittest js/tests/jalios/core/jalios-common.html 1579 */ 1580 $.fn.serializeObject = function(filter) { 1581 var o = {}; 1582 var a = this.serializeArray(); 1583 1584 $.each(a, function() { 1585 if (filter && filter[this.name] === undefined) { 1586 return; 1587 } // Filter 1588 if (o[this.name] !== undefined) { 1589 if (!o[this.name].push) { 1590 o[this.name] = [o[this.name]]; 1591 } 1592 o[this.name].push(this.value || ''); 1593 } else { 1594 o[this.name] = this.value || ''; 1595 } 1596 }); 1597 1598 return $.extend(true, {}, filter, o); 1599 }; 1600 1601 /** 1602 * Fill a form with a JSON Object 1603 * @param json the json object 1604 */ 1605 $.fn.populate = function(json) { 1606 var $this = $(this); 1607 $.each(json, function(key, value) { 1608 $('[name=' + key + ']', $this).val(value); 1609 }); 1610 } 1611 1612 /** 1613 * Returns all form element with given names 1614 * @param names an array of names 1615 */ 1616 $.fn.named = function(names) { 1617 var selector = '[name=' + names.join('],[name=') + ']'; 1618 return $(this).find(selector); 1619 } 1620 1621 // Portal functions 1622 // ================ 1623 1624 /** 1625 * Check if the elment is a Portlet<br/> 1626 * <strong>Implementation note:</strong> check element has Class 'Portlet' and a JcmsId 1627 * 1628 * @return {boolean} true if the given element match 1629 * @unittest js/tests/jalios/core/jalios-common.html 1630 */ 1631 $.fn.isPortlet = function() { 1632 if (!$(this).hasClass('Portlet') && !$(this).hasClass('PortalJspCollection') && !$(this).hasClass('JPortal')) { 1633 return false; 1634 } 1635 var i = 0, 1636 l = this.length; 1637 for (; i < l; i++) { 1638 if (this[i].className == 'Portlet' || this[i].className == 'PortalJspCollection' || this[i].className == 'JPortal') { 1639 continue; 1640 } 1641 if (this[i].className.match(rJcmsId)) { 1642 return true; 1643 } 1644 } 1645 1646 return false; 1647 } 1648 1649 /** 1650 * Return the Jcms Id associated with the given element.<br/> 1651 * @param dataOnly only check the data-jalios-id 1652 * @return {string} the element's JcmsId. Or false if missing. 1653 * @unittest js/tests/jalios/core/jalios-common.html 1654 */ 1655 $.fn.getJcmsId = function(dataOnly) { 1656 var i = 0, 1657 l = this.length; 1658 for (; i < l; i++) { 1659 var $this = $(this[i]); 1660 if ($this.attr('data-jalios-id')) { 1661 return $this.attr('data-jalios-id'); 1662 } 1663 if (dataOnly) return; 1664 1665 var clazz = $this.attr('class'); 1666 if (!clazz) continue; 1667 1668 var match = clazz.match(rJcmsId); 1669 if (match) { 1670 return match[1]; 1671 } 1672 } 1673 return false; 1674 } 1675 1676 /** 1677 * Return the template usage of a given element<br/> 1678 * FIXME: Should handle data-jalios-usage attribute 1679 * 1680 * @return {string} the element's template usage. Or false if missing. 1681 * @unittest js/tests/jalios/core/jalios-common.html 1682 */ 1683 $.fn.getUsage = function() { 1684 var i = 0, 1685 l = this.length; 1686 for (; i < l; i++) { 1687 var clazz = this[i].className; 1688 if (!clazz) continue; 1689 1690 var match = clazz.match(rUsage); 1691 if (match) { 1692 return match[1]; 1693 } 1694 } 1695 return false; 1696 }; 1697 1698 $.fn['bounds'] = function() { 1699 var t = this, 1700 e = t[0]; 1701 if (!e) return; 1702 1703 var offset = t.offset(), 1704 pos = { 1705 width: e.offsetWidth, 1706 height: e.offsetHeight, 1707 left: 0, 1708 top: 0, 1709 right: 0, 1710 bottom: 0, 1711 x: 0, 1712 y: 0 1713 }; 1714 1715 pos.left = offset.left; 1716 pos.top = offset.top; 1717 1718 //right and bottom 1719 pos.right = (pos.left + pos.width); 1720 pos.bottom = (pos.top + pos.height); 1721 pos.x = pos.left; 1722 pos.y = pos.top; 1723 pos.inner = { 1724 width: t.width(), 1725 height: t.height() 1726 }; 1727 1728 $.extend(pos, { 1729 toString: function() { 1730 var t = this; 1731 return 'x: ' + t.x + ' y: ' + t.y + ' width: ' + t.width + ' height: ' + t.height + ' right: ' + t.right + ' bottom: ' + t.bottom; 1732 } 1733 });
1734 1735 return pos; 1736 }; 1737 1738 /** 1739 * Return the max of the given applied function 1740 * @param selector function to call on collection 1741 * @return the max 1742 */ 1743 $.fn.max = function(selector) { 1744 return Math.max.apply(null, this.map(function(index, el) { 1745 return selector.apply(el); 1746 }).get()); 1747 }; 1748 1749 /** 1750 * Retrieve the original context.<br/> 1751 * The 'context' property is deprecated in jQuery 1.10, and no longer present in jQuery 3.x.<br/> 1752 * Step back into the stack of 'prevObject' properties to retrieve the 'context'. 1753 */ 1754 $.fn.getOriginalContext = function() { 1755 var context; 1756 1757 var $prevObject = this; 1758 while ($prevObject) { 1759 var context = $prevObject.context; 1760 $prevObject = $prevObject.prevObject; 1761 } 1762 1763 return context; 1764 }; 1765 1766 // ------------------------------------------ 1767 // DOM READY 1768 // ------------------------------------------ 1769 1770 $(document).ready(function($) { 1771 1772 // Plug notifier 1773 registerTimer(); 1774 1775 // Plug focus 1776 registerFocus(); 1777 1778 // Plug element query 1779 registerResponsive(); 1780 1781 // Plug Ajax prefilter 1782 $.ajaxPrefilter($.jalios.Ajax._fixHeader); 1783 $.ajaxPrefilter($.jalios.Ajax._fixWait); 1784 1785 // Trap hash click 1786 registerBTFix(); 1787 1788 // Plug IFrame detection 1789 $.jalios.DOM.registerIFrame(); 1790 1791 // Plug Really Simple History 1792 $.jalios.Ajax._history(); 1793 }); 1794 1795}(window.jQuery);
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.