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('&').split('<').join('<').split('"').join('"'); 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 <script src="Common.js">;</script> 667 <script src="HttpURL.js">;</script> 668 <script> 669 var httpUrl = new cm4all.HttpURL(); 670 </script> 671 672 example "juppes"-namespace: 673 <script> 674 var juppes = LIBCM4ALL_JS_WIDGET_NAMESPACE = {}; 675 </script> 676 <script src="Common.js">;</script> 677 <script src="HttpURL.js">;</script> 678 <script> 679 var httpUrl = new juppes.HttpURL(); 680 </script> 681 682 to put classes into "global" namespace, use: 683 <script> 684 LIBCM4ALL_JS_WIDGET_NAMESPACE = window; 685 </script> 686 <script src="Common.js">;</script> 687 <script src="HttpURL.js">;</script> 688 <script> 689 var httpUrl = new HttpURL(); 690 </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 * "<url>", isLoaded : function() { return <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 <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 <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 == " " || 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<c:widget xmlns:c="http://cm4all.com/ng/widget" type="widget-runtime-js" /> 2162<c:widget xmlns:c="http://cm4all.com/ng/widget" type="xframetunnel-loader-js"> 2163 <parameter name="jumpback" value="/.cm4all/widgetres.php/exampleWidget/res/jumpback.html" /> 2164</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: ["ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼æ", "ï¼ï¼æ", "ï¼ï¼æ", "ï¼ï¼æ"], 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<body onload="xlate.translateHTML();"> 3376 <div lang="x-late">You have to create a new buddy first</div> 3377</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(/&/)) { 3392 id = id.replace(/&/, "&"); 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<body onload="Xlate.translateHTML('pl','PL');"> 3591 <div lang="x-late-extras">You have to create a new buddy first</div> 3592</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(/&/)) { 3611 id = id.replace(/&/, "&"); 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.