PageSourceSearch

https://museumdecrypte.nl/.cm4all/stcfb/.cm4all/res/static/libcm4all-js-widget/3.88.11/js/widget-runtime.js

js museumdecrypte.nl collected 2026-10-02 21:19:00 UTC 164,961 bytes, 4,752 lines download raw bytes

1    window.__loadedJsLibraries = window.__loadedJsLibraries || (window.__loadedJsLibraries = new Object());
2    window.__loadedCssLibraries = window.__loadedCssLibraries || (window.__loadedCssLibraries = new Object());
3    if(window.__loadedJsLibraries["/res/js/lib/wrkrndz/jquery-register.js"] !== true){
4        window.__loadedJsLibraries["/res/js/lib/wrkrndz/jquery-register.js"] = true;
5        window.$j = jQuery;
6// clear noConflict, to prevent $ being overwritten with undefined!
7if (window.$ === window.jQuery) {
8    jQuery.noConflict();
9}
10/**
11    @private
12*/
13jQuery.noConflict = function() {
14    return jQuery;
15};
16    };
17    if(window.__loadedJsLibraries["/res/js/lib/HttpURL.js"] !== true){
18        window.__loadedJsLibraries["/res/js/lib/HttpURL.js"] = true;
19        (function(PKG) {
20"PKG:nomunge"
21//-WRAP switch on library wrapping
22/**
23    In older browser versions encodeURIComponent/decodeURIComponent
24    are not supported, so we simulate it with escape/unescape,
25    HttpURL.escape and HttpURL.unescape post-process both to an unified form.
26
27*/
28if (typeof(window.encodeURIComponent) == "undefined") {
29    /**
30        @private
31    */
32    window.encodeURIComponent = function(s) {
33        return window.escape(s);
34    }
35}
36if (typeof(window.decodeURIComponent) == "undefined") {
37    /**
38        @private
39    */
40    window.decodeURIComponent = function(s) {
41        return window.unescape(s);
42    }
43}
44
45PKG.HttpURL = Class.create(
46/**
47    @lends HttpURL#
48*/
49{
50    /**
51        @description
52            HttpURL Class for easy HTTP-URL handling.
53        @constructs
54        @param {string} spec
55            A string containing an absoulte or relative URL
56    */
57    initialize: function(spec) {
58        this.isAbsolute = (spec.startsWith("http://") || spec.startsWith("https://"));
59        this.pathStartsWithSlash = true;
60        if (!this.isAbsolute) {
61            this.pathStartsWithSlash = /^\//.test(spec);
62            spec = PKG.HttpURL.DUMMY_PREFIX + spec.replace(/^\//, "");
63        }
64
65        this.protocol = null;
66        this.host = null;
67        this.port = -1;
68        this.file = null;
69        this.query = null;
70        this.authority = null;
71        this.path = null;
72        this.userInfo = null;
73        this.ref = null;
74        this.qParams = new Hash();
75
76        var i, limit, c;
77
78        var original = spec;
79        var start = 0;
80        var newProtocol = null;
81        var aRef = false;
82
83        limit = spec.length;
84
85        while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) {
86            limit--; //eliminate trailing whitespace
87        }
88
89        while ((start < limit) && (spec.charAt(start) <= ' ')) {
90            start++; // eliminate leading whitespace
91        }
92
93        if (spec.substr(start, 4).toLowerCase() == "url:") {
94            start += 4;
95        }
96
97        if (start < spec.length && spec.charAt(start) == '#') {
98            /* we're assuming this is a ref relative to the context URL.
99             * This means protocols cannot start w/ '#', but we must parse
100             * ref URL's like: "hello:there" w/ a ':' in them.
101             */
102            aRef = true;
103        }
104
105        for (i = start; !aRef && (i < limit) && ((c = spec.charAt(i)) != '/'); i++) {
106
107            if (c == ':') {
108                var s = spec.substring(start, i).toLowerCase();
109
110                //if (this.isValidProtocol(s)) {
111                newProtocol = s;
112                start = i + 1;
113                //}
114
115                break;
116            }
117        }
118
119        // Only use our context if the protocols match.
120        this.protocol = newProtocol;
121
122        if (this.protocol == null) {
123            // ignored here
124        }
125
126        i = spec.indexOf('#', start);
127
128        if (i >= 0) {
129            this.ref = spec.substring(i + 1, limit);
130            limit = i;
131        }
132
133        this.parseURL(spec, start, limit);
134        this.parseQueryString();
135    },
136
137    /**
138        @private
139    */
140    parseURL: function(spec, start, limit) {
141        var isRelPath = false;
142        var queryOnly = false;
143
144        // FIX: should not assume query if opaque
145        // Strip off the query part
146        if (start < limit) {
147            var queryStart = spec.indexOf('?');
148            queryOnly = (queryStart == start);
149
150            if (queryStart != -1) {
151                this.query = spec.substring(queryStart + 1, limit);
152
153                if (limit > queryStart)
154                    limit = queryStart;
155
156                spec = spec.substring(0, queryStart);
157            }
158        }
159
160        var i = 0;
161        // Parse the authority part if any
162        if ((start <= limit - 2) && (spec.charAt(start) == '/') && (spec.charAt(start + 1) == '/')) {
163            start += 2;
164            i = spec.indexOf('/', start);
165            if (i < 0) {
166                i = spec.indexOf('?', start);
167
168                if (i < 0)
169                    i = limit;
170            }
171
172            this.host = this.authority = spec.substring(start, i);
173
174            var ind = this.authority.indexOf('@');
175
176            if (ind != -1) {
177                this.userInfo = this.authority.substring(0, ind);
178                this.host = this.authority.substring(ind + 1);
179            }
180
181            ind = this.host.indexOf(':');
182            this.port = -1;
183            if (ind >= 0) {
184                // port can be null according to RFC2396
185                if (this.host.length > (ind + 1)) {
186                    this.port = parseInt(this.host.substring(ind + 1));
187                }
188                this.host = this.host.substring(0, ind);
189            }
190
191            start = i;
192            // If the authority is defined then the path is defined by the
193            // spec only; See RFC 2396 Section 5.2.4.
194            if (this.authority != null && this.authority.length > 0)
195                this.file = "";
196        }
197
198        if (this.host == null) {
199            this.host = "";
200        }
201
202        // Parse the file path if any
203        if (start < limit) {
204            if (spec.charAt(start) == '/') {
205                this.file = spec.substring(start, limit);
206            } else if (this.file != null && this.file.length > 0) {
207                isRelPath = true;
208                var ind = this.file.lastIndexOf('/');
209
210                var seperator = "";
211
212                if (ind == -1 && this.authority != null)
213                    seperator = "/";
214
215                this.file = this.file.substring(0, ind + 1) + seperator + spec.substring(start, limit);
216            } else {
217                var seperator = (this.authority != null) ? "/" : "";
218                this.file = seperator + spec.substring(start, limit);
219            }
220        } else if (queryOnly && this.file != null) {
221            var ind = this.file.lastIndexOf('/');
222            if (ind < 0)
223                ind = 0;
224            this.file = this.file.substring(0, ind) + "/";
225        }
226
227        if (this.file == null)
228            this.file = "";
229
230        if (isRelPath) {
231            // Remove embedded /./
232            while ((i = this.file.indexOf("/./")) >= 0) {
233                this.file = this.file.substring(0, i) + this.file.substring(i + 2);
234            }
235            // Remove embedded /../
236            while ((i = this.file.indexOf("/../")) >= 0) {
237                if ((limit = this.file.lastIndexOf('/', i - 1)) >= 0) {
238                    this.file = this.file.substring(0, limit) + this.file.substring(i + 3);
239                } else {
240                    this.file = this.file.substring(i + 3);
241                }
242            }
243            // Remove trailing ..
244            while (this.file.substring(this.file.length - 3, this.file.length) == "/..") {
245                //while (file.endsWith("/..")) {
246                i = this.file.indexOf("/..");
247                if ((limit = this.file.lastIndexOf('/', i - 1)) >= 0) {
248                    this.file = this.file.substring(0, limit + 1);
249                } else {
250                    this.file = this.file.substring(0, i);
251                }
252            }
253            // Remove trailing .
254            if (this.file.substring(this.file.length - 2, this.file.length) == "/.")
255            //if (file.endsWith("/."))
256                this.file = this.file.substring(0, this.file.length() - 1);
257        }
258        if(!this.pathStartsWithSlash){
259            this.file = this.file.replace(/^\//, "");
260        }
261        this.path = this.file;
262        this.file = this.query == null ? this.file : this.file + "?" + this.query;
263    },
264
265    /**
266        @private
267    */
268    parseQueryString: function() {
269        if (this.query == null || this.query.length == 0) {
270            return;
271        }
272
273        this.qParams = $H(this.query.toQueryParams());
274    },
275
276    /**
277        @description
278            Get a query parameter from HttpURL. This function always returns
279            the first parameter when more than one exist
280        @param {string} key
281            the key of the query parameter to get
282        @param {string} defval
283            the default value to return, if no value for key is found
284        @type
285            string
286    */
287    getParameter: function(key, defval) {
288        if (!key) {
289            return defval;
290        }
291
292        var toret = this.qParams.get(key);
293        return toret == null ? defval : Object.isArray(toret) ? toret.first() : toret;
294    },
295
296    /**
297        @description
298            Sets a query parameter to url.
299        @param {string} key
300            the key of the query parameter to set
301        @param {string} val
302            the value of the query parameter to set
303        @param {boolean} replace
304            decides, wether the value is added, or key/value-pair is replaced
305        @type
306            void
307    */
308    setParameter: function(key, val, replace) {
309        if (!key) {
310            return;
311        }
312
313        var valuez = this.qParams.get(key);
314        // create an array, if only a string is contained
315        if (Object.isString(valuez)) {
316            this.qParams.set(key, [valuez]);
317        }
318
319        // create a new array, if replace is true
320        if (replace || valuez == null) {
321            this.qParams.set(key, new Array());
322        }
323
324        var data = this.qParams.get(key);
325        if (Object.isArray(val)) {
326            this.qParams.set(key, data.concat(val));
327        } else {
328            data.push(val);
329        }
330    },
331
332    /**
333        @description
334            Sets query parameters to url from object.
335        @param {Object} obj
336            the object to set the query parameters from
337        @param {boolean} replace
338            decides, wether the value is added, or key/value-pair is replaced
339        @type
340            void
341    */
342    setParameters: function(obj, replace) {
343        $H(obj || {}).each(function(kv) {
344            this.setParameter(kv.key, kv.value, replace);
345        }.bind(this));
346    },
347
348    /**
349        @description
350            Removes a key from query params
351        @param {string} key
352            the key of the query parameter to remove
353        @type
354            void
355    */
356    removeParameter: function(key) {
357        this.qParams.unset(key);
358    },
359
360    /**
361        @description
362            Deletes all query params
363        @type
364            void
365    */
366    removeAllParams: function() {
367        this.qParams = new Hash();
368    },
369
370    /**
371        @description
372            Get all query parameter values for a key
373        @param {string} key
374            the key of the query parameters to get
375        @type
376            string|string[]
377    */
378    getParameterValues: function(key) {
379        return this.qParams.get(key);
380    },
381
382    /**
383        @description
384            Get all query parameter names
385        @type
386            string[]
387    */
388    getParameterNames: function() {
389        return this.qParams.keys();
390    },
391
392    /**
393        @see HttpURL#toExternalForm
394    */
395    toString: function() {
396        return this.toExternalForm();
397    },
398
399    /**
400        @description
401            Converts a HttpURL back to a string
402        @type
403            string
404    */
405    toExternalForm: function() {
406        return this._toExternalForm(false);
407    },
408
409    /**
410        @private
411    */
412    _toExternalForm: function(skipQuery) {
413        var result = this.protocol;
414
415        result += ":";
416
417        if (this.authority != null && this.authority.length > 0) {
418            result += "//";
419            result += this.authority;
420        }
421
422        if (this.path != null) {
423            result += ((this.pathStartsWithSlash ? "" : "/") + this.path);
424        }
425
426        if (!skipQuery) {
427            var query = this.qParams.toQueryString();
428
429            if (query.length > 0) {
430                result += "?" + query;
431            }
432        }
433
434        if (this.ref != null) {
435            result += "#";
436            result += this.ref;
437        }
438
439        if (!this.isAbsolute) {
440            result = result.substring(PKG.HttpURL.DUMMY_PREFIX.length - (this.pathStartsWithSlash ? 1 : 0));
441        }
442
443        return result;
444    },
445
446    /**
447        @description
448            Returns an Object containing url as 'url' and parameter
449            as 'parameters' for use in prototype's Ajax object
450        @type
451            Object
452    */
453    getPrototypePair: function() {
454        return {
455            url: this._toExternalForm(true),
456            parameters: this.qParams
457        }
458    },
459
460    /**
461        @description
462            Debugs the url. If console.log is available the debug info is
463            printed there, else it's alerted
464        @type
465            void
466    */
467    debug: function() {
468        var debug = "protocol:  " + this.protocol + "\n" + "host:      " + this.host + "\n" + "port:      " + this.port + "\n" + "file:      " + this.file + "\n" + "userInfo:  " + this.userInfo + "\n" + "path:      " + this.path + "\n" + "ref:       " + this.ref + "\n" + "query:     " + this.query + "\n" + "authority: " + this.authority + "\n" + "qParams:   " + this.qParams.toQueryString() + "\n\n";
469
470        if (typeof(console) != "undefined" && typeof(console.log) == "function") {
471            console.log(debug);
472        } else {
473            alert(debug);
474        }
475    }
476});
477
478Object.extend(PKG.HttpURL,
479/**
480    @lends HttpURL
481*/
482{
483    DUMMY_PREFIX: "http://dummy/",
484
485    /**
486        @description
487            URL-encodes an string
488        @param {string} s
489            the string to encode
490        @type
491            string
492    */
493    urlencode: function(s) {
494        var re1 = /\+/g;
495        var re2 = /%20/g;
496        var re3 = /'/g;
497        s = encodeURIComponent(s);
498        return s.replace(re1, "%2B").replace(re2, "+").replace(re3, "%27");
499    },
500
501    /**
502        @description
503            URL-decodes an string
504        @param {string} s
505            the string to decode
506        @type
507            string
508    */
509    urldecode: function(s) {
510        var re = /\+/g;
511        s = s.replace(re, "%20");
512        return decodeURIComponent(s);
513    },
514
515    /**
516        @see HttpURL.qualify
517    */
518    makeAbsolute: function(url) {
519        return PKG.HttpURL.qualify(url);
520    },
521
522    /**
523        @description
524            makes an URL fully-qualified
525        @param {string|HttpURL} s
526            the string/HttpURL to qualify
527        @type
528            string
529    */
530    qualify: function(url) {
531        if (!this.qualifyCache) {
532            this.qualifyCache = {};
533            this.anchor = new Element('a', {
534                href: "#"
535            }).update('x');
536            // wird das div benoetigt?
537            this.div = new Element('div').insert(
538                this.anchor);
539        }
540        if (!this.qualifyCache[url]) {
541            this.anchor.href = url;
542            this.qualifyCache[url] = this.anchor.href;
543        }
544        return this.qualifyCache[url];
545    },
546
547    /**
548        @private
549    */
550    quEscape: function(s) {
551        return s.split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
552    }
553});
554
555// TODO: remove this
556window.HttpURL = PKG.HttpURL;
557
558
559
560/**
561    @description
562        HttpURLUtils Class for modifing a HttpURL.
563*/
564/* reverseString, get+setParameter are helper methods to workaround an IE8+ XSS-Filter issue */
565window.HttpURLUtils = {
566    /**
567        @private
568    */
569    rotBase: 1,
570
571    rotateString: function(text, base) {
572        var keycode = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
573        var textrot = new String();
574
575        base = new Number(base);
576
577        for (var i = 0; i < text.length; i++) {
578            var codechar = text.substring(i, i + 1);
579            var pos = keycode.indexOf(codechar.toUpperCase());
580
581            if (pos >= 0) {
582                pos = (pos + base) % keycode.length;
583                codechar = (codechar == codechar.toUpperCase()) ? keycode.substring(pos, pos + 1) : keycode.substring(pos, pos + 1).toLowerCase();
584            }
585            textrot = textrot + codechar;
586        }
587        return textrot;
588    },
589
590    reverseString: function(str) {
591        str = (str || "");
592        return str.split("").reverse().join("");
593    },
594
595    /**
596        @description
597            set a parameter with the chararcters sorted in a reversed order.
598            We need this to workaround an IE8+ XSS-Filter issue.
599        @param {string|HttpURL} name
600            parameter name
601        @param {string|HttpURL} value
602            parameter value
603    */
604    setReverseParameter: function(url, name, value) {
605        var base = url.getParameter("rot-base");
606        base = url.getParameter("rot-base");
607        if (!base) {
608            base = new HttpURL(document.location.href).getParameter("rot-base");
609            if (base) {
610                base = ((new Number(base) + 1) % 26) + 1;
611            }
612            if (!base) {
613                base = ((HttpURLUtils.rotBase++) % 26) + 1;
614            }
615            url.setParameter("rot-base", base);
616        }
617        value = HttpURLUtils.rotateString(value, base);
618        url.setParameter(name, HttpURLUtils.reverseString(value));
619    },
620
621    /**
622        @description
623            get a parameter with the chararcters sorted in a reversed order.
624            We need this to workaround an IE8+ XSS-Filter issue.
625        @param {string|HttpURL} name
626            parameter name
627        @param {string|HttpURL} value
628            parameter value
629        @param {string|HttpURL} _default
630            default value
631
632    */
633    getReverseParameter: function(url, name, _default) {
634        var value = HttpURLUtils.reverseString(url.getParameter(name));
635        var base;
636        if (value && (base = url.getParameter("rot-base")) != "") {
637            base = 26 - new Number(base);
638            /* alert(name + "\n" + value + "\n" + base + "\n" + HttpURLUtils.rotateString(value, base)); */
639            value = HttpURLUtils.rotateString(value, base);
640        }
641        return (value || _default);
642    }
643};
644})((function() {
645    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
646        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
647    }
648    if (typeof(window.cm4all) == "undefined") {
649        window.cm4all = {};
650    }
651    return window.cm4all;
652})());
653    };
654    if(window.__loadedJsLibraries["/res/js/lib/Common.js"] !== true){
655        window.__loadedJsLibraries["/res/js/lib/Common.js"] = true;
656        (function(PKG) {
657"PKG:nomunge"
658//-WRAP switch on library wrapping
659/**
660 @name LIBCM4ALL_JS_WIDGET_NAMESPACE
661 @description
662 This variable controls to which "namespace" the library is bound.
663 If not set the default-namespace "cm4all" will be used.
664 @example
665 default:
666 &lt;script src="Common.js">;&lt;/script>
667 &lt;script src="HttpURL.js">;&lt;/script>
668 &lt;script>
669 var httpUrl = new cm4all.HttpURL();
670 &lt;/script>
671
672 example "juppes"-namespace:
673 &lt;script>
674 var juppes = LIBCM4ALL_JS_WIDGET_NAMESPACE = {};
675 &lt;/script>
676 &lt;script src="Common.js">;&lt;/script>
677 &lt;script src="HttpURL.js">;&lt;/script>
678 &lt;script>
679 var httpUrl = new juppes.HttpURL();
680 &lt;/script>
681
682 to put classes into "global" namespace, use:
683 &lt;script>
684 LIBCM4ALL_JS_WIDGET_NAMESPACE = window;
685 &lt;/script>
686 &lt;script src="Common.js">;&lt;/script>
687 &lt;script src="HttpURL.js">;&lt;/script>
688 &lt;script>
689 var httpUrl = new HttpURL();
690 &lt;/script>
691
692 */
693
694/**
695 * @name Common
696 * @namespace
697 * @description Base Object for all common stuff
698 */
699
700
701
702PKG.Common = ({
703  notTooOften: function(obj, fn) { /* little helper function: we dont want to call a eventhandler (i.e. hintingHandler) too often */
704    var lastCall = 0;
705    var timerId = 0;
706    if (obj) {
707      fn = fn.bind(obj);
708    }
709    return function(ev) {
710      if (timerId) {
711        clearTimeout(timerId);
712        timerId = 0;
713      }
714      const now = new Date();
715      if (now - lastCall >= 150) {
716        // dont wait more than 150 ms
717        lastCall = now;
718        fn(ev);
719      } else {
720        timerId = setTimeout(function() {
721          lastCall = new Date();
722          fn(ev);
723        }, 150);
724      }
725    };
726  }
727});
728
729Object.extend(PKG.Common, {
730  /**
731   * @lends Common
732   */
733  _defaultLogger: null,
734
735  /**
736   * @type string
737   * @description returns the server from where you can load additional libraries -
738   */
739
740  getLibServer: function() {
741    if (window.jslibServer) {
742      return window.jslibServer;
743    }
744    if (window.beng && window.beng.env && window.beng.env.common_prefix) {
745      return window.beng.env.common_prefix;
746    }
747    return "";
748  },
749
750  /**
751   * @param {string|string[]|object|object[]}
752   *            urls URLs of Javascript files to load as string or as object:<br/> { url :
753   *            "&lt;url>", isLoaded : function() { return &lt;true-if-loaded> }}
754   * @param {function}
755   *            callback Callback function, which is invoked when all js files are loaded
756   * @type void
757   * @description Scripts are appended to &lt;head>, so document.write or similar funtions are
758   *              not allowed here. An optional callback can be invoked after loading is done.
759   *              Scripts, which are already loaded are not loaded again.
760   * @example It's possible to load files parallel: [ [ "parallel-1a.js", "parallel-1b.js",
761   *          "parallel-1c.js", "parallel-1d.js" ], "serial2.js", { url :
762   *          "res/parallel-1a.js", isLoaded : function() { return false; } }, "serial3.js",
763   *          "serial4.js" ]
764   */
765  requireLibrary: function(urls, callback) {
766    var thiz = this;
767    if (!Object.isArray(urls)) {
768      urls = [urls];
769    }
770
771    var url = urls[0];
772
773    if (Object.isArray(url)) {
774      var newurls = urls.findAll(function(e) {
775        return Object.isArray(e) ? Object.toJSON(e) != Object.toJSON(url) : true;
776      });
777      var _callback = function() {
778        PKG.Common.requireLibrary.bind(thiz, newurls, callback).defer( /* break the recursion */ );
779      };
780      var _urls = {
781        paylord: url
782      };
783      url.each(function(_url) {
784        PKG.Common.__requireLibrary(_url, _urls, _callback, true);
785      });
786      return;
787    } else
788    // serial urls left ...
789    if (url) {
790      PKG.Common.__requireLibrary(url, {
791        paylord: urls
792      }, callback, false);
793    } else
794    // NO serial urls left ...
795    if (typeof(callback) == "function") {
796      callback();
797    }
798
799  },
800
801  /**
802   * @private
803   */
804  __requireLibrary: function(url, urls, callback, isParallel) {
805    var test;
806    var script = null;
807    var func;
808    var observe = Event.observe || Event.prototype.constructor.observe; // (PBT: #11772) IE
809    // has another Event object if webcomponents-lite.js is loaded in page
810    var ljl = window.__loadedJsLibraries || (window.__loadedJsLibraries = new Object());
811    if (Object.isFunction(url.isLoaded)) {
812      test = url.isLoaded();
813    } else if (ljl[url] === true) {
814      test = true;
815    } else {
816      test = (script = $$("script").find(function(e) {
817        return (PKG.HttpURL.qualify(e.src) == PKG.HttpURL.qualify(url.url || url));
818      })) ? true : false;
819    }
820
821    if (!test) {
822      // import the file
823      script = new Element('script');
824
825      var head = PKG.Common.getOrCreateHeadElement();
826      /**
827       * @private
828       */
829      func = function() {
830        var _url = url.url || url;
831        if (!ljl[_url] && (!script.readyState || script.readyState == "loaded" || script
832            .readyState == "complete")) {
833          ljl[_url] = true;
834          script.removeAttribute("dirty");
835          PKG.Common.callbackFunc(url, urls, {
836            callback: callback,
837            script: script,
838            skipCheck: false,
839            isParallel: isParallel
840          });
841        }
842      };
843
844      /*
845              Currently, it's not possible to decide whether loading
846              script was successful in a cross-browser way, so the
847              callback function is invoked also onerror, so that all
848              browsers behave the same way ...
849              FF3     : calls onload on success, onerror on error
850              Safari3 : calls onload on success and error
851              IE7     : calls onreadystatechange with readyState loaded
852                        and complete on success and error
853          */
854
855      observe(script, "error", func);
856      observe(script, "load", func);
857      observe(script, "readystatechange", func);
858      /*  set the src later, because starts loading immendiately
859              after setting src */
860      script.setAttribute("dirty", "dirty");
861      script.src = url.url || url;
862
863      head.insert({
864        bottom: script
865      });
866      head = null;
867    } else {
868      // file is already loaded, just call the callback func
869      func = function() {
870        if (script && script.getAttribute("dirty")) {
871          window.setTimeout(func, 10);
872          return;
873        }
874        PKG.Common.callbackFunc(url, urls, {
875          callback: callback,
876          script: new Element('script'),
877          skipCheck: true,
878          isParallel: isParallel
879        });
880        script = null;
881        func = null;
882      };
883      func.call(this);
884    }
885  },
886
887  /**
888   * @param {string|string[]}
889   *            urls URLs of Javascript files to load
890   * @param {string}
891   *            insertPosition Position in the head where the link tag is inserted - 'bottom'
892   *            or 'top'
893   * @type void
894   * @description CSSs are appended to &lt;head>, if a css was NOT loaded before
895   */
896  loadCss: function(urls, insertPosition) {
897    if (!Object.isArray(urls)) {
898      urls = [urls];
899    }
900
901    var head = PKG.Common.getOrCreateHeadElement();
902
903    urls.each(function(url) {
904      if (Object.isArray(url)) {
905        PKG.Common.loadCss(url);
906      } else {
907        var test;
908        var lcl = window.__loadedCssLibraries || (window.__loadedCssLibraries = new Object());
909        if (lcl[url] === true) {
910          test = true;
911        } else {
912          test = $$("link").any(function(e) {
913            return (PKG.HttpURL.qualify(e.href) == PKG.HttpURL.qualify(url));
914          });
915        }
916        if (!test) {
917          var o = {};
918          o[insertPosition || "bottom"] = new Element('link', {
919            "type": "text/css",
920            "rel": "stylesheet",
921            "href": url
922          });
923          head.insert(o);
924          lcl[url] = true;
925        }
926      }
927    });
928  },
929
930  /**
931   * @param (string)
932   *            the css selector
933   * @param ((object{})
934   *            styles to set
935   * @type void
936   * @description
937   *            adds css rules to the document heaad element
938   * @example createCssRule("body", {"background-color": "red"});
939   */
940  createCssRule: function(selector, properties) {
941    var $styleElement = jQuery("style#jslib-css");
942    if ($styleElement.length == 0) {
943      $styleElement = jQuery("<style></style>");
944      jQuery("head").append($styleElement);
945    }
946    var rule = selector + " {";
947    jQuery.each(properties,
948      function(key, value) {
949        rule += key + ":" + value + ";\n";
950      }
951    );
952    rule += "};"
953    $styleElement.append(rule);
954  },
955
956
957  /**
958   * @param (object)
959   *          the dom element where to start the search from
960   * @param (string)
961   *          the css name of the color to search for
962   *          ["color", "background-color", "border-color"]
963   * @param (string)
964   *          the defaultColor. Can be empty
965   * @description
966   *          returns the computed css-color of a given element
967   *          this function searches the element itself and all parents
968   *          all colors like 'transparent' and rgba(*,*,*,0) will be ignored
969   */
970
971  findColor: function(elem, color, defaultColor) {
972    color = color || "color";
973    defaultColor = defaultColor || null;
974
975    var ignoreRe = /rgba*\(\d+,\d+,\d+,0\)/;
976    while (elem != document) {
977      var compStyle = window.getComputedStyle(elem);
978      if (compStyle) {
979        var val = compStyle[color];
980        val = val.replace(/\s/g, '');
981        if (val !== 'transparent' && !ignoreRe.test(val)) {
982          return val;
983        }
984      }
985      elem = elem.parentNode;
986    }
987    return defaultColor;
988  },
989
990
991  /**
992   * @param {object[]}
993   *            requests Array of objects, each with two properties 'url' and 'options', which
994   *            are passed to Ajax.Request
995   * @param {function}
996   *            callback Callback function, which is invoked after all ajax requests are
997   *            finished
998   * @type void
999   * @description Loads multiple ajax requests in parallel and invokes the callback after all
1000   *              requests are finished. onSuccess/onFailure - if defined - are called for
1001   *              each request. method is set to 'GET' per default.
1002   * @example cm4all.Common.loadAssets([ { url : '/beng/designset.js', options : { onSuccess :
1003   *          this.onDesignSetLoaded.bind(this), onFailure : this.onDesignSetFailed.bind(this) } }, {
1004   *          url : '/beng/colorsets.js', options : { onSuccess :
1005   *          this.onColorSetsLoaded.bind(this) } }, { url :
1006   *          createBengRequestUrl('/.cm4all/e/Editor', {action: 'setDesignData'}),
1007   *          options : { method : 'post', postBody : this.designdataDoc, contentType :
1008   *          'text/xml', onSuccess: this.onDesignDataSaved.bind(this) } } ],
1009   *          this.myCallback.bind(this));
1010   *
1011   */
1012  loadAssets: function(requests, callback) {
1013    requests = Object.ensureArray(requests);
1014    if (requests.length == 0 && Object.isFunction(callback)) {
1015      callback();
1016      return;
1017    }
1018
1019    requests.each(function(req) {
1020      req.options.method = req.options.method || 'get';
1021      var origFuncs = {
1022        onSuccess: req.options.onSuccess || null,
1023        onFailure: req.options.onFailure || null
1024      };
1025      var onResponse = function(func, res) {
1026        if (origFuncs[func]) {
1027          try {
1028            origFuncs[func](res);
1029          } catch (e) {
1030            if (typeof console != 'undefined') {
1031              console.log("Error in callback after loading " + req.url);
1032              console.log(e);
1033            }
1034          }
1035        }
1036        req.ready = true;
1037        if (requests.pluck('ready').all() && Object.isFunction(callback)) {
1038          callback();
1039        }
1040      };
1041      req.options.onSuccess = onResponse.curry('onSuccess');
1042      req.options.onFailure = onResponse.curry('onFailure');
1043      new Ajax.Request(req.url, req.options);
1044    });
1045  },
1046
1047  /**
1048   * @param {string}
1049   *            message the message to log
1050   * @type void
1051   * @description Logs a message, if a non-blocking logging facility is available.
1052   * @deprecated Use a specific Logger instead <a href="Common.Logger.html">Common.Logger</a>
1053   */
1054  log: function(message) {
1055    if (PKG.Common._defaultLogger == null) {
1056      PKG.Common._defaultLogger = new PKG.Common.Logger();
1057    }
1058    PKG.Common._defaultLogger.debug(message);
1059  },
1060
1061  /**
1062   * @param {string}
1063   *            category event category
1064   * @param {string}
1065   *            type event type
1066   * @param {object}
1067   *            [attributes] payload of the event
1068   * @param {function}
1069   *            [callback] optional callback function called on request completion with response parameter
1070   * @type void
1071   * @description Logs events generated in the frontend via history service backend.
1072   */
1073  logViaHistoryService: function(category, type, attributes, callback) {
1074    var serviceUrl = new PKG.HttpURL("/.cm4all/e/Editor/action=log/;translate=skipProcess$3Dtrue");
1075    serviceUrl.setParameter("category", category);
1076    serviceUrl.setParameter("type", type);
1077    new Ajax.Request(serviceUrl.toExternalForm(), {
1078      method: "post",
1079      contentType: "application/json",
1080      postBody: attributes ? Object.toJSON(attributes) : "{}",
1081      onComplete: function(response) {
1082        if (typeof callback == "function") {
1083          callback(response);
1084        }
1085      }
1086    });
1087  },
1088
1089  /**
1090   * @param {string}
1091   *            CSS3 selector for elements to modifiy
1092   * @type void
1093   * @description Adds doubleTapToGo functionality to elements from selector
1094   */
1095  doubleTapToGo: function(selector) {
1096
1097    if (navigator.userAgent.match(/iPhone|iPad|iPod/) &&
1098      Number((navigator.userAgent.match(/OS (\d+)_(\d+)/) || false)[1]) <= 7) {
1099      return;
1100    }
1101
1102    (function($, window, document, undefined) {
1103      $.fn.doubleTapToGo = function(params) {
1104        if (!('ontouchstart' in window) &&
1105          !navigator.msMaxTouchPoints &&
1106          !navigator.userAgent.toLowerCase().match(/windows phone os 7/i)) return false;
1107
1108        this.each(function() {
1109          var curItem = false;
1110
1111          $(this).on('click', function(e) {
1112            var item = $(this);
1113            if (item[0] != curItem[0]) {
1114              e.preventDefault();
1115              curItem = item;
1116            }
1117          });
1118
1119          $(document).on('click touchstart MSPointerDown', function(e) {
1120            var resetItem = true,
1121              parents = $(e.target).parents();
1122
1123            for (var i = 0; i < parents.length; i++)
1124              if (parents[i] == curItem[0])
1125                resetItem = false;
1126
1127            if (resetItem)
1128              curItem = false;
1129          });
1130        });
1131        return this;
1132      };
1133    })(jQuery, window, document);
1134
1135    jQuery(selector).doubleTapToGo();
1136  },
1137
1138  /**
1139   * @param {string|Element}
1140   *            content A HTML string or an element.
1141   * @param {number|string}
1142   *            options.width Width of the "fullscreen" layer. Number means pixel, string can
1143   *            be a percent value, e.g. "80%"
1144   * @param {number|string}
1145   *            options.height Height of the "fullscreen" layer. Number means pixel, string
1146   *            can be a percent value, e.g. "80%"
1147   * @param {number}
1148   *            options.left left margin of the "fullscreen" layer in pixel.
1149   * @param {number}
1150   *            options.right right margin of the "fullscreen" layer in pixel.
1151   * @param {number}
1152   *            options.top top margin of the "fullscreen" layer in pixel.
1153   * @param {number}
1154   *            options.bottom bottom margin of the "fullscreen" layer in pixel.
1155   * @param {string}
1156   *            options.scrollbars Allowed values: "x" "y" "xy". If set the, content will get
1157   *            scrollbars in the given directions if needed.
1158   * @type Element
1159   * @description "Opens" a layer with options.width and options.height. If the current
1160   *              viewport is smaller than width and/or height. The values are scaled to fit
1161   *              viewport keeping aspect ratio. <br/>
1162   */
1163  openFullscreen: function(content, options = {}) {
1164    // convert "123px" to numbers
1165    if (options.width && /px$/.test(options.width)) {
1166      options.width = Number(/(.*)px$/.exec(options.width)[1]);
1167    }
1168
1169    if (options.height && /px$/.test(options.height)) {
1170      options.height = Number(/(.*)px$/.exec(options.height)[1]);
1171    }
1172
1173    if (options.width && options.height && !/%$/.test(options.width)) {
1174      var dimz = document.viewport.getDimensions();
1175      dimz.width = dimz.width - 40;
1176      dimz.height = dimz.height - 40;
1177
1178      if (options.width >
1178 dimz.width && !(/x/i).test(options.scrollbars)) {
1179        var aspect = options.height / options.width;
1180        options.width = dimz.width;
1181        options.height = options.width * aspect;
1182      }
1183
1184      if (options.height > dimz.height && !(/y/i).test(options.scrollbars)) {
1185        var aspect = options.width / options.height;
1186        options.height = dimz.height;
1187        options.width = options.height * aspect;
1188      }
1189    }
1190
1191    var lcontainer;
1192    var lbackground;
1193    var lcontent;
1194    var lcloser;
1195    var pnode;
1196    var rnode;
1197
1198    if (Object.isElement(content)) {
1199      content = $(content);
1200      pnode = content.up();
1201      rnode = content.next();
1202    }
1203
1204    lcontainer = new Element('div', { 'class': 'cm-fullscreen container' });
1205    lbackground = new Element('div', { 'class': 'cm-fullscreen background' });
1206    lcontent = new Element('div', { 'class': 'cm-fullscreen content' });
1207    lscrollbars = new Element('div', { 'class': 'cm-fullscreen scrollbars' });
1208    lborder = new Element('div', { 'class': 'cm-fullscreen border' });
1209
1210    if ((/x/i).test(options.scrollbars)) {
1211      lscrollbars.addClassName("scrollbars-x");
1212    }
1213    if ((/y/i).test(options.scrollbars)) {
1214      lscrollbars.addClassName("scrollbars-y");
1215    }
1216    lcloser = new Element('div', { 'class': 'cm-fullscreen close' });
1217    lcloser.observe("click", function() {
1218      if (pnode) {
1219        pnode.insertBefore(content, rnode || null);
1220      }
1221      /* (PBT: #3911) */
1222      var iframes = lcontainer.select("iframe");
1223      iframes.each(function(iframe) {
1224        try {
1225          iframe.src = 'about:blank';
1226        } catch (e) {
1227          Common.log(e.message);
1228        }
1229      });
1230      lcontainer.remove();
1231    });
1232
1233    if (options.width) {
1234      if (/%$/.test(options.width)) {
1235        lcontent.setStyle({
1236          width: options.width,
1237          minWidth: options.width,
1238        });
1239      } else {
1240        lcontent.style.width = options.width + 'px';
1241        lcontent.style.minWidth = options.width + 'px';
1242      }
1243    } else if (options.left && options.right) {
1244      lcontent.setStyle({
1245        left: options.left + 'px',
1246        right: options.right + 'px',
1247        transform: 'initial'
1248      });
1249    } else {
1250      throw new Error("Illegal Arguments: either options.width or options.left/options.right must be set");
1251    }
1252
1253    if (options.height) {
1254      if (/%$/.test(options.height)) {
1255        lcontent.setStyle({
1256          height: options.height,
1257        });
1258      } else {
1259        lcontent.style.height = options.height + 'px';
1260      }
1261    } else if (!(options.top && options.bottom)) {
1262      throw new Error("Illegal Arguments: either options.height or options.top/options.bottom must be set");
1263    }
1264    if (options.top) {
1265      lcontent.setStyle({
1266        top: options.top + 'px',
1267      });
1268    } else if (options.bottom) {
1269      lcontent.setStyle({
1270        bottom: options.bottom + 'px'
1271      });
1272    }
1273
1274    lcontainer.insert(lbackground);
1275    lcontainer.insert(lcontent);
1276    lcontent.insert(lscrollbars);
1277    lcontent.insert(lborder);
1278    lborder.insert(lscrollbars);
1279    lscrollbars.insert(content);
1280
1281    // lborder.style.height = lbackground.offsetHeight + 'px';
1282
1283    // iframes need a height
1284    let fec = lscrollbars.firstElementChild;
1285    if (fec && fec.tagName.toLowerCase() === 'iframe') {
1286       fec.style.height = options.height + 'px';
1287    }
1288
1289    lborder.insert(lcloser);
1290    $(document.body).insert(lcontainer);
1291
1292    return lcontent;
1293  },
1294
1295  /**
1296   * @param {string|Element}
1297   *            imageUrl The url of the image to show.
1298   * @param {number}
1299   *            options.minWidth
1300   *              The minimal width of the image. If the image is narrower it will be upscaled.
1301   * @param {number}
1302   *            options.minHeight
1303   *              The minimal height of the image. If the image is smaller  it will be upscaled.
1304   * @type Element
1305   * @description Shows the image in its original size in a fullscreen layer.
1306   *                  If the image is larger than the viewport it is scaled down to fit the viewport.
1307   */
1308  openFullscreenImage: function(imageUrl, options) {
1309    options = options || {};
1310    var imageId = "cm4all-common-fullscreen-image-" +
1311      ((new Date().getTime() + Math.random()).toString(32).replace(/\./, "-"));
1312
1313    // TODO : "auto" is not an option recognized by "openFullScreen" !
1314    var popup = PKG.Common.openFullscreen(`<img id="${imageId}" src="${imageUrl}" />`, {
1315      "width": "auto",
1316      "height": "auto"
1317    });
1318
1319    var content = document.querySelector('.cm-fullscreen.content');
1320    var img = document.getElementById(imageId);
1321
1322    content.style.minWidth = 'max-content';
1323    content.style.display = 'block';
1324
1325    img = PKG.Common.scaleImage(img);
1326
1327    if (options.minHeight || options.minWidth) {
1328      content.style.maxWidth = 'initial';
1329      img.style.minHeight = options.minHeight + 'px';
1330      img.style.minWidth = options.minWidth + 'px';
1331    } else {
1332      content.style.transform = 'translate(calc(-50%), calc(-50%))';
1333    }
1334    document.querySelector('.cm-fullscreen.scrollbars').style.maxHeight = img.style.maxHeight;
1335    document.querySelector('.cm-fullscreen.scrollbars').style.maxWidth = img.style.maxWidth;
1336
1337    return popup;
1338  },
1339
1340  getNativeDimension: function(url) {
1341    return new Promise(function( resolve, reject ) {
1342      var image = new Image();
1343
1344      // Chrome default size for images without width or height. e.g. SVG;
1345      var dimension = {nativeWidth: 640, nativeHeight: 480, url: url, error: null};
1346
1347      image.onload = function(event) {
1348          dimension.nativeWidth = this.width || dimension.nativeWidth;
1349          dimension.nativeHeight = this.height || dimension.nativeHeight;
1350          resolve(dimension);
1351      };
1352
1353      image.onerror = function(event) {
1354          dimension.error = event;
1355          reject(dimension);
1356      };
1357
1358      image.src = url;
1359    });
1360  },
1361
1362  // ---------------------------------------------------------------------
1363
1364  setImageHeightAndWidth: function(imageElement, targetHeight, targetWidth) {
1365    imageElement.style.maxHeight = targetHeight + 'px';
1366    imageElement.style.minHeight = targetHeight + 'px';
1367    imageElement.style.height = targetHeight + 'px';
1368    imageElement.closest('.cm-fullscreen.scrollbars').style.height = targetHeight + 'px';
1369
1370    imageElement.style.maxWidth = targetWidth + 'px';
1371    imageElement.style.minWidth = targetWidth + 'px';
1372    imageElement.style.width = targetWidth + 'px'
1373    return imageElement;
1374  },
1375
1376  scaleImage: function(imageElement) {
1377    if (imageElement != null) {
1378      PKG.Common.getNativeDimension([imageElement.src]).then(function(result) {
1379        var nativeWidth = result.nativeWidth;
1380        var nativeHeight = result.nativeHeight;
1381
1382        var maxAvailableHeight = window.innerHeight - 40;
1383        var maxAvailableWidth = window.innerWidth - 40;
1384
1385        var widthRatio = maxAvailableWidth / nativeWidth;
1386        var heightRatio = maxAvailableHeight / nativeHeight;
1387
1388        var scale = Math.min(widthRatio, heightRatio);
1389
1390        if (scale <= 1) {
1391          var targetDisplayHeight = (nativeHeight * scale);
1392          var targetDisplayWidth = (nativeWidth * scale);
1393          PKG.Common.setImageHeightAndWidth(imageElement, targetDisplayHeight, targetDisplayWidth);
1394        } else {
1395          PKG.Common.setImageHeightAndWidth(imageElement, nativeHeight, nativeWidth);
1396        }
1397      });
1398    }
1399    return imageElement;
1400  },
1401
1402  /**
1403   * @param {string|Element}
1404   *            imageUrls Arrays of urls of the images to show.
1405   * @param {number}
1406   *            index of the image to show
1407   * @param {number}
1408   *            id of the img to change the picture
1409   * @type Element
1410   * @description Shows the next/prev image in its original size in a fullscreen layer.
1411   *              If the image is larger than the viewport it is scaled down to fit the viewport.
1412   */
1413  plusSlides: function(imageUrls, index, img) {
1414    index = (index + imageUrls.length) % imageUrls.length;
1415    img.src = imageUrls[index];
1416    img = PKG.Common.scaleImage(img);
1417  },
1418
1419  /**
1420   * @param {string|Element}
1421   *            imageUrls Arrays of urls of the images to show.
1422   * @param {number}
1423   *            index of the image to show
1424   * @param {number}
1425   *            options.minWidth
1426   *              The minimal width of the image. If the image is narrower it will be upscaled.
1427   * @param {number}
1428   *            options.minHeight
1429   *              The minimal height of the image. If the image is smaller  it will be upscaled.
1430   * @type Element
1431   * @description Shows the image in its original size in a fullscreen layer.
1432   *                  If the image is larger than the viewport it is scaled down to fit the viewport.
1433   */
1434  openFullscreenImageSlideshow: function(imageUrls, index, options) {
1435    options = options || {};
1436    index = index || 0;
1437    var imageId = "cm4all-common-fullscreen-image-" + ((new Date().getTime() + Math.random()).toString(32).replace(/\./, "-"));
1438    var slideshow = '<div id="myModal" class="cm-fullscreen modal"><div class="cm-fullscreen modal-content">';
1439    slideshow += `<img id="${imageId}" src="${imageUrls[index]}">`;
1440    slideshow += '<a class="cm-fullscreen prev"></a><a class="cm-fullscreen next"></a></div></div>';
1441
1442    // TODO : "auto" is not an option recognized by "openFullScreen" !
1443    var popup = PKG.Common.openFullscreen(slideshow, {
1444      "width": "auto",
1445      "height": "auto"
1446    });
1447
1448    var content = document.querySelector('.cm-fullscreen.content');
1449    var img = document.getElementById(imageId);
1450
1451    content.style.minWidth = 'max-content';
1452    content.style.display = 'block';
1453
1454    img = PKG.Common.scaleImage(img);
1455
1456    if (options.minHeight || options.minWidth) {
1457      content.style.maxWidth = 'initial';
1458      img.style.minHeight = options.minHeight + 'px';
1459      img.style.minWidth = options.minWidth + 'px';
1460    } else {
1461      img.style.width = '100%'
1462      content.style.transform = 'translate(calc(-50%), calc(-50%))';
1463    }
1464
1465    var prev = document.querySelector('.cm-fullscreen.prev');
1466    var next = document.querySelector('.cm-fullscreen.next');
1467    prev.addEventListener('click', function prev() {
1468      PKG.Common.plusSlides(imageUrls, --index, img);
1469    })
1470
1471    next.addEventListener('click', function next() {
1472      PKG.Common.plusSlides(imageUrls, ++index, img);
1473    })
1474    return popup;
1475  },
1476  /**
1477   * @private
1478   */
1479  callbackFunc: function(url, urls, data
1480    //    /**string|object*/   url,
1481    //    /**string[]*/ urls,
1482    //    /**function*/ callback,
1483    //    /**Element*/  script,
1484    //    /**boolean*/  skipCheck,
1485    //    /**boolean*/  isParallel
1486  ) {
1487    if (data.script.importDone) {
1488      return;
1489    }
1490
1491    // skipCheck is here if script.readyState is not there anymore
1492    // on a later class ( IE 7 had a problem with it )
1493    if (!data.skipCheck && data.script.readyState && data.script.readyState != "loaded" && data
1494      .script.readyState != "complete") {
1495      return;
1496    }
1497    data.script.importDone = true; // dont call me twice
1498    urls.paylord = urls.paylord.findAll(function(e) {
1499      return Object.toJSON(e) != Object.toJSON(url);
1500    });
1501
1502    if (urls.paylord.length == 0) { // all imports done?
1503      if (typeof(data.callback) == "function") {
1504        data.callback();
1505      }
1506      return;
1507    }
1508
1509    if (!data.isParallel) {
1510      PKG.Common.requireLibrary.bind(this, urls.paylord, data.callback).defer( /* break the recursion */ );
1511    }
1512  },
1513
1514  /**
1515   * @private
1516   */
1517  hintingHandler: function() {
1518    var hintingHandlerFn = function(ev, elem, parent) {
1519      //var viewportWidth = jQuery(window).width();
1520      var changed42 = false;
1521      var breakpoints = {
1522        'cm-pixel-small': function(w) {
1523          return w < 200;
1524        },
1525        'cm-pixel-medium': function(w) {
1526          return w >= 200 && w < 400;
1527        },
1528        'cm-pixel-large': function(w) {
1529          return w >= 400;
1530        },
1531        'cm-pixel-xlarge': function(w) {
1532          return w >= 550;
1533        }
1534      };
1535      var container_breakpoints = {
1536        'cm-container-small': breakpoints['cm-pixel-small'],
1537        'cm-container-medium': breakpoints['cm-pixel-medium'],
1538        'cm-container-large': breakpoints['cm-pixel-large'],
1539        'cm-container-xlarge': breakpoints['cm-pixel-xlarge'],
1540        'cm-container-no-columns-2': function(w) {
1541          return w < 660;
1542        },
1543        'cm-container-no-columns-3': function(w) {
1544          return w >= 660 && w < 740;
1545        },
1546        'cm-container-4-columns-to-2': function(w) {
1547          return w >= 660 && w < 1060;
1548        }
1549      };
1550      var processElems = function(breakpoints, i, elem) {
1551        var jElem = jQuery(elem);
1552        var width = jElem.width();
1553
1554        jQuery.each(breakpoints, function(name, isBreakpoint) {
1555          if (isBreakpoint(width)) {
1556            jElem.addClass(name);
1557          } else {
1558            if (name == "cm-container-4-columns-to-2" && jElem.hasClass("cm-container-4-columns-to-2")) {
1559              changed42 = true;
1560            }
1561            jElem.removeClass(name);
1562          }
1563        });
1564      };
1565
1566      if (elem) {
1567        jQuery(elem).filter(".cm_widget").each(processElems.curry(breakpoints));
1568        jQuery(elem).filter(".content_main_dho, [data-cm-hintable], [cm_type], #mobileContent, .cm_
1568column").each(processElems
1569          .curry(container_breakpoints));
1570      } else {
1571        jQuery(".cm_widget", parent).each(processElems.curry(breakpoints));
1572        jQuery(".content_main_dho, [data-cm-hintable], [cm_type], #mobileContent, .cm_column", parent).each(processElems.curry(container_breakpoints));
1573      }
1574
1575      /* Workaround for Chrome - Chrome doesn't handle display change correctly :( */
1576      if (changed42) {
1577        document.querySelectorAll(".cm_column_wrapper").forEach(function(e) {
1578          e.style.display = "block";
1579          window.setTimeout(function() {
1580            e.style.display = "";
1581          }, 0);
1582        });
1583      }
1584
1585      PKG.Common.ensureFloatingSpace();
1586    }
1587
1588    return PKG.Common.notTooOften(null, hintingHandlerFn);
1589  }(),
1590
1591
1592
1593  /**
1594   *  Sets class "cm_empty" / "cm_empty_editor" to title-, subtitle-, sidebar-, and footer-container if contents is empty.
1595   */
1596  emptyHandler: function() {
1597    if (!window.beng || !beng.env) {
1598      return;
1599    }
1600    if (beng.env.mode != "edit" && !beng.env.hideEmptyAreas) {
1601      return;
1602    }
1603
1604    var classname = "cm_empty";
1605    if (beng.env.mode == "edit") {
1606      classname = "cm_empty_editor";
1607    }
1608
1609    var container = document.querySelectorAll("[cm_type=title], [cm_id=title], [cm_id=subtitle], [id=title], [id=subtitle], .title, .subtitle");
1610    [].forEach.call(container, function(elem) {
1611      /* Test if empty copied from EditorNG.__specialTreatment() */
1612      if (elem.innerHTML.stripTags().strip().blank() || elem.innerHTML == "&nbsp;" ||
1613        elem.textContent == elem.getAttribute("cm_defaultText")) {
1614        if (beng.env.hideEmptyAreas) {
1615          elem.addClassName(classname);
1616        } else {
1617          elem.removeClassName(classname);
1618        }
1619      }
1620    });
1621    var otherElements = document.querySelectorAll("[cm_type=sidebar], .sidebar, [cm_type=footer], #footer");
1622    [].forEach.call(otherElements, function(elem) {
1623      if (!elem.querySelector(".cm_widget") && !PKG.Common.containsTextNode_recourse(elem) || elem.textContent == elem.getAttribute("cm_defaultText")) {
1624        if (beng.env.hideEmptyAreas) {
1625          elem.addClassName(classname);
1626        } else {
1627          elem.removeClassName(classname);
1628        }
1629      }
1630    });
1631
1632    PKG.Common.updateCanBeEmptys();
1633
1634    if (typeof cmEmptyApply === 'function') {
1635      cmEmptyApply();
1636    }
1637
1638  },
1639
1640  updateCanBeEmptys: function() {
1641    if (!window.beng || !beng.env) {
1642      return;
1643    }
1644    if (beng.env.mode != "edit" && !beng.env.hideEmptyAreas) {
1645      return;
1646    }
1647
1648    var classname = "cm_empty";
1649    if (beng.env.mode == "edit") {
1650      classname = "cm_empty_editor";
1651    }
1652
1653    canBeEmptys = document.querySelectorAll(".cm_can_be_empty");
1654    for (var i = 0; i < canBeEmptys.length; i++) {
1655      var canBeEmpty = canBeEmptys[i];
1656      var container = canBeEmpty.querySelectorAll("[cm_type=title], [cm_id=title], [cm_id=subtitle], [id=title], [id=subtitle], .title, .subtitle, [cm_type=sidebar], .sidebar, [cm_type=footer], #footer, [cm_type=keyvisual], #keyvisual, [cm_type=logo], #logo");
1657      if (container.length <= 0) {
1658        continue;
1659      }
1660      var allEmpty = true;
1661      for (var j = 0; j < container.length && allEmpty; j++) {
1662        if ((canBeEmpty.getAttribute("cmtype") == "keyvisual" || canBeEmpty.id == "keyvisual") && !canBeEmpty.classList.contains("cm_empty") && !canBeEmpty.classList.contains("cm_empty_editor")) {
1663          allEmpty = false;
1664        } else {
1665          for (var j = 0; j < container.length && allEmpty; j++) {
1666            if (!container[j].classList.contains("cm_empty") && !container[j].classList.contains("cm_empty_editor")) {
1667              allEmpty = false;
1668              break;
1669            }
1670          }
1671        }
1672      }
1673      if (allEmpty) {
1674        canBeEmpty.addClassName(classname);
1675      } else {
1676        canBeEmpty.removeClassName(classname);
1677      }
1678    }
1679  },
1680
1681  containsTextNode_recourse: function(element) {
1682    var i, node;
1683    var nodes = element.childNodes;
1684    for (i = 0; i < nodes.length; i++) {
1685      node = nodes[i];
1686      if (node.nodeType == Node.ELEMENT_NODE) {
1687        if (node.getAttribute("cm_dont_save") == "true" || node.getAttribute("id") == "dropmarker") {
1688          continue; // ignore cm_dont_save="true"
1689        }
1690        if (PKG.Common.containsTextNode_recourse(node)) {
1691          return true;
1692        }
1693      } else if (node.nodeType == Node.TEXT_NODE) {
1694        if (jQuery.trim(node.nodeValue) == "") {
1695          continue; // ignore whitespace
1696        }
1697        return true;
1698      }
1699    }
1700    return false;
1701  },
1702
1703  /**
1704   * @private
1705   * Set width of floating images to 100% if there remains only a small space less than 150px for text.
1706   * This is called by hintingHandler.
1707   */
1708  ensureFloatingSpace: function() {
1709    if (!window.beng || !beng.env || beng.env.mode == 'edit') {
1710      return;
1711    }
1712    try {
1713      document.querySelectorAll('.cm_widget.cm_widget_float_left, .cm_widget.cm_widget_float_right').forEach(function(w) {
1714        if (w.dataset.originalWidth) {
1715          w.style.width = w.dataset.originalWidth; // reset to original width
1716          delete w.dataset.originalWidth;
1717        }
1718        if (w.closest('.cm-container-small, .cm-container-medium, .cm-container-large')) {
1719          if (w.parentNode.clientWidth - w.offsetWidth < 150) {
1720            if (!w.dataset.originalWidth) {
1721              w.dataset.originalWidth = w.style.width; // store original width
1722            }
1723            w.style.width = '100%';
1724          }
1725        }
1726      });
1727    } catch (e) {}
1728  },
1729
1730  /**
1731   * @private
1732   */
1733  getOrCreateHeadElement: function() {
1734    var list = $$("head");
1735
1736    if (list.first()) {
1737      return list.first();
1738    }
1739
1740    var head = new Element("head");
1741    $$("html").first().insert({
1742      'top': head
1743    });
1744
1745    return head;
1746  }
1747});
1748
1749Object.extend(PKG.Common, {
1750  /**
1751   * @lends Common
1752   */
1753  /**
1754   * @constant
1755   *
1756   * @description
1757   *      Predefined categories for use with cm4all.Common.logViaHistoryService().
1758   */
1759  HISTORY_EVENT_CATEGORY_WIDGET: "editor-widget",
1760  HISTORY_EVENT_CATEGORY_DESIGN: "editor-design",
1761  HISTORY_EVENT_CATEGORY_SETTINGS: "editor-settings",
1762  HISTORY_EVENT_CATEGORY_MARKETING: "editor-marketing",
1763  HISTORY_EVENT_CATEGORY_PUBLISH: "editor-publish"
1764});
1765
1766Object.extend(PKG.Common, {
1767  Logger: Class.create({
1768    /**
1769     * @lends Common.Logger#
1770     */
1771    _logMessages: "",
1772    _logLevel: null,
1773
1774    /**
1775     * @description Logger class. Currently, logs via console.log if available.
1776     * @constructs
1777     * @param {string}
1778     *            [context=""] A string describing the logger (e.g. classname)
1779     */
1780    initialize: function(context) {
1781      this.context = context || "";
1782    },
1783
1784    /**
1785     * @description Log an event with priority of "debug"
1786     */
1787    debug: function() {
1788      var args = $A(arguments);
1789      args.unshift(PKG.Common.Logger.DEBUG);
1790      this._log.apply(this, args);
1791    },
1792
1793    /**
1794     * @description Log an event with priority of "info"
1795     */
1796    info: function() {
1797      var args = $A(arguments);
1798      args.unshift(PKG.Common.Logger.INFO);
1799      this._log.apply(this, args);
1800    },
1801
1802    /**
1803     * @description Log an event with priority of "warn"
1804     */
1805    warn: function() {
1806      var args = $A(arguments);
1807      args.unshift(PKG.Common.Logger.WARN);
1808      this._log.apply(this, args);
1809    },
1810
1811    /**
1812     * @description Log an event with priority of "error"
1813     */
1814    error: function() {
1815      var args = $A(arguments);
1816      args.unshift(PKG.Common.Logger.ERROR);
1817      this._log.apply(this, args);
1818    },
1819
1820    /**
1821     * @description Log an event with priority of "fatal"
1822     */
1823    fatal: function() {
1824      var args = $A(arguments);
1825      args.unshift(PKG.Common.Logger.FATAL);
1826      this._log.apply(this, args);
1827    },
1828
1829    /**
1830     * @description Sets the log level for <strong>this</strong> logger.
1831     * @param {level}
1832     *            level the log level to set
1833     */
1834    setLogLevel: function(level) {
1835      this._logLevel = level;
1836    },
1837
1838    /**
1839     * @description Get the current log level or null if no log level has been set.
1840     *              <p>
1841     *              <i>In the future this should be set automatically via a configuration read
1842     *              from server. (log4j-like)</i>
1843     *              </p>
1844     * @type level
1845     */
1846    getLogLevel: function() {
1847      return this._logLevel;
1848    },
1849
1850    /**
1851     * @private
1852     */
1853    _log: function(level, obj) {
1854      if (!PKG.Common.Logger.isEnabled()) {
1855        return;
1856      }
1857      var xlevel = this.getLogLevel() || PKG.Common.Logger.getLogLevel();
1858      if (level[0] < xlevel[0]) {
1859        return;
1860      }
1861
1862      var message = (new Date().toString() + (this.context ? " [" + this.context + "]" : " [<default>]") +
1863        " " + level[1] + ": " + obj);
1864
1865      if (typeof console != "undefined"
1866        /* we can't use Object.isFunction, cause IE8s console.log has the type 'object' */
1867        &&
1868        !Object.isUndefined(console.log)) {
1869        console.log(message);
1870
1871        for (var i = 2; i < arguments.length; i++) {
1872          console.log(arguments[i]);
1873        }
1874      }
1875    }
1876  })
1877});
1878
1879Object.extend(PKG.Common.Logger, {
1880  /**
1881   * @lends Common.Logger
1882   */
1883  /**
1884   * @constant
1885   */
1886  DEBUG: [0, "DEBUG"],
1887  /**
1888   * @constant
1889   */
1890  INFO: [1, "INFO"],
1891  /**
1892   * @constant
1893   */
1894  WARN: [2, "WARN"],
1895  /**
1896   * @constant
1897   */
1898  ERROR: [3, "ERROR"],
1899  /**
1900   * @constant
1901   */
1902  FATAL: [4, "FATAL"],
1903
1904  /**
1905   * @constant
1906   */
1907  DISABLED: [5, ""],
1908
1909  /**
1910   * @description You must enable the logger via console with "Common.Logger.enable();"
1911   */
1912  enable: function() {
1913    PKG.Common.Logger._enabled = true;
1914    getTopWindow().document.cookie = "cm_debug=true";
1915  },
1916
1917  /**
1918   * @description See enable()
1919   */
1920  isEnabled: function() {
1921    if (typeof(PKG.Common.Logger._enabled) == 'undefined') {
1922      if (typeof(getTopWindow) == 'undefined') {
1923        return false;
1924      }
1925      PKG.Common.Logger._enabled = false;
1926      var c = getTopWindow().document.cookie;
1927      var i = c.indexOf("cm_debug=");
1928      if (i >= 0 && c.substring(i + 9, i + 9 + 4) == 'true') {
1929        PKG.Common.Logger._enabled = true;
1930      }
1931    }
1932    return PKG.Common.Logger._enabled;
1933  },
1934
1935  /**
1936   * @description Sets the log level for <strong>all</strong> loggers, which is used if no log
1937   *              level for a specific logger instance has been set.
1938   * @param {level}
1939   *            level the log level to set
1940   */
1941  setLogLevel: function(level) {
1942    PKG.Common.Logger._logLevel = level;
1943    getTopWindow().document.cookie = "cm_debug_level=" + level[1];
1944  },
1945
1946  /**
1947   * @description Get the current global log level. Returns a configuration specific log level.
1948   *              For development/debug installations this should be Common.Logger.DEBUG
1949   * @type level
1950   */
1951  getLogLevel: function() {
1952    if (typeof(PKG.Common.Logger._logLevel) == 'undefined') {
1953      if (typeof(getTopWindow) == 'undefined') {
1954        return false;
1955      }
1956      PKG.Common.Logger._logLevel = null;
1957      var c = getTopWindow().document.cookie;
1958      var i = c.indexOf("cm_debug_level=");
1959      if (i >= 0) {
1960        var jj = c.indexOf(";", i);
1961        PKG.Common.Logger._logLevel = PKG.Common.Logger[c.substring(i + 15, jj != -1 ? jj : c
1962          .length)];
1963      }
1964    }
1965    return PKG.Common.Logger._logLevel || PKG.Common.Logger.DEBUG;
1966  }
1967});
1968
1969Object.extend(PKG.Common, {
1970  Lib: {
1971    _: (window.beng && window.beng.env && window.beng.env.common_prefix ? window.beng.env.common_prefix : "")
1972  }
1973});
1974
1975Object.extend(PKG.Common.Lib, {
1976  scriptaculous: {
1977    builder: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/builder.js"],
1978    effects: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/effects.js"],
1979    slider: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/slider.js"],
1980    sound: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/sound.js"],
1981    unittest: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/unittest.js"],
1982    dragdrop: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/effects.js",
1983      PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/dragdrop.js"
1984    ],
1985    controls: [PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/effects.js",
1986      PKG.Common.Lib._ + "/res/js/thirdparty/scriptaculous-1.8/controls.js"
1987    ]
1988  },
1989  jquery: {
1990    ui: [
1991      PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/ui/minified/jquery-ui.min.js",
1992      PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/ui/i18n/jquery-ui-i18n.js"
1993    ],
1994    ui_datepicker: [
1995      PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/ui/minified/jquery.ui.core.min.js",
1996      PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/ui/minified/jquery.ui.datepicker.min.js",
1997      PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/ui/i18n/jquery-ui-i18n.js"
1998    ]
1999  }
2000});
2001
2002Object.extend(PKG.Common, {
2003  Css: {
2004    jquery: {
2005      ui: [PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/themes/base/jquery.ui.all.css"],
2006      ui_datepicker: [
2007        PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/themes/base/jquery.ui.base.css",
2008        PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/themes/base/jquery.ui.datepicker.css"
2009      ],
2010      ui_theme: [PKG.Common.Lib._ + "/res/js/thirdparty/jquery-ui-1.8/themes/base/jquery.ui.theme.css"]
2011    }
2012  }
2013});
2014
2015window.Common = PKG.Common;
2016
2017// install size hinting & empty hinting
2018jQuery(document)
2019  .on("ready load", PKG.Common.hintingHandler)
2020  .on("pageshow", function(ev) { PKG.Common.hintingHandler.call(this, ev); });
2021jQuery(window)
2022  .on("resize transitionend webkitTransitionEnd", PKG.Common.hintingHandler);
2023jQuery(document)
2024  .on("ready load", PKG.Common.emptyHandler)
2025  .on("pageshow", function(ev) { PKG.Common.emptyHandler.call(this, ev); });
2026
2027// install touch hinting
2028jQuery(window).one("touchstart", function() {
2029  jQuery(document.body).addClass("cm4all-touch-device");
2030})
2031
2032jQuery(document).one("ready", function() {
2033  // install iframe not sizeable hinting
2034  (function() {
2035    const iframe = document.createElement("IFRAME");
2036    iframe.src = "data:text/html,%3Cdiv%20style%3D%22width%3A%20100%25%3Bheight%3A200px" +
2037      "%3B%22%3E%3C%2Fdiv%3E";
2038
2039    function onLoad() {
2040      iframe.removeEventListener("error", onError);
2041      var reducedHeight = iframe.clientHeight - 1;
2042      iframe.style.height = reducedHeight + "px";
2043      var iframeHeight = iframe.clientHeight;
2044      iframe.parentNode.removeChild(iframe);
2045      if (iframeHeight !== reducedHeight) {
2046        jQuery(document.body).addClass("cm4all-iframe-not-sizable");
2047      }
2048    };
2049
2050    function onError() {
2051      iframe.removeEventListener("load", onLoad);
2052      iframe.removeEventListener("error", onError);
2053      iframe.parentNode.removeChild(iframe);
2054    }
2055    iframe.addEventListener("load", onLoad);
2056    iframe.addEventListener("error", onError);
2057    document.body.appendChild(iframe);
2058  })();
2059
2060  // hide anchor title on hover
2061  (function() {
2062    if (!window.beng || !beng.env || beng.env.mode == 'edit') {
2063      return;
2064    }
2065    document.querySelectorAll('.cm_anchor').forEach(function(a) {
2066      var t = a.title;
2067      if (t) {
2068        a.addEventListener('mouseenter', function() { a.title = ''; });
2069        a.addEventListener('mouseleave', function() { a.title = t; });
2070      }
2071    });
2072  })();
2073});
2074
2075/**
2076 * @private
2077 */
2078window.createBengRequestUrl = function(url, parameterObj, headerObj, translationParameter, noCacheControl, focus, mode) {
2079  // Diese Methode erstellt eine URL, die einen direkten Request vom Browser an das ControlPanel ermöglicht,
2080  // ohne dazu widgets zu benötigen.
2081  // Parameter und Header müssen aus technischen Gründen als ExtraPathInfo übergeben werden.
2082  // In dieser EPI müssen % durch $ ersetzt und serverseitig zurückgesetzt werden.
2083
2084  // Simuliert java.net.URLDecoder.encode()
2085  function jencode(s) {
2086    var re1 = /\+/g;
2087    var re2 = /%20/g;
2088    var re3 = /'/g;
2089    s = encodeURIComponent(s);
2090    return s.replace(re1, "%2B").replace(re2, "+").replace(re3, "%27");
2091  }
2092
2093  headerObj = (headerObj || {});
2094  parameterObj = (parameterObj || {});
2095  translationParameter = (translationParameter || {});
2096  var header = "";
2097  var tparameter = "";
2098  var name, value;
2099
2100  for (name in headerObj) {
2101    header += name + "=" + headerObj[name] + "&";
2102  }
2103
2104  for (name in translationParameter) {
2105    tparameter += name + "=" + translationParameter[name] + "&";
2106  }
2107
2108  header = jencode(header);
2109  var re = /%/g;
2110
2111  header = header.replace(re, "$");
2112
2113  for (var name in parameterObj) {
2114    value = jencode(parameterObj[name]);
2115    value = value.replace(re, "$");
2116    url += "/" + name + "=" + value;
2117  }
2118
2119  if (header)
2120    url += "/header=" + header;
2121
2122  if (!noCacheControl) {
2123    url += "/cc=" + new Date().getTime();
2124  }
2125
2126  var sessionId = "";
2127  try {
2128    sessionId = getTopWindow().urlSessionId || "";
2129  } catch (e) {}
2130
2131  url = beng_widget_uri(url, sessionId, null, typeof focus == "string" ? focus : null, mode || null, null, (tparameter != "" ? tparameter : null), null);
2132  return url;
2133};
2134})((function() {
2135    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
2136        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
2137    }
2138    if (typeof(window.cm4all) == "undefined") {
2139        window.cm4all = {};
2140    }
2141    return window.cm4all;
2142})());
2143    };
2144    if(window.__loadedJsLibraries["/res/js/lib/Common.Widget.js"] !== true){
2145        window.__loadedJsLibraries["/res/js/lib/Common.Widget.js"] = true;
2146        (function(PKG) {
2147"PKG:nomunge"
2148//-WRAP switch on library wrapping
2149
2150Object.extend(PKG.Common, {
2151    Widget: Class.create(
2152    /**
2153        @lends Common.Widget#
2154    */
2155    {
2156        /**
2157            @description
2158                Contains helper functions for widgets. <br/>
2159                In an untrusted (iframed) widget you must include the library by your own.
2160            @example
2161&lt;c:widget xmlns:c="http://cm4all.com/ng/widget" type="widget-runtime-js" />
2162&lt;c:widget xmlns:c="http://cm4all.com/ng/widget" type="xframetunnel-loader-js">
2163    &lt;parameter name="jumpback" value="/.cm4all/widgetres.php/exampleWidget/res/jumpback.html" />
2164&lt;/c:widget>
2165
2166
2167            @constructs
2168            @param {string} definition.classId
2169            @param {string} definition.wiid
2170            @param {string} definition.base
2171            @param {string} definition.session
2172            @param {string} definition.frame
2173            @param {string} definition.path
2174        */
2175        initialize: function(definition) {
2176            this.definition = definition || {};
2177            this.__dirty = 0;
2178            PKG.Common.EventDispatcher.registerListener(PKG.Common.Event.WidgetConf, function(evt) {
2179                if (!Object.isUndefined(window.currentWidgetConf)) {
2180                    ++this.__dirty;
2181                }
2182            }.bind(this));
2183        },
2184
2185        /**
2186            @description
2187                Creates an Ajax.Request
2188            @param {String} uri
2189                Relative request uri (createUrl is invoked)
2190            @param {Object} [ajaxOptions={}]
2191                Options passed to the Ajax.Request
2192            @param {Object} [queryParams={}]
2193                Query parameter passed to the Ajax.Request
2194            @param {Object} [proxyParams={doProcess: [false]}]
2195                If doProcess is set to true, beng proxy will process response
2196            @type Ajax.Request
2197        */
2198        doRequest: function(uri, ajaxOptions, queryParams, proxyParams) {
2199            // prepare it
2200            var httpUrl = new PKG.HttpURL(this.createUrl(uri, proxyParams));
2201            var options = $H(ajaxOptions || {});
2202            var params = options.get("parameters") || {};
2203            var pair = null;
2204            var _uri;
2205
2206            // convert to hashtable
2207            params = $H(Object.isString(params) ? params.toQueryParams() : params);
2208
2209            // merge params via httpUrl
2210            httpUrl.setParameters(queryParams);
2211            httpUrl.setParameters(params);
2212            pair = httpUrl.getPrototypePair();
2213
2214            //
2215            if (options.get("postBody")) {
2216                _uri = httpUrl.toExternalForm();
2217            } else {
2218                _uri = pair.url;
2219                options.set("parameters", pair.parameters);
2220            }
2221
2222            return new Ajax.Request(_uri, options.toObject());
2223        },
2224
2225        /**
2226            @param {string} language
2227            @param {string} country
2228            @param {Function} callbackFn
2229            @type
2230                void
2231            @description
2232                calls Xlate.invoke, which invokes callbackFn with xlate-object as first parameter
2233        */
2234        invokeXlate: function(language, country, callbackFn) {
2235            Xlate.invoke({
2236                namespace: this.getCatalogNameFromClassId(),
2237                language: language,
2238                country: country,
2239                callback: callbackFn,
2240                urlGenerator: function(defaultUriIsIgnoredHere, namespace, language, country) {
2241                    return this.createUrl(
2242                        "res/LC_MESSAGES/" + language + (country ? "_" + country : "") + namespace + ".js");
2243                }.bind(this)
2244            });
2245        },
2246
2247        /**
2248            @private
2249        */
2250        getCatalogNameFromClassId: function() {
2251            if (!this.definition.classId) {
2252                throw new Error("definition.classId must be set!");
2253            }
2254
2255            return this.definition.classId.split(/\./).last().sub(/^./, function(match) {
2256                return match[0].toLowerCase();
2257            });
2258        },
2259
2260        /**
2261            @private
2262        */
2263        getLocale: function() {
2264            var editro, locale, language_country, country;
2265            try{
2266                try{
2267                    editro = cm4all.Common.Widget.getEditro();
2268                }catch(e){
2269                    Common.log(e);
2270                }
2271                if(editro){
2272                    var xlate = editro.getXlate();
2273                    if(xlate){
2274                        return {
2275                            "language" : xlate.language,
2276                            "country" : xlate.country
2277                        };
2278                    }
2279                }
2280                locale = window.locale || parent.locale || navigator.language || navigator.browserLanguage;
2281                if(locale){
2282                    language_country = locale.split(/[-_]/);
2283                    country;
2284                    if(language_country.length < 2){
2285                        switch(language_country[0]){
2286                            case "en":
2287                                country = "US";
2288                                break;
2289                            default:
2290                                country = language_country[0].toUpperCase();
2291                        }
2292                    }else{
2293                        country = language_country[1];
2294                    }
2295                    return {
2296                        "language" : language_country[0],
2297                        "country" : country
2298                    };
2299                }
2300            }catch(e){
2301                Common.log(e);
2302                return {
2303                    language: "en",
2304                    country: "US"
2305                };
2306            }
2307            return {
2308                language: "en",
2309                country: "US"
2310            };
2311        },
2312
2313        /**
2314            @param {Function} callbackFn
2315            @param {string|boolean} [selector|false(autoInit off)]
2316            @param {boolean} if true ui-theme.css is not loaded
2317            @type
2318                void
2319            @description
2320                <strong>Note: Not available on published website!</strong><br/>
2321                Loads all libraries required for GUI-Renderer and invokes
2322                callbackFn when finished.<br/>
2323                If selector is false, no automatic rendering is done.<br/>
2324                If selector is undefined, the first form is automatically rendered.<br/>
2325                If selector is a string, the form identified by the selector
2326                is automatically rendered.
2327
2328                func
2329
2330                {
2331                    onSuccess : func
2332                    onError : func
2333                }
2334
2335        */
2336        loadGuiRenderer: function(callbackFn, selector, noUITheme) {
2337            var self = this;
2338            var onBootstrapLoaded = function() {
2339                var ld = {
2340                    css: [],
2341                    js: []
2342                };
2343                try {
2344                    ld = jQuery.cm4all.guilib.bootstrap.data;
2345                    if(!ld){
2346                        throw new Error("No data");
2347                    }
2348                } catch (e) {
2349                    PKG.Common.log("No guilib bootstrap data found");
2350                    try{
2351                        ld = PKG.Common.Widget.getMainWindow().jQuery.cm4all.guilib.bootstrap.data;
2352                    }catch(e){
2353                        PKG.Common.log("No guilib bootstrap data found in main window");
2354                    }
2355                }
2356                if (typeof ld.css == 'string') {
2357                    ld.css = [ld.css];
2358                }
2359                if(noUITheme !== true){
2360                    ld.css.push("/.cm4all/e/dynamic/ui-theme.css");
2361                }
2362                // load css stuff
2363                PKG.Common.loadCss(ld.css);
2364                // load libraries
2365                PKG.Common.requireLibrary(ld.js, function() {
2366                    var onRequireLibrary = function() {
2367                        var locale;
2368                        //support for guilib 2.1.x
2369                        if (window.cm4all.ui.OPTIONS && window.cm4all.ui.OPTIONS.RENDER_MODE) {
2370                            locale = self.getLocale();
2371                            Xlate.invoke({
2372                                namespace: "guilib",
2373                                language: locale.language,
2374                                country: locale.country,
2375                                callback: function(xlate) {
2376
2377                                    var guilibLocale = !jQuery.isEmptyObject(xlate.data) ? xlate : {};
2378                                    guilibLocale[window.cm4all.ui.OPTIONS.I18N_LANGUAGE] = locale.language;
2379                                    guilibLocale[window.cm4all.ui.OPTIONS.I18N_COUNTRY] = locale.country;
2380                                    jQuery.cm4all.guilib.getRenderer().setOption(
2381                                        window.cm4all.ui.OPTIONS.I18N,
2382                                        guilibLocale);
2383
2384                                    if (selector === false) {
2385                                        // no automatic rendering
2386                                        // only callback is called
2387                                        if (Object.isFunction(callbackFn)) {
2388                                            callbackFn(jQuery);
2389                                        }
2390                                    } else {
2391                                        var adaptOptions = {};
2392                                        adaptOptions[window.cm4all.ui.OPTIONS.RENDER_MODE] = window.cm4all.ui.VALUES.RENDER_MODE_CONFIG;
2393
2394                                        // workaround for inline render mode
2395                                        var editro = null;
2396                                        try {
2397                                            editro = PKG.Common.Widget.getEditro();
2398                                        } catch (ignored) {
2399                                        }
2400                                        var stub = editro && editro.get
2400Stub() || null;
2401                                        if (stub && stub.skin == "toi") {
2402                                            try {
2403                                                if (self.definition && self.definition.base && self.definition.base.indexOf("action=showNotifications") != -1) { 
2404                                                   adaptOptions[ window.cm4all.ui.OPTIONS.RENDER_MODE ] = window.cm4all.ui.VALUES.RENDER_MODE_INLINE;
2405                                                }
2406                                            } catch (ignored) {}
2407                                        }
2408
2409                                        // error callback is called if an error occures while rendering
2410                                        adaptOptions[window.cm4all.ui.OPTIONS.ERROR_CALLBACK] = function( /*the error*/ throwable) {
2411                                            window.console && window.console.error && window.console.error(throwable);
2412                                        };
2413
2414                                        if (window.currentWidgetConf && window.currentWidgetConf.options) {
2415                                            adaptOptions[window.cm4all.ui.OPTIONS.DIALOG_TITLE] = window.currentWidgetConf.options.dialogTitle;
2416                                            if (window.currentWidgetConf.options.dialogSize) {
2417                                                //normalize dialog size
2418                                                var h = window.currentWidgetConf.options.dialogSize.height;
2419                                                var w = window.currentWidgetConf.options.dialogSize.width;
2420                                                var sizeClass;
2421                                                if (w <= 400 && h <= 150) {
2422                                                    sizeClass = 'xsmall';
2423                                                } else if (w <= 400) {
2424                                                    sizeClass = 'small';
2425                                                } else if (w <= 600) {
2426                                                    sizeClass = 'medium';
2427                                                } else {
2428                                                    sizeClass = 'large';
2429                                                }
2430                                                adaptOptions[window.cm4all.ui.OPTIONS.DIALOG_PREFERRED_SIZE] = sizeClass;
2431                                            }
2432                                        }
2433
2434                                        if (parent.closeWidgetConfiguration) {
2435                                            adaptOptions[window.cm4all.ui.OPTIONS.DIALOG_CLOSE_ACTION] =
2436                                                parent.closeWidgetConfiguration.bind(parent, false);
2437                                        }
2438
2439                                        // render callback is called after rendering
2440                                        if (Object.isFunction(callbackFn)) {
2441                                            adaptOptions[window.cm4all.ui.OPTIONS.RENDER_CALLBACK] = callbackFn;
2442                                        }
2443
2444                                        window.cm4all.ui.adapt(
2445                                            jQuery(selector || 'form:first'),
2446                                            adaptOptions);
2447                                    }
2448                                }
2449                            });
2450                        } else {
2451                            //support guilib before 2.1.x
2452                            try {
2453                                /* Workaround for IE having problems with behaviours when overlay is loaded too late */
2454                                window.cm4all.ui.overlay(jQuery("<div id=\"io-" + (new Date().getTime()) + "\"></div>"), {
2455                                    "autoShow": false
2456                                });
2457                            } catch (e) {
2458                                PKG.Common.log(e.message);
2459                            }
2460
2461                            if (selector === false) {
2462                                // no automatic rendering
2463                                // only callback is called
2464                                if (Object.isFunction(callbackFn)) {
2465                                    callbackFn(jQuery);
2466                                }
2467                            } else {
2468                                //support for guilib 2.0.x
2469                                var options = {};
2470                                // error callback is called if an error occures while rendering
2471                                options[jQuery.cm4all.guilib.theme.OPTIONS.ERROR_CALLBACK] = function( /*the error*/ throwable) {
2472                                    window.console && window.console.error && window.console.error(throwable);
2473                                };
2474                                // render callback is called after rendering
2475                                options[jQuery.cm4all.guilib.theme.OPTIONS.RENDER_CALLBACK] = Object.isFunction(callbackFn) ? callbackFn : function() {};
2476                                options[jQuery.cm4all.guilib.theme.OPTIONS.IS_WIDGET_CONFIG] = true;
2477                                if (jQuery.cm4all.guilib.themes.generic.OPTIONS.DIALOG_CLOSE_ACTION) {
2478                                    options[jQuery.cm4all.guilib.themes.generic.OPTIONS.DIALOG_CLOSE_ACTION] =
2479                                        parent.closeWidgetConfiguration ?
2480                                        parent.closeWidgetConfiguration.bind(parent, false) :
2481                                        false;
2482                                }
2483                                jQuery.cm4all.guilib.theme.adapt(
2484                                    jQuery(selector || 'form:first'),
2485                                // additional renderer options
2486                                options);
2487                            }
2488                        }
2489                    };
2490                    if (document.readyState != 'loading') {
2491                        onRequireLibrary();
2492                    } else {
2493                        document.addEventListener('DOMContentLoaded', onRequireLibrary);
2494                    }
2495                });
2496            };
2497
2498            onBootstrapLoaded();
2499        },
2500
2501        /**
2502            @private
2503            @param {Function} callbackFn
2504            @param {String|Array} [additionalLibs=[]]
2505            @type
2506                void
2507            @description
2508                Loads all libraries required for Widget Runtime and invokes
2509                callbackFn when finished
2510            @deprecated
2511                Since version 0.3.20<br/>
2512                Use <a href="Common.html#.requireLibrary">Common.requireLibrary</a> instead to load required libraries.<br/>
2513                The widget-runtime libraries are already loaded by including <strong>/res/js/lib/widget-runtime.js</strong>.<br/>
2514                This calls Common.requireLibrary for additionalLibs with callbackFn.
2515        */
2516        loadWidgetRuntime: function(callbackFn, additionalLibs) {
2517            // load libraries
2518            PKG.Common.requireLibrary(additionalLibs || [], callbackFn);
2519        },
2520
2521        /**
2522            @param {string} path
2523                path to rewrite
2524            @param {Object} [proxyParams={doProcess: [false]}]
2525                If doProcess is set to true, beng proxy will process response
2526            @type
2527                string
2528            @description
2529                creates an url from an url relative to the widget for
2530                requesting e.g. resources
2531                The mode is proxy and partial when doProcess is set.
2532                See <a href="http://mke-doc.intern.cm-ag/doc/cm4all-beng-proxy-doc/beng.pdf">beng-proxy documentation</a>
2533                for details.
2534                If no beng-proxy is present, the path is returned unchanged.
2535        */
2536        createUrl: function(path, proxyParams) {
2537            if (typeof(beng_widget_uri) != "undefined" && Object.isFunction(beng_widget_uri)) {
2538                return beng_widget_uri(
2539                    this.definition.base, // base_uri
2540                    this.definition.session, // session_id
2541                    this.definition.frame, // frame
2542                    this.definition.path, // focus
2543                    "partial", // mode
2544                    path ? path : null, // path
2545                    null, // translate
2546                    null // view
2547                );
2548            }
2549
2550            if (this.__dirty > 0) {
2551                path = path.replace(/\/cc=([0-9]+)/, "/cc=$1_" + this.__dirty);
2552            }
2553
2554            return path;
2555        },
2556
2557        /**
2558            @param {string} path
2559                path to rewrite
2560            @type
2561                string
2562            @description
2563                creates a static url relative to the widget class
2564        */
2565        createStaticClassUrl: function(path) {
2566            if (!this.definition.classId) {
2567                throw new Error("definition.classId must be set!");
2568            }
2569            return "/.cm4all/widgetres.php/" + this.definition.classId + (path.indexOf("/") != 0 ? "/" : "") + path;
2570        },
2571
2572        /**
2573            @param {string} path
2574                path to rewrite
2575            @type
2576                string
2577            @description
2578                creates an url to a common resource
2579        */
2580        createCommonUrl: function(path) {
2581            if (window.beng && window.beng.env && window.beng.env.common_prefix) {
2582                return window.beng.env.common_prefix + path;
2583            }
2584
2585            return path;
2586        },
2587        /**
2588            @param {Common.Event} eventClass
2589                the eventClass of the event to dispatch.
2590            @param {Array} constructorArguments
2591                event-specific array of arguments for the event-constructor. See
2592                documentation on each event-class for details.
2593            @type
2594                void
2595            @description
2596                fires a new event of the given event-class with the current widget-
2597                instance as event-source.
2598        */
2599        fireEvent: function(eventClass, constructorArguments) {
2600            var wiid = this.definition.frame;
2601            var editro = cm4all.Common.Widget.getEditro();
2602            var wcid = editro.widgetCatalog[wiid].wcid;
2603            var widget = cm4all.Common.Widget.getMainWindow().beng.WidgetManager.getInstance(wcid, wiid);
2604            constructorArguments.unshift(widget);
2605            constructorArguments.unshift(editro);
2606            // TODO: unschön hier: der Konstruktor wird 2mal aufgerufen. FIXME!
2607            var ev = new eventClass(editro, widget);
2608            ev.initialize.apply(ev, constructorArguments);
2609            PKG.Common.EventDispatcher.fireEvent(ev);
2610        },
2611
2612        /**
2613            @param {string} maxWidth
2614                the maxWidth of the widgetContainer
2615            @param {string} mediaQuery
2616                a css mediaquery
2617            @type
2618                void
2619            @description
2620                adds a style element to the page to set the maxWidth
2621                of a widget container. Use the mediaquery for responsive designs.<br/>
2622                Used for display only; does not actually change the widget headers!
2623                Example:
2624                widget.setWidgetMaxWidth(
2625                        "30%",
2626                        "all and (max-width: 480px)"
2627                    );
2628        */
2629        setWidgetMaxWidth: function(maxWidth, mediaquery) {
2630            if (!this.definition.wiid) {
2631                throw new Error("definition.wiid must be set!");
2632            }
2633            var mqs = "";
2634            var mqe = "";
2635            if (mediaquery) {
2636                mqs = "@media " + mediaquery + " {";
2637                mqe = "}";
2638            }
2639
2640            jQuery("<style>" + mqs + " #widgetcontainer_" + this.definition.wiid + "{max-width: " + maxWidth + " 
2640!important;}" + mqe + "</style>").appendTo("head");
2641        },
2642
2643        /**
2644            @param {string} mediaQuery
2645                a css mediaquery
2646            @type
2647                void
2648            @description
2649                Changes the widget display from 'inline-block' to 'block'.<br/>
2650                Used for display only; does not actually change the widget headers!
2651                Example:
2652                widget.setWidgetToBlock(
2653                        "all and (max-width: 480px)"
2654                    );
2655            */
2656        setWidgetToBlock: function(mediaquery) {
2657            if (!this.definition.wiid) {
2658                throw new Error("definition.wiid must be set!");
2659            }
2660            var mqs = "";
2661            var mqe = "";
2662            if (mediaquery) {
2663                mqs = "@media " + mediaquery + " {";
2664                mqe = "}";
2665            }
2666
2667            jQuery("<style>" + mqs + " #widgetcontainer_" + this.definition.wiid + "{width: 100% !important; max-width: 100% !important;}" + mqe + "</style>").appendTo("head");
2668        }
2669    })
2670});
2671
2672Object.extend(PKG.Common.Widget,
2673/**
2674    @lends Common.Widget
2675*/
2676{
2677    /**
2678        @type
2679            cm4all.Editro
2680        @description
2681            returns the instance of editro
2682    */
2683    getEditro: function() {
2684        var editro = Try.these(function() {
2685            return cm4all.Editro.getInstance();
2686        }, function() {
2687            return parent.cm4all.Editro.getInstance();
2688        }, function() {
2689            return parent.parent.cm4all.Editro.getInstance();
2690        }, function() {
2691            return controlpanel.getEditorWnd().cm4all.Editro.getInstance();
2692        }, function() {
2693            return top.frames["main-frame"].cm4all.Editro.getInstance();            // sites + hcr
2694        }, function() {
2695            return top.frames["editorWebsiteIFrame"].cm4all.Editro.getInstance();   // w4b
2696        }) || null;
2697        if (!editro) {
2698            throw new Error("No editor context found! (Are you trying to access editor in published website?)");
2699        }
2700        return editro;
2701    },
2702
2703    /**
2704        @type
2705            DOMWindow
2706        @description
2707            returns the main environment window (was: getTopWindow())
2708    */
2709    getMainWindow: function() {
2710        var editro = null;
2711        try {
2712            editro = PKG.Common.Widget.getEditro();
2713        } catch (ignoredinthiscontext) {}
2714        if (editro) {
2715            return editro.getMainWindow();
2716        } else {
2717            Common.log("Falling back to 'getTopWindow()'!");
2718            return getTopWindow();
2719        }
2720    },
2721
2722    /**
2723        @type
2724            DOMWindow
2725        @description
2726            returns the a Popup implementation instance
2727    */
2728    getPopupImpl: function() {
2729        var popup = Try.these(function() {
2730            return PKG.Common.Widget.getEditro().getStub().getPopupImpl();
2731        }, function() {
2732            // this only works if guistrap is already loaded in main window
2733            return new (Common.Widget.getMainWindow()).cm4all.Infrastructure.GuistrapPopup();
2734        }, function() {
2735            // this only works if guistrap is already loaded
2736            return new cm4all.Infrastructure.GuistrapPopup();
2737        }, function() {
2738            // this only works if guilib is already loaded
2739            return new cm4all.Infrastructure.GuilibPopup();
2740        });
2741        return popup;
2742    }
2743});
2744
2745/* works only with NS window.cm4all */
2746if (PKG === window.cm4all && !PKG.Common.Event) {
2747    Object.extend(PKG.Common, {
2748        Event: Class.create(
2749        /**
2750            @lends Common.Event#
2751        */
2752        {
2753            __isEvent: true,
2754            clsid: "PKG.Common.Event",
2755            /**
2756            @description
2757                Base class for events
2758            @constructs
2759            @param {Object} source
2760                the source to be reported by the event
2761            */
2762            initialize: function(source) {
2763                this.__source = source;
2764            },
2765            /**
2766             * @type
2767             *      Object
2768             * @description
2769             *      returns the event-source of this event-object
2770             */
2771            getSource: function() {
2772                return this.__source;
2773            }
2774        })
2775    });
2776
2777    cm4all.Common.Event.WidgetConf = Class.create(cm4all.Common.Event, {
2778        clsid: "cm4all.Common.Event.WidgetConf",
2779        initialize: function($super, func) {
2780            $super(func);
2781        }
2782    });
2783}
2784
2785if (PKG === window.cm4all && !PKG.Common.EventDispatcher) {
2786    Object.extend(PKG.Common,
2787    /**
2788        @lends Common
2789    */
2790    {
2791        /**
2792        @class
2793        @description
2794            Static object to register/unregister event-listeners and to fire events
2795        */
2796        EventDispatcher:
2797        /**
2798            @lends Common.EventDispatcher
2799        */
2800        {
2801            __id: new Date().toTimeString() + Math.random(),
2802            __eventListeners: {},
2803
2804            /**
2805            @param {Common.Event} uiEvent
2806                the event instance to be fired
2807            @param {boolean} async
2808                if 'true' the event is fired in a separate thread.
2809            @type
2810                void
2811            @description
2812                fires the given event-instance -  all event-listeners registered for
2813                events of this class or any of this event's class superclasses in any
2814                window from the current window up to the top-window are notified.
2815            */
2816            fireEvent: function(uiEvent, async) {
2817                var currentClass, listenerList, i, oWindow, common;
2818                var cWindow = window;
2819                do {
2820                    common = cWindow.cm4all.Common;
2821                    if (common) {
2822                        currentClass = uiEvent.constructor;
2823                        do {
2824                            listenerList = common.EventDispatcher.__eventListeners[currentClass.prototype.clsid] || (common.EventDispatcher.__eventListeners[currentClass.prototype.clsid] = []);
2825                            if (listenerList) {
2826                                for (i = 0; i < listenerList.length; i++) {
2827                                    if (!async) {
2828                                        listenerList[i].call(cWindow, uiEvent);
2829                                    } else {
2830                                        (function() {
2831                                            var _cWindow = cWindow;
2832                                            var currentFunction = listenerList[i];
2833                                            _cWindow.setTimeout(function() {
2834                                                currentFunction.call(_cWindow, uiEvent);
2835                                            }, 0);
2836                                        })();
2837                                    }
2838                                }
2839                            }
2840                        } while (currentClass = /* sic! */ currentClass.superclass);
2841                    }
2842                    oWindow = cWindow;
2843                    cWindow = cWindow.parent;
2844                } while (oWindow != cWindow && cWindow.cm4all && cWindow.cm4all.Common);
2845            },
2846
2847            /**
2848                @param {Common.Event} eventClass
2849                    the event-class to register a listener for
2850                @param {Function} listener
2851                    the listener function to be called if an event of the given
2852                    class is fired. the listener is passed the event-object as first
2853                    (and only) parameter.
2854                @type
2855                    void
2856                @description
2857                    registers a listener for events of the given class.
2858            */
2859            registerListener: function(eventClass, listener) {
2860                if (!eventClass.prototype.__isEvent) {
2861                    throw new Error("Not an Event class: " + eventClass.toString());
2862                }
2863                var common = PKG.Common;
2864                var listenerList = common.EventDispatcher.__eventListeners[eventClass.prototype.clsid] || (common.EventDispatcher.__eventListeners[eventClass.prototype.clsid] = []);
2865                listenerList.push(listener);
2866            },
2867
2868            /**
2869                @param {Common.Event} eventClass
2870                    the event-class to deregister a listener for
2871                @param {Function} listener
2872                    the listener function that is to be removed form the list of registered
2873                    listeners. .
2874                @type
2875                    void
2876                @description
2877                    deregisters a listener for events of the given class.
2878                    NOTE: only listeners registered in the current window will
2879                    be removed, if the same listener is registered in different windows you have
2880                    to deregister it seperately
2881            */
2882            deregisterListener: function(eventClass, listener) {
2883                if (!eventClass.prototype.__isEvent) {
2884                    throw new Error("Not an Event class: " + eventClass.toString());
2885                }
2886                var common = PKG.Common;
2887                var listenerList = common.EventDispatcher.__eventListeners[eventClass.prototype.clsid] || (common.EventDispatcher.__eventListeners[eventClass.prototype.clsid] = []);
2888                var i;
2889                for (i = listenerList.length - 1; i >= 0; i--) {
2890                    if (listener === listenerList[i]) {
2891                        listenerList.splice(i, 1);
2892                    }
2893                }
2894            }
2895        }
2896    });
2897}
2898
2899// TODO: remove this
2900window.Common.Widget = PKG.Common.Widget;
2901})((function() {
2902    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
2903        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
2904    }
2905    if (typeof(window.cm4all) == "undefined") {
2906        window.cm4all = {};
2907    }
2908    return window.cm4all;
2909})());
2910    };
2911    if(window.__loadedJsLibraries["/res/js/lib/Common.MobileBrowserSwitch.js"] !== true){
2912        window.__loadedJsLibraries["/res/js/lib/Common.MobileBrowserSwitch.js"] = true;
2913        (function(PKG) {
2914"PKG:nomunge"
2915//-WRAP switch on library wrapping
2916Object.extend(PKG.Common, {
2917
2918    MobileBrowserSwitch: {
2919
2920        mobileAgents: [
2921        /* DEVICES ... */
2922        /* Apple */
2923        "iphone", "ipod",
2924        /* Blackberry */
2925        "blackberry",
2926        /* Palm */
2927        "pre/", "palm", "hiptop", "avantgo", "plucker", "xiino", "blazer", "elaine",
2928        /* Bada */
2929        "bada/",
2930        /* E-Book-Reader */
2931        "kindle",
2932        /* OS ... */
2933        /* Android */
2934        "android",
2935        /* Windows Mobile */
2936        "iris", "3g_t", "windows ce",
2937        /* Windows Phone */
2938        "windows phone",
2939        /* BROWSERS ... */
2940        /* IE */
2941        "iemobile",
2942        /* Opera */
2943        "opera mini", "opera mobi"],
2944
2945        isMobileAgent: function(_userAgent) {
2946            var i;
2947            _userAgent = _userAgent.toLowerCase();
2948            for (i = 0; i < MobileBrowserSwitch.mobileAgents.length; i++) {
2949                if (_userAgent.indexOf(MobileBrowserSwitch.mobileAgents[i]) != -1) {
2950                    return true;
2951                }
2952            }
2953            return false;
2954        }
2955    }
2956});
2957
2958// deprecated
2959window.MobileBrowserSwitch = PKG.Common.MobileBrowserSwitch;})((function() {
2960    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
2961        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
2962    }
2963    if (typeof(window.cm4all) == "undefined") {
2964        window.cm4all = {};
2965    }
2966    return window.cm4all;
2967})());
2968    };
2969    if(window.__loadedJsLibraries["/res/js/lib/Strftime.js"] !== true){
2970        window.__loadedJsLibraries["/res/js/lib/Strftime.js"] = true;
2971        (function(PKG) {
2972"PKG:nomunge"
2973//-WRAP switch on library wrapping
2974// äöü utf-8 mode on
2975
2976/**
2977    @name Strftime
2978    @namespace
2979    @description
2980        Javascript strftime implementation
2981*/
2982PKG.Strftime = ({});
2983
2984Object.extend(PKG.Strftime,
2985/**
2986    @lends Strftime
2987*/
2988{
2989    /**
2990        @class
2991        @static
2992        @description
2993            Converts date strings to Date objects
2994    */
2995    Date: (
2996    /**
2997        @lends Strftime.Date
2998    */
2999    {
3000        /**
3001            @description
3002                Converts an UTC iso timestamp (yyyy-mm-dd HH:MM:SS)
3003                into a Date object
3004            @type Date
3005            @param {String} tstr
3006                datestring to convert in iso format
3007        */
3008        fromUtcIso: function(tstr) {
3009            return PKG.Strftime.Date.fromIso(tstr, true);
3010        },
3011
3012        /**
3013            @description
3014                Converts an iso timestamp (yyyy-mm-dd HH:MM:SS)
3015                into a Date object
3016            @type Date
3017            @param {String} tstr
3018                datestring to convert in iso format
3019            @param {boolean} [isUtc=false]
3020                set to true, if datestring is utc or use {@link Strftime.Date.fromUtcIso}
3021        */
3022        fromIso: function(tstr, isUtc) {
3023            return PKG.Strftime.Date._fromPattern(tstr, [0, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19], isUtc);
3024        },
3025
3026        /**
3027            @description
3028                Converts an UTC timestamp (yyyymmddHHMMSS)
3029                into a Date object
3030            @type Date
3031            @param {String} tstr
3032                datestring to convert as timestamp
3033        */
3034        fromUtcTimestamp: function(tstr) {
3035            return PKG.Strftime.Date.fromTimestamp(tstr, true);
3036        },
3037
3038        /**
3039            @description
3040                Converts an timestamp (yyyymmddHHMMSS)
3041                into a Date object
3042            @type Date
3043            @param {String} tstr
3044                datestring to convert as timestamp
3045            @param {boolean} [isUtc=false]
3046                set to true, if datestring is utc or use {@link Strftime.Date.fromUtcTimestamp}
3047        */
3048        fromTimestamp: function(tstr, isUtc) {
3049            return PKG.Strftime.Date._fromPattern(tstr, [0, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14], isUtc);
3050        },
3051
3052        /**
3053            @private
3054            @description
3055                Helper method to convert date strings to javascript Date objects
3056            @type Date
3057            @param {String} tstr
3058                Time string to convert to a date object
3059            @param {Number[]} p
3060                Number array, which contains information how to split the string in parts
3061            @example
3062                Strftime.Date._fromPattern("19740101180512", [0,4,4,6,6,8,8,10,10,12,12,14])
3063        */
3064        _fromPattern: function(tstr, p, isUtc) {
3065            return function(y, m, d, H, M, S) {
3066                return (isUtc ? new Date(Date.UTC(y, m, d, H, M, S)) : new Date(y, m, d, H, M, S));
3067            }.apply(
3068                this, [
3069                tstr.substring(p[0], p[1]),
3070                tstr.substring(p[2], p[3]) - 1,
3071                tstr.substring(p[4], p[5]),
3072                tstr.substring(p[6], p[7]),
3073                tstr.substring(p[8], p[9]),
3074                tstr.substring(p[10], p[11])
3075            ]);
3076        }
3077    }),
3078
3079    /**
3080        @description
3081            Converts a strftime format string and a Date object to a date string
3082        @example
3083format: (currently supported subset of strftime)
3084    %a    The abbreviated weekday name according to the current locale.
3085    %A    The full weekday name according to the current locale.
3086    %b    The abbreviated month name according to the current locale.
3087    %B    The full month name according to the current locale.
3088    %d    The day of the month as a decimal number (range 01 to 31).
3089    %e    Like %d, the day of the month as a decimal number, but a leading
3090          zero is replaced by a space. (SU)
3091    %H    The  hour as a decimal number using a 24-hour clock (range 00 to
3092          23).
3093    %I    The  hour as a decimal number using a 12-hour clock (range 01 to
3094          12).
3095    %k    The hour (24-hour clock) as a decimal number (range  0  to  23);
3096          single digits are preceded by a blank. (See also %H.) (TZ)
3097    %l    The  hour  (12-hour  clock) as a decimal number (range 1 to 12);
3098          single digits are preceded by a blank. (See also %I.) (TZ)
3099    %m    The month as a decimal number (range 01 to 12).
3100    %M    The minute as a decimal number (range 00 to 59).
3101    %n    A newline character. (SU)
3102    %p    Either `AM' or `PM' according to the given time  value,  or  the
3103          corresponding  strings  for the current locale.  Noon is treated
3104          as `pm' and midnight as `am'.
3105    %S    The second as a decimal number (range 00 to 60).  (The range  is
3106          up to 60 to allow for occasional leap seconds.)
3107    %y    The year as a decimal number without a century (range 00 to 99).
3108    %Y    The year as a decimal number including the century.
3109        @param {String} format
3110            strftime format string (as described below)
3111        @param {Date} date
3112            Javascript Date object to format
3113        @param {String} language
3114            Language identifier in ISO format (e.g. en,de,..)
3115        @param {String} country
3116            Country identifier in ISO format (e.g. US,DE,..)
3117    */
3118
3119    format: function(format, date, language, country) {
3120        var result = format;
3121        var config = PKG.Strftime.getConfig(language, country);
3122        var r_year = date.getFullYear();
3123        var r_month = date.getMonth();
3124        var r_date = date.getDate();
3125        var r_day = date.getDay();
3126        var r_hours = date.getHours();
3127        var r_minutes = date.getMinutes();
3128        var r_seconds = date.getSeconds();
3129        var year = "" + r_year;
3130        var usHours = (r_hours > 12 ? r_hours - 12 : (r_hours == 0 ? 12 : r_hours));
3131        var sNoon = (r_hours >= 12 ? "PM" : "AM");
3132        var ftable = [
3133                /%a/g, config.dayNames[r_day].substring(0, config.dayShortcutLength),
3134                /%A/g, config.dayNames[r_day],
3135                /%b/g, config.monthNames[r_month].substring(0, config.monthShortcutLength),
3136                /%B/g, config.monthNames[r_month],
3137                /%d/g, (r_date < 10 ? "0" : "") + r_date,
3138                /%e/g, (r_date < 10 ? " " : "") + r_date,
3139                /%H/g, (r_hours < 10 ? "0" : "") + r_hours,
3140                /%I/g, (usHours < 10 ? "0" : "") + usHours,
3141                /%k/g, (r_hours < 10 ? " " : "") + r_hours,
3142                /%l/g, (usHours < 10 ? " " : "") + usHours,
3143                /%m/g, (r_month < 9 ? "0" : "") + (r_month + 1),
3144                /%M/g, (r_minutes < 10 ? "0" : "") + r_minutes,
3145                /%n/g, "\n",
3146                /%p/g, sNoon,
3147                /%S/g, (r_seconds < 10 ? "0" : "") + r_seconds,
3148                /%y/g, year.substring(2, 4),
3149                /%Y/g, year
3150        ];
3151
3152        for (var i = 0; i < ftable.length; i += 2) {
3153            result = result.replace(ftable[i], ftable[i + 1]);
3154        }
3155
3156        return result;
3157    },
3158
3159    /**
3160        @private
3161        @description
3162            Get a configuration object for Strftime
3163        @type Object
3164        @param {String} language
3165            Language identifier in ISO format (e.g. en,de,..)
3166        @param {String} country
3167            Country identifier in ISO format (e.g. US,DE,..)
3168    */
3169    getConfig: function(language, country) {
3170        return (PKG.Strftime.configuration[language] || PKG.Strftime.configuration["en"]);
3171    },
3172
3173    /**
3174        @private
3175    */
3176    configuration: {
3177
3178        de: {
3179            monthNames: ["Januar", "Februar", "März", "April", "May", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
3180            dayNames: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
3181            week: [1, 2, 3, 4, 5, 6, 0],
3182            monthShortcutLength: 3,
3183            dayShortcutLength: 2
3184        },
3185
3186        en: {
3187            monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
3187November", "December"],
3188            dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
3189            week: [0, 1, 2, 3, 4, 5, 6],
3190            monthShortcutLength: 3,
3191            dayShortcutLength: 3
3192        },
3193
3194        it: {
3195            monthNames: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"],
3196            dayNames: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"],
3197            week: [1, 2, 3, 4, 5, 6, 0],
3198            monthShortcutLength: 3,
3199            dayShortcutLength: 2
3200        },
3201
3202        es: {
3203            monthNames: ["Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"],
3204            dayNames: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
3205            week: [0, 1, 2, 3, 4, 5, 6],
3206            monthShortcutLength: 3,
3207            dayShortcutLength: 2
3208        },
3209
3210        pt: {
3211            monthNames: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
3212            dayNames: ["Domingo", "Segunda-feira", "Terça-feira", "Quarta-feira", "Quinta-feira", "Sexta-feira", "Sábado"],
3213            week: [0, 1, 2, 3, 4, 5, 6],
3214            monthShortcutLength: 3,
3215            dayShortcutLength: 3
3216        },
3217
3218        jp: {
3219            monthNames: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
3220            dayNames: ["日", "月", "火", "水", "木", "金", "土"],
3221            week: [0, 1, 2, 3, 4, 5, 6],
3222            monthShortcutLength: 100,
3223            dayShortcutLength: 100
3224        },
3225
3226        pl: {
3227            monthNames: ["stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "pazdziernika", "listopada", "grudnia"],
3228            dayNames: ["niedziela", "poniedziałek", "wtorek", "środa", "czwartek", "piątek", "sobota"],
3229            week: [1, 2, 3, 4, 5, 6, 0],
3230            monthShortcutLength: 3,
3231            dayShortcutLength: 3
3232        }
3233    }
3234});
3235
3236window.Strftime = PKG.Strftime;
3237})((function() {
3238    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
3239        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
3240    }
3241    if (typeof(window.cm4all) == "undefined") {
3242        window.cm4all = {};
3243    }
3244    return window.cm4all;
3245})());
3246    };
3247    if(window.__loadedJsLibraries["/res/js/lib/Xlate.js"] !== true){
3248        window.__loadedJsLibraries["/res/js/lib/Xlate.js"] = true;
3249        (function(PKG) {
3250"PKG:nomunge"
3251//-WRAP switch on library wrapping
3252// äöü utf-8 mode on
3253
3254PKG.Xlate = Class.create(
3255/**
3256    @lends Xlate#
3257*/
3258{
3259    namespace: null,
3260    language: null,
3261    country: null,
3262    /*
3263        translations : new Hash(),
3264        pluralrule : function() { return "r1"; }
3265    */
3266    data: null,
3267
3268    /**
3269        @constructs
3270        @description
3271            Javascript xlate implementation.<br/>
3272            DO NOT generate the class directly, use {@link Xlate.load}
3273            or {@link Xlate.invoke} instead.
3274    */
3275    initialize: function(namespace, language, country, urlGenerator) {
3276        this.namespace = namespace;
3277        this.language = language;
3278        this.country = country;
3279        this.data = {};
3280    },
3281
3282    /**
3283        @private
3284    */
3285    setData: function(data) {
3286        if (data != null) {
3287            this.data = data;
3288        }
3289    },
3290
3291    /**
3292        @description
3293            Translates key using variables.
3294        @type void
3295        @param {String} key
3296            The xlate key
3297        @param {Object} [variables=null]
3298            An object containing name-value definition of variables used in
3299            key.
3300        @example
3301xlate.format("${#entries} entry/entries", { entries : 5 });
3302xlate.format(
3303    "${pubDate%T:%A, %e. %B %Y, %H:%M} ${author}",
3304    { pubDate : Strftime.Date.fromTimestamp("19740118180500"),
3305      author : "Me" }
3306);
3307    */
3308    format: function(key, variables) {
3309
3310        var ns = this.data.translations;
3311        var ret = null;
3312        var numerus = null;
3313
3314        variables = $H(variables || {});
3315        ret = ns ? ns.get(key) : key;
3316
3317        if (ret != null) {
3318
3319            var numerusIdx = key.indexOf("${#");
3320            if (numerusIdx != -1) {
3321                numerus = variables.get(key.substring(numerusIdx + 3, key.indexOf("}", numerusIdx + 3)));
3322            }
3323
3324            if (numerus != null) {
3325                var plurals = ns ? ns.get(key) : key;
3326
3327                // assure we got an object here
3328                if (!Object.isString(plurals)) {
3329                    ret = $H(plurals).get(this.data.pluralrule(numerus));
3330                }
3331            }
3332        }
3333
3334        // if no translation was found do a fallback to provided key
3335        if (!ret) {
3336            ret = key;
3337        }
3338
3339        variables.each(function(kvPair) {
3340            try {
3341                ret = ret.replace(new RegExp("\\$\\{\\#?" + kvPair.key + "(%T:[^}]*)?\\}", "g"), function(m, g) {
3342                    if (g && g.length > 3) {
3343                        return PKG.Strftime.format(g.substring(3), kvPair.value, this.language, this.country);
3344                    }
3345                    return kvPair.value;
3346                }.bind(this));
3347            } catch (e) {
3348                PKG.Common.log(ret + "\n" + kvPair.key + "\n" + this.namespace);
3349            }
3350        }.bind(this));
3351
3352        return ret;
3353    },
3354
3355    /**
3356        @description
3357            Checks if this xlate-object contains  the specified key
3358        @type boolean
3359    */
3360    hasKey: function(key) {
3361        var ret = ( !! (this.data.translations) &&
3362            ( !! (this.data.translations.get(key) == "") || !! (this.data.translations.get(key))));
3363        return ret;
3364    },
3365
3366    /**
3367        @description
3368            Translates html with the language and namespace of this xlate object.
3369        @type void
3370        @param {window} wnd
3371                The window the elements to translate belong to
3372        @param {Element} rootElement (optional)
3373                The element which children are to be translated
3374        @example
3375&lt;body onload="xlate.translateHTML();">
3376    &lt;div lang="x-late">You have to create a new buddy first&lt;/div>
3377&lt;/body>
3378    */
3379    translateHTML: function(wnd, rootElement) {
3380        var elementsToXlate;
3381        if (rootElement && rootElement.querySelectorAll) {
3382            elementsToXlate = jQuery(rootElement.querySelectorAll("[lang=x-late]"));
3383        } else {
3384            elementsToXlate = (rootElement ? wnd.jQuery(rootElement).find("[lang^=x-late]") :
3385                wnd.jQuery("[lang^=x-late]"));
3386        }
3387        elementsToXlate.each(function(wnd, i, node) {
3388            node = wnd.$(node);
3389            var id = PKG.Xlate._extractId(node);
3390            var html = this.format(id);
3391            if (html == id && id.match(/&amp;/)) {
3392                id = id.replace(/&amp;/, "&");
3393                html = this.format(id);
3394            }
3395            if (html) {
3396                node.removeAttribute("xml:lang");
3397                node.setAttribute("lang", this.language + "-" + this.country);
3398                node.update(html);
3399                // (PBT: #9368) IE Workaround.
3400                // IE puts html into several text nodes here which angular cannot handle properly.
3401                // node.normalize() does not work here.
3402                // node.innerHTML = html doesn't work either.
3403                // Only this seemingly useless assignment merges all text nodes into one.
3404                node.innerHTML = node.innerHTML
3405            }
3406        }.bind(this, wnd));
3407    }
3408});
3409
3410Object.extend(PKG.Xlate,
3411/**
3412    @lends Xlate
3413*/
3414{
3415    data: new Hash(),
3416    xlates: new Hash(),
3417
3418    /**
3419        @description
3420            Javascript xlate factory.
3421        @type void
3422        @param {String|Array} definition.namespace
3423            Namespace(s) to load, e.g. "sites" or ["sites", "beng.editor"]
3424        @param {String} definition.language
3425            Language identifier in ISO format (e.g. en,de,..)
3426        @param {String} definition.country
3427            Country identifier in ISO format (e.g. US,DE,..)
3428        @param {String} definition.callback
3429            Callback function. The first parameter passed to the function
3430            is the loaded Xlate object
3431        @param {String|Function} [definition.urlGenerator=null]
3432            An url which prefixes the language definition urls, or a
3433            url generator function which must return a url to load
3434            the definition files
3435        @return {Promise} Returns a promise which will be resolved with the xlate object
3436        @example
3437function init() {
3438    Xlate.invoke({
3439        namespace : ["sites", "beng.editor"],
3440        language : "de",
3441        country : "DE",
3442        callback : init2
3443    });
3444}
3445
3446or
3447
3448function init() {
3449    Xlate.invoke({
3450        namespace : ["sites", "beng.editor"],
3451        language : "de",
3452        country : "DE"
3453    }).done(init2);
3454}
3455
3456function init2(xlate) {
3457    // xlate object of first namespace of array of namespaces been loaded, here "sites".
3458    alert(xlate.format(
3459        "Only the following file types are supported: ${types}.",
3460        { types : "jpeg, png") }
3461    ));
3462}
3463    */
3464    invoke: function(definition) {
3465        var xlateDeferred = jQuery.Deferred();
3466        if (!Object.isArray(definition.namespace)) {
3467            definition.namespace = [definition.namespace];
3468        }
3469
3470        var refIds = definition.namespace.map(function(namespace) {
3471            return PKG.Xlate.createRefId(namespace, definition.language, definition.country);
3472        });
3473        var xlates = refIds.map(function(refId) {
3474            return PKG.Xlate.xlates.get(refId);
3475        });
3476
3477        if (xlates.all()) {
3478            definition.callback(xlates[0]);
3479            xlateDeferred.resolve(xlates[0]);
3480        } else {
3481            var urlGenerator = definition.namespace.map(function(namespace, i) {
3482                var urlGenerator = Prototype.K;
3483                if (Object.isFunction(definition.urlGenerator)) {
3484                    urlGenerator = definition.urlGenerator;
3485                } else if (Object.isString(definition.urlGenerator)) {
3486                    urlGenerator = function(url) {
3487                        return definition.urlGenerator + url;
3488                    };
3489                } else if (Object.isArray(definition.urlGenerator)) {
3490                    urlGenerator = definition.urlGenerator[i] || Prototype.K;
3491                }
3492                return urlGenerator;
3493            });
3494
3495            var urls = xlates.map(function(xlate, i) {
3496                if (xlate) {
3497                    // already loaded
3498                    return null;
3499                }
3500                var namespace = definition.namespace[i];
3501                return urlGenerator[i](
3502                    "/res/generated/i18n" + "/" + definition.language + "/" + definition.country + "/" + namespace + ".js",
3503                    namespace,
3504                    definition.language,
3505                    definition.country);
3506            }).filter(Prototype.K);
3507            PKG.Common.requireLibrary(
3508                urls, function() {
3509                // Merge all texts of additionally loaded namespaces to the first namespace.
3510                // First namespace must be installed.
3511                var data_0 = PKG.Xlate.data.get(refIds[0]);
3512                if (data_0) {
3513                    for (var i = 1; i < definition.namespace.length; i++) {
3514                        var data = PKG.Xlate.data.get(refIds[i]);
3515                        if (data) {
3516                            PKG.Xlate.set(definition.namespace[0], definition.language, definition.country,
3517                                data.translations, /*force*/ true, data_0.pluralrule);
3518                        }
3519                    }
3520                } else {
3521                    Common.log("po file not installed: " + refIds[0]);
3522                }
3523                var xlate = new PKG.Xlate(
3524                    definition.namespace[0],
3525                    definition.language,
3526                    definition.country);
3527                xlate.setData(PKG.Xlate.data.get(refIds[0]));
3528                PKG.Xlate.xlates.set(refIds[0], xlate);
3529                definition.callback(xlate);
3530                xlateDeferred.resolve(xlate);
3531            });
3532        }
3533        return xlateDeferred.promise();
3534    },
3535
3536    /**
3537        @private
3538        @description
3539            The loaded language definition file calls this method after
3540            beeing loaded
3541    */
3542    set: function(namespace, language, country, obj, force, pluralrule) {
3543        var refId = PKG.Xlate.createRefId(namespace, language, country);
3544        var ns = (
3545            PKG.Xlate.data.get(refId) || PKG.Xlate.data.set(refId, {
3546            translations: new Hash(),
3547            pluralrule: new Hash()
3548        }));
3549
3550        if (force) {
3551            // overwrite ns with values of obj
3552            ns.translations.update(obj);
3553            ns.pluralrule = pluralrule;
3554        } else {
3555            /*
3556                    merge ns into obj (overwriting obj-values with ns one
3556s)
3557                    and replacing original reference with it
3558                */
3559            PKG.Xlate.data.set(refId, {
3560                translations: $H(obj).update(ns.translations),
3561                pluralrule: pluralrule
3562            });
3563        }
3564    },
3565
3566    /**
3567        @private
3568        @description
3569            Creates key under which objects are stored.
3570    */
3571    createRefId: function(namespace, language, country) {
3572        return (language + "/" + country + "/" + namespace);
3573    },
3574
3575    /**
3576        @description
3577            Translates html
3578        @type void
3579        @param {String} language
3580            Language identifier in ISO format (e.g. en,de,..)
3581        @param {String} country
3582            Country identifier in ISO format (e.g. US,DE,..)
3583        @param {String|Function} [urlGenerator=null]
3584            An url which prefixes the language definition urls, or a
3585            url generator function which must return a url to load
3586            the definition files
3587        @param {Element}  rootElement
3588            An optional element which children will be translated
3589        @example
3590&lt;body onload="Xlate.translateHTML('pl','PL');">
3591    &lt;div lang="x-late-extras">You have to create a new buddy first&lt;/div>
3592&lt;/body>
3593    */
3594    translateHTML: function(language, country, urlGenerator, rootElement) {
3595        var triggered = new Hash();
3596        (rootElement ? Element.select(rootElement, "[lang^=x-late-]") : $$("[lang^=x-late-]")).each(function(node) {
3597            var namespace = node.readAttribute("lang").substring(7).replace(/-/g, ".");
3598
3599            if (!triggered.get(namespace)) {
3600                triggered.set(namespace, true);
3601                PKG.Xlate.invoke({
3602                    namespace: namespace,
3603                    language: language,
3604                    country: country,
3605                    urlGenerator: urlGenerator,
3606                    callback: function(xlate) {
3607                        (rootElement ? Element.select(rootElement, "[lang^=x-late-]") : $$("[lang^=x-late-]")).each(function(node) {
3608                            var id = PKG.Xlate._extractId(node);
3609                            var html = xlate.format(id);
3610                            if (html == id && id.match(/&amp;/)) {
3611                                id = id.replace(/&amp;/, "&");
3612                                html = xlate.format(id);
3613                            }
3614                            if (html) {
3615                                node.setAttribute("lang", xlate.language + "-" + xlate.country);
3616                                node.update(html);
3617                                // (PBT: #9368) IE Workaround.
3618                                // IE puts html into several text nodes here which angular cannot handle properly.
3619                                // node.normalize() does not work here.
3620                                // node.innerHTML = html doesn't work either.
3621                                // Only this seemingly useless assignment merges all text nodes into one.
3622                                node.innerHTML = node.innerHTML
3623                            }
3624                        });
3625                    }
3626                });
3627            }
3628        });
3629    },
3630
3631    _extractId: function(node) {
3632        return PKG.Xlate._removeComments(node.cloneNode(true))
3633            .innerHTML.replace(/^\s*(.*?)\s*$/, "$1").replace(/\s+/g, " ");
3634    },
3635
3636    _removeComments: function(node) {
3637        node = $(node);
3638        node.childElements().each(function(childNode) {
3639            PKG.Xlate._removeComments(childNode);
3640        });
3641
3642        if (node.nodeType == Node.COMMENT_NODE) {
3643            node.remove();
3644        }
3645
3646        return node;
3647    }
3648});
3649
3650// TODO: remove this
3651window.Xlate = PKG.Xlate;
3652
3653// legacy stuff
3654/**
3655    @name I18N
3656    @namespace
3657    @description
3658        Static legacy class to provide compatibility to I18N javascript files
3659*/
3660window.I18N = (
3661/**
3662    @lends I18N
3663*/
3664{
3665    loaded: {},
3666
3667    //
3668    langObjects: {},
3669    language: (
3670           window.theLanguage
3671           || (document.documentElement.getAttribute('lang') || '').replace(/-.*$/,'')
3672           || getTopWindow().theLanguage
3673           || (getTopWindow().locale ? getTopWindow().locale.replace(/_.*/, "") : null)
3674           || (getTopWindow().beng && getTopWindow().beng.env && getTopWindow().beng.env.language ? getTopWindow().beng.env.language : null )
3675    ),
3676    country: (
3677            window.theCountry
3678            || (document.documentElement.getAttribute('lang') || '').replace(/^.*-/,'')
3679            || getTopWindow().theCountry
3680            || (getTopWindow().locale ? getTopWindow().locale.replace(/.*_/, "") : null)
3681            || (getTopWindow().beng && getTopWindow().beng.env && getTopWindow().beng.env.country ? getTopWindow().beng.env.country : null )
3682    ),
3683    /**
3684        @static
3685        @private
3686    */
3687    setTextObject: function(namespace, obj, force, pluralrule, language, country) {
3688        PKG.Xlate.set(namespace, language, country, obj, force, pluralrule);
3689
3690        var refId = PKG.Xlate.createRefId(namespace, language, country);
3691        var xlate = new PKG.Xlate(namespace, language, country);
3692
3693        xlate.setData(PKG.Xlate.data.get(refId));
3694        PKG.Xlate.xlates.set(refId, xlate);
3695    },
3696
3697    load: function(namespaces, params, language, country) {
3698        if (language) I18N.language = language;
3699        if (country) I18N.country = country;
3700
3701        params = params || {};
3702        namespaces = (namespaces instanceof Array ? namespaces : [namespaces]);
3703
3704        var defs = [];
3705
3706        for (var i = 0; i < namespaces.length; i++) {
3707            var xRef = I18N.language + "/" + I18N.country + "/" + namespaces[i];
3708
3709            if (!I18N._createXRefClosure(xRef)()) {
3710
3711                var xUrl = "/res/generated/i18n/" + xRef + ".js";
3712
3713                if (params.url) {
3714                    if (typeof(params.url) == "function") {
3715                        xUrl = params.url(xUrl);
3716                    } else {
3717                        xUrl = params.url + xUrl;
3718                    }
3719                }
3720
3721                defs.push({
3722                    url: xUrl,
3723                    test: I18N._createXRefClosure(xRef)
3724                });
3725            }
3726        }
3727
3728        if (params.mode == "preload") {
3729            var def;
3730            while (defs.length > 0) {
3731                def = defs.shift();
3732                document.write('<SCRIPT src="' + def.url + '"></SCRIPT>');
3733            }
3734        } else {
3735            throw new Error("Operation not supported, use cm4all.Xlate object instead!");
3736        }
3737    },
3738
3739    _createXRefClosure: function(xRef) {
3740        return function() {
3741            return typeof I18N.langObjects[xRef] != 'undefined';
3742        };
3743    },
3744
3745    xlate: function(namespace, key, variables) {
3746        var xlate = PKG.Xlate.xlates.get(PKG.Xlate.createRefId(namespace, I18N.language, I18N.country));
3747        if (xlate) {
3748            return xlate.format(key, variables);
3749        } else if (typeof getTopWindow == "function" && getTopWindow() != window && getTopWindow().I18N) {
3750            return getTopWindow().I18N.xlate(namespace, key, variables);
3751        } else {
3752            return key;
3753        }
3754    }
3755});
3756})((function() {
3757    if (typeof LIBCM4ALL_JS_WIDGET_NAMESPACE == "object") {
3758        return LIBCM4ALL_JS_WIDGET_NAMESPACE;
3759    }
3760    if (typeof(window.cm4all) == "undefined") {
3761        window.cm4all = {};
3762    }
3763    return window.cm4all;
3764})());
3765    };
3766    if(window.__loadedJsLibraries["/res/js/lib/XSLTProcessor.js"] !== true){
3767        window.__loadedJsLibraries["/res/js/lib/XSLTProcessor.js"] = true;
3768        Transformer = Class.create({
3769
3770    xslt: null,
3771    xml: null,
3772
3773    _loadDocument: function(url) {
3774        if (Prototype.Browser.IE) {
3775            var doc = new ActiveXObject("Microsoft.XMLDOM");
3776            doc.async = false;
3777            doc.load(url);
3778            return doc;
3779        } else {
3780            var xmlhttp = new window.XMLHttpRequest();
3781            xmlhttp.open("GET", url, false);
3782            xmlhttp.send(null);
3783            return xmlhttp.responseXML.documentElement;
3784        }
3785    },
3786
3787    setStylesheetUrl: function(url) {
3788        this.xslt = this._loadDocument(url);
3789        return this;
3790    },
3791
3792    setDocumentUrl: function(url) {
3793        this.setDocument(this._loadDocument(url));
3794        return this;
3795    },
3796    setDocument: function(doc) {
3797        this.xml = doc;
3798        return this;
3799    },
3800
3801    transform: function(elem) {
3802        var output;
3803        elem = $(elem);
3804
3805        if (Prototype.Browser.IE) {
3806            output = this.xml.transformNode(this.xslt);
3807        } else {
3808            var processor = new XSLTProcessor();
3809            processor.importStylesheet(this.xslt);
3810
3811            var XmlDom = processor.transformToDocument(this.xml);
3812
3813            var serializer = new XMLSerializer();
3814            output = serializer.serializeToString(XmlDom.documentElement);
3815        }
3816        elem.update(output);
3817    }
3818
3819});
3820    };
3821    if(window.__loadedJsLibraries["/res/js/lib/XFrameTunnel/Initiator.js"] !== true){
3822        window.__loadedJsLibraries["/res/js/lib/XFrameTunnel/Initiator.js"] = true;
3823        (function(window) {
3824
3825    window.cm4all = window.cm4all  || {};
3826
3827    cm4all.XFrameTunnelInitiator = Class.create({
3828
3829        commands: null,
3830        alienFrame: null,
3831        alienOrigin: null,
3832        txnid: null,
3833        opener: null,
3834
3835        initialize: function(ref, opener, commands) {
3836            var self = this;
3837            this.alienFrame = $(ref);
3838            this.txnid = Math.random().toString(16).replace(/^0./, "");
3839            this.opener = opener;
3840            this.commands = Object.extend(this, commands || cm4all.XFrameTunnelInitiator.defaultCommands);
3841            this.messageHandler = this.messageHandler.bind(this);
3842            (typeof getTopWindow !== 'undefined' && getTopWindow() || top).addEventListener("message", this.messageHandler, false);
3843            window.addEventListener("unload", function() {self.free.call(self)});
3844        },
3845
3846        messageHandler: function(event) {
3847            var message = event.data;
3848
3849            if (!message || message['xft-txnid'] !== this.txnid) {
3850                return;
3851            }
3852            var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
3853            if (origin !== this.alienOrigin) {
3854                return;
3855            }
3856            var command = message['xft-command'] || "";
3857            var data = message['xft-request'] || {};
3858
3859            if (Object.isFunction(this.commands[command])) {
3860                if (this.commands[command](data)) {
3861                    var messageOut = {
3862                        "xft-txnid": this.txnid,
3863                        "xft-command": command,
3864                        "xft-response": {
3865                            'returnValue': 'OK',
3866                            'data': data
3867                        }
3868                    };
3869                    this.alienFrame.contentWindow.postMessage(messageOut, origin);
3870                }
3871            } else {
3872                console.log("INVALID COMMAND: " + command);
3873            }
3874        },
3875
3876        open: function(url, callbackFn) {
3877            if (url.indexOf("javascript:") == 0) {
3878                return;
3879            }
3880
3881            var xurl = new cm4all.HttpURL(url);
3882            HttpURLUtils.setReverseParameter(xurl, "xft-txnid", this.txnid);
3883            HttpURLUtils.setReverseParameter(xurl, "xft-base", cm4all.XFrameTunnelInitiator.getBaseUrl());
3884            HttpURLUtils.setReverseParameter(xurl, "xft-path", cm4all.XFrameTunnelInitiator.getPath());
3885
3886            if (callbackFn) {
3887                var _load = function () {
3888                    this.alienFrame.stopObserving("load", _load);
3889                    callbackFn(this.alienFrame.contentWindow);
3890                }.bind(this);
3891                this.alienFrame.observe("load", _load);
3892            }
3893
3894            this.alienFrame.src = xurl.toString();
3895            xurl.removeAllParams();
3896            xurl.path = '';
3897            this.alienOrigin = xurl.toString() ||
3898              /* xurl is a relative url, this means same proto and host as local window */ (location.protocol + "//" + location.host);
3899        },
3900
3901        free: function() {
3902          (typeof getTopWindow !== 'undefined' && getTopWindow() || top).removeEventListener("message", this.messageHandler);
3903        }
3904    });
3905
3906    Object.extend(cm4all.XFrameTunnelInitiator, {
3907
3908        defaultCommands: {
3909            "popup-open": function(data) {
3910                var _data = Object.extend(Object.extend({}, data), {
3911                    url: "javascript:void(0)"
3912                });
3913                var iframe = Common.Widget.getPopupImpl().custom(_data).getFrame();
3914                if (iframe) {
3915                    var xfti = new cm4all.XFrameTunnelInitiator(iframe, this);
3916                    xfti.open(data.url);
3917                }
3918                return false;
3919            },
3920            "popup-close": function(data) {
3921                Common.Widget.getPopupImpl().peek().close();
3922                if (this.opener) {
3923                    try {
3924                        var messageOut = {
3925                            "xft-txnid": this.opener.txnid,
3926                            "xft-command": "popup-closed",
3927                            "xft-response": {
3928                                'returnValue': 'OK',
3929                                'data': data
3930                            }
3931                        };
3932                        this.opener.alienFrame.contentWindow.postMessage(messageOut, this.alienOrigin);
3933                    } catch (err) {
3934                        console.error(err);
3935                    }
3936                }
3937                return false;
3938            },
3939            "popup-closed": function(data) {
3940                return true;
3941            },
3942            "resize": function(data) {
3943                // Resizing must be done at the widgetcontainer
3944                var $alienFrame = jQuery(this.alienFrame);
3945                var container = $alienFrame.parent();
3946                if (container.length < 1) {
3947                    // alienframe has no parent? Maybe because it is not in the dom yet? So, the brutal way:
3948                    var id = this.alienFrame.id.substring(7, this.alienFrame.id.lastIndexOf("_"));
3949                    container = jQuery("#widgetcontainer_" + id);
3950                }
3951                var css = {};
3952                if (data.width && isNaN(data.width)) {
3953                    css.width = data.width; // with unit
3954                } else if (data.width) {
3955                    css.width = data.width + "px"; // unit-less
3956                }
3957                if (data.height && isNaN(data.height)) {
3958                    css.height = data.height;
3959                } else if (data.height) {
3960                    css.height = data.height + "px";
3961                }
3962                if(container.css("position") === "static"){
3963                    css.position = "relative";
3964                }
3965                container.css(css);
3966                $alienFrame.css({"position" : "absolute"});
3967                if (data.overflow) {
3968                    this.alienFrame.setAttribute('scrolling', (data.overflow == 'hidden') ? 'no' : 'auto');
3969                }
3970                return true;
3971            },
3972            "get-wrapper-style": function(cssObject) {
3973                var $wrapper = jQuery(this.alienFrame).parent();
3974                jQuery.each(cssObject, function(key, value) {
3975                    cssObject[key] = $wrapper.css(key);
3976                });
3977                return cssObject;
3978            },
3979            getContainerClass: function(data) {
3980                var container = jQuery(this.alienFrame).parent();
3981                var classname = container.closest("[data-container-class]").data("data-container-class");
3982
3983                if (!classname) {
3984                    if (container.closest(".content_main").length > 0) {
3985                        classname="content_main";
3986                    } else if (container.closest(".content_main_dho").length > 0) {
3987                            classname="content_main_dho";
3988                    } else if (container.closest(".content_sidebar").length > 0) {
3989                        classname="content_sidebar";
3990                    } else if (container.closest(".content_mobile").length > 0) {
3991                        classname="content_mobile";
3992                    }
3993                }
3994                data.classname = classname || "";
3995                return true;
3996            },
3997            getCSS: function(data) {
3998                var list = [];
3999                var nl = document.getElementsByTagName("link");
4000                for (var i = 0; i < nl.length; i++) {
4001                    var href = nl.item(i).href;
4002
4003                    if (href && (
4004                             href.match(/.*\/beng\/designs\/.*\.css/)
4005                          || href.match(/.*\/1,css,8,1/)
4006                          || href.match(/.*\/1,mcss,8,1/)
4007                          || href.match(/.*\/vars\.css/)
4008                          || href.match(/.*\/mvars\.css/)
4009                          || href.match(/.*\/.cm4all\/e\/Design\/action=getCss.*/
4010                    ))) {
4011
4012                        if (href.indexOf("/") == 0)
4013                            href = "//" + document.location.host + href;
4014                        list.push(href);
4015                    }
4016                }
4017                data.cssUrls = list;
4018                return true;
4019            }
4020        },
4021
4022        getBaseUrl: function() {
4023            var url = new cm4all.HttpURL(document.location.href);
4024            url.ref = null;
4025            url.path = "";
4026            return url.toString();
4027        },
4028
4029        getPath: function() {
4030            var url = new cm4all.HttpURL(document.location.href);
4031            var path = url.path;
4032            // remove proxy session information
4033            path = path.replace(/;.*$/, "");
4034            return path;
4035        },
4036    });
4037
4038    /* dummy implementation for demonstration */
4039    DummyPopup = Class.create({
4040        initialize: function(data) {
4041            data = data || {};
4042            var httpUrl = new HttpURL(data.url);
4043
4044            var width = data.width || "80%";
4045            var height = data.height || "80%";
4046            var scrollbars = data.scrollbars || "";
4047            var checkRe = /^\d+(px|%)$/;
4048
4049            if (!checkRe.test(width) || !checkRe.test(height)
4050                ||
4051                httpUrl.protocol != "http" && httpUrl.protocol != "https") {
4052                alert("illegal parameter");
4053                return;
4054            }
4055
4056            this.popupDiv = Common.openFullscreen(
4057                "<iframe style='width: 100%; height: 100%; border: none;' ></iframe>",
4058                {
4059                    "width": width,
4060                    "height": height,
4061                    "scrollbars" : scrollbars
4062                }
4063            );
4064            this.iframe = jQuery("iframe", this.popupDiv)[0];
4065        },
4066
4067        close: function() {
4068            jQuery(".close", this.popupDiv.parent()).click();
4069        },
4070
4071        resize: function(w, h) {
4072            jQuery(this.iframe).parents(".cm-fullscreen.justify").css({
4073                width: w + 'px',
4074                height: h + 'px'
4075            });
4076        }
4077    });
4078})(window);
4079    };
4080    if(window.__loadedJsLibraries["/res/js/lib/DOM2JSON.js"] !== true){
4081        window.__loadedJsLibraries["/res/js/lib/DOM2JSON.js"] = true;
4082        (function(window) {
4083
4084    /**
4085      @namespace
4086      @name cm4all
4087     */
4088    var cm4all = (window.cm4all = window.cm4all || {});
4089
4090    // add trim if not present to trim text nodes
4091    if (!String.prototype.trim) {
4092        String.prototype.trim = function() {
4093            return this.replace(/^\s+|\s+$/g, '');
4094        };
4095    }
4096    var TEXT_ACCESSOR = "nodeValue";
4097    var IE8 = (document.documentMode && document.documentMode < 9);
4098    if (IE8) {
4099        /* IE8 fallback */
4100        Object.defineProperty = function(target, name, config) {
4101            if (config.value) {
4102                target[name] = config.value;
4103            } else {
4104                target[name] = (config.get || config.set) ? function() {
4105                    if (arguments.length > 0) {
4106                        /*setter*/
4107                        config.set.apply(target, arguments);
4108                    } else {
4109                        /*getter*/
4110                        return config.get();
4111                    }
4112                } : target[name];
4113            }
4114        };
4115    }
4116
4117    /**
4118       Badgerfish wrapper for DOM
4119       
4120       Creates a badgerfish json-object which is synchronized to the given dom node.
4121       That means changes in the dom are directly reflected in the object and vice versa.
4122       
4123       Additionally you can gain access to dom elements by the special property '$dom' which is 
4124       available on json element objects;
4125        
4126       E.g.:
4127       var dom = <your dom>; // <root><element/></root>
4128       var json = new cm4all.DOM2JSON(dom)
4129       
4130       var element = json.root.element.$dom; // would give you the <element>
4130 node
4131       
4132       Another feature is the json-path selection:
4133       You can select child-json-objects with the $get method of all json element objects
4134       
4135       var json.$get("root.element"); // would give you the element json-object
4136       
4137       Cool is also the $set method:
4138       
4139       json.root.$set("element.child.grandchild[1]", { "@age" : "16", "$" : "hans"});
4140       
4141       this generates a json which corresponds to the xml:
4142       
4143       <root><element><child><grandchild></grandchild><grandchild age=16">hans</grandchild></child></element></root>
4144       
4145       
4146       
4147       RESTRICTIONS: 
4148       
4149       1) You cannot simply add completely new child-elements, attributes or text-nodes by assignment,
4150        you have to use the $set method. 
4151       
4152       So to add a new element named newelement to the root node, you would be doing this:
4153       
4154       json.root.$set("newelement", {});
4155       
4156       Same goes for new attributes:
4157       
4158       json.root.$set("@newatt" , "value");
4159       
4160       Same for text-nodes where no text-node was before:
4161       
4162       json.root.$set("$" ,"new text");
4163       
4164       2) If you want to support IE < 9 you MUST NOT use direct property access. You MUST only use
4165       the $get and $set methods!
4166       
4167        e.g 
4168        json.$get("root.element")
4169        json.$get("root").$get("element")
4170       
4171       @constructor
4172       @name cm4all.DOM2JSON
4173       @param {Node} the dom-node to synchronize with
4174       @return {cm4all.DOM2JSON} A synchronized  badgerfish json-object
4175     */
4176
4177    cm4all.DOM2JSON = function(node) {
4178        if (node) {
4179            Object.defineProperty(this, "$dom", {
4180                enumerable: false,
4181                configurable: false,
4182                value: node
4183            });
4184            switch (node.nodeType) {
4185                case 3 /* TEXT_NODE */ :
4186                case 4 /* CDATA_SECTION_NODE */ :
4187                    text2json(node, this);
4188                    break;
4189                case 9 /* DOCUMENT_NODE */ :
4190                    element2json(node.documentElement, this);
4191                    break;
4192                case 1 /* ELEMENT_NODE */ :
4193                    element2json(node, this);
4194                    break;
4195                case 2 /* ATTRIBUTE_NODE */ :
4196                    attribute2json(node, this);
4197            }
4198        }
4199    };
4200
4201    /**
4202       @constructor
4203       @name cm4all.JSONAccess
4204       @param o
4205       @return {cm4all.JSONAccess}
4206     */
4207    cm4all.JSONAccess = function(o) {
4208        this.o = o || window;
4209    };
4210
4211    /**
4212       @param jsonPath
4213       @return {Object}
4214     */
4215    cm4all.JSONAccess.prototype.$get = function(jsonPath) {
4216        return $get.call(this.o, jsonPath);
4217    };
4218
4219    /**
4220       @param jsonPath
4221       @param jsonObject
4222       @return {Object}
4223     */
4224    cm4all.JSONAccess.prototype.$set = function(jsonPath, jsonObject) {
4225        $set.call(this.o, jsonPath, jsonObject);
4226        return this.$get(jsonPath);
4227    };
4228
4229    /**
4230       @param jsonPath
4231       @param baseObject
4232       @return {Object}
4233     */
4234    cm4all.DOM2JSON.prototype.$getValue = function(jsonPath, baseObject) {
4235        return cm4all.DOM2JSON.prototype.$get.call(baseObject || window, jsonPath);
4236    };
4237
4238    /**
4239       Helper class to provide $get and $set methods on JSON Objects
4240       @constructor
4241       @name JSONAccess
4242       @private
4243     */
4244
4245    function JSONAccess() {};
4246
4247    JSONAccess.prototype.$get = function(jsonPath) {
4248        return $get.call(this, jsonPath);
4249    };
4250    Object.defineProperty(JSONAccess.prototype, "$get", {
4251        "enumerable": false
4252    });
4253
4254    JSONAccess.prototype.$set = function(jsonPath, jsonObject) {
4255        $set.call(this, jsonPath, jsonObject);
4256        return this.$get(jsonPath);
4257    };
4258    Object.defineProperty(JSONAccess.prototype, "$set", {
4259        "enumerable": false
4260    });
4261
4262    cm4all.DOM2JSON.prototype.$get = JSONAccess.prototype.$get;
4263
4264    cm4all.DOM2JSON.prototype.$set = JSONAccess.prototype.$set;
4265
4266    /**
4267       
4268       @param {String} jsonPath a path in json notation relative to the current object  
4269       @return {Object} The child object denoted by the given json path 
4270     */
4271
4272    function $get(jsonPath) {
4273        try {
4274            return eval("this" + functionalizeNormalizedJsonPath(normalizeJsonPath(jsonPath)));
4275        } catch (e) {
4276            return undefined;
4277        }
4278    };
4279
4280    /**
4281       
4282       @param {String} jsonPath a path in json notation relative to the current object
4283       @param {Object} jsonObject  
4284       @return {Object} The copy of the added object that is actually part of the json-tree
4285     */
4286
4287    function $set(jsonPath, jsonObject) {
4288        jsonPath = normalizeJsonPath(jsonPath);
4289        var steps = jsonPath.split(/\[|\]?\[|\]/);
4290        if (steps[0] === "") {
4291            /* depending on browser the first step is an empty string */
4292            steps.shift();
4293        }
4294        try {
4295            ensureObject(steps, this, jsonObject);
4296        } catch (e) {
4297            Common.log(e.message);
4298        }
4299    };
4300
4301    function ensureAttribute(element, name, value, jsonElement) {
4302        var valueType = typeof value;
4303        if (value !== null && valueType !== undefined && valueType !== "string") {
4304            Common.log("Illegal type for attribute value " + value);
4305            return;
4306        }
4307        var i;
4308        if (value == null || typeof value == "undefined") {
4309            element.removeAttribute(name);
4310            delete jsonElement["@" + name];
4311        } else {
4312            element.setAttribute(name, value);
4313        }
4314        children = element.attributes;
4315        for (i = 0; i < children.length; i++) {
4316            attribute2json(children.item(i), jsonElement);
4317        }
4318    }
4319
4320    function ensureTextNode(element, text, jsonElement) {
4321        var valueType = typeof text;
4322        if (text !== null && valueType !== "undefined" && valueType !== "string") {
4323            return;
4324        }
4325        var textNode = element.ownerDocument.createTextNode(text);
4326        element.appendChild(textNode);
4327        text2json(textNode, jsonElement);
4328
4329    }
4330
4331    function appendElement(parentElement, parentJsonElement, name, childJsonElement) {
4332        var newElement = parentElement.ownerDocument.createElement(name);
4333        parentElement.appendChild(newElement);
4334        if (parentJsonElement) {
4335            element2json(newElement, parentJsonElement);
4336        }
4337        jsonElement2element(childJsonElement, newElement);
4338    }
4339
4340    /**
4341       @private  
4342       @param {array} steps An array of path steps in the json-tree 
4343       @param {Object} current The object the steps are relative to  
4344       @param {Object} jsonObject The object to append to the last objcet in the steps
4345       @return {void}
4346     */
4347
4348    function ensureObject(steps, current, jsonObject) {
4349        var
4350        element,
4351            step = steps.shift();
4352        step = step.trim();
4353        step = /^"/.test(step) ? step.replace(/^"(.*)"$/, "$1") : Number(step);
4354        element = resolve(current.$dom);
4355        if (typeof resolve(current[step]) === "undefined") {
4356            ensureJsonPath(steps, step, element, current, jsonObject);
4357            return;
4358        }
4359        if (Boolean(steps[0])) {
4360            ensureObject(steps, resolve(current[step]), jsonObject);
4361        } else {
4362            setJsonObject(step, element, current, jsonObject);
4363        }
4364    }
4365
4366    function setJsonObject(step, element, current, jsonObject) {
4367        var
4368        currentElement,
4369            i,
4370            children;
4371        if (/^@/.test(step)) {
4372            /* an attribute */
4373            ensureAttribute(element, step.replace(/^@/, ""), jsonObject, current);
4374        } else if (/^\$$/.test(step)) {
4375            /* a text node */
4376            children = element.childNodes;
4377            for (i = children.length - 1; i >= 0; i--) {
4378                currentElement = children.item(i);
4379                switch (currentElement.nodeType) {
4380                    case 3 /* TEXT_NODE */ :
4381                    case 4 /* CDATA_SECTION_NODE */ :
4382                        element.removeChild(currentElement);
4383                }
4384            }
4385            ensureTextNode(element, jsonObject, current);
4386        } else if (typeof step === "number") {
4387            /* we replace a single element in a list of siblings with the same name */
4388            /* 
4389             * we have something like element[1] which translates to
4390             * { element : [{}, {}] }. The element selected here is 
4391             * the second of the array. 
4392             * */
4393            element = resolve(resolve(current[step]).$dom);
4394            jsonElement2element(jsonObject, element);
4395        } else {
4396            /* element node */
4397            children = element.childNodes;
4398            /* since the element node is replaced by the definitions in
4399             * jsonObject, we have to remove all already existing children 
4400             * with the same name 
4401             * */
4402            for (i = children.length - 1; i >= 0; i--) {
4403                currentElement = children.item(i);
4404                if (currentElement.nodeName === step) {
4405                    switch (currentElement.nodeType) {
4406                        case 1 /* ELEMENT_NODE */ :
4407                            element.removeChild(currentElement);
4408                    }
4409                }
4410            }
4411            if (jsonObject == null || jsonObject == undefined) {
4412                /* delete an element */
4413                return;
4414            }
4415            jsonObject = Object.isArray(jsonObject) ? jsonObject : [jsonObject];
4416            for (i = 0; i < jsonObject.length; i++) {
4417                appendElement(element, i === jsonObject.length - 1 ? resolve(current.$parent) : null, step, resolve(jsonObject[i]));
4418            }
4419        }
4420    }
4421
4422    function ensureJsonPath(steps, step, element, current, jsonObject) {
4423        var
4424        i;
4425        /* ensure the current step */
4426        if (typeof step === "number") {
4427            element = resolve(resolve(current.$parent).$dom);
4428            for (i = Object.isArray(current) ? current.length : 1; i <= step; i++) {
4429                /* append the missing child elements to the parent */
4430                appendElement(element, resolve(current.$parent), resolve(current.$name), {});
4431            }
4432            /* reload the current element */
4433            current = resolve(resolve(current.$parent)[resolve(current.$name)]);
4434
4435        } else {
4436            if (element) {
4437                if (/^@/.test(step)) {
4438                    /* case 2: missing attribute */
4439                    ensureAttribute(element, step.replace(/^@/, ""), "", current);
4440                } else if (/^\$$/.test(step)) {
4441                    /* case 3: missing text node */
4442                    ensureTextNode(element, "", current);
4443                } else {
4444                    /* add one child */
4445                    appendElement(element, current, step, {});
4446                }
4447            } else {
4448                Common.log("Expected element node but found other.");
4449            }
4450        }
4451        /* repeat this step */
4452        steps.unshift(String(typeof step === "number" ? step : "\"" + step + "\""));
4453        ensureObject(steps, current, jsonObject);
4454
4455    }
4456    /**
4457       Normalizes a path in json notation to the square-bracket form.
4458       E.g.: 
4459       
4460       root.child[3].grandson["hans"]["17"] will be normalized to:
4461       
4462       ["root"]["child"][3]["grandson"]["hans"][17]
4463       
4464       @private
4465       @param {String} jsonPath A path in json notation.
4466     */
4467
4468    function normalizeJsonPath(jsonPath) {
4469        return ("." + jsonPath /* trigger first step as  bracket-notation */ )
4470        /* replace all square brackets with point notation */
4471            .replace(/\[\s*"(.*?)"\s*\]/g, function($0, $1) {
4472            return "." + $1.replace(/\./g, "\\.") /* escape '.' to '\.' */ ;
4473        })
4474            .replace(/\[\s*'(.*?)'\s*\]/g, function($0, $1) {
4475            return "." + $1.replace(/\./g, "\\.") /* escape '.' to '\.' */ ;
4476        })
4477            .replace(/\[\s*(.*?)\s*\]/g, function($0, $1) {
4478            return "." + $1.replace(/\./g, "\\.") /* escape '.' to '\.' */ ;
4479        })
4480            .replace(/^\.\./, "." /* remove double .. induced by prefixing jsonPath with '.'*/ )
4481        /* replace point notation with bracket notation */
4482            .replace(/\.(([\\][\.]|[^.])*)/g, function($0, $1) {
4483            var val = $1.replace(/"/g, "\\\"") /* escape '"' to '\"' */
4484                .replace(/\\./g, "." /* unescape '\.'to '.' */ );
4485            var quote = isNaN(Number(val)) ? "\"" : "";
4486            return "[" + quote + val + quote + "]";
4487        });
4488    }
4489
4490    function functionalizeNormalizedJsonPath(normalizedJsonPath) {
4491        return normalizedJsonPath.replace(/\]/g, IE8 ? "]()" : "]");
4492    }
4493    /**
4494       Sets the given element as child object on the given jsonElement
4495       
4496       @private
4497       @param {Object} jsonElement
4498       @param {Element} element
4499       
4500       @return {void}
4501     */
4502
4503    function element2json(element, parentJsonElement) {
4504        if (element == null || element.nodeType == undefined || element.nodeType != 1)
4505            return;
4506        collectSiblingElements(parentJsonElement, element);
4507    };
4508
4509    /**
4510       Parses the given element into a badgerfish json-object
4511       
4512       @private
4513       @param {Element} element
4514       
4515     */
4516
4517    function element2jsonElement(element, parentJsonObject) {
4518        var i,
4519            jsonObject = new JSONAccess(),
4520            children = element.childNodes;
4521        Object.defineProperty(jsonObject, "$dom", {
4522            enumerable: false,
4523            configurable: false,
4524            value: element
4525        });
4526        Object.defineProperty(jsonObject, "$parent", {
4527            enumerable: false,
4528            configurable: false,
4529            value: parentJsonObject
4530        });
4531        Object.defineProperty(jsonObject, "$name", {
4532            enumerable: false,
4533            configurable: false,
4534            value: element.nodeName
4535        });
4536
4537        for (i = 0; i < children.length; i++) {
4538            collectSiblingElements(jsonObject, children.item(i));
4539        }
4540
4541        children = element.attributes;
4542        for (i = 0; i < children.length; i++) {
4543            attribute2json(children.item(i), jsonObject);
4544        }
4545
4546        return jsonObject;
4547    };
4548
4549    /**
4550       
4551     */
4552
4553    function collectSiblingElements(parentJsonElement, element) {
4554        var parent = element.parentNode;
4555        switch (element.nodeType) {
4556            case 1 /* ELEMENT_NODE */ :
4557                if (!parentJsonElement.hasOwnProperty(element.nodeName)) {
4558                    Object.defineProperty(parentJsonElement, element.nodeName, {
4559                        configurable: true,
4560                        enumerable: true,
4561                        get: function() {
4562                            var store = [],
4563                                j,
4564                                elements = parent.childNodes;
4565                            for (j = 0; j < elements.length; j++) {
4566                                collectAllSiblingsWithNodeName(elements.item(j), element.nodeName, store, parentJsonElement);
4567                            }
4568                            if (store.length > 1) {
4569                                store.$parent = parentJsonElement;
4570                                store.$name = element.nodeName;
4571                                return store;
4572                            }
4573                            return resolve(store[0]);
4574                        },
4575                        set: function(newValue) {
4576                            /* delete all elements with this nodeName  */
4577                            var elements = parent.childNodes,
4578                                j, ce;
4579                            for (j = elements.length - 1; j >= 0; j--) {
4580                                ce = elements.item(j);
4581                                if (ce.nodeName === element.nodeName && ce.nodeType === 1 /* ELEMENT_NODE */ ) {
4582                                    parent.removeChild(ce);
4583                                }
4584                            }
4585                            if (newValue) {
4586                                newValue = Object.isArray(newValue) ? newValue : [newValue];
4587                                for (j = 0; j < newValue.length; j++) {
4588                                    appendElement(parent, parentJsonElement, element.nodeName, resolve(newValue[j]));
4589                                }
4590                            }
4591                        }
4592                    });
4593                }
4594                break;
4595            case 3 /* TEXT_NODE */ :
4596            case 4 /* CDATA_SECTION_NODE */ :
4597                text2json(element, parentJsonElement);
4598        }
4599    }
4600
4601    /**
4602       
4603     */
4604
4605    function collectAllSiblingsWithNodeName(element, nodeName, store, parentJsonObject) {
4606        /* collect all children with the same nodeName into an array */
4607        if (element.nodeName === nodeName) {
4608            switch (element.nodeType) {
4609                case 1 /* ELEMENT_NODE */ :
4610                    /* since we need a trigger to update the dom when array content is changed,
4611                     *  we have to use the defineProperty for setting the array content. This 
4612                     *  leads to an array with restricted modification access */
4613                    Object.defineProperty(store, store.length, {
4614                        configurable: true,
4615                        enumerable: true,
4616                        get: function() {
4617                            if (!element) {
4618                                return element;
4619                            }
4620                            return element2jsonElement(element, parentJsonObject);
4621                        },
4622                        set: function(newValue) {
4623                            if (!newValue) {
4624                                element.parentNode.removeChild(element);
4625                                element = undefined;
4626                            } else {
4627                                jsonElement2element(newValue, element);
4628                            }
4629                        }
4630                    });
4631            }
4632        }
4633    }
4634
4635    /**
4636       
4637     */
4638
4639    function jsonElement2element(
4640        jsonElement, element) {
4641        var key = undefined,
4642            value, children, current, i;
4643
4644
4645        children = element.childNodes;
4646        for (i = children.length - 1; i >= 0; i--) {
4647            element.removeChild(children.item(i));
4648        }
4649
4650        children = element.attributes;
4651        for (i = children.length - 1; i >= 0; i--) {
4652            element.removeAttributeNode(children.item(i));
4653        }
4654
4655        for (key in jsonElement) {
4656            value = resolve(jsonElement[key]);
4657            if (/^@/.test(key)) {
4658                element.setAttribute(key.replace(/^@/, ""), value);
4659            } else if (/^\$$/.test(key)) {
4660                element.appendChild(element.ownerDocument.createTextNode(value));
4661            } else if (Object.isArray(value)) {
4662                for (i = 0; i < value.length; i++) {
4663                    current = element.ownerDocument.createElement(key);
4664                    element.appendChild(current);
4665                    jsonElement2element(resolve(value[i]), current);
4666                }
4667            } else if (value) {
4668                current = element.ownerDocument.createElement(key);
4669                element.appendChild(current);
4670                jsonElement2element(value, current);
4671            }
4672        }
4673
4674    }
4675
4676    /**
4677       
4678     */
4679
4680    function attribute2json(attribute, jsonElement) {
4681        Object.defineProperty(jsonElement, "@" + attribute.name, {
4682            configurable: true,
4683            enumerable: true,
4684            get: function() {
4685                return attribute.value;
4686            },
4687            set: function(newValue) {
4688                if (newValue == null || typeof newValue === "undefined") {
4689                    attribute.ownerElement.removeAttributeNode(attribute);
4690                } else {
4691                    attribute.value = newValue;
4692                }
4693            }
4694        });
4695    }
4696
4697    /**
4698       
4699     */
4700
4701    function text2json(textNode, jsonElement) {
4702        Object
4703            .defineProperty(
4704            jsonElement,
4705            "$", {
4706            configurable: true,
4707            enumerable: true,
4708            get: function() {
4709                var current, children = textNode.parentNode.childNodes,
4710                    i, text = undefined;
4711                for (i = 0; i < children.length; i++) {
4712                    current = children.item(i);
4713                    switch (current.nodeType) {
4714                        case 3 /* TEXT_NODE */ :
4715                        case 4 /* CDATA_SECTION_NODE */ :
4716                            text = (text || "") + current[TEXT_ACCESSOR];
4717                    }
4718                }
4719                return (text ? text.trim() : text);
4720            },
4721            set: function(newValue) {
4722                var parent = textNode.parentNode,
4723                    current, children = parent.childNodes,
4724                    i;
4725                for (i = children.length - 1; i >= 0; i--) {
4726                    current = children.item(i);
4727                    switch (current.nodeType) {
4728                        case 3 /* TEXT_NODE */ :
4729                        case 4 /* CDATA_SECTION_NODE */ :
4730                            if (i > 0) {
4731                                parent.removeChild(current);
4732                            } else {
4733                                current.data = newValue;
4734                                textNode = current;
4735                            }
4736                    }
4737                }
4738            }
4739        });
4740    }
4741
4742    function resolve(o) {
4743        if (typeof o == "function") {
4744            return o();
4745        }
4746        return o;
4747    }
4748
4749})(window);
4750    };
4751    window.__loadedCssLibraries["/res/js/lib/css/xlate.css"] = true;
4752    window.__loadedCssLibraries["/res/js/lib/css/fullscreen.css"] 
4752= true;

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.