PageSourceSearch

https://www.moselle.fr/js/jalios/core/jalios-common.js

js moselle.fr collected 2026-09-25 02:41:57 UTC 55,486 bytes, 1,795 lines download raw bytes

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&amp;param1=value3&amp;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>&lt;jalios:javascript&gt; 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 &lt;jalios:javascript&gt; 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.