1/* 2 * ADOBE CONFIDENTIAL 3 * 4 * Copyright 2012 Adobe Systems Incorporated 5 * All Rights Reserved. 6 * 7 * NOTICE: All information contained herein is, and remains 8 * the property of Adobe Systems Incorporated and its suppliers, 9 * if any. The intellectual and technical concepts contained 10 * herein are proprietary to Adobe Systems Incorporated and its 11 * suppliers and may be covered by U.S. and Foreign Patents, 12 * patents in process, and are protected by trade secret or copyright law. 13 * Dissemination of this information or reproduction of this material 14 * is strictly forbidden unless prior written permission is obtained 15 * from Adobe Systems Incorporated. 16 * 17 */ 18(function(factory) { 19 "use strict"; 20 21 if (typeof module === "object" && module.exports) { 22 module.exports = factory(); 23 } else { 24 var g = window.Granite = window.Granite || {}; 25 g.Sling = factory(); 26 } 27}(function() { 28 "use strict"; 29 30 /** 31 * A helper class providing a set of Sling-related utilities. 32 * @static 33 * @singleton 34 * @class Granite.Sling 35 * @deprecated Using the constants is no longer needed and actually is not a best practice as it is not RESTful, 36 * where the server should drive the client via hypermedia and the client should not make any 37 * assumption about the URL. 38 */ 39 return { 40 /** 41 * The selector for infinite hierarchy depth when retrieving repository content. 42 * @static 43 * @final
44 * @type String 45 */ 46 SELECTOR_INFINITY: ".infinity", 47 48 /** 49 * The parameter name for the used character set. 50 * @static 51 * @final 52 * @type String 53 */ 54 CHARSET: "_charset_", 55 56 /** 57 * The parameter name for the status. 58 * @static 59 * @final 60 * @type String 61 */ 62 STATUS: ":status", 63 64 /** 65 * The parameter value for the status type "browser". 66 * @static 67 * @final 68 * @type String 69 */ 70 STATUS_BROWSER: "browser", 71 72 /** 73 * The parameter name for the operation. 74 * @static 75 * @final 76 * @type String 77 */ 78 OPERATION: ":operation", 79 80 /** 81 * The parameter value for the delete operation. 82 * @static 83 * @final 84 * @type String 85 */ 86 OPERATION_DELETE: "delete", 87 88 /** 89 * The parameter value for the move operation. 90 * @static 91 * @final
92 * @type String 93 */ 94 OPERATION_MOVE: "move", 95 96 /** 97 * The parameter name suffix for deleting. 98 * @static 99 * @final 100 * @type String 101 */ 102 DELETE_SUFFIX: "@Delete", 103 104 /** 105 * The parameter name suffix for setting a type hint. 106 * @static 107 * @final 108 * @type String 109 */ 110 TYPEHINT_SUFFIX: "@TypeHint", 111 112 /** 113 * The parameter name suffix for copying. 114 * @static 115 * @final 116 * @type String 117 */ 118 COPY_SUFFIX: "@CopyFrom", 119 120 /** 121 * The parameter name suffix for moving. 122 * @static 123 * @final 124 * @type String 125 */ 126 MOVE_SUFFIX: "@MoveFrom", 127 128 /** 129 * The parameter name for the ordering. 130 * @static 131 * @final 132 * @type String 133 */ 134 ORDER: ":order", 135 136 /** 137 * The parameter name for the replace flag. 138 * @static 139 * @final
140 * @type String 141 */ 142 REPLACE: ":replace", 143 144 /** 145 * The parameter name for the destination flag. 146 * @static 147 * @final 148 * @type String 149 */ 150 DESTINATION: ":dest", 151 152 /** 153 * The parameter name for the save parameter prefix. 154 * @static 155 * @final 156 * @type String 157 */ 158 SAVE_PARAM_PREFIX: ":saveParamPrefix", 159 160 /** 161 * The parameter name for input fields that should be ignored by Sling. 162 * @static 163 * @final 164 * @type String 165 */ 166 IGNORE_PARAM: ":ignore", 167 168 /** 169 * The parameter name for login requests. 170 * @static 171 * @final 172 * @type String 173 */ 174 REQUEST_LOGIN_PARAM: "sling:authRequestLogin", 175 176 /** 177 * The login URL. 178 * @static 179 * @final 180 * @type String 181 */ 182 LOGIN_URL: "/system/sling/login.html", 183 184 /** 185 * The logout URL. 186 * @static 187 * @final
188 * @type String 189 */ 190 LOGOUT_URL: "/system/sling/logout.html" 191 }; 192})); 193 194/* 195 * ADOBE CONFIDENTIAL 196 * 197 * Copyright 2012 Adobe Systems Incorporated 198 * All Rights Reserved. 199 * 200 * NOTICE: All information contained herein is, and remains 201 * the property of Adobe Systems Incorporated and its suppliers, 202 * if any. The intellectual and technical concepts contained 203 * herein are proprietary to Adobe Systems Incorporated and its 204 * suppliers and may be covered by U.S. and Foreign Patents, 205 * patents in process, and are protected by trade secret or copyright law. 206 * Dissemination of this information or reproduction of this material 207 * is strictly forbidden unless prior written permission is obtained 208 * from Adobe Systems Incorporated. 209 * 210 */ 211(function(factory) { 212 "use strict"; 213 214 if (typeof module === "object" && module.exports) { 215 module.exports = factory(); 216 } else { 217 var g = window.Granite = window.Granite || {}; 218 g.Util = factory(); 219 } 220}(function() { 221 "use strict"; 222 223 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray#Polyfill 224 var isArray = function(arg) { 225 return Object.prototype.toString.call(arg) === "[object Array]"; 226 }; 227 228 /** 229 * A helper class providing a set of general utilities. 230 * @static 231 * @singleton 232 * @class Granite.Util 233 */ 234 return { 235 /** 236 * Replaces occurrences of <code>{n}</code> in the specified text with the texts from the snippets. 237 * 238 * @example 239 * var text = Granite.Util.patchText("{0} has signed in.", "Jack"); 240 * // text = "Jack has signed in." 241 * var text2 = Granite.Util.patchText("{0} {1} has signed in from {2}.", ["Jack", "McFarland", "x.x.x.x"]); 242 * // text2 = "Jack McFarland has signed in from x.x.x.x." 243 * 244 * @param {String} text The text. 245 * @param {String|String[]} snippets The text(s) replacing <code>{n}</code>. 246 * @returns {String} The patched text. 247 */ 248 patchText: function(text, snippets) { 249 if (snippets) { 250 if (!isArray(snippets)) { 251 text = text.replace("{0}", snippets); 252 } else { 253 for (var i = 0; i < snippets.length; i++) { 254 text = text.replace(("{" + i + "}"), snippets[i]); 255 } 256 } 257 } 258 return text; 259 }, 260 261 /** 262 * Returns the top most accessible window. 263 * Check {@link .setIFrameMode} to avoid security exception message on WebKit browsers 264 * if this method is called in an iFrame included in a window from different domain. 265 * 266 * @returns {Window} The top window. 267 */ 268 getTopWindow: function() { 269 var win = window; 270 if (this.iFrameTopWindow) { 271 return this.iFrameTopWindow; 272 } 273 try { 274 // try to access parent 275 // win.parent.location.href throws an exception if not authorized (e.g. different location in a portlet) 276 while (win.parent && win !== win.parent && win.parent.location.href) { 277 win = win.parent; 278 } 279 } catch (error) { 280 // ignored 281 } 282 return win; 283 }, 284 285 /** 286 * Allows to define if Granite.Util is running in an iFrame and parent window is in another domain 287 * (and optionally define what would be the top window in that case. 288 * This is necessary to use {@link .getTopWindow} in a iFrame on WebKit based browsers because 289 * {@link .getTopWindow} iterates on parent windows to find the top one which triggers a security exception 290 * if one parent window is in a different domain. Exception cannot be caught but is not breaking the JS 291 * execution. 292 * 293 * @param {Window} [topWindow=window] The iFrame top window. Must be running on the same host to avoid 294 * security exception. 295 */ 296 setIFrameMode: function(topWindow) { 297 this.iFrameTopWindow = topWindow || window; 298 }, 299 300 /** 301 * Applies default properties if non-existent into the base object. 302 * Child objects are merged recursively. 303 * REMARK: 304 * - objects are recursively merged 305 * - simple type object properties are copied over the base 306 * - arrays are cloned and override the base (no value merging) 307 * 308 * @param {Object} base The object. 309 * @param {...Object} pass The objects to be copied onto the base. 310 * @returns {Object} The base object with defaults. 311 */ 312 applyDefaults: function() { 313 var override; 314 var base = arguments[0] || {}; 315 316 for (var i = 1; i < arguments.length; i++) { 317 override = arguments[i]; 318 319 for (var name in override) { 320 var value = override[name]; 321 322 if (override.hasOwnProperty(name) && value !== undefined) { 323 if (value !== null && typeof value === "object" && !(value instanceof Array)) { 324 // nested object 325 base[name] = this.applyDefaults(base[name], value); 326 } else if (value instanceof Array) { 327 // override array 328 base[name] = value.slice(0); 329 } else { 330 // simple type 331 base[name] = value; 332 } 333 } 334 } 335 } 336 337 return base; 338 }, 339 340 /** 341 * Returns the keycode from the given event. 342 * It is a normalized value over variation of browsers' inconsistencies. 343 * 344 * @param {UIEvent} event The event. 345 * @returns {Number} The keycode. 346 */ 347 getKeyCode: function(event) { 348 return event.keyCode ? event.keyCode : event.which; 349 } 350 }; 351})); 352 353/* 354 * ADOBE CONFIDENTIAL 355 * 356 * Copyright 2012 Adobe Systems Incorporated 357 * All Rights Reserved. 358 *
359 * NOTICE: All information contained herein is, and remains 360 * the property of Adobe Systems Incorporated and its suppliers, 361 * if any. The intellectual and technical concepts contained 362 * herein are proprietary to Adobe Systems Incorporated and its 363 * suppliers and may be covered by U.S. and Foreign Patents, 364 * patents in process, and are protected by trade secret or copyright law. 365 * Dissemination of this information or reproduction of this material 366 * is strictly forbidden unless prior written permission is obtained 367 * from Adobe Systems Incorporated. 368 * 369 */ 370/* global CQURLInfo:false, G_XHR_HOOK:false */ 371/* eslint strict: 0 */ 372(function(factory) { 373 "use strict"; 374 375 if (typeof module === "object" && module.exports) { 376 module.exports = factory(require("@granite/util"), require("jquery")); 377 } else { 378 window.Granite.HTTP = factory(Granite.Util, jQuery); 379 } 380}(function(util, $) { 381 /** 382 * A helper class providing a set of HTTP-related utilities. 383 * @static 384 * @singleton 385 * @class Granite.HTTP 386 */ 387 return (function() { 388 /** 389 * The context path used on the server. 390 * May only be set by {@link #detectContextPath}.
391 * @type String 392 */ 393 var contextPath = null; 394 395 /** 396 * The regular expression to detect the context path used 397 * on the server using the URL of this script. 398 * @readonly 399 * @type RegExp 400 */ 401 // eslint-disable-next-line max-len 402 var SCRIPT_URL_REGEXP = /^(?:http|https):\/\/[^/]+(\/.*)\/(?:etc\.clientlibs|etc(\/.*)*\/clientlibs|libs(\/.*)*\/clientlibs|apps(\/.*)*\/clientlibs|etc\/designs).*\.js(\?.*)?$/; 403 404 /** 405 * The regular expression to match `#` and other non-ASCII characters in a URI. 406 * @readonly 407 * @type RegExp 408 */ 409 var ENCODE_PATH_REGEXP = /[^\w-.~%:/?[\]@!$&'()*+,;=]/; 410 411 /** 412 * The regular expression to parse URI. 413 * @readonly 414 * @type RegExp 415 * @see https://tools.ietf.org/html/rfc3986#appendix-B 416 */ 417 var URI_REGEXP = /^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; 418 419 /** 420 * Indicates after a session timeout if a refresh has already been triggered 421 * in order to avoid multiple alerts.
422 * @type String 423 */ 424 var loginRedirected = false; 425 426 var self = {}; 427 428 /** 429 * Returns the scheme and authority (userinfo, host, port) components of the given URI; 430 * or an empty string if the URI does not have the components. 431 * 432 * This method assumes the URI is valid. 433 * 434 * e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80` 435 * 436 * @param {String} uri The URI 437 * @returns {String} The scheme and authority components 438 */ 439 self.getSchemeAndAuthority = function(uri) { 440 if (!uri) { 441 return ""; 442 } 443 444 var result = URI_REGEXP.exec(uri); 445 446 if (result === null) { 447 return ""; 448 } 449 450 return [ result[1], result[3] ].join(""); 451 }; 452 453 /** 454 * Returns the context path used on the server. 455 * 456 * @returns {String} The context path 457 */ 458 self.getContextPath = function() { 459 // Keep cache of calculated path. 460 if (contextPath === null) { 461 contextPath = self.detectContextPath(); 462 } 463 return contextPath; 464 }; 465 466 /** 467 * Detects the context path used on the server. 468 * 469 * @returns {String} The context path 470 * @private 471 */ 472 self.detectContextPath = function() { 473 try { 474 if (window.CQURLInfo) { 475 contextPath = CQURLInfo.contextPath || ""; 476 } else { 477 var scripts = document.getElementsByTagName("script"); 478 for (var i = 0; i < scripts.length; i++) { 479 var result = SCRIPT_URL_REGEXP.exec(scripts[i].src); 480 if (result) { 481 contextPath = result[1]; 482 return contextPath; 483 } 484 } 485 contextPath = ""; 486 } 487 } catch (e) { 488 // ignored 489 } 490 491 return contextPath; 492 }; 493 494 /** 495 * Makes sure the specified relative URL starts with the context path 496 * used on the server. If an absolute URL is passed, it will be returned 497 * as-is. 498 * 499 * @param {String} url The URL 500 * @returns {String} The externalized URL 501 */ 502 self.externalize = function(url) { 503 try { 504 if (url.indexOf("/") === 0 && self.getContextPath() && url.indexOf(self.getContextPath() + "/") !== 0) { 505 url = self.getContextPath() + url; 506 } 507 } catch (e) { 508 // ignored 509 } 510 return url; 511 }; 512 513 /** 514 * Removes scheme, authority and context path from the specified 515 * absolute URL if it has the same scheme and authority as the 516 * specified document (or the current one). If a relative URL is passed, 517 * the context path will be stripped if present. 518 * 519 * @param {String} url The URL 520 * @param {String} doc (optional) The document 521 * @returns {String} The internalized URL 522 */ 523 self.internalize = function(url, doc) { 524 if (url.charAt(0) === "/") { 525 if (contextPath === url) { 526 return ""; 527 } else if (contextPath && url.indexOf(contextPath + "/") === 0) { 528 return url.substring(contextPath.length); 529 } else { 530 return url; 531 } 532 } 533 534 if (!doc) { 535 doc = document; 536 } 537 var docHost = self.getSchemeAndAuthority(doc.location.href); 538 var urlHost = self.getSchemeAndAuthority(url); 539 if (docHost === urlHost) { 540 return url.substring(urlHost.length + (contextPath ? contextPath.length : 0)); 541 } else { 542 return url; 543 } 544 }; 545 546 /** 547 * Removes all parts but the path from the specified URL. 548 * <p>Examples:<pre><code> 549 /x/y.sel.html?param=abc => /x/y 550 </code></pre> 551 * <pre><code> 552 http://www.day.com/foo/bar.html => /foo/bar 553 </code></pre><p> 554 * 555 * @param {String} url The URL, may be empty. If empty <code>window.location.href</code> is taken. 556 * @returns {String} The path 557 */ 558 self.getPath = function(url) { 559 if (!url) { 560 if (window.CQURLInfo && CQURLInfo.requestPath) { 561 return CQURLInfo.requestPath; 562 } else { 563 url = window.location.pathname; 564 } 565 } else { 566 url = self.removeParameters(url); 567 url = self.removeAnchor(url); 568 } 569 570 url = self.internalize(url); 571 var i = url.indexOf(".", url.lastIndexOf("/")); 572 if (i !== -1) { 573 url = url.substring(0, i); 574 } 575 return url; 576 }; 577 578 /** 579 * Removes the fragment component from the given URI. 580 * 581 * This method assumes the URI is valid. 582 * 583 * e.g. `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path?query` 584 * 585 * @param {String} uri The URI 586 * @returns {String} The URI without fragment component 587 */ 588 self.removeAnchor = function(uri) { 589 var fragmentIndex = uri.indexOf("#"); 590 if (fragmentIndex >= 0) { 591 return uri.substring(0, fragmentIndex); 592 } else { 593 return uri; 594 } 595 }; 596 597 /** 598 * Removes the query component and its subsequent fragment component from the given URI. 599 * i.e. When query component exists, the subsequent fragment component is also removed. 600 * However, when query component doesn't exist, fragment component is not removed. 601 * 602 * The assumption here is that the usages of `#` before the `?` are intended as part of the path component 603 * that need to be encoded separately. 604 * This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` allows `#`. 605 * 606 * e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment` -> `scheme://userinfo@host:80/path#with#hash` 607 * 608 * @param {String} uri The URL 609 * @returns {String} The URI without the query component and its subsequent fragment component 610 */ 611 self.removeParameters = function(uri) { 612 var queryIndex = uri.indexOf("?"); 613 if (queryIndex >= 0) { 614 return uri.substring(0, queryIndex); 615 } else { 616 return uri; 617 } 618 }; 619 620 /** 621 * Encodes the path component of the given URI if it is not already encoded. 622 * See {@link #encodePath} for the details of the encoding. 623 * 624 * e.g. `scheme://userinfo@host:80/path#with#hash?query#fragment` 625 * -> `scheme://userinfo@host:80/path%23with%23hash?query#fragment` 626 * 627 * @param {String} uri The URI to encode 628 * @returns {String} The encoded URI 629 */ 630 self.encodePathOfURI = function(uri) { 631 var DELIMS = [ "?", "#" ]; 632 633 var parts = [ uri ]; 634 var delim; 635 for (var i = 0, ln = DELIMS.length; i < ln; i++) { 636 delim = DELIMS[i]; 637 if (uri.indexOf(delim) >= 0) { 638 parts = uri.split(delim); 639 break; 640 } 641 } 642 643 if (ENCODE_PATH_REGEXP.test(parts[0])) { 644 parts[0] = self.encodePath(parts[0]); 645 } 646 647 return parts.join(delim); 648 }; 649 650 /** 651 * Encodes the given URI using `encodeURI`. 652 * 653 * This method is used to encode URI components from the scheme component up to the path component (inclusive). 654 * Therefore, `?` and `#` are also encoded in addition. 655 * 656 * However `[` and `]` are not encoded. 657 * The assumption here is that the usages of `[` and `]` are only at the host component (for IPv6), 658 * not at the path component. 659 * This assumption is made because `c.d.cq.commons.jcr.JcrUtil#isValidName` disallows `[` and `]`. 660 * 661 * Examples 662 * 663 * * `scheme://userinfo@host:80/path?query#fragment` -> `scheme://userinfo@host:80/path%3Fquery%23fragment` 664 * * `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/` -> `http://[2001:db8:85a3:8d3:1319:8a2e:370:7348]/` 665 * 666 * @param {String} uri The URI to encode 667 * @returns {String} The encoded URI 668 */ 669 self.encodePath = function(uri) { 670 uri = encodeURI(uri); 671 672 // Decode back `%5B` and `%5D`. 673 // The `[` and `]` are not valid characters at the path component and need to be encoded, 674 // which `encodeURI` does correctly. 675 // However as mentioned in the doc, they are assumed to be used for authority component only. 676 uri = uri.replace(/%5B/g, "[").replace(/%5D/g, "]"); 677 678 uri = uri.replace(/\?/g, "%3F"); 679 uri = uri.replace(/#/g, "%23"); 680 681 return uri; 682 }; 683 684 /** 685 * Handles login redirection if needed. 686 */ 687 self.handleLoginRedirect = function() { 688 if (!loginRedirected) { 689 loginRedirected = true; 690 alert(Granite.I18n.get("Your request could not be completed because you have been signed out.")); 691 692 var l = util.getTopWindow().document.location; 693 l.href = self.externalize("/") + "?resource=" + encodeURIComponent(l.pathname + l.search + l.hash); 694 } 695 }; 696 697 /** 698 * Gets the XHR hooked URL if called in a portlet context 699 * 700 * @param {String} url The URL to get 701 * @param {String} method The method to use to retrieve the XHR hooked URL 702 * @param {Object} params The parameters 703 * @returns {String} The XHR hooked URL if available, the provided URL otherwise 704 */ 705 self.getXhrHook = function(url, method, params) { 706 method = method || "GET"; 707 if (window.G_XHR_HOOK && typeof G_XHR_HOOK === "function") { 708 var p = { 709 "url": url, 710 "method": method 711 }; 712 if (params) { 713 p["params"] = params; 714 } 715 return G_XHR_HOOK(p); 716 } 717 return null; 718 }; 719 720 /** 721 * Evaluates and returns the body of the specified response object. 722 * Alternatively, a URL can be specified, in which case it will be 723 * requested using a synchronous {@link #get} in order to acquire 724 * the response object. 725 * 726 * @param {Object|String} response The response object or URL 727 * @returns {Object} The evaluated response body 728 * @since 5.3 729 */ 730 self.eval = function(response) { 731 if (typeof response !== "object") { 732 response = $.ajax({ 733 url: response, 734 type: "get", 735 async: false 736 }); 737 } 738 try { 739 // support responseText for backward compatibility (pre 5.3) 740 var text = response.body ? response.body : response.responseText; 741 return JSON.parse(text); 742 } catch (e) { 743 // ignored 744 } 745 return null; 746 }; 747 748 return self; 749 }()); 750})); 751 752/* 753 * ADOBE CONFIDENTIAL 754 * ___________________ 755 * 756 * Copyright 2012 Adobe 757 * All Rights Reserved. 758 *
759 * NOTICE: All information contained herein is, and remains 760 * the property of Adobe and its suppliers, if any. The intellectual 761 * and technical concepts contained herein are proprietary to Adobe 762 * and its suppliers and are protected by all applicable intellectual 763 * property laws, including trade secret and copyright laws. 764 * Dissemination of this information or reproduction of this material 765 * is strictly forbidden unless prior written permission is obtained 766 * from Adobe. 767 */ 768(function(factory) { 769 "use strict"; 770 771 if (typeof module === "object" && module.exports) { 772 module.exports = factory(require("@granite/http")); 773 } else { 774 window.Granite.I18n = factory(window.Granite.HTTP); 775 } 776}(function(HTTP) { 777 "use strict"; 778 779 /** 780 * A helper class providing a set of utilities related to internationalization (i18n). 781 * 782 * <h3>Locale Priorities</h3> 783 * <p>The locale is read based on the following priorities:</p> 784 * <ol> 785 * <li>manually specified locale</li> 786 * <li><code>document.documentElement.lang</code></li> 787 * <li><code>Granite.I18n.LOCALE_DEFAULT</code></li> 788 * </ol> 789 * 790 * <h3>Dictionary Priorities</h3> 791 * <p>The dictionary URL is read based on the following priorities:</p> 792 * <ol> 793 * <li>manually specified URL (<code>urlPrefix</code, <code>urlSuffix</code>)</li> 794 * <li><code>data-i18n-dictionary-src</code> attribute at <html> element, 795 * which has the type of <a href="http://tools.ietf.org/html/rfc6570">URI Template</a> string</li> 796 * <li>The URL resolved from default <code>urlPrefix</code> and <code>urlSuffix</code></li> 797 * </ol> 798 * 799 * <h3>URI Template of data-i18n-dictionary-src</h3> 800 * <p>It expects the variable named <code>locale</code>, 801 * which will be fetched from the locale (based on priorities above). 802 * E.g. <code><html lang="en" data-i18n-dictionary-src="/libs/cq/i18n/dict.{+locale}.json"></code>.</p> 803 * 804 * @static 805 * @class Granite.I18n 806 */ 807 return (function() { 808 /** 809 * The map where the dictionaries are stored under their locale. 810 * @type Object 811 */ 812 var dicts = {}; 813 814 /** 815 * The prefix for the URL used to request dictionaries from the server.
816 * @type String 817 */ 818 var urlPrefix = "/libs/cq/i18n/dict."; 819 820 /** 821 * The suffix for the URL used to request dictionaries from the server. 822 * @type String 823 */ 824 var urlSuffix = ".json"; 825 826 /** 827 * The manually specified locale as a String or a function that returns the locale as a string. 828 * @type String 829 */ 830 var manualLocale = undefined; 831 832 /** 833 * If the current locale represents pseudo translations. 834 * In that case the dictionary is expected to provide just a special 835 * translation pattern to automatically convert all original strings. 836 */ 837 var pseudoTranslations = false; 838 839 var languages = null; 840 841 var self = {}; 842 843 /** 844 * Indicates if the dictionary parameters are specified manually. 845 */ 846 var manualDictionary = false; 847 848 var getDictionaryUrl = function(locale) { 849 if (manualDictionary) { 850 return urlPrefix + locale + urlSuffix; 851 } 852 853 var dictionarySrc; 854 var htmlEl = document.querySelector("html"); 855 if (htmlEl) { 856 dictionarySrc = htmlEl.getAttribute("data-i18n-dictionary-src"); 857 } 858 859 if (!dictionarySrc) { 860 return urlPrefix + locale + urlSuffix; 861 } 862 863 // dictionarySrc is a URITemplate 864 // Use simple string replacement for now; for more complicated scenario, please use Granite.URITemplate 865 return dictionarySrc.replace("{locale}", encodeURIComponent(locale)).replace("{+locale}", locale); 866 }; 867 868 var patchText = function(text, snippets) { 869 if (snippets) { 870 if (Array.isArray(snippets)) { 871 for (var i = 0; i < snippets.length; i++) { 872 text = text.replace("{" + i + "}", snippets[i]); 873 } 874 } else { 875 text = text.replace("{0}", snippets); 876 } 877 } 878 return text; 879 }; 880 881 /** 882 * The default locale (en). 883 * @readonly
884 * @type String 885 */ 886 self.LOCALE_DEFAULT = "en"; 887 888 /** 889 * The language code for pseudo translations. 890 * @readonly 891 * @type String 892 */ 893 self.PSEUDO_LANGUAGE = "zz"; 894 895 /** 896 * The dictionary key for pseudo translation pattern. 897 * @readonly 898 * @type String 899 */ 900 self.PSEUDO_PATTERN_KEY = "_pseudoPattern_"; 901 902 /** 903 * Initializes I18n with the given config options: 904 * <ul> 905 * <li>locale: the current locale (defaults to "en")</li> 906 * <li>urlPrefix: the prefix for the URL used to request dictionaries from 907 * the server (defaults to "/libs/cq/i18n/dict.")</li> 908 * <li>urlSuffix: the suffix for the URL used to request dictionaries from 909 * the server (defaults to ".json")</li> 910 * </ul> 911 * Sample config. The dictionary would be requested from 912 * "/apps/i18n/dict.fr.json": 913 <code><pre>{ 914 "locale": "fr", 915 "urlPrefix": "/apps/i18n/dict.", 916 "urlSuffix": ".json" 917 }</pre></code> 918 * 919 * @param {Object} config The config 920 */ 921 self.init = function(config) { 922 config = config || {}; 923 924 this.setLocale(config.locale); 925 this.setUrlPrefix(config.urlPrefix); 926 this.setUrlSuffix(config.urlSuffix); 927 }; 928 929 /** 930 * Sets the current locale. 931 * 932 * @param {String|Function} locale The locale or a function that returns the locale as a string 933 */ 934 self.setLocale = function(locale) { 935 if (!locale) { 936 return; 937 } 938 manualLocale = locale; 939 }; 940 941 /** 942 * Returns the current locale based on the priorities. 943 * 944 * @returns {String} The locale 945 */ 946 self.getLocale = function() { 947 if (typeof manualLocale === "function") { 948 // execute function first time only and store result in currentLocale 949 manualLocale = manualLocale(); 950 } 951 return manualLocale || document.documentElement.lang || self.LOCALE_DEFAULT; 952 }; 953 954 /** 955 * Sets the prefix for the URL used to request dictionaries from 956 * the server. The locale and URL suffix will be appended. 957 * 958 * @param {String} prefix The URL prefix 959 */ 960 self.setUrlPrefix = function(prefix) { 961 if (!prefix) { 962 return; 963 } 964 urlPrefix = prefix; 965 manualDictionary = true; 966 }; 967 968 /** 969 * Sets the suffix for the URL used to request dictionaries from 970 * the server. It will be appended to the URL prefix and locale. 971 * 972 * @param {String} suffix The URL suffix 973 */ 974 self.setUrlSuffix = function(suffix) { 975 if (!suffix) { 976 return; 977 } 978 urlSuffix = suffix; 979 manualDictionary = true; 980 }; 981 982 /** 983 * Returns the dictionary for the specified locale. This method 984 * will request the dictionary using the URL prefix, the locale, 985 * and the URL suffix. If no locale is specified, the current 986 * locale is used. 987 * 988 * @param {String} locale (optional) The locale 989 * @returns {Object} The dictionary 990 */ 991 self.getDictionary = function(locale) { 992 locale = locale || self.getLocale(); 993 994 if (!dicts[locale]) { 995 pseudoTranslations = locale.indexOf(self.PSEUDO_LANGUAGE) === 0; 996 997 try { 998 var xhr = new XMLHttpRequest(); 999 xhr.open("GET", HTTP.externalize(getDictionaryUrl(locale)), false); 1000 xhr.send(); 1001 1002 dicts[locale] = JSON.parse(xhr.responseText); 1003 } catch (e) { 1004 // ignored 1005 } 1006 if (!dicts[locale]) { 1007 dicts[locale] = {}; 1008 } 1009 } 1010 return dicts[locale]; 1011 }; 1012 1013 /** 1014 * Translates the specified text into the current language. 1015 * 1016 * @param {String} text The text to translate 1017 * @param {String[]} snippets The snippets replacing <code>{n}</code> (optional) 1018 * @param {String} note A hint for translators (optional) 1019 * @returns {String} The translated text 1020 */ 1021 self.get = function(text, snippets, note) { 1022 var dict; 1023 var newText; 1024 var lookupText; 1025 1026 dict = self.getDictionary(); 1027 1028 // note that pseudoTranslations is initialized in the getDictionary() call above 1029 lookupText = pseudoTranslations ? self.PSEUDO_PATTERN_KEY 1030 : note ? text + " ((" + note + "))" 1031 : text; 1032 if (dict) { 1033 newText = dict[lookupText]; 1034 } 1035 if (!newText) { 1036 newText = text; 1037 } 1038 if (pseudoTranslations) { 1039 newText = newText.replace("{string}", text).replace("{comment}", note ? note : ""); 1040 } 1041 return patchText(newText, snippets); 1042 }; 1043 1044 /** 1045 * Translates the specified text into the current language. Use this 1046 * method to translate String variables, e.g. data from the server. 1047 * 1048 * @param {String} text The text to translate 1049 * @param {String} note A hint for translators (optional) 1050 * @returns {String} The translated text 1051 */ 1052 self.getVar = function(text, note) { 1053 if (!text) { 1054 return null; 1055 } 1056 return self.get(text, null, note); 1057 }; 1058 1059 /** 1060 * Returns the available languages, including a "title" property with a display name: 1061 * for instance "German" for "de" or "German (Switzerland)" for "de_ch". 1062 * 1063 * @returns {Object} An object with language codes as keys and an object with "title", 1064 * "language", "country" and "defaultCountry" members. 1065 */ 1066 self.getLanguages = function() { 1067 if (!languages) { 1068 try { 1069 // use overlay servlet so customers can define /apps/wcm/core/resources/languages 1070 // TODO: broken!!! 1071 var url = HTTP.externalize("/libs/wcm/core/resources/languages.overlay.infinity.json"); 1072 var xhr = new XMLHttpRequest(); 1073 xhr.open("GET", url, false); 1074 xhr.send(); 1075 1076 var json = JSON.parse(xhr.responseText); 1077
1078 Object.keys(json).forEach(function(prop) { 1079 var lang = json[prop]; 1080 if (lang.language) { 1081 lang.title = self.getVar(lang.language); 1082 } 1083 if (lang.title && lang.country && lang.country !== "*") { 1084 lang.title += " (" + self.getVar(lang.country) + ")"; 1085 } 1086 }); 1087 languages = json; 1088 } catch (e) { 1089 languages = {}; 1090 } 1091 } 1092 return languages; 1093 }; 1094 1095 /** 1096 * Parses a language code string such as "de_CH" and returns an object with 1097 * language and country extracted. The delimiter can be "_" or "-". 1098 * 1099 * @param {String} langCode a language code such as "de" or "de_CH" or "de-ch" 1100 * @returns {Object} an object with "code" ("de_CH"), "language" ("de") and "country" ("CH") 1101 * (or null if langCode was null) 1102 */ 1103 self.parseLocale = function(langCode) { 1104 if (!langCode) { 1105 return null; 1106 } 1107 var pos = langCode.indexOf("_"); 1108 if (pos < 0) { 1109 pos = langCode.indexOf("-"); 1110 } 1111 1112 var language; 1113 var country; 1114 if (pos < 0) { 1115 language = langCode; 1116 country = null; 1117 } else { 1118 language = langCode.substring(0, pos); 1119 country = langCode.substring(pos + 1); 1120 } 1121 return { 1122 code: langCode, 1123 language: language, 1124 country: country 1125 }; 1126 }; 1127 1128 return self; 1129 }()); 1130})); 1131 1132/* 1133 * ADOBE CONFIDENTIAL 1134 * 1135 * Copyright 2012 Adobe Systems Incorporated 1136 * All Rights Reserved. 1137 *
1138 * NOTICE: All information contained herein is, and remains 1139 * the property of Adobe Systems Incorporated and its suppliers, 1140 * if any. The intellectual and technical concepts contained 1141 * herein are proprietary to Adobe Systems Incorporated and its 1142 * suppliers and may be covered by U.S. and Foreign Patents, 1143 * patents in process, and are protected by trade secret or copyright law. 1144 * Dissemination of this information or reproduction of this material 1145 * is strictly forbidden unless prior written permission is obtained 1146 * from Adobe Systems Incorporated. 1147 * 1148 */ 1149(function(factory) { 1150 "use strict"; 1151 1152 if (typeof module === "object" && module.exports) { 1153 module.exports = factory(); 1154 } else { 1155 var g = window.Granite = window.Granite || {}; 1156 g.TouchIndicator = factory(); 1157 } 1158}(function() { 1159 "use strict"; 1160 1161 function createIndicator() { 1162 var el = document.createElement("div"); 1163 el.style.visibility = "hidden"; 1164 // fixed would be better, but flickers on ipad while scrolling 1165 el.style.position = "absolute"; 1166 el.style.width = "30px"; 1167 el.style.height = "30px"; 1168 el.style.borderRadius = "20px"; 1169 el.style.border = "5px solid orange"; 1170 el.style.userSelect = "none"; 1171 el.style.opacity = "0.5"; 1172 el.style.zIndex = "2000"; 1173 el.style.pointerEvents = "none"; 1174 return el; 1175 } 1176 1177 var used = {}; 1178 1179 var unused = []; 1180 1181 /** 1182 * Implements the "Adobe Dynamic Touch Indicator" that tracks touch events and displays a visual indicator for 1183 * screen sharing and presentation purposes. 1184 * 1185 * To enable it, call <code>Granite.TouchIndicator.init()</code> e.g. on document ready: 1186 * <pre><code> 1187 * Granite.$(document).ready(function() { 1188 * Granite.TouchIndicator.init(); 1189 * }); 1190 * </code></pre> 1191 * 1192 * AdobePatentID="2631US01" 1193 */ 1194 return { 1195 debugWithMouse: false, 1196 1197 init: function() { 1198 var self = this; 1199 1200 var update = function(e) { 1201 self.update(e.touches); 1202 return true; 1203 }; 1204 document.addEventListener("touchstart", update); 1205 document.addEventListener("touchmove", update); 1206 document.addEventListener("touchend", update); 1207 1208 if (this.debugWithMouse) { 1209 document.addEventListener("mousemove", function(e) { 1210 e.identifer = "fake"; 1211 self.update([ e ]); 1212 return true; 1213 }); 1214 } 1215 }, 1216 1217 update: function(touches) { 1218 // go over all touch events present in the array 1219 var retained = {}; 1220 for (var i = 0; i < touches.length; i++) { 1221 var touch = touches[i]; 1222 var id = touch.identifier; 1223 1224 // check if we already have a indicator with the correct id 1225 var indicator = used[id]; 1226 if (!indicator) { 1227 // if not, check if we have an unused one 1228 indicator = unused.pop(); 1229 1230 // if not, create a new one and append it to the dom 1231 if (!indicator) { 1232 indicator = createIndicator(); 1233 document.body.appendChild(indicator); 1234 } 1235 } 1236 1237 retained[id] = indicator; 1238 indicator.style.left = (touch.pageX - 20) + "px"; 1239 indicator.style.top = (touch.pageY - 20) + "px"; 1240 indicator.style.visibility = "visible"; 1241 } 1242 1243 // now hide all unused ones and stuff them in the unused array 1244 for (id in used) { 1245 if (used.hasOwnProperty(id) && !retained[id]) { 1246 indicator = used[id]; 1247 indicator.style.visibility = "hidden"; 1248 unused.push(indicator); 1249 } 1250 } 1251 used = retained; 1252 } 1253 }; 1254})); 1255 1256/* 1257 * ADOBE CONFIDENTIAL 1258 * 1259 * Copyright 2012 Adobe Systems Incorporated 1260 * All Rights Reserved. 1261 *
1262 * NOTICE: All information contained herein is, and remains 1263 * the property of Adobe Systems Incorporated and its suppliers, 1264 * if any. The intellectual and technical concepts contained 1265 * herein are proprietary to Adobe Systems Incorporated and its 1266 * suppliers and may be covered by U.S. and Foreign Patents, 1267 * patents in process, and are protected by trade secret or copyright law. 1268 * Dissemination of this information or reproduction of this material 1269 * is strictly forbidden unless prior written permission is obtained 1270 * from Adobe Systems Incorporated. 1271 * 1272 */ 1273(function(factory) { 1274 "use strict"; 1275 1276 if (typeof module === "object" && module.exports) { 1277 module.exports = factory(); 1278 } else { 1279 var g = window.Granite = window.Granite || {}; 1280 g.OptOutUtil = factory(); 1281 } 1282}(function($) { 1283 "use strict"; 1284 1285 function trim(s) { 1286 if (String.prototype.trim) { 1287 return s.trim(); 1288 } 1289 return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); 1290 } 1291 1292 /** 1293 * A library to determine whether any opt-out cookie is set and whether a given cookie name is white-listed. 1294 * 1295 * The opt-out and white-list cookie names are determined by a server-side configuration 1296 * (<code>com.adobe.granite.security.commons.OptOutService</code>) and provided to this tool by an optionally 1297 * included component (<code>/libs/granite/security/components/optout</code>) which provides a global JSON object 1298 * named <code>GraniteOptOutConfig</code>. 1299 * 1300 * @static 1301 * @class Granite.OptOutUtil 1302 */ 1303 return (function() { 1304 var self = {}; 1305 1306 /** 1307 * The names of cookies the presence of which indicates the user has opted out.
1308 * @type String[] 1309 */ 1310 var optOutCookieNames = []; 1311 1312 /** 1313 * The names of cookies which may still be set in spite of the user having opted out. 1314 * @type String[] 1315 */ 1316 var whitelistedCookieNames = []; 1317 1318 /** 1319 * Initializes this tool with an opt-out configuration. 1320 * 1321 * The following options are supported: 1322 * <ul> 1323 * <li>cookieNames: an array of cookie names representing opt-out cookies. Defaults to empty.</li> 1324 * <li>whitelistCookieNames: an array of cookies representing white-listed cookies. Defaults to empty.</li> 1325 * </ul> 1326 * 1327 * @param {Object} config The opt-out configuration. 1328 * 1329 * @example 1330 * { 1331 * "cookieNames": ["omniture_optout","cq-opt-out"], 1332 * "whitelistCookieNames": ["someAppCookie", "anotherImportantAppCookie"] 1333 * } 1334 */ 1335 self.init = function(config) { 1336 if (config) { 1337 optOutCookieNames = config.cookieNames || []; 1338 whitelistedCookieNames = config.whitelistCookieNames || []; 1339 } else { 1340 optOutCookieNames = []; 1341 whitelistedCookieNames = []; 1342 } 1343 }; 1344 1345 /** 1346 * Returns the array of configured cookie names representing opt-out cookies. 1347 * 1348 * @returns {String[]} The cookie names. 1349 */ 1350 self.getCookieNames = function() { 1351 return optOutCookieNames; 1352 }; 1353 1354 /** 1355 * Returns the array of configured cookie names representing white-listed cookies. 1356 * 1357 * @returns {String[]} The cookie names. 1358 */ 1359 self.getWhitelistCookieNames = function() { 1360 return whitelistedCookieNames; 1361 }; 1362 1363 /** 1364 * Determines whether the user (browser) has elected to opt-out. 1365 * This is indicated by the presence of one of the cookies retrieved through {@link #getCookieNames()}. 1366 * 1367 * @returns {Boolean} <code>true</code> if an opt-cookie was found in the browser's cookies; 1368 * <code>false</code> otherwise. 1369 */ 1370 self.isOptedOut = function() { 1371 var browserCookies = document.cookie.split(";"); 1372 for (var i = 0; i < browserCookies.length; i++) { 1373 var cookie = browserCookies[i]; 1374 var cookieName = trim(cookie.split("=")[0]); 1375 if (self.getCookieNames().indexOf(cookieName) >= 0) { 1376 return true; 1377 } 1378 } 1379 return false; 1380 }; 1381 1382 /** 1383 * Determines whether the given <code>cookieName</code> may be used to set a cookie. 1384 * This is the case if either opt-out is inactive (<code>{@link #isOptedOut()} === false</code>) or it is 1385 * active and the give cookie name was found in the white-list ({@link #getWhitelistCookieNames()}). 1386 * 1387 * @param {String} cookieName The name of the cookie to check. 1388 * @returns {Boolean} <code>true</code> if a cookie of this name may be used with respect to the opt-out status; 1389 * <code>false</code> otherwise. 1390 */ 1391 self.maySetCookie = function(cookieName) { 1392 return !(self.isOptedOut() && self.getWhitelistCookieNames().indexOf(cookieName) === -1); 1393 }; 1394 1395 return self; 1396 }()); 1397})); 1398 1399/************************************************************************* 1400 * ADOBE CONFIDENTIAL 1401 * ___________________ 1402 * 1403 * Copyright 2019 Adobe 1404 * All Rights Reserved. 1405 *
1406 * NOTICE: All information contained herein is, and remains 1407 * the property of Adobe and its suppliers, if any. The intellectual 1408 * and technical concepts contained herein are proprietary to Adobe 1409 * and its suppliers and are protected by all applicable intellectual 1410 * property laws, including trade secret and copyright laws. 1411 * Dissemination of this information or reproduction of this material 1412 * is strictly forbidden unless prior written permission is obtained 1413 * from Adobe. 1414 **************************************************************************/ 1415(function(factory) { 1416 "use strict"; 1417 1418 if (typeof module === "object" && module.exports) { 1419 module.exports = factory(); 1420 } else { 1421 var g = window.Granite = window.Granite || {}; 1422 g.Toggles = factory(); 1423 } 1424}(function() { 1425 "use strict"; 1426 1427 var toggles = null; 1428 1429 /** 1430 * Requests toggle status from the toggle router servlet. 1431 * 1432 * To use it, call <code>Granite.Toggles.isEnabled("toggle-name")</code> e.g. on document ready: 1433 * <pre><code> 1434 * Granite.$(document).ready(function() { 1435 * Granite.Toggles.isEnabled("sprint7-ft21"); 1436 * }); 1437 * </code></pre> 1438 */ 1439 return { 1440 isEnabled: function(toggleName) { 1441 toggles = toggles || fetchToggles(); 1442 return (toggles || { enabled: [] }).enabled.includes(toggleName); 1443 1444 function fetchToggles() { 1445 var request = new XMLHttpRequest(); 1446 request.open("GET", Granite.HTTP.externalize("/etc.clientlibs/toggles.json"), false); 1447 request.send(null); 1448 if (request.status === 200) { 1449 return JSON.parse(request.responseText); 1450 } else { 1451 return null; 1452 } 1453 } 1454 } 1455 }; 1456})); 1457 1458/* 1459 * ADOBE CONFIDENTIAL 1460 * 1461 * Copyright 2012 Adobe Systems Incorporated 1462 * All Rights Reserved. 1463 *
1464 * NOTICE: All information contained herein is, and remains 1465 * the property of Adobe Systems Incorporated and its suppliers, 1466 * if any. The intellectual and technical concepts contained 1467 * herein are proprietary to Adobe Systems Incorporated and its 1468 * suppliers and may be covered by U.S. and Foreign Patents, 1469 * patents in process, and are protected by trade secret or copyright law. 1470 * Dissemination of this information or reproduction of this material 1471 * is strictly forbidden unless prior written permission is obtained 1472 * from Adobe Systems Incorporated. 1473 * 1474 */ 1475 1476 1477//------------------------------------------------------------------------------ 1478// Initialize the Granite utils library 1479 1480Granite.OptOutUtil.init(window.GraniteOptOutConfig); 1481Granite.HTTP.detectContextPath(); 1482
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.