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 * Copyright 2012 Adobe Systems Incorporated 756 * All Rights Reserved. 757 *
758 * NOTICE: All information contained herein is, and remains 759 * the property of Adobe Systems Incorporated and its suppliers, 760 * if any. The intellectual and technical concepts contained 761 * herein are proprietary to Adobe Systems Incorporated and its 762 * suppliers and may be covered by U.S. and Foreign Patents, 763 * patents in process, and are protected by trade secret or copyright law. 764 * Dissemination of this information or reproduction of this material 765 * is strictly forbidden unless prior written permission is obtained 766 * from Adobe Systems Incorporated. 767 * 768 */ 769(function(factory) { 770 "use strict"; 771 772 if (typeof module === "object" && module.exports) { 773 module.exports = factory(require("@granite/http")); 774 } else { 775 window.Granite.I18n = factory(window.Granite.HTTP); 776 } 777}(function(HTTP) { 778 "use strict"; 779 780 /** 781 * A helper class providing a set of utilities related to internationalization (i18n). 782 * 783 * <h3>Locale Priorities</h3> 784 * <p>The locale is read based on the following priorities:</p> 785 * <ol> 786 * <li>manually specified locale</li> 787 * <li><code>document.documentElement.lang</code></li> 788 * <li><code>Granite.I18n.LOCALE_DEFAULT</code></li> 789 * </ol> 790 * 791 * <h3>Dictionary Priorities</h3> 792 * <p>The dictionary URL is read based on the following priorities:</p> 793 * <ol> 794 * <li>manually specified URL (<code>urlPrefix</code, <code>urlSuffix</code>)</li> 795 * <li><code>data-i18n-dictionary-src</code> attribute at <html> element, 796 * which has the type of <a href="http://tools.ietf.org/html/rfc6570">URI Template</a> string</li> 797 * <li>The URL resolved from default <code>urlPrefix</code> and <code>urlSuffix</code></li> 798 * </ol> 799 * 800 * <h3>URI Template of data-i18n-dictionary-src</h3> 801 * <p>It expects the variable named <code>locale</code>, 802 * which will be fetched from the locale (based on priorities above). 803 * E.g. <code><html lang="en" data-i18n-dictionary-src="/libs/cq/i18n/dict.{+locale}.json"></code>.</p> 804 * 805 * @static 806 * @class Granite.I18n 807 */ 808 return (function() { 809 /** 810 * The map where the dictionaries are stored under their locale. 811 * @type Object 812 */ 813 var dicts = {}; 814 815 /** 816 * The prefix for the URL used to request dictionaries from the server.
817 * @type String 818 */ 819 var urlPrefix = "/libs/cq/i18n/dict."; 820 821 /** 822 * The suffix for the URL used to request dictionaries from the server. 823 * @type String 824 */ 825 var urlSuffix = ".json"; 826 827 /** 828 * The manually specified locale as a String or a function that returns the locale as a string. 829 * @type String 830 */ 831 var manualLocale = undefined; 832 833 /** 834 * If the current locale represents pseudo translations. 835 * In that case the dictionary is expected to provide just a special 836 * translation pattern to automatically convert all original strings. 837 */ 838 var pseudoTranslations = false; 839 840 var languages = null; 841 842 var self = {}; 843 844 /** 845 * Indicates if the dictionary parameters are specified manually. 846 */ 847 var manualDictionary = false; 848 849 var getDictionaryUrl = function(locale) { 850 if (manualDictionary) { 851 return urlPrefix + locale + urlSuffix; 852 } 853 854 var dictionarySrc; 855 var htmlEl = document.querySelector("html"); 856 if (htmlEl) { 857 dictionarySrc = htmlEl.getAttribute("data-i18n-dictionary-src"); 858 } 859 860 if (!dictionarySrc) { 861 return urlPrefix + locale + urlSuffix; 862 } 863 864 // dictionarySrc is a URITemplate 865 // Use simple string replacement for now; for more complicated scenario, please use Granite.URITemplate 866 return dictionarySrc.replace("{locale}", encodeURIComponent(locale)).replace("{+locale}", locale); 867 }; 868 869 var patchText = function(text, snippets) { 870 if (snippets) { 871 if (Array.isArray(snippets)) { 872 for (var i = 0; i < snippets.length; i++) { 873 text = text.replace("{" + i + "}", snippets[i]); 874 } 875 } else { 876 text = text.replace("{0}", snippets); 877 } 878 } 879 return text; 880 }; 881 882 /** 883 * The default locale (en). 884 * @readonly
885 * @type String 886 */ 887 self.LOCALE_DEFAULT = "en"; 888 889 /** 890 * The language code for pseudo translations. 891 * @readonly 892 * @type String 893 */ 894 self.PSEUDO_LANGUAGE = "zz"; 895 896 /** 897 * The dictionary key for pseudo translation pattern. 898 * @readonly 899 * @type String 900 */ 901 self.PSEUDO_PATTERN_KEY = "_pseudoPattern_"; 902 903 /** 904 * Initializes I18n with the given config options: 905 * <ul> 906 * <li>locale: the current locale (defaults to "en")</li> 907 * <li>urlPrefix: the prefix for the URL used to request dictionaries from 908 * the server (defaults to "/libs/cq/i18n/dict.")</li> 909 * <li>urlSuffix: the suffix for the URL used to request dictionaries from 910 * the server (defaults to ".json")</li> 911 * </ul> 912 * Sample config. The dictionary would be requested from 913 * "/apps/i18n/dict.fr.json": 914 <code><pre>{ 915 "locale": "fr", 916 "urlPrefix": "/apps/i18n/dict.", 917 "urlSuffix": ".json" 918 }</pre></code> 919 * 920 * @param {Object} config The config 921 */ 922 self.init = function(config) { 923 config = config || {}; 924 925 this.setLocale(config.locale); 926 this.setUrlPrefix(config.urlPrefix); 927 this.setUrlSuffix(config.urlSuffix); 928 }; 929 930 /** 931 * Sets the current locale. 932 * 933 * @param {String|Function} locale The locale or a function that returns the locale as a string 934 */ 935 self.setLocale = function(locale) { 936 if (!locale) { 937 return; 938 } 939 manualLocale = locale; 940 }; 941 942 /** 943 * Returns the current locale based on the priorities. 944 * 945 * @returns {String} The locale 946 */ 947 self.getLocale = function() { 948 if (typeof manualLocale === "function") { 949 // execute function first time only and store result in currentLocale 950 manualLocale = manualLocale(); 951 } 952 return manualLocale || document.documentElement.lang || self.LOCALE_DEFAULT; 953 }; 954 955 /** 956 * Sets the prefix for the URL used to request dictionaries from 957 * the server. The locale and URL suffix will be appended. 958 * 959 * @param {String} prefix The URL prefix 960 */ 961 self.setUrlPrefix = function(prefix) { 962 if (!prefix) { 963 return; 964 } 965 urlPrefix = prefix; 966 manualDictionary = true; 967 }; 968 969 /** 970 * Sets the suffix for the URL used to request dictionaries from 971 * the server. It will be appended to the URL prefix and locale. 972 * 973 * @param {String} suffix The URL suffix 974 */ 975 self.setUrlSuffix = function(suffix) { 976 if (!suffix) { 977 return; 978 } 979 urlSuffix = suffix; 980 manualDictionary = true; 981 }; 982 983 /** 984 * Returns the dictionary for the specified locale. This method 985 * will request the dictionary using the URL prefix, the locale, 986 * and the URL suffix. If no locale is specified, the current 987 * locale is used. 988 * 989 * @param {String} locale (optional) The locale 990 * @returns {Object} The dictionary 991 */ 992 self.getDictionary = function(locale) { 993 locale = locale || self.getLocale(); 994 995 if (!dicts[locale]) { 996 pseudoTranslations = locale.indexOf(self.PSEUDO_LANGUAGE) === 0; 997 998 $.ajax({ 999 url: getDictionaryUrl(locale), 1000 type: 'GET', 1001 async: false, 1002 error: function(){ 1003 return true; 1004 }, 1005 success: function(data){ 1006 dicts[locale] = data; 1007 1008 if (!dicts[locale]) { 1009 dicts[locale] = {}; 1010 } 1011 } 1012 }); 1013 //try { 1014 1015 /*var xhr = new XMLHttpRequest(); 1016 xhr.open("GET", HTTP.externalize(getDictionaryUrl(locale)), false); 1017 xhr.send(); 1018 1019 dicts[locale] = JSON.parse(xhr.responseText);*/ 1020 1021 1022 //} catch (e) { 1023 // ignored 1024 //} 1025 /*if (!dicts[locale]) { 1026 dicts[locale] = {}; 1027 }*/ 1028 } 1029 1030 return dicts[locale]; 1031 1032 }; 1033 1034 /** 1035 * Translates the specified text into the current language. 1036 * 1037 * @param {String} text The text to translate 1038 * @param {String[]} snippets The snippets replacing <code>{n}</code> (optional) 1039 * @param {String} note A hint for translators (optional) 1040 * @returns {String} The translated text 1041 */ 1042 self.get = function(text, snippets, note) { 1043 var dict; 1044 var newText; 1045 var lookupText; 1046 1047 dict = self.getDictionary(); 1048 1049 // note that pseudoTranslations is initialized in the getDictionary() call above 1050 lookupText = pseudoTranslations ? self.PSEUDO_PATTERN_KEY 1051 : note ? text + " ((" + note + "))" 1052 : text; 1053 if (dict) { 1054 newText = dict[lookupText]; 1055 } 1056 if (!newText) { 1057 newText = text; 1058 } 1059 if (pseudoTranslations) { 1060 newText = newText.replace("{string}", text).replace("{comment}", note ? note : ""); 1061 } 1062 return patchText(newText, snippets); 1063 }; 1064 1065 /** 1066 * Translates the specified text into the current language. Use this 1067 * method to translate String variables, e.g. data from the server. 1068 * 1069 * @param {String} text The text to translate 1070 * @param {String} note A hint for translators (optional) 1071 * @returns {String} The translated text 1072 */ 1073 self.getVar = function(text, note) { 1074 if (!text) { 1075 return null; 1076 } 1077 return self.get(text, null, note); 1078 }; 1079 1080 /** 1081 * Returns the available languages, including a "title" property with a display name: 1082 * for instance "German" for "de" or "German (Switzerland)" for "de_ch". 1083 * 1084 * @returns {Object} An object with language codes as keys and an object with "title", 1085 * "language", "country" and "defaultCountry" members. 1086 */ 1087 self.getLanguages = function() { 1088 if (!languages) { 1089 try { 1090 // use overlay servlet so customers can define /apps/wcm/core/resources/languages 1091 // TODO: broken!!! 1092 var url = HTTP.externalize("/libs/wcm/core/resources/languages.overlay.infinity.json"); 1093 var xhr = new XMLHttpRequest(); 1094 xhr.open("GET", url, false); 1095 xhr.send(); 1096 1097 var json = JSON.parse(xhr.responseText); 1098
1099 Object.keys(json).forEach(function(prop) { 1100 var lang = json[prop]; 1101 if (lang.language) { 1102 lang.title = self.getVar(lang.language); 1103 } 1104 if (lang.title && lang.country && lang.country !== "*") { 1105 lang.title += " (" + self.getVar(lang.country) + ")"; 1106 } 1107 }); 1108 languages = json; 1109 } catch (e) { 1110 languages = {}; 1111 } 1112 } 1113 return languages; 1114 }; 1115 1116 /** 1117 * Parses a language code string such as "de_CH" and returns an object with 1118 * language and country extracted. The delimiter can be "_" or "-". 1119 * 1120 * @param {String} langCode a language code such as "de" or "de_CH" or "de-ch" 1121 * @returns {Object} an object with "code" ("de_CH"), "language" ("de") and "country" ("CH") 1122 * (or null if langCode was null) 1123 */ 1124 self.parseLocale = function(langCode) { 1125 if (!langCode) { 1126 return null; 1127 } 1128 var pos = langCode.indexOf("_"); 1129 if (pos < 0) { 1130 pos = langCode.indexOf("-"); 1131 } 1132 1133 var language; 1134 var country; 1135 if (pos < 0) { 1136 language = langCode; 1137 country = null; 1138 } else { 1139 language = langCode.substring(0, pos); 1140 country = langCode.substring(pos + 1); 1141 } 1142 return { 1143 code: langCode, 1144 language: language, 1145 country: country 1146 }; 1147 }; 1148 1149 return self; 1150 }()); 1151})); 1152 1153/* 1154 * ADOBE CONFIDENTIAL 1155 * 1156 * Copyright 2012 Adobe Systems Incorporated 1157 * All Rights Reserved. 1158 *
1159 * NOTICE: All information contained herein is, and remains 1160 * the property of Adobe Systems Incorporated and its suppliers, 1161 * if any. The intellectual and technical concepts contained 1162 * herein are proprietary to Adobe Systems Incorporated and its 1163 * suppliers and may be covered by U.S. and Foreign Patents, 1164 * patents in process, and are protected by trade secret or copyright law. 1165 * Dissemination of this information or reproduction of this material 1166 * is strictly forbidden unless prior written permission is obtained 1167 * from Adobe Systems Incorporated. 1168 * 1169 */ 1170(function(factory) { 1171 "use strict"; 1172 1173 if (typeof module === "object" && module.exports) { 1174 module.exports = factory(); 1175 } else { 1176 var g = window.Granite = window.Granite || {}; 1177 g.TouchIndicator = factory(); 1178 } 1179}(function() { 1180 "use strict"; 1181 1182 function createIndicator() { 1183 var el = document.createElement("div"); 1184 el.style.visibility = "hidden"; 1185 // fixed would be better, but flickers on ipad while scrolling 1186 el.style.position = "absolute"; 1187 el.style.width = "30px"; 1188 el.style.height = "30px"; 1189 el.style.borderRadius = "20px"; 1190 el.style.border = "5px solid orange"; 1191 el.style.userSelect = "none"; 1192 el.style.opacity = "0.5"; 1193 el.style.zIndex = "2000"; 1194 el.style.pointerEvents = "none"; 1195 return el; 1196 } 1197 1198 var used = {}; 1199 1200 var unused = []; 1201 1202 /** 1203 * Implements the "Adobe Dynamic Touch Indicator" that tracks touch events and displays a visual indicator for 1204 * screen sharing and presentation purposes. 1205 * 1206 * To enable it, call <code>Granite.TouchIndicator.init()</code> e.g. on document ready: 1207 * <pre><code> 1208 * Granite.$(document).ready(function() { 1209 * Granite.TouchIndicator.init(); 1210 * }); 1211 * </code></pre> 1212 * 1213 * AdobePatentID="2631US01" 1214 */ 1215 return { 1216 debugWithMouse: false, 1217 1218 init: function() { 1219 var self = this; 1220 1221 var update = function(e) { 1222 self.update(e.touches); 1223 return true; 1224 }; 1225 document.addEventListener("touchstart", update); 1226 document.addEventListener("touchmove", update); 1227 document.addEventListener("touchend", update); 1228 1229 if (this.debugWithMouse) { 1230 document.addEventListener("mousemove", function(e) { 1231 e.identifer = "fake"; 1232 self.update([ e ]); 1233 return true; 1234 }); 1235 } 1236 }, 1237 1238 update: function(touches) { 1239 // go over all touch events present in the array 1240 var retained = {}; 1241 for (var i = 0; i < touches.length; i++) { 1242 var touch = touches[i]; 1243 var id = touch.identifier; 1244 1245 // check if we already have a indicator with the correct id 1246 var indicator = used[id]; 1247 if (!indicator) { 1248 // if not, check if we have an unused one 1249 indicator = unused.pop(); 1250 1251 // if not, create a new one and append it to the dom 1252 if (!indicator) { 1253 indicator = createIndicator(); 1254 document.body.appendChild(indicator); 1255 } 1256 } 1257 1258 retained[id] = indicator; 1259 indicator.style.left = (touch.pageX - 20) + "px"; 1260 indicator.style.top = (touch.pageY - 20) + "px"; 1261 indicator.style.visibility = "visible"; 1262 } 1263 1264 // now hide all unused ones and stuff them in the unused array 1265 for (id in used) { 1266 if (used.hasOwnProperty(id) && !retained[id]) { 1267 indicator = used[id]; 1268 indicator.style.visibility = "hidden"; 1269 unused.push(indicator); 1270 } 1271 } 1272 used = retained; 1273 } 1274 }; 1275})); 1276 1277/* 1278 * ADOBE CONFIDENTIAL 1279 * 1280 * Copyright 2012 Adobe Systems Incorporated 1281 * All Rights Reserved. 1282 *
1283 * NOTICE: All information contained herein is, and remains 1284 * the property of Adobe Systems Incorporated and its suppliers, 1285 * if any. The intellectual and technical concepts contained 1286 * herein are proprietary to Adobe Systems Incorporated and its 1287 * suppliers and may be covered by U.S. and Foreign Patents, 1288 * patents in process, and are protected by trade secret or copyright law. 1289 * Dissemination of this information or reproduction of this material 1290 * is strictly forbidden unless prior written permission is obtained 1291 * from Adobe Systems Incorporated. 1292 * 1293 */ 1294(function(factory) { 1295 "use strict"; 1296 1297 if (typeof module === "object" && module.exports) { 1298 module.exports = factory(); 1299 } else { 1300 var g = window.Granite = window.Granite || {}; 1301 g.OptOutUtil = factory(); 1302 } 1303}(function($) { 1304 "use strict"; 1305 1306 function trim(s) { 1307 if (String.prototype.trim) { 1308 return s.trim(); 1309 } 1310 return s.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); 1311 } 1312 1313 /** 1314 * A library to determine whether any opt-out cookie is set and whether a given cookie name is white-listed. 1315 * 1316 * The opt-out and white-list cookie names are determined by a server-side configuration 1317 * (<code>com.adobe.granite.security.commons.OptOutService</code>) and provided to this tool by an optionally 1318 * included component (<code>/libs/granite/security/components/optout</code>) which provides a global JSON object 1319 * named <code>GraniteOptOutConfig</code>. 1320 * 1321 * @static 1322 * @class Granite.OptOutUtil 1323 */ 1324 return (function() { 1325 var self = {}; 1326 1327 /** 1328 * The names of cookies the presence of which indicates the user has opted out.
1329 * @type String[] 1330 */ 1331 var optOutCookieNames = []; 1332 1333 /** 1334 * The names of cookies which may still be set in spite of the user having opted out. 1335 * @type String[] 1336 */ 1337 var whitelistedCookieNames = []; 1338 1339 /** 1340 * Initializes this tool with an opt-out configuration. 1341 * 1342 * The following options are supported: 1343 * <ul> 1344 * <li>cookieNames: an array of cookie names representing opt-out cookies. Defaults to empty.</li> 1345 * <li>whitelistCookieNames: an array of cookies representing white-listed cookies. Defaults to empty.</li> 1346 * </ul> 1347 * 1348 * @param {Object} config The opt-out configuration. 1349 * 1350 * @example 1351 * { 1352 * "cookieNames": ["omniture_optout","cq-opt-out"], 1353 * "whitelistCookieNames": ["someAppCookie", "anotherImportantAppCookie"] 1354 * } 1355 */ 1356 self.init = function(config) { 1357 if (config) { 1358 optOutCookieNames = config.cookieNames || []; 1359 whitelistedCookieNames = config.whitelistCookieNames || []; 1360 } else { 1361 optOutCookieNames = []; 1362 whitelistedCookieNames = []; 1363 } 1364 }; 1365 1366 /** 1367 * Returns the array of configured cookie names representing opt-out cookies. 1368 * 1369 * @returns {String[]} The cookie names. 1370 */ 1371 self.getCookieNames = function() { 1372 return optOutCookieNames; 1373 }; 1374 1375 /** 1376 * Returns the array of configured cookie names representing white-listed cookies. 1377 * 1378 * @returns {String[]} The cookie names. 1379 */ 1380 self.getWhitelistCookieNames = function() { 1381 return whitelistedCookieNames; 1382 }; 1383 1384 /** 1385 * Determines whether the user (browser) has elected to opt-out. 1386 * This is indicated by the presence of one of the cookies retrieved through {@link #getCookieNames()}. 1387 * 1388 * @returns {Boolean} <code>true</code> if an opt-cookie was found in the browser's cookies; 1389 * <code>false</code> otherwise. 1390 */ 1391 self.isOptedOut = function() { 1392 var browserCookies = document.cookie.split(";"); 1393 for (var i = 0; i < browserCookies.length; i++) { 1394 var cookie = browserCookies[i]; 1395 var cookieName = trim(cookie.split("=")[0]); 1396 if (self.getCookieNames().indexOf(cookieName) >= 0) { 1397 return true; 1398 } 1399 } 1400 return false; 1401 }; 1402 1403 /** 1404 * Determines whether the given <code>cookieName</code> may be used to set a cookie. 1405 * This is the case if either opt-out is inactive (<code>{@link #isOptedOut()} === false</code>) or it is 1406 * active and the give cookie name was found in the white-list ({@link #getWhitelistCookieNames()}). 1407 * 1408 * @param {String} cookieName The name of the cookie to check. 1409 * @returns {Boolean} <code>true</code> if a cookie of this name may be used with respect to the opt-out status; 1410 * <code>false</code> otherwise. 1411 */ 1412 self.maySetCookie = function(cookieName) { 1413 return !(self.isOptedOut() && self.getWhitelistCookieNames().indexOf(cookieName) === -1); 1414 }; 1415 1416 return self; 1417 }()); 1418})); 1419 1420/* 1421 * ADOBE CONFIDENTIAL 1422 * 1423 * Copyright 2012 Adobe Systems Incorporated 1424 * All Rights Reserved. 1425 *
vendor: 17,841 bytes, lines 1426-1451
1426 * NOTICE: All information contained herein is, and remains 1427 * the property of Adobe Systems Incorporated and its suppliers, 1428 * if any. The intellectual and technical concepts contained 1429 * herein are proprietary to Adobe Systems Incorporated and its 1430 * suppliers and may be covered by U.S. and Foreign Patents, 1431 * patents in process, and are protected by trade secret or copyright law. 1432 * Dissemination of this information or reproduction of this material 1433 * is strictly forbidden unless prior written permission is obtained 1434 * from Adobe Systems Incorporated. 1435 * 1436 */ 1437 1438 1439//------------------------------------------------------------------------------ 1440// Initialize the Granite utils library 1441 1442Granite.OptOutUtil.init(window.GraniteOptOutConfig); 1443Granite.HTTP.detectContextPath(); 1444 1445 1446/*! Hammer.JS - v2.0.8 - 2016-04-23 1447 * http://hammerjs.github.io/ 1448 * 1449 * Copyright (c) 2016 Jorik Tangelder; 1450 * Licensed under the MIT license */ 1451!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(b,c,d){var e="DEPRECATED METHOD: "+c+"\n"+d+" AT \n";return function(){var c=new Error("get-stack-trace"),d=c&&c.stack?c.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function s(a){return Array.prototype.slice.call(a,0)}function t(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];r(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ma.length;){if(c=ma[g],e=c?c+f:b,e in a)return e;g++}return d}function v(){return ua++}function w(b){var c=b.ownerDocument||b;return c.defaultView||c.parentWindow||a}function x(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){k(a.options.enable,[a])&&c.handler(b)},this.init()}function y(a){var b,c=a.options.inputClass;return new(b=c?c:xa?M:ya?P:wa?R:L)(a,z)}function z(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&Ea&&d-e===0,g=b&(Ga|Ha)&&d-e===0;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,A(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function A(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=D(b)),e>1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:pa(a.pointers[c].clientX),clientY:pa(a.pointers[c].clientY)},c++;return{timeStamp:ra(),pointers:b,center:E(b),deltaX:a.deltaX,deltaY:a.deltaY}}function E(a){var b=a.length;if(1===b)return{x:pa(a[0].clientX),y:pa(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Ga|Ha)&&delete d[g[e].identifier],e++;return h.length?[t(f.concat(h),"identifier",!0),h]:void 0}function R(){x.apply(this,arguments);var a=j(this.handler,this);this.touch=new P(this.manager,a),this.mouse=new L(this.manager,a),this.primaryTouch=null,this.lastTouches=[]}function S(a,b){a&Ea?(this.primaryTouch=b.changedPointers[0].identifier,T.call(this,b)):a&(Ga|Ha)&&T.call(this,b)}function T(a){var b=a.changedPointers[0];if(b.identifier===this.primaryTouch){var c={x:b.clientX,y:b.clientY};this.lastTouches.push(c);var d=this.lastTouches,e=function(){var a=d.indexOf(c);a>-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d<this.lastTouches.length;d++){var e=this.lastTouches[d],f=Math.abs(b-e.x),g=Math.abs(c-e.y);if(db>=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;c<arguments.length;c++){var e=arguments[c];if(e!==d&&null!==e)for(var f in e)e.hasOwnProperty(f)&&(b[f]=e[f])}return b}:Object.assign;var sa=h(function(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a},"extend","Use `assign`."),ta=h(function(a,b){return sa(a,b,!0)},"merge","Use `assign`."),ua=1,va=/mobile|tablet|ip(ad|hone|od)|android/i,wa="ontouchstart"in a,xa=u(a,"PointerEvent")!==d,ya=wa&&va.test(navigator.userAgent),za="touch",Aa="pen",Ba="mouse",Ca="kinect",Da=25,Ea=1,Fa=2,Ga=4,Ha=8,Ia=1,Ja=2,Ka=4,La=8,Ma=16,Na=Ja|Ka,Oa=La|Ma,Pa=Na|Oa,Qa=["x","y"],Ra=["clientX","clientY"];x.prototype={handler:function(){},init:function(){this.evEl&&m(this.element,this.evEl,this.domHandler),this.evTarget&&m(this.target,this.evTarget,this.domHandler),this.evWin&&m(w(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&n(this.element,this.evEl,this.domHandler),this.evTarget&&n(this.target,this.evTarget,this.domHandler),this.evWin&&n(w(this.element),this.evWin,this.domHandler)}};var Sa={mousedown:Ea,mousemove:Fa,mouseup:Ga},Ta="mousedown",Ua="mousemove mouseup";i(L,x,{handler:function(a){var b=Sa[a.type];b&Ea&&0===a.button&&(this.pressed=!0),b&Fa&&1!==a.which&&(b=Ga),this.pressed&&(b&Ga&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:Ba,srcEvent:a}))}});var Va={pointerdown:Ea,pointermove:Fa,pointerup:Ga,pointercancel:Ha,pointerout:Ha},Wa={2:za,3:Aa,4:Ba,5:Ca},Xa="pointerdown",Ya="pointermove pointerup pointercancel";a.MSPointerEvent&&!a.PointerEvent&&(Xa="MSPointerDown",Ya="MSPointerMove MSPointerUp MSPointerCancel"),i(M,x,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=Va[d],f=Wa[a.pointerType]||a.pointerType,g=f==za,h=r(b,a.pointerId,"pointerId");e&Ea&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(tb|nb)))return!1;a++}return!0},recognize:function(a){var b=la({},a);return k(this.options.enable,[this,b])?(this.state&(rb|sb|tb)&&(this.state=nb),this.state=this.process(b),void(this.state&(ob|pb|qb|sb)&&this.tryEmit(b))):(this.reset(),void(this.state=tb))},process:function(a){},getTouchAction:function(){},reset:function(){}},i(aa,Y,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(ob|pb),e=this.attrTest(a);return d&&(c&Ha||!e)?b|sb:d||e?c&Ga?b|qb:b&ob?b|pb:ob:tb}}),i(ba,aa,{defaults:{event:"pan",threshold:10,pointers:1,direction:Pa},getTouchAction:function(){var a=this.options.direction,b=[];return a&Na&&b.push(lb),a&Oa&&b.push(kb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&Na?(e=0===f?Ia:0>f?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaT
1451ime<b.time;if(this.reset(),a.eventType&Ea&&0===this.count)return this.failTimeout();if(d&&f&&c){if(a.eventType!=Ga)return this.failTimeout();var g=this.pTime?a.timeStamp-this.pTime<b.interval:!0,h=!this.pCenter||H(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,h&&g?this.count+=1:this.count=1,this._input=a;var i=this.count%b.taps;if(0===i)return this.hasRequireFailures()?(this._timer=e(function(){this.state=rb,this.tryEmit()},b.interval,this),ob):rb}return tb},failTimeout:function(){return this._timer=e(function(){this.state=tb},this.options.interval,this),tb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==rb&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),ha.VERSION="2.0.8",ha.defaults={domEvents:!1,touchAction:gb,enable:!0,inputTarget:null,inputClass:null,preset:[[ea,{enable:!1}],[ca,{enable:!1},["rotate"]],[fa,{direction:Na}],[ba,{direction:Na},["swipe"]],[ga],[ga,{event:"doubletap",taps:2},["tap"]],[da]],cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var ub=1,vb=2;ia.prototype={set:function(a){return la(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?vb:ub},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&rb)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===vb||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(ob|pb|qb)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof Y)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(f(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(f(a,"remove",this))return this;if(a=this.get(a)){var b=this.recognizers,c=r(b,a);-1!==c&&(b.splice(c,1),this.touchAction.update())}return this},on:function(a,b){if(a!==d&&b!==d){var c=this.handlers;return g(q(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this}},off:function(a,b){if(a!==d){var c=this.handlers;return g(q(a),function(a){b?c[a]&&c[a].splice(r(c[a],b),1):delete c[a]}),this}},emit:function(a,b){this.options.domEvents&&ka(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&ja(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},la(ha,{INPUT_START:Ea,INPUT_MOVE:Fa,INPUT_END:Ga,INPUT_CANCEL:Ha,STATE_POSSIBLE:nb,STATE_BEGAN:ob,STATE_CHANGED:pb,STATE_ENDED:qb,STATE_RECOGNIZED:rb,STATE_CANCELLED:sb,STATE_FAILED:tb,DIRECTION_NONE:Ia,DIRECTION_LEFT:Ja,DIRECTION_RIGHT:Ka,DIRECTION_UP:La,DIRECTION_DOWN:Ma,DIRECTION_HORIZONTAL:Na,DIRECTION_VERTICAL:Oa,DIRECTION_ALL:Pa,Manager:ia,Input:x,TouchAction:V,TouchInput:P,MouseInput:L,PointerEventInput:M,TouchMouseInput:R,SingleTouchInput:N,Recognizer:Y,AttrRecognizer:aa,Tap:ga,Pan:ba,Swipe:fa,Pinch:ca,Rotate:ea,Press:da,on:m,off:n,each:g,merge:ta,extend:sa,assign:la,inherit:i,bindFn:j,prefixed:u});var wb="undefined"!=typeof a?a:"undefined"!=typeof self?self:{};wb.Hammer=ha,"function"==typeof define&&define.amd?define(function(){return ha}):"undefined"!=typeof module&&module.exports?module.exports=ha:a[c]=ha}(window,document,"Hammer"); 1452//# sourceMappingURL=hammer.min.js.map 1453 1454 1455window.ATVI = window.ATVI || {}; 1456ATVI.components = ATVI.components || {}; 1457 1458// atvi-utils 1459 1460(function($, ATVI) { 1461 1462 var utils = ATVI.utils = {}; 1463 var cookieMap, queryMap, idCounter = 0; 1464 1465 utils.renderTemplate = function(template, fieldData, prefix, suffix) { 1466 prefix = prefix || "{{"; 1467 suffix = suffix || "}}"; 1468 var ret = template; 1469 for(var field in fieldData) { 1470 ret = ret.replace(new RegExp(prefix + field + suffix, "g"), fieldData[field]); 1471 } 1472 return ret; 1473 }; 1474 1475 utils.getCookies = function(update) { 1476 if(!cookieMap || update) { 1477 cookieMap = {}; 1478 var i, cookies = document.cookie.split(";"); 1479 for (i = 0; i < cookies.length; i++) { 1480 var index = cookies[i].indexOf('='); 1481 var x = cookies[i].substr(0, index); 1482 var y = cookies[i].substr(index + 1); 1483 x = x.replace(/^\s+|\s+$/g, '');
1484 if(x) cookieMap[x] = unescape(y); 1485 } 1486 } 1487 return cookieMap; 1488 }; 1489 1490 utils.getCookie = function(c, update) { 1491 return this.getCookies(update)[c]; 1492 }; 1493 1494 utils.setCookie = function(name, value, opts) { 1495 var value = escape(value); 1496 opts = opts || {}; 1497 1498 value += ";path=" + (opts.path || "/"); 1499 1500 if(opts.domain) value += ";domain=" + opts.domain; 1501 1502 var t = typeof opts.maxAge; 1503 if(t == "number" || t == "string") value += ";max-age=" + opts.maxAge; 1504 1505 var e = opts.expireDate; 1506 if(typeof e == "number") e = new Date((new Date()).getTime() + e * 1000); 1507 if(e) value += ';expires=' + e.toUTCString(); 1508 1509 if(opts.secure) value += ";secure"; 1510 1511 document.cookie = name + '=' + value; 1512 cookieMap = null; 1513 }; 1514 1515 utils.deleteCookie = function(name) { 1516 document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; 1517 } 1518 1519 utils.getQueryParameters = function(update) { 1520 if(!queryMap || update) { 1521 queryMap = {}; 1522 var q = window.location.href; 1523 var ind = q.indexOf("?"); 1524 q = (ind >= 0) ? q.substring(ind + 1) : ""; 1525 ind = q.indexOf("#"); 1526 if(ind >= 0) q = q.substring(0, ind); 1527 q = q.split("&"); 1528 for(var i = 0; i < q.length; i++) { 1529 p = q[i].split("="); 1530 if(p[0]) queryMap[p[0]] = p[1] ? decodeURIComponent(p[1]) : p[1]; 1531 } 1532 } 1533 return queryMap; 1534 }; 1535 1536 utils.getQueryParameter = function(p, update) { 1537 return this.getQueryParameters(update)[p]; 1538 }; 1539 1540 utils.uniqueId = function($els) { 1541 $els = $($els); 1542 var prefix = "atvi-unique-" + (new Date().getTime()) + "-"; 1543 $els.each(function() { 1544 if(this.id) return; 1545 var id; 1546 while(!id || $("#" + id).length) { 1547 id = prefix + (idCounter++); 1548 } 1549 this.id = id; 1550 }); 1551 return $els; 1552 }; 1553 1554 utils.parseUrl = function(url) { 1555 if(!url) return; 1556 var ret = {originalUrl: url}; 1557 var m = url.match(/^(([^\/:]+:)?\/\/)?(.*)$/); 1558 if(m[1]) ret.protocol = m[2] || window.location.protocol; 1559 else { 1560 ret.protocol = "http:"; 1561 var domainNeeded = true; 1562 } 1563 url = m[3]; 1564 if(!url) return; 1565 m = url.match(/^(([\w-]+(\.[\w-]+)*)(:0*([1-9][0-9]*))?)?(\/.*)?$/); 1566 ret.host = m[1]; 1567 if(!ret.host && domainNeeded) return; 1568 ret.domain = m[2]; 1569 ret.port = parseInt(m[5] || 0) || undefined; 1570 ret.usedPort = ret.port || ret.protocol == "http:" ? 80 : 443; 1571 url = m[6]; 1572 var ind = url.indexOf("#"); 1573 if(ind >= 0) { 1574 ret.hash = url.substring(ind); 1575 ret.hashValue = ret.hash(1); 1576 url = url.substring(0, ind); 1577 } 1578 ind = url.indexOf("?"); 1579 if(ind >= 0) { 1580 ret.query = url.substring(ind); 1581 var p = ret.queryParameters = {}; 1582 var params = ret.query.substring(1).split("&"); 1583 for(var i = 0; i < params.length; i++) { 1584 var e = params[i].split("="); 1585 if(e[0]) { 1586 var name = e.shift(); 1587 params[name] = e.join("+"); 1588 } 1589 } 1590 url = url.substring(0, ind); 1591 } 1592 return ret; 1593 }; 1594 1595 utils.localeRegex = /^\/(\w\w(\/\w\w)?)($|\/.*$)/; 1596 utils.locales = { 1597 en: "en_us", 1598 da: "da_dk", 1599 en_uk: "en_gb", 1600 mx: "es_mx", 1601 pt: "br_pt", 1602 jp: "ja_jp" 1603 }; 1604 1605 utils.parseLocalizedPath = function(path) { 1606 var m = path.match(utils.localeRegex); 1607 var n = m ? m[3] || "/" : path || "/"; 1608 var lp = m ? m[1] : ""; 1609 var loc = (lp || "en").replace(/(\w\w)\/(\w\w)/, "$2_$1"); 1610 loc = utils.locales[loc] || loc; 1611 loc = loc.replace(/^(\w\w)$/, "$1_$1"); 1612 if(lp) lp = "/" + lp; 1613 return { 1614 normalized: n, 1615 locPart: lp, 1616 locale: loc, 1617 region: loc.substring(3), 1618 language: loc.substring(0, 2) 1619 }; 1620 }; 1621 1622 utils.base64Map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
1622+/="; 1623 utils.decodeBase64 = function(inp) { 1624 var map = utils.base64Map; 1625 var ret = ""; 1626 var in1, in2, in3, in4, out1, out2, out3, i = 0; 1627 1628 inp = inp.replace(/[^a-zA-Z0-9\+\/\=]/g, ""); 1629 do { 1630 in1 = map.indexOf(inp.charAt(i++) || "="); 1631 in2 = map.indexOf(inp.charAt(i++) || "="); 1632 in3 = map.indexOf(inp.charAt(i++) || "="); 1633 in4 = map.indexOf(inp.charAt(i++) || "="); 1634 1635 out1 = (in1 << 2) | (in2 >> 4); 1636 out2 = ((in2 & 15) << 4) | (in3 >> 2); 1637 out3 = ((in3 & 3) << 6) | in4; 1638 1639 ret = ret + String.fromCharCode(out1); 1640 if (in3 != 64) ret = ret + String.fromCharCode(out2); 1641 if (in4 != 64) ret = ret + String.fromCharCode(out3); 1642 } while (i < inp.length); 1643 1644 return ret; 1645 }; 1646 1647 utils.createRegistry = (function() { 1648 1649 var register = function(r, $el, obj, cl) { 1650 var id; 1651 if(typeof $el == "string") id = $el; 1652 else { 1653 $el = resolve($el, cl); 1654 if(!$el.length) return null; 1655 id = $el[0].id; 1656 } 1657 var c = r.store[id]; 1658 if(!c) { 1659 c = r.store[id] = obj || {}; 1660 } 1661 return { 1662 $el: $el, 1663 context: c 1664 }; 1665 }; 1666 1667 var get = function(r, $el, cl) { 1668 var id = typeof $el == "string" ? $el : resolve($el, cl)[0].id; 1669 return r.store[id]; 1670 }; 1671 1672 var getAll = function(r) { 1673 var ret = []; 1674 for(var id in r.store) { 1675 if(r.store.hasOwnProperty(id)) ret.push({id: id, context: r.store[id]}); 1676 } 1677 return ret; 1678 }; 1679 1680 var purge = function(r, $el, cl) { 1681 var id = typeof $el == "string" ? $el : resolve($el, cl)[0].id; 1682 var a = r.store[id]; 1683 r.store[id] = null; 1684 delete r.store[id]; 1685 return !!a; 1686 }; 1687 1688 var purgeAll = function(r) { 1689 for(var id in r.store) { 1690 if(r.store.hasOwnProperty(id)) { 1691 r.store[id] = null; 1692 delete r.store[id]; 1693 } 1694 } 1695 }; 1696 1697 var resolve = function($el, cl) { 1698 if(cl && !$el.hasClass(cl)) { 1699 var c = $el.find("." + cl); 1700 if(c.length) $el = c.first(); 1701 else { 1702 c = $el.parents("." + cl); 1703 if(c.length) $el = c.first(); 1704 } 1705 } 1706 return utils.uniqueId($el); 1707 }; 1708 1709 return function(reqClass) { 1710 var r = { 1711 store: {}, 1712 register: function($el, obj) { 1713 return register(r, $el, obj, reqClass); 1714 }, 1715 get: function($el) { 1716 return get(r, $el, reqClass); 1717 }, 1718 purge: function($el) { 1719 return purge(r, $el, reqClass); 1720 }, 1721 getAll: function() { 1722 return getAll(r); 1723 }, 1724 purgeAll: function() { 1725 return purgeAll(r); 1726 } 1727 }; 1728 return r; 1729 }; 1730 1731 })(); 1732 1733 utils.createReadyQueue = function(arr, alwaysAfter) { 1734 1735 var ready = false; 1736 var queue = []; 1737 var onReady = function(callback) { 1738 if(ready) { 1739 if(alwaysAfter) setTimeout(callback, 0); 1740 else callback(); 1741 } 1742 else queue.push(callback); 1743 }; 1744 1745 var events = arr.slice(0); 1746 1747 var processQueue = function() { 1748 while(queue.length) queue.shift()(); 1749 }; 1750 1751 var trigger = function(ev) { 1752 for(var i = 0; i < events.length; i++) { 1753 if(events[i] == ev) { 1754 events.splice(i, 1); 1755 break; 1756 } 1757 } 1758 if(!events.length) { 1759 ready = true; 1760 processQueue(); 1761 } 1762 }; 1763 1764 var add = function(ev) { 1765 events.push(ev); 1766 ready = false; 1767 }; 1768 1769 return { 1770 on: onReady, 1771 trigger: trigger, 1772 add: add, 1773 get: function() { return events.slice(0); } 1774 }; 1775 }; 1776 1777 utils.assignId = function(str, type) { 1778 var rando = Math.round(Math.random() * 1000000 + 1); 1779 if (str == "" || str == null) return "atvi-" + type + "-" + rando; 1780 else return str + '-' + rando; 1781 }; 1782 1783 // Define onYouTubeIframeAPIReady in the global scope 1784 /*window.onYouTubeIframeAPIReady = function() { 1785 // Your existing code here 1786 console.log('YouTube API ready'); 1787 }; 1788 1789 //Master array to hold all videos added to page 1790 window.ATVIPageVideos = window.ATVIPageVideos || []; 1791 window.ATVIVideoAPIReady = window.ATVIVideoAPIReady || false; 1792 1793 utils.buildYoutubeVideo = function(containerId, youtubeId, configObj) { 1794 1795 var player; 1796 1797 // Move onYouTubeIframeAPIReady inside utils.buildYoutubeVideo 1798 function onYouTubeIframeAPIReady() { 1799 1800 window.ATVIVideoAPIReady = true; 1801 1802 player = new YT.Player(containerId, { 1803 videoId: youtubeId, 1804 playerVars: { 1805 autoplay: (configObj && configObj.autoplay) ? configObj.autoplay : 0, // Autoplay disabled initially 1806 controls: 1, // Show video controls 1807 mute: 0, // Mute the video initially 1808 }, 1809 events: { 1810 'onReady': function(event) { 1811 // Optional: Handle player ready event 1812 console.log('YouTube player ready'); 1813 1814 //Push player object to global pageVideos array to be referenced anytime 1815 ATVIPageVideos.push({ 1816 1817 iframeId : containerId, 1818 videoContext: player 1819 1820 }); 1821 1822 //onPlayReady 1823 onVideoPlayerReady(player); 1824 1825 }, 1826 'onStateChange': function(event) { 1827 // Optional: Handle player state changes 1828 console.log('Player state changed:', event.data); 1829 onVideoPlayerStateChange(event); 1830 } 1831 1832 } 1833 }); 1834 1835 //Thumbnail click 1836 var $thumbnail = $("#" + containerId).parent().find(".atvi-video-thumbnail"); 1837 1838 $thumbnail.on("click", function() { 1839
1840 //Hide thumbnail, caption, and play icon 1841 $(this).hide(); 1842 1843 //Play video 1844 player.playVideo(); 1845 1846 //Unmute 1847 player.unMute(); 1848 }); 1849 } 1850 1851 // Assign onYouTubeIframeAPIReady to the global scope 1852 window.onYouTubeIframeAPIReady = onYouTubeIframeAPIReady; 1853 1854 // Check if the YouTube API is already loaded 1855 //if (typeof YT === 'undefined' || typeof YT.Player === 'undefined') { 1856 if(!window.ATVIVideoAPIReady) { 1857 // Create a script element to load the YouTube API 1858 var tag = document.createElement('script'); 1859 tag.src = 'https://www.youtube.com/iframe_api'; 1860 1861 // Get the first script element on the page 1862 var firstScriptTag = document.getElementsByTagName('script')[0]; 1863 1864 // Insert the YouTube API script before the first script element 1865 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 1866 1867 } else { 1868 onYouTubeIframeAPIReady(); 1869 } 1870 }; 1871 1872 utils.getVideoContext = function(containerId) { 1873 1874 for (let i = 0; i < ATVIPageVideos.length; i++) { 1875 if (ATVIPageVideos[i].iframeId === containerId) { 1876 return ATVIPageVideos[i].videoContext; 1877 } 1878 } 1879 return null; // Return null if containerId is not found 1880 1881 }; 1882 1883 function onVideoPlayerReady(player) { 1884 1885 setInterval(() => { 1886 let progress = (player.playerInfo.currentTime / player.playerInfo.duration) * 100; 1887 if ( (progress - Math.floor(progress)) <= 0.5) { 1888 progress = Math.floor(progress); 1889 } 1890 switch (progress) { 1891 case 1: 1892 console.log("Video started playing from Set Interval Function"); 1893 analytics_handlePlayAnalytics("play", player.playerInfo.videoData.video_id); 1894 break; 1895 case 25: 1896 // Video has played 25% 1897 console.log("Video played 25%"); 1898 analytics_handlePlayAnalytics("25%", player.playerInfo.videoData.video_id); 1899 break; 1900 case 50: 1901 // Video has played 50% 1902 console.log("Video played 50%"); 1903 analytics_handlePlayAnalytics("50%", player.playerInfo.videoData.video_id); 1904 break; 1905 case 75: 1906 // Video has played 75% 1907 console.log("Video played 75%"); 1908 analytics_handlePlayAnalytics("75%", player.playerInfo.videoData.video_id); 1909 break; 1910 default: 1911 break; 1912 } 1913 }, (500)); 1914 1915 }; 1916 1917 function analytics_handlePlayAnalytics(per, youtubeID) { 1918 if (dataLayer) { 1919 dataLayer.push({ 1920 video_provider: "youtube", 1921 label: youtubeID, //this needs to get replaced with the youtube ID of the video 1922 action: per == "play" ? "play" : per, 1923 event: "media", 1924 category: "media", 1925 pageURL: window.location.href, 1926 gameName: dataLayer[0].siteSection, 1927 }); 1928 } 1929 }; 1930 1931 function analytics_handlePauseAnalytics(youtubeID) { 1932 if (dataLayer) { 1933 dataLayer.push({ 1934 video_provider: "youtube", 1935 label: youtubeID, //this needs to get replaced with the youtube ID of the video 1936 action: "pause", 1937 event: "media", 1938 category: "media", 1939 pageURL: window.location.href, 1940 gameName: dataLayer[0].siteSection, 1941 }); 1942 } 1943 }; 1944 1945 function analytics_handleEndAnalytics(youtubeID) { 1946 if (dataLayer) { 1947 dataLayer.push({ 1948 video_provider: "youtube", 1949 label: youtubeID, //this needs to get replaced with the youtube ID of the video 1950 action: "complete", 1951 event: "media", 1952 category: "media", 1953 pageURL: window.location.href, 1954 gameName: dataLayer[0].siteSection, 1955 }); 1956 } 1957 }; 1958 1959 function onVideoPlayerStateChange(event) { 1960 1961 // Calculate video progress 1962 const trackVideoProgress = (player) => { 1963 let videoDuration = player.playerInfo.duration; 1964 let currentTime = player.playerInfo.currentTime; 1965 1966 // Calculate progress as a percentage 1967 let progress = (currentTime / videoDuration) * 100; 1968 1969 if (progress == 1) { 1970 // Video has begun playing 1971 console.log("Video started playing in the Player State Change"); 1972 analytics_handlePlayAnalytics("play", player.playerInfo.videoData.video_id); 1973 } else if (progress == 25) { 1974 // Video has played 25% 1975 console.log("Video played 25%"); 1976 analytics_handlePlayAnalytics("25%", player.playerInfo.videoData.video_id); 1977 } 1978 if (progress == 50) { 1979 // Video has played 50% 1980 console.log("Video played 50%"); 1981 analytics_handlePlayAnalytics("50%", player.playerInfo.videoData.video_id); 1982 } 1983 if (progress == 75) { 1984 // Video has played 75% 1985 console.log("Video played 75%"); 1986 analytics_handlePlayAnalytics("75%", player.playerInfo.videoData.video_id); 1987 } 1988 }; 1989 1990 if (event.data == YT.PlayerState.PLAYING) { 1991 // Video is playing 1992 trackVideoProgress(event.target); 1993 } else if (event.data == YT.PlayerState.PAUSED) { 1994 // Video is paused 1995 analytics_handlePauseAnalytics(event.target.playerInfo.videoData.video_id); 1996 } else if (event.data == YT.PlayerState.ENDED) { 1997 // Video has ended 1998 analytics_handleEndAnalytics(event.target.playerInfo.videoData.video_id); 1999 } 2000 };*/ 2001 2002 /*utils.buildYoutubeEl = function(youtubeId) { 2003 var elId = utils.assignId('', 'video'),
2004 $wrapperEl = $('<div>', {'id': elId, 'class': 'atvi-video-component', 'data-youtube-id': youtubeId}), 2005 $inner = $('<div>', { 'class': 'player atvi-instrument atvi-instrument-video-player'}), 2006 $embedEl = $('<div>', {'id': elId + '-embed'}), 2007 $el = $wrapperEl.append($inner.append($embedEl)), 2008 configObj = { youtubeId: youtubeId, start: 0, customControls: false }; 2009 2010 window.ATVIVideoEls = window.ATVIVideoEls || []; 2011 2012 window.ATVIVideoEls.push({ 2013 $el: $el, 2014 config: configObj 2015 }); 2016 2017 function generatePlayer() { 2018 ATVI.components.video.generatePlayer($el, configObj); 2019 if (!$el.find('.' + $el.attr('id') + '-embed').children().length) { 2020 setTimeout(function() { 2021 ATVI.components.video.purgeContext($el); 2022 ATVI.components.video.generatePlayer($el, configObj); 2023 }, 500); 2024 } 2025 } 2026 2027 ATVI.library.withDependency('atvi-video', function() { 2028 if (ATVI.components.video.YTApiReady) generatePlayer(); 2029 else { 2030 document.addEventListener('youtubeApiReady', function() { 2031 generatePlayer(); 2032 }); 2033 } 2034 }); 2035 2036 return $el; 2037 }; 2038 2039 utils.purgeYoutubeEl = function($el){ 2040 var i; 2041 ATVI.components.video.purgeContext($el); 2042 for (i = 0; i < window.ATVIVideoEls.length; i++) { 2043 if ($el.is(window.ATVIVideoEls[i].$el)) { 2044 window.ATVIVideoEls.splice(i, 1); 2045 } 2046 } 2047 };*/ 2048 2049 utils.scrollToTarget = function($el, duration, offsetTop) { 2050 2051 var o = offsetTop || 0; 2052 var d = duration || 0; 2053 2054 $('html, body').animate({ 2055 scrollTop: $el.offset().top - o 2056 }, d, function () { 2057 // Callback after animation 2058 // Must change focus! 2059 var $target = $el; 2060 $target.focus(); 2061 if ($target.is(":focus")) { 2062 // Checking if the target was focused 2063 return false; 2064 } else { 2065 $target.attr("tabindex", "-1"); // Adding tabindex for elements not focusable 2066 $target.focus(); // Set focus again 2067 } 2068 }); 2069 2070 }; 2071 2072 utils.isInViewport = function($el) { 2073 2074 let selector = $el; 2075 if(selector.length == 0) return false; 2076 let elementTop = selector.offset().top; 2077 let elementBottom = elementTop + selector.outerHeight(); 2078 2079 let viewportTop = $(window).scrollTop(); 2080 let viewportBottom = viewportTop + $(window).height(); 2081 2082 return elementBottom > viewportTop && elementTop < viewportBottom; //returns true or false 2083 2084 }; 2085 2086 /*utils.interectObserver = function($el) { 2087 2088 let selector = $el[0] || $el; //if passing jquery selector or js node 2089 2090 //intersection observer call back 2091 const handleCallback = (entries) => { 2092 entries.forEach( (entry) => { 2093 //if target passes half way in viewport 2094 if (entry.intersectionRatio >= 0.5) { 2095 const { target } = entry; 2096 2097 return true; 2098 } 2099 }); 2100 } 2101 2102 //create new intersection observer instance 2103 let observer = new IntersectionObserver(handleCallback, {threshold: 0.5}); 2104 2105 observer.observe(selector); 2106 }*/ 2107 2108 utils.addPrivacyLinks = function($container) { 2109 2110 var parseRegionStr = function(r) { 2111 var str = r; 2112 if (str == null || str == "") str = "en"; 2113 str = str.toLowerCase().replace("-", "_").replace("en_us", "en"); 2114 2115 return str; 2116 }; 2117 2118 var ld = ATVI.localeDetector; 2119 2120 //Get page region 2121 var region = parseRegionStr($('html').attr("lang")); 2122 2123 //Set locale for Granite i18n library 2124 Granite.I18n.setLocale(region); 2125 2126 //Declare which i18n keys we want translations for 2127 var yourPrivacyChoiceKey = "global.footer.label.yourPrivacyChoices"; 2128 var caPrivacyNoticeKey = "global.caPrivacyNotice"; 2129 2130 //Get translations from the keys 2131 var yourPrivacyChoicesText = Granite.I18n.get(yourPrivacyChoiceKey); 2132 var caPrivacyNoticeText = Granite.I18n.get(caPrivacyNoticeKey); 2133 2134 //If for some reason, it can't get i18n translation from keys, then default them to their EN strings 2135 if(yourPrivacyChoicesText == yourPrivacyChoiceKey) yourPrivacyChoicesText = "Your Privacy Choices"; 2136 if(caPrivacyNoticeText == caPrivacyNoticeKey) caPrivacyNoticeText = "California Privacy Notice"; 2137 2138 //If user is in California, Colorado, Virginia, Connecticut, Utah, Oregon, Texas, Florida, Montana, Iowa, Delaware, Nebraska, New Hampshire, Tennessee, Minnesota, Maryland 2139 const validRegions = ['ca', 'co', 'va', 'ct', 'ut', 'or', 'tx', 'fl', 'mt', 'ia', 'de', 'ne', 'nh', 'nj', 'tn', 'mn', 'md', 'in', 'ky', 'ri']; 2140 2141 if (ld.region && validRegions.includes(ld.region)) { 2142 var anchor = $('<a/>', { 2143 'href': 'https://support.activision.com/privacy/request?st=' + ld.region, 2144 'text': yourPrivacyChoicesText, 2145 'target': '_blank' 2146 }); 2147 var item = $('<li/>', { 'class': 'privacy-check' }); 2148 item.append(anchor); 2149 $container.append(item); 2150 } 2151 else { 2152 var anchor = $('<a/>', { 2153 'href': 'https://support.activision.com/privacy', 2154 'text': yourPrivacyChoicesText, 2155 'target': '_blank' 2156 }); 2157 var item = $('<li/>', { 'class': 'privacy-check' }); 2158 item.append(anchor); 2159 $container.append(item); 2160 2161 /*document.addEventListener('localeDetectionReady', function() { 2162 2163 if (ld.region && validRegions.includes(ld.region)) { 2164 var anchor = $('<a/>', { 2165 'href': 'https://support.activision.com/privacy/request?st=' + ld.region, 2166 'text': yourPrivacyChoicesText, 2167 'target': '_blank' 2168 }); 2169 var item = $('<li/>', { 'class': 'privacy-check' }); 2170 item.append(anchor); 2171 $container.append(item); 2172 } 2173 });*/ 2174 } 2175 2176 //If user is in California 2177 if(ld.region && ld.region == 'ca') { 2178 var anchor = $('<a/>', { 2179 'href':'https://www.activision.com/legal/privacy-policy#toc10b', 2180 'text': caPrivacyNoticeText, 2181 'target': '_blank' 2182 }), 2183 item = $('<li/>'); 2184 item.append(anchor); 2185 $container.append(item); 2186 } 2187 else { 2188 document.addEventListener('localeDetectionReady', function() { 2189 if (ld.region == 'ca') { 2190 var anchor = $('<a/>', { 2191 'href':'https://www.activision.com/legal/privacy-policy#toc10b', 2192 'text': caPrivacyNoticeText, 2193 'target': '_blank' }), 2194 item = $('<li/>'); 2195 item.append(anchor); 2196 $container.append(item); 2197 } 2198 }); 2199 } 2200 2201 }; 2202 2203 utils.getElementMarkup = async function(url, selector) { 2204 try { 2205 // Fetch the HTML of the page 2206 const response = await fetch(url); 2207 2208 // Ensure the request was successful 2209 if (!response.ok) { 2210 throw new Error(`Failed to fetch page: ${response.statusText}`); 2211 } 2212 2213 // Get the HTML text 2214 const htmlText = await response.text(); 2215 2216 // Parse the HTML string into a document 2217 const parser = new DOMParser(); 2218 const doc = parser.parseFromString(htmlText, 'text/html'); 2219 2220 // Query the specified element 2221 const element = doc.querySelector(selector); 2222 2223 // Return the element's outer HTML, or null if not found 2224 return element ? element.outerHTML : null; 2225 } catch (error) { 2226 console.error(error); 2227 return null; 2228 } 2229 }; 2230 2231 utils.initSSO = function(obj = {}) { 2232 2233 /* sample obj input 2234 obj = { 2235 domain: "atvi", 2236 login: ${".sso-login"), 2237 signUp: ${".sso-signup"), 2238 profile: ${".sso-profile"), 2239 logOut: ${".sso-logout"), 2240 username: ${"#username") 2241 } 2242 */ 2243 2244 const { 2245 login, 2246 signUp, 2247 profile, 2248 logOut, 2249 username = $("#username") 2250 } = obj; 2251 2252 const apiOrigin = ATVI.utils.getSSOOrigin(); 2253 2254 // Update SSO links 2255 const links = { 2256 login: login?.attr("href", ATVI.utils.getSSOLink("login")), 2257 signup: signUp?.attr("href", ATVI.utils.getSSOLink("signup")), 2258 profile: profile?.attr("href", ATVI.utils.getSSOLink("profile")), 2259 logout: logOut?.attr("href", ATVI.utils.getSSOLink("logout")) 2260 }; 2261 2262 // Reflect login state 2263 const loggedIn = ATVI.utils.isLoggedIn(); 2264 $("body").toggleClass("sso-logged-in", loggedIn) 2265 .toggleClass("sso-logged-out", !loggedIn); 2266 2267 // Fetch and set username asynchronously 2268 if (username && username.length > 0) { 2269 ATVI.utils.setSSOUsername().then(userName => { 2270 if (userName) username.text(userName); 2271 }); 2272 2273 } 2274 2275 }; 2276 2277 utils.getEnv = function() { 2278 const url = window.location.href; 2279 if (url.includes("stage.")) return "stage"; 2280 if (url.includes("cmsauthor.") || url.includes("preview.") || url.includes("test.")) return "dev"; 2281 return "prod"; 2282 }; 2283 2284 utils.getSSOOrigin = function() { 2285 switch (ATVI.utils.getEnv()) { 2286 case "stage": return "https://stage-xo-client.activision.com"; 2287 case "dev": 2288 if(window.location.href.includes("/ko/transactions")) return "https://xo-client.activision.com"; 2289 else return "https://dev-xo-client.activision.com"; 2290 default: return "https://xo-client.activision.com"; 2291 } 2292 }; 2293 2294 utils.getSSOPrefix = function() { 2295 switch (ATVI.utils.getEnv()) { 2296 case "stage": return "s-stage"; 2297 case "dev": 2298 if(window.location.href.includes("/ko/transactions")) return "s"; 2299 else return "s-dev"; 2300 default: return "s"; 2301 } 2302 }; 2303 2304 utils.getSSOCookies = function() { 2305 return { 2306 ssoCookie: ATVI.utils.getCookie("ACT_SSO_COOKIE"), 2307 atkn: ATVI.utils.getCookie("X-xo-atkn"), 2308 rtkn: ATVI.utils.getCookie("X-xo-rtkn") 2309 }; 2310 }; 2311 2312 utils.setSSOUsername = function(cb) { 2313 2314 return new Promise((resolve, reject) => { 2315 if (!ATVI.utils.isLoggedIn()) { 2316 ATVI.utils.logUserOut(); 2317 return resolve(null); 2318 } 2319 2320 const apiOrigin = ATVI.utils.getSSOOrigin(); 2321 const { ssoCookie, atkn, rtkn } = ATVI.utils.getSSOCookies(); 2322 2323 if(ssoCookie && atkn && rtkn) { 2324 $.ajax({ 2325 url: `${apiOrigin}/profile/v1`, 2326 method: "GET", 2327 headers: { 2328 "ACT_SSO_COOKIE": ssoCookie, 2329 "X-xo-atkn": atkn, 2330 "X-xo-rtkn": rtkn 2331 } 2332 }) 2333 .done(response => { 2334 2335 ATVI.utils.userInfo = response; 2336 2337 resolve(response?.userName || null); 2338 })
2339 .fail(xhr => { 2340 if (xhr.status === 401 || xhr.status === 403) ATVI.utils.logUserOut(); 2341 reject(xhr); 2342 }); 2343 2344 } 2345 }); 2346 2347 }; 2348 2349 utils.logUserOut = function() { 2350 ATVI.utils.deleteCookie("ACT_SSO_COOKIE"); 2351 ATVI.utils.deleteCookie("X-xo-atkn"); 2352 ATVI.utils.deleteCookie("X-xo-rtkn"); 2353 $("body").removeClass("sso-logged-in").addClass("sso-logged-out"); 2354 }; 2355 2356 utils.isLoggedIn = function() { 2357 2358 if(window.location.href.includes("support.")) { 2359 const { ssoCookie } = ATVI.utils.getSSOCookies(); 2360 return !!(ssoCookie); 2361 } 2362 2363 else { 2364 const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies(); 2365 return !!(ssoCookie && atkn && rtkn); 2366 } 2367 2368 }; 2369 2370 utils.getSSOLink = function(key) { 2371 2372 let envPrefix = ATVI.sso.getSSOPrefix(); 2373 const apiOrigin = ATVI.sso.getSSOOrigin(); 2374 const currentUrl = encodeURIComponent(window.location.href); 2375 2376 let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase(); 2377 if (locale === "fr_lu") locale = "fr"; 2378 2379 const urls = { 2380 login: `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`, 2381 logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`, 2382 signup: "", 2383 profile: "" 2384 }; 2385 2386 const href = window.location.href; 2387 2388 let brand = "activision"; 2389 if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) { 2390 brand = "crash"; 2391 } else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) { 2392 brand = "tonyhawk"; 2393 } else if (href.includes("callofduty.com") || href.includes("/content/atvi/callofduty")) { 2394 brand = "cod"; 2395 } 2396 2397 const redirectMap = { 2398 activision: "https://www.activision.com", 2399 cod: "https://www.callofduty.com", 2400 crash: "https://www.crashbandicoot.com", 2401 tonyhawk: "https://www.tonyhawkthegame.com" 2402 }; 2403 2404 const signupRedirect = encodeURIComponent(redirectMap[brand]); 2405 2406 urls.signup = `https://profile.activision.com/signup?redirectUrl=${signupRedirect}`; 2407 2408 const baseDomains = { 2409 activision: "activision.com/activision", 2410 crash: "crashbandicoot.com/crash", 2411 tonyhawk: "tonyhawkthegame.com/th", 2412 cod: "callofduty.com/cod" 2413 }; 2414 2415 const prefixMap = { 2416 "s-dev": "profile-dev", 2417 "s-stage": "profile-stage", 2418 "s": "profile" 2419 }; 2420 2421 if (brand === "cod" && prefixMap[envPrefix]) { 2422 envPrefix = prefixMap[envPrefix]; // this will give profile link a prefix of profile-dev, or profile-stage, or profile 2423 } 2424 2425 //urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`; 2426 2427 2428 if (prefixMap[envPrefix] && key == "signup") { 2429 envPrefix = prefixMap[envPrefix]; 2430 urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`; 2431 } 2432 2433 //urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`; 2434 urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`; 2435 2436 return urls[key] || ""; 2437 }; 2438 2439 /*utils.getSSOLink = function(key) { 2440 2441 const envPrefix = ATVI.utils.getSSOPrefix(); 2442 const apiOrigin = ATVI.utils.getSSOOrigin(); 2443 const currentUrl = encodeURIComponent(window.location.href); 2444 let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase(); 2445 if(locale == "fr_lu") locale = "fr"; 2446 2447 const urls = { 2448 login: `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`, 2449 logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`, 2450 signup: "", 2451 profile: "" 2452 }; 2453 2454 const baseDomains = { 2455 activision: "activision.com/activision", 2456 crash: "crashbandicoot.com/crash", 2457 tonyhawk: "tonyhawkthegame.com/th" 2458 }; 2459 2460 let brand = "activision"; 2461 const href = window.location.href; 2462 if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) brand = "crash"; 2463 else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) brand = "tonyhawk"; 2464 2465 urls.signup = `https://${envPrefix}.${baseDomains[brand]}/signup`; 2466 urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`; 2467 2468 return urls[key] || ""; 2469 2470 };*/ 2471 2472 2473})(jQuery, ATVI); 2474 2475window.ATVI = window.ATVI || {}; 2476 2477// atvi-sso 2478 2479(function($, ATVI) { 2480 2481 var sso = ATVI.sso = {}; 2482 2483 sso.init = function(obj = {}) { 2484 2485 /* sample obj input 2486 obj = { 2487 domain: "atvi", 2488 login: ${".sso-login"), 2489 signUp: ${".sso-signup"), 2490 profile: ${".sso-profile"), 2491 logOut: ${".sso-logout"), 2492 username: ${"#username") 2493 } 2494 */ 2495 2496 const { 2497 login, 2498 signUp, 2499 profile, 2500 logOut, 2501 username = $("#username") 2502 } = obj; 2503 2504 const apiOrigin = ATVI.sso.getSSOOrigin(); 2505 2506 // Update SSO links 2507 const links = { 2508 login: login?.attr("href", ATVI.sso.getSSOLink("login")), 2509 signup: signUp?.attr("href", ATVI.sso.getSSOLink("signup")), 2510 profile: profile?.attr("href", ATVI.sso.getSSOLink("profile")), 2511 logout: logOut?.attr("href", ATVI.sso.getSSOLink("logout")) 2512 }; 2513 2514 // Reflect login state 2515 const loggedIn = ATVI.sso.isLoggedIn(); 2516 $("body").toggleClass("sso-logged-in", loggedIn) 2517 .toggleClass("sso-logged-out", !loggedIn); 2518 2519 // Set user info 2520 if(loggedIn) ATVI.sso.setUserInfo(username); 2521 2522 // Fetch and set username asynchronously 2523 /*if (username && username.length > 0) { 2524 ATVI.sso.setSSOUsername().then(userName => { 2525 if (userName) username.text(userName); 2526 }); 2527 2528 }*/ 2529 2530 }; 2531 2532 sso.getEnv = function() { 2533 const url = window.location.href; 2534 if (url.includes("stage.")) return "stage"; 2535 if (url.includes("cmsauthor.") || url.includes("preview.") || url.includes("test.")) return "dev"; 2536 return "prod"; 2537 }; 2538 2539 sso.getSSOOrigin = function() { 2540 switch (ATVI.sso.getEnv()) { 2541 case "stage": return "https://stage-xo-client.activision.com"; 2542 case "dev": 2543 if(window.location.href.includes("/ko/transactions")) return "https://xo-client.activision.com"; 2544 else return "https://dev-xo-client.activision.com"; 2545 default: return "https://xo-client.activision.com"; 2546 } 2547 }; 2548 2549 sso.getSSOPrefix = function() { 2550 switch (ATVI.sso.getEnv()) { 2551 case "stage": return "s-stage"; 2552 case "dev": 2553 if(window.location.href.includes("/ko/transactions")) return "s"; 2554 else return "s-dev"; 2555 default: return "s"; 2556 } 2557 }; 2558 2559 sso.getSSOCookies = function() { 2560 return { 2561 ssoCookie: ATVI.utils.getCookie("ACT_SSO_COOKIE"), 2562 atkn: ATVI.utils.getCookie("X-xo-atkn"), 2563 rtkn: ATVI.utils.getCookie("X-xo-rtkn") 2564 }; 2565 }; 2566 2567 sso.setSSOUsername = function(cb) { 2568 2569 return new Promise((resolve, reject) => { 2570 if (!ATVI.sso.isLoggedIn()) { 2571 ATVI.sso.logUserOut(); 2572 return resolve(null); 2573 } 2574 2575 const apiOrigin = ATVI.sso.getSSOOrigin(); 2576 const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies(); 2577 2578 if(ssoCookie && atkn && rtkn) { 2579 $.ajax({ 2580 url: `${apiOrigin}/profile/v1`, 2581 method: "GET", 2582 headers: { 2583 "ACT_SSO_COOKIE": ssoCookie, 2584 "X-xo-atkn": atkn, 2585 "X-xo-rtkn": rtkn 2586 } 2587 }) 2588 .done(response => { 2589 2590 ATVI.sso.userInfo = response; 2591 2592 resolve(response?.userName || null); 2593 })
2594 .fail(xhr => { 2595 if (xhr.status === 401 || xhr.status === 403) ATVI.sso.logUserOut(); 2596 reject(xhr); 2597 }); 2598 2599 } 2600 }); 2601 2602 }; 2603 2604 sso.setUserInfo = function(username) { 2605 2606 let apiOrigin = ATVI.sso.getSSOOrigin(); 2607 let { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies(); 2608 2609 if(ssoCookie && atkn && rtkn) { 2610 $.ajax({ 2611 url: `${apiOrigin}/profile/v1`, 2612 method: "GET", 2613 headers: { 2614 "ACT_SSO_COOKIE": ssoCookie, 2615 "X-xo-atkn": atkn, 2616 "X-xo-rtkn": rtkn 2617 } 2618 }) 2619 .done(response => { 2620 2621 ATVI.sso.userInfo = response; 2622 2623 //trigger custom event and pass data 2624 $(document).trigger("sso:userInfoReady", [response]); 2625 2626 //Set username in username element 2627 if (username && username.length > 0) { 2628 username.text(response.userName); 2629 } 2630 }) 2631 .fail(xhr => { 2632 $(document).trigger("sso:userInfoError", [xhr]); 2633 }); 2634 2635 } 2636 2637 }; 2638 2639 sso.logUserOut = function() { 2640 ATVI.utils.deleteCookie("ACT_SSO_COOKIE"); 2641 ATVI.utils.deleteCookie("X-xo-atkn"); 2642 ATVI.utils.deleteCookie("X-xo-rtkn"); 2643 $("body").removeClass("sso-logged-in").addClass("sso-logged-out"); 2644 }; 2645 2646 sso.isLoggedIn = function() { 2647 2648 if(window.location.href.includes("support.")) { 2649 const { ssoCookie } = ATVI.sso.getSSOCookies(); 2650 return !!(ssoCookie); 2651 } 2652 2653 else { 2654 const { ssoCookie, atkn, rtkn } = ATVI.sso.getSSOCookies(); 2655 return !!(ssoCookie && atkn && rtkn); 2656 } 2657 2658 }; 2659 2660 /*sso.getSSOLink = function(key) { 2661 2662 let envPrefix = ATVI.sso.getSSOPrefix(); 2663 const apiOrigin = ATVI.sso.getSSOOrigin(); 2664 const currentUrl = encodeURIComponent(window.location.href); 2665 let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase(); 2666 if(locale == "fr_lu") locale = "fr"; 2667 2668 const urls = { 2669 login: `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`, 2670 logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`, 2671 signup: "", 2672 profile: "" 2673 }; 2674 2675 const baseDomains = { 2676 activision: "activision.com/activision", 2677 crash: "crashbandicoot.com/crash", 2678 tonyhawk: "tonyhawkthegame.com/th", 2679 cod: "callofduty.com/cod" 2680 }; 2681 2682 let brand = "activision"; 2683 const href = window.location.href; 2684 if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) brand = "crash"; 2685 else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) brand = "tonyhawk"; 2686 else if (href.includes("callofduty.com") || href.includes("/contenta/atvi/callofduty")) brand = "cod"; 2687 2688 //cod specific 2689 const prefixMap = { 2690 "s-dev": "profile-dev", 2691 "s-stage": "profile-stage", 2692 "s": "profile" 2693 }; 2694 2695 if (brand === "cod" && prefixMap[envPrefix]) { 2696 envPrefix = prefixMap[envPrefix]; 2697 } 2698 2699 urls.signup = `https://${envPrefix}.${baseDomains[brand]}/signup`; 2700 urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`; 2701 2702 return urls[key] || ""; 2703 2704 };*/ 2705 2706 sso.getSSOLink = function(key) { 2707 2708 let envPrefix = ATVI.sso.getSSOPrefix(); 2709 const apiOrigin = ATVI.sso.getSSOOrigin(); 2710 const currentUrl = encodeURIComponent(window.location.href); 2711 2712 let locale = (ATVI.pageLocale || "en").replace("-", "_").toLowerCase(); 2713 if (locale === "fr_lu") locale = "fr"; 2714 2715 const urls = { 2716 login: `${apiOrigin}/auth/v1/xLogin/init?redirectUrl=${currentUrl}&locale=${locale}`, 2717 logout: `${apiOrigin}/auth/v1/xLogout?redirectUrl=${currentUrl}`, 2718 signup: "", 2719 profile: "" 2720 }; 2721 2722 const href = window.location.href; 2723 2724 let brand = "activision"; 2725 if (href.includes("crashbandicoot.com") || href.includes("/content/atvi/crash")) { 2726 brand = "crash"; 2727 } else if (href.includes("tonyhawkthegame.com") || href.includes("/content/atvi/tony-hawk")) { 2728 brand = "tonyhawk"; 2729 } else if (href.includes("callofduty.com") || href.includes("/content/atvi/callofduty")) { 2730 brand = "cod"; 2731 } 2732 2733 const redirectMap = { 2734 activision: "https://www.activision.com", 2735 cod: "https://www.callofduty.com", 2736 crash: "https://www.crashbandicoot.com", 2737 tonyhawk: "https://www.tonyhawkthegame.com" 2738 }; 2739 2740 const signupRedirect = encodeURIComponent(redirectMap[brand]); 2741 2742 urls.signup = `https://profile.activision.com/signup?redirectUrl=${signupRedirect}`; //default prod 2743 2744 const baseDomains = { 2745 activision: "activision.com/activision", 2746 crash: "crashbandicoot.com/crash", 2747 tonyhawk: "tonyhawkthegame.com/th", 2748 cod: "callofduty.com/cod" 2749 }; 2750 2751 const prefixMap = { 2752 "s-dev": "profile-dev", 2753 "s-stage": "profile-stage", 2754 "s": "profile" 2755 }; 2756 2757 if (prefixMap[envPrefix] && key == "signup") { 2758 envPrefix = prefixMap[envPrefix]; 2759 urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`; 2760 } 2761 2762 else if (brand == "cod" && prefixMap[envPrefix] && key == "signup") { 2763 envPrefix = prefixMap[envPrefix]; 2764 urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`; 2765 } 2766 2767 else if (brand === "cod" && prefixMap[envPrefix]) { 2768 envPrefix = prefixMap[envPrefix]; // this will give profile link a prefix of profile-dev, or profile-stage, or profile 2769 } 2770 2771 urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`; 2772 2773 2774 /*if (prefixMap[envPrefix]) { 2775 envPrefix = prefixMap[envPrefix]; 2776 } 2777 2778 urls.signup = `https://${envPrefix}.activision.com/signup?redirectUrl=${signupRedirect}`; 2779 urls.profile = `https://${envPrefix}.${baseDomains[brand]}/profile`;*/ 2780 2781 return urls[key] || ""; 2782 }; 2783 2784})(jQuery, ATVI); 2785window.ATVI = window.ATVI || {}; 2786ATVI.components = ATVI.components || {}; 2787 2788var dataLayer = dataLayer || undefined, 2789 digitalData = digitalData || undefined; 2790 2791ATVI.franchiseMap = { 2792 vanguard: "vgd", 2793 blackopscoldwar: "bocw", 2794 modernwarfare: "mw", 2795 modernwarfare2: "mw2", 2796 modernwarfare3: "mw3", 2797 warzone: "wz", 2798 warzone2: "wz", 2799 warzonemobile: "wzm", 2800 tonyhawkthegame: "thps", 2801 alcatraz: "thps", 2802 crash: "crash", 2803 "/crash/quantum": "crash 4", 2804 crash4: "crash 4", 2805 lava: "rumble", 2806 crashontherun: "crash on the run", 2807 crashteamracing: "crash team racing", 2808 "nsane-trilogy": "nsane trilogy", 2809 sekirothegame: "sekiro", 2810 spyrothedragon: "spyro rt", 2811 "/1+2": "thps-1-2", 2812 "/3+4": "thps-3-4", 2813}; 2814 2815ATVI.dataLayerGameName = ""; 2816 2817(function ($, ATVI) { 2818 var url = window.location.href, 2819 franchises = Object.keys(ATVI.franchiseMap), 2820 i; 2821 2822 for (i = 0; i < franchises.length; i++) { 2823 if (url.indexOf(franchises[i]) > -1) { 2824 ATVI.dataLayerGameName = ATVI.franchiseMap[franchises[i]]; 2825 } 2826 } 2827 // NOTE: Should we continue to default to cod or modify the code/site map to give better results? 2828 if (!ATVI.dataLayerGameName) ATVI.dataLayerGameName = "cod"; 2829 2830 ATVI.definePageView = function () { 2831 if (!digitalData) return; 2832 var url = window.location.href; 2833 2834 if ( 2835 //url.indexOf("stage.callofduty.com") > -1 || 2836 url.indexOf("callofduty.com/store") > -1 2837 ) 2838 return; 2839 var d = digitalData.page, 2840 obj = {}, 2841 siteSubsectionStr = d.pageInfo.siteSubsection; 2842 if ( 2843 siteSubsectionStr == "hub" && 2844 ATVI.dataLayerGameName.indexOf("crash") > -1 2845 ) 2846 siteSubsectionStr = "home"; 2847 if (d.pageInfo.pageName.indexOf("callofduty:store:bundles:") >= 0) 2848 siteSubsectionStr = "bundles"; 2849 obj.event = "pageView"; 2850 obj.site = d.pageInfo.site; 2851 obj.siteSection = d.pageInfo.siteSection; 2852 obj.siteSubsection = siteSubsectionStr; 2853 obj.pageType = d.pageCategory.pageType; 2854 obj.pageName = d.pageInfo.pageName; 2855 obj.name = d.targetEntity.name; 2856 obj.description = d.targetEntity.description; 2857 //obj.pageURL = d.targetEntity.pageURL; 2858 obj.pageURL = window.location.href; 2859 obj.country = d.pageInfo.country; 2860 obj.locale = d.targetEntity.locale; 2861 obj.language = d.pageInfo.language; 2862 obj.charSet = d.pageInfo.charSet; 2863 obj.skill = d.targetEntity.skill; 2864 2865 /*if(url.includes("callofduty")) { 2866 obj.loggedIn = (ATVI.utils.getCookie("ACT_SSO_COOKIE") && ATVI.utils.getCookie("atkn")) ? true : false;
2867 } 2868 else { 2869 2870 obj.loggedIn = ATVI.sso.isLoggedIn(); 2871 }*/ 2872 //obj.loggedIn = ATVI.utils.getCookie("ACT_SSO_COOKIE") ? true : false; 2873 obj.loggedIn = ATVI.sso.isLoggedIn(); 2874 2875 //cod store only 2876 if (url.indexOf("callofduty.com") > 0 && url.indexOf("/store") > 0) 2877 obj.event = "page_view"; 2878 2879 2880 2881 //CODE 2882 if (digitalData.page.pageInfo.siteSection == "endowment") { 2883 obj.site = "endowment"; 2884 obj.siteSubsection = digitalData.page.pageInfo.siteSubsection; 2885 obj.siteSection = digitalData.page.pageInfo.siteSubsection; 2886 2887 if ( 2888 obj.siteSubsection == "about" || 2889 obj.siteSubsection == "leadership" || 2890 obj.siteSubsection == "our_founding_story" 2891 ) 2892 obj.siteSection = "about"; 2893 else if ( 2894 obj.siteSubsection == "veteran_support" || 2895 obj.siteSubsection == "us_veteran_support" || 2896 obj.siteSubsection == "uk_veteran_support" || 2897 obj.siteSubsection == "veteran_testimonials" || 2898 obj.siteSubsection == "research" 2899 ) 2900 obj.siteSection = "veterans"; 2901 else if ( 2902 obj.siteSubsection == "media_center" || 2903 obj.siteSubsection == "in_the_news" || 2904 obj.siteSubsection == "blog" || 2905 obj.siteSubsection == "awards" 2906 ) 2907 obj.siteSection = "news"; 2908 else if (window.location.href.indexOf("awards") > -1) 2909 obj.siteSection = "awards"; 2910 2911 if (obj.siteSubsection == "about") 2912 obj.siteSubsection = "our mission"; 2913 } 2914 2915 //COD BRAND 2916 if (digitalData.page.pageInfo.siteSection == "brand") { 2917 if ( 2918 digitalData.page.pageInfo.siteSubsection == 2919 "logos-and-wordmark" || 2920 digitalData.page.pageInfo.siteSubsection == "media-center" 2921 ) { 2922 obj.siteSubsection = "home"; 2923 obj.pageType = "home"; 2924 } 2925 2926 if ( 2927 digitalData.page.pageInfo.siteSubsection == "typeface" || 2928 digitalData.page.pageInfo.siteSubsection == 2929 "building-creative" || 2930 digitalData.page.pageInfo.siteSubsection == "types-in-use" 2931 ) { 2932 obj.siteSubsection = "typography"; 2933 } 2934 } 2935 2936 //THPS 2937 if (digitalData.page.pageInfo.site == "tony-hawk") { 2938 if (digitalData.page.pageInfo.siteSection == "alcatraz-v2") { 2939 obj.siteSection = "thps-1-2"; 2940 } 2941 2942 if (digitalData.page.pageInfo.siteSection == "chicago") { 2943 obj.siteSection = "thps-3-4"; 2944 } 2945 } 2946 2947 //PROMOTIONS: VERDANSK REPLAY / BETA STATS CAMPAIGN 2948 if (digitalData.page.pageInfo.siteSection === "promotions") { 2949 if ( 2950 digitalData.page.targetEntity.pageURL.includes( 2951 "verdansk-replay" 2952 ) || 2953 digitalData.page.targetEntity.pageURL.includes("verdanskreplay") 2954 ) { 2955 obj.pageName = "callofduty:promotions:verdansk-replay:home"; 2956 } 2957 if ( 2958 digitalData.page.targetEntity.pageURL.includes( 2959 "bo7-beta-stats" 2960 ) || 2961 digitalData.page.targetEntity.pageURL.includes("bo7betastats") 2962 ) { 2963 obj.pageName = "callofduty:promotions:home"; 2964 } 2965 } 2966 2967 //WARZONE 2968 if (digitalData.page.pageInfo.siteSection === "warzone2") { 2969 obj.siteSection = "warzone"; 2970 } 2971 2972 $(window).on("load", function() { 2973 2974 //If logged in 2975 if(obj.loggedIn) { 2976 2977 var id; 2978 2979 //if on cod site 2980 if(url.includes("callofduty")) { 2981 2982 //check if sso identities is available 2983 if (Array.isArray(ssobar?.user?.identities)) { 2984 2985 //get provider that equals to uno 2986 const unoIdentity = ssobar.user.identities.find(id => id.provider === "uno"); 2987 2988 //if uno id is available
2989 if (unoIdentity?.accountID) { 2990 id = unoIdentity.accountID; 2991 hashId(id); 2992 } 2993 2994 } 2995 2996 } 2997 else { 2998 2999 //if on support atvi site 3000 if(window.location.href.includes("support.activision")) { 3001 hashId(); 3002 } 3003 3004 else { 3005 3006 if(ATVI.sso.userInfo) { 3007 hashId(ATVI.sso.userInfo.unoID); 3008 } 3009 else { 3010 hashId(); 3011 } 3012 3013 } 3014 } 3015 3016 } 3017 3018 else { 3019 //Push to data layer once page is fully loaded 3020 dataLayer.push(obj); 3021 } 3022 3023 }); 3024 3025 function hashId(id) { 3026 3027 if(id) { 3028 3029 var salt = "ATVI_SALT"; 3030 var saltedId = `${salt}:${id}`; // Concatenate UnoID and salt with colon 3031 3032 var encoder = new TextEncoder(); 3033 3034 var data = encoder.encode(saltedId); 3035 3036 window.crypto.subtle.digest("SHA-256", data) 3037 .then((hashBuffer) => { 3038 // Convert digest to hex string first 3039 const hashArray = Array.from(new Uint8Array(hashBuffer)); 3040 const hexString = hashArray 3041 .map((b) => b.toString(16).padStart(2, "0")) 3042 .join(""); 3043 3044 // Then base64-encode that hex string 3045 const base64String = btoa(hexString); 3046 const base64NoPadding = base64String.replace(/=+$/, ""); 3047 3048 obj.userId = base64NoPadding; 3049 3050 // Push to data layer 3051 dataLayer.push(obj); 3052 }) 3053 .catch((error) => { 3054 console.error("Hashing error:", error); 3055 }); 3056 3057 } 3058 else { 3059 dataLayer.push(obj); 3060 } 3061 3062 } 3063 3064 //Logged In 3065 var loggedInObj = {}; 3066 3067 loggedInObj.event = "login"; 3068 loggedInObj.category = "sso"; 3069 }; 3070 3071 ATVI.definePageView(); 3072})(jQuery, ATVI); 3073 3074// add callback methods for any components affected by cookie acceptance/denial changes 3075window.onload = () => { 3076 ATVI.cookiesAccepted = window.OptanonActiveGroups; 3077 document.addEventListener('OneTrustGroupsUpdated', function() { 3078 if (ATVI.components.video) ATVI.components.video.handleOptanonChange(); 3079 ATVI.cookiesAccepted = window.OptanonActiveGroups; 3080 }); 3081}; 3082 3083 3084// banner pop up 3085(function() { 3086 3087 var init = function() { 3088 3089 //var enableBanner = false; 3090 var banner = $(".atvi-privacy-policy-module"); //set to banner that needs to be active 3091 var cookieName = "atvi-pp"; //name of cookie to check. Change name slightly each time a new update goes live 3092 3093 //if(typeof ATVI.utils.getCookie(cookieName) == "undefined" && enableBanner == true) { 3094 if(typeof ATVI.utils.getCookie(cookieName) == "undefined") { 3095 3096 if(banner.length) { 3097 banner.addClass("show"); 3098 3099 var btn = banner.find(".close-modal"); 3100 btn.click(function(e){ 3101 banner.removeClass("show"); 3102 $(this).attr("tabindex","-1"); 3103 setCookie(cookieName); 3104 }); 3105 } 3106 3107 } 3108 3109 }; 3110 3111 var setCookie = function(cName) { 3112 ATVI.utils.setCookie(cName, true, {expireDate: (3600 * 24 * 365)}); 3113 }; 3114 3115 $(init); 3116 3117})(); 3118 3119 3120 3121 3122(function($, ATVI) { 3123 3124 var lib = ATVI.library = {}; 3125 3126 var dependencies = { 3127 jScrollPane: "basic-ui" 3128 }; 3129 3130 var loaded = {}; 3131 var onLoadHandlers = {}; 3132 var loading = {}; 3133 3134 lib.registerLibrary = function(n) { 3135 loaded[n] = true; 3136 getOnLoadQueue(n).trigger("load"); 3137 var q = loading[n] || []; 3138 while(q.length) { 3139 q.shift()(); 3140 } 3141 }; 3142 3143 lib.loadDependencies = function() { 3144 for(var i = 0; i < arguments.length; i++) { 3145 lib.withDependency(arguments[i]); 3146 } 3147 }; 3148 3149 lib.withDependency = function(deps, enableCookies = false, callback) { 3150 var i, library, types = ""; 3151 if($.isArray(deps)) { 3152 var evs = []; 3153 for(i = 0; i < deps.length; i++) { 3154 var dep = deps[i]; 3155 var depName = typeof dep == "object" ? dep.name : dep; 3156 if(evs.indexOf(depName) >= 0) continue;
3157 var library = dependencies[depName] || depName; 3158 if(loaded[library]) continue; 3159 evs.push(dep); 3160 } 3161 if(!evs.length) { 3162 if(callback) callback(); 3163 return; 3164 } 3165 var q = ATVI.utils.createReadyQueue(evs); 3166 if(callback) q.on(callback); 3167 for(i = 0; i < evs.length; i++) { 3168 var cb = (function(l) { 3169 return function() { 3170 q.trigger(l); 3171 }; 3172 })(evs[i]); 3173 lib.withDependency(evs[i], false, cb); 3174 } 3175 return; 3176 } 3177 3178 if(typeof deps == "object") { 3179 var o = deps; 3180 depName = o.name; 3181 types = o.types; 3182 } else { 3183 depName = deps; 3184 } 3185 library = dependencies[depName] || depName; 3186 if(loaded[library]) { 3187 if(callback) callback(); 3188 return; 3189 } 3190 3191 var a = loading[library]; 3192 if(!a) { 3193 var doLoad = true; 3194 a = loading[library] = []; 3195 } 3196 if(callback) a.push(callback); 3197 if(doLoad) loadLibrary(library, enableCookies, types); 3198 }; 3199 3200 var loadLibrary = function(libName, enableCookies = false, types) { 3201 var urlBase = "/apps/atvi/global/components/content/" + libName; 3202 if(types != "css") 3203 $.ajax({ 3204 dataType: "script", 3205 cache: true, 3206 url: urlBase + "/clientlibs.js", 3207 className: (enableCookies) ? 'optanon-category-3': '' 3208 }); 3209 if(types != "js") 3210 $("<link>", {"type": "text/css", "rel": "stylesheet", "href": urlBase + "/clientlibs.css"}) 3211 .appendTo($('head')); 3212 }; 3213 3214 var getOnLoadQueue = function(dep) { 3215 if(!onLoadHandlers[dep]) onLoadHandlers[dep] = ATVI.utils.createReadyQueue(["load"]); 3216 return onLoadHandlers[dep]; 3217 }; 3218 3219 lib.onDependencyLoad = function(dep, handler) { 3220 getOnLoadQueue(dep).on(handler); 3221 }; 3222 3223})(jQuery, ATVI); 3224 3225// browser 3226(function() { 3227 var b = ATVI.browser = {}; 3228 b.hasPointerEvents = !!window.PointerEvent; 3229 b.hasTouchEvents = 'ontouchend' in document; 3230 b.isTouch = b.hasPointerEvents || b.hasTouchEvents; 3231 3232 var ua = navigator.userAgent; 3233 b.isAndroid = !!ua.match(/Android/i); 3234 b.isAndroidMobile = b.isAndroid && !!ua.match(/Mobile/i); 3235 b.isAndroidTablet = b.isAndroid && !b.isAndroidMobile; 3236 b.isBlackberry = !!ua.match(/BlackBerry/i); 3237 b.isIPhone = !!ua.match(/iPhone/i); 3238 b.isIPad = !!ua.match(/iPad/i); 3239 b.isIPod = !!ua.match(/iPod/i); 3240 b.isIos = b.isIPhone || b.isIPad || b.isIPod; 3241 b.isOperaMini = !!ua.match(/Opera Mini/i); 3242 b.isIeMobile = !!ua.match(/IEMobile/i); 3243 3244 b.isBot = !!ua.match(/googlebot|yahoo|msnbot|bingbot|slurp|teoma/i); 3245 3246 b.isPhone = b.isAndroidMobile || b.isBlackberry || b.isIPhone || b.isIPod || b.isOperaMini || b.isIeMobile; 3247 b.isTablet = b.isAndroidTablet || b.isIPad; 3248 3249})(); 3250 3251 3252// analytics 3253 3254ATVI.analytics = ATVI.analytics || {}; 3255(function($, ATVI) { 3256 3257 var ana = ATVI.analytics; 3258 3259 ana.siteId = "cms-generic"; 3260 ana.ns_site = "dev"; 3261 ana.prefixesToStrip = []; 3262 ana.homePageFilename = "home"; 3263 ana.inited = false; 3264 3265 ana.init = function() { 3266 ana.$body = $("body"); 3267 ana.setupPageLoad(); 3268 var go = function() { 3269 ana.inited = true; 3270 //ana.setupClickHandlers($("body")); 3271 }; 3272 3273 if(window.ssobar && ssobar.onReady) ssobar.onReady(go); 3274 else go(); 3275 }; 3276 3277 ana.setupClickHandlers = function(root) { 3278 if(!ana.inited) return; 3279 /* 3280 root = $(root); 3281 this.setupTaggedElements(root); 3282 this.setupLinks(root); 3283 */ 3284 }; 3285 3286 ana.stripPathPrefixes = function(path) { 3287 var ret = path; 3288 for(var i = 0; i < this.prefixesToStrip.length; i++) { 3289 ret = ret.replace(new RegExp("^" + this.prefixesToStrip[i] + "(/.*)?$"), "$1"); 3290 } 3291 return ret; 3292 }; 3293 3294 ana.splitPath = function(path, includeFileExtension) { 3295 var ret = path.replace(/^\//, "").replace(/\/$/, ""); 3296 if(!includeFileExtension) ret = ret.replace(/(.*)\.\w+$/, "$1"); 3297 ret = ret.replace(/\./g, '_').replace(/\/+/g, '.'); 3298 if(ret.length == 0) ret = this.homePageFilename; 3299 return ret.split('.'); 3300 }; 3301 3302 ana.getSiteData = function() { 3303 var sitename = ana.siteId; 3304 var locPathname = ana.stripPathPrefixes(window.location.pathname); 3305 var parsed = ATVI.utils.parseLocalizedPath(locPathname); 3306 locPathname = ana.stripPathPrefixes(parsed.normalized); 3307 locPathname = ana.splitPath(locPathname); 3308 3309 var hierarchy = []; 3310 var i = locPathname.length - 4; 3311 if(i < 0) i = 0; 3312 var top = sitename; 3313 for(; i < locPathname.length; i++) { 3314 top += "." + locPathname[i]; 3315 hierarchy.push(top); 3316 } 3317 3318 while(hierarchy.length < 4) { 3319 hierarchy.push(top); 3320 } 3321 3322 return { 3323 csName: top, 3324 csSection: hierarchy[0], 3325 csSubSection: hierarchy[1], 3326 csCtitle: hierarchy[2], 3327 csCtype: hierarchy[0], 3328 csPathLocale: parsed.locale 3329 }; 3330 }; 3331 3332 ana.setupPageLoad = function() { 3333 if (location.hostname.indexOf("activision") == -1 && location.hostname.indexOf("guitarhero") == -1) { 3334 var cookies = ATVI.utils.getCookies(true); 3335 var instr = {};
3336 if(cookies.ATVI_INSTRUMENT) { 3337 try { 3338 instr = JSON.parse(cookies.ATVI_INSTRUMENT); 3339 } catch(e) { 3340 instr = {}; 3341 } 3342 } 3343 3344 var siteData = this.getSiteData(); 3345 3346 var prevPage = instr.page; 3347 instr.page = siteData.csName; 3348 3349 var pageData = { 3350 site: this.siteId, 3351 language: cookies.ACT_SSO_LOCALE || "en_US", 3352 "name": siteData.csName, 3353 previous_page: prevPage, 3354 c_type: siteData.csCtype, 3355 c_title: siteData.csCtitle, 3356 section: siteData.csSection, 3357 sub_section: siteData.csSubSection, 3358 path_locale: siteData.csPathLocale 3359 }; 3360 3361 var eventCookie = cookies.ACT_SSO_EVENT; 3362 if(eventCookie) { 3363 eventCookie = eventCookie.replace(/^\"(.*)\"$/, "$1"); 3364 if(instr.event != eventCookie) { 3365 instr.event = eventCookie; 3366 eventCookie = eventCookie.split(":"); 3367 if(eventCookie[0]) 3368 pageData.sso_event = eventCookie[0]; 3369 } 3370 } 3371 3372 //ATVI.utils.setCookie("ATVI_INSTRUMENT", JSON.stringify(instr)); 3373 //this.sendData(pageData); 3374 } 3375 }; 3376 3377 ana.setupTaggedElements = function(root) { 3378 /* 3379 var self = this; 3380 root.find(".atvi-instrument").click(function() { 3381 var classes = this.className.split(/\s+/); 3382 var className; 3383 3384 for(i in classes) { 3385 if(classes[i].indexOf("atvi-instrument-") >= 0) { 3386 className = classes[i]; 3387 className = className.substring("atvi-instrument-".length); 3388 break; 3389 } 3390 } 3391 3392 if(className) { 3393 3394 var $this = $(this); 3395 var id = ana.findComponentId($this); 3396 var strippedId = id.replace(/^(.+)-analytics-suffix-.*$/, "$1"); 3397 3398 var data = { 3399 action_type: className, 3400 action_details: strippedId, 3401 ns_type: "hidden" 3402 }; 3403 3404 var go = function() { 3405 ana.sendData(data); 3406 }; 3407 3408 if(ana.customData[className]) { 3409 if(!ana.customData[className]($this, data, go)) go(); 3410 } else go(); 3411 } 3412 }); 3413 */ 3414 }; 3415 3416 // add to this for component handling 3417 ana.customData = {} 3418 // e.g. 3419 ana.customData.wheretobuy = ana.customData.wheretobuy ||function($el, data) {}; 3420 3421 ana.setupLinks = function(root) { 3422 3423 root.find("a").not(".atvi-instrument").not(".atvi-no-instrument").click(function() { 3424 3425 var href = this.href; 3426 var $this = $(this); 3427 3428 var data = { 3429 action_type: "atvi-anchor", 3430 href: href, 3431 ns_type: "hidden" 3432 }; 3433 3434 var detail = ""; 3435 var id = ana.findComponentId($this); 3436 if(id) { 3437 var strippedId = id.replace(/^(.+)-analytics-suffix-.*$/, "$1"); 3438 detail += strippedId + ": "; 3439 } 3440 var linkText = $this.text().substring(0, 30); 3441 if(linkText.length >= 30) linkText += "..."; 3442 detail += linkText; 3443 data.action_details = detail; 3444 3445 //ana.sendData(data); 3446 3447 }); 3448 }; 3449 3450 ana.findComponentId = function($el, selector) { 3451 var id = $el.attr("id"); 3452 if(id && !$el.hasClass("ignore-id")) return id; 3453 var i, p = $el.parents(selector); 3454 for(i = 0; i < p.length; i++) { 3455 id = p[i].id; 3456 if(id && !p.eq(i).hasClass("ignore-id")) return id; 3457 } 3458 return ""; 3459 }; 3460 3461 ana.sendEvent = function(actionType, actionDetails, params) { 3462 var data = { 3463 action_type: actionType,
3464 action_details: actionDetails, 3465 ns_type: "hidden" 3466 }; 3467 params = params || {}; 3468 for(var i in params) { 3469 if(!params.hasOwnProperty(i)) continue; 3470 data[i] = params[i]; 3471 } 3472 //this.sendData(data); 3473 3474 var ev = document.createEvent("CustomEvent"); 3475 ev.initCustomEvent("atviInstrumentEvent", true, true, { type: actionType, details: actionDetails, data: data }); 3476 document.body.dispatchEvent(ev); 3477 }; 3478 3479 ana.sendData = function (data) { 3480 /** 3481 var loc = 'http' + (document.location.href.charAt(4) == 's' ? 's://sb' : '://b') + '.scorecardresearch.com/p?c1=2&c2=14880931'; 3482 3483 // common values 3484 data.visitorID = this.getVisitorId(); 3485 data.anonVisitorID = this.getAnonVisitorId(); 3486 data.ns__t = "" + new Date().getTime(); 3487 data.ns_c = document.characterSet || document.defaultCharset || ""; 3488 data.c8 = document.title; 3489 data.c7 = document.location.href || document.URL; 3490 data.c9 = document.referrer; 3491 3492 if(ATVI.uxTest && ATVI.uxTest.campaigns) { 3493 var campaigns = ATVI.uxTest.campaigns; 3494 var campaignNames = [], campaignIds = []; 3495 var recipeNames = [], recipeIds = []; 3496 var offerNames = [], offerIds = []; 3497 var mboxNames = []; 3498 for(var i = 0; i < campaigns.length; i++) { 3499 campaignNames.push(campaigns[i].campaignName); 3500 campaignIds.push(campaigns[i].campaignId); 3501 recipeNames.push(campaigns[i].recipeName); 3502 recipeIds.push(campaigns[i].recipeId); 3503 offerNames.push(campaigns[i].offerName); 3504 offerIds.push(campaigns[i].offerId); 3505 mboxNames.push(campaigns[i].mboxName); 3506 } 3507 data.campaignName = campaignNames.join(","); 3508 data.campaignId = campaignIds.join(","); 3509 data.recipeName = recipeNames.join(","); 3510 data.recipeId = recipeIds.join(","); 3511 data.offerName = offerNames.join(","); 3512 data.offerId = offerIds.join(","); 3513 data.mboxName = mboxNames.join(","); 3514 } 3515 3516 var cookies = ATVI.utils.getCookies(true); 3517 if(cookies.comScore) data.comScore = cookies.comScore; 3518 3519 data.ns_site = ATVI.pageEnv == "prod" ? (this.ns_site || "dev") : "dev"; 3520 3521 for(var i in data) { 3522 loc += "&" + i + "=" + encodeURIComponent(data[i]); 3523 } 3524 3525 if (loc.length > 2048) { 3526 var s = loc.substr(0, 2040).lastIndexOf("&"); 3527 loc = (loc.substring(0, s) + "&ns_cut=" + encodeURIComponent(loc.substring(s + 1))).substr(0, 2048); 3528 } 3529
3530 if(!ana.$container) ana.$container = $('<div>').css({height: 0, width: 0, overflow: "hidden"}).appendTo(ana.$body); 3531 $('<div>').css({height: 0, width: 0, overflow: "hidden"}).appendTo(ana.$container) 3532 .append('<img src="' + loc + '" height="1" width="1" alt="*" />' ); 3533 **/ 3534 }; 3535 3536 ana.getVisitorId = function() { 3537 var c = ATVI.utils.getCookies(true); 3538 3539 var s = c.ACT_SSO_COOKIE || c.s_ACT_SSO_COOKIE; 3540 3541 if(s) { 3542 var dec = ATVI.utils.decodeBase64(s); 3543 var index = dec.indexOf(":"); 3544 if(index >= 0) dec = dec.substring(0, index); 3545 return dec; 3546 } 3547 3548 return this.getAnonVisitorId(); 3549 }; 3550 3551 ana.getAnonVisitorId = function() { 3552 3553 var c = ATVI.utils.getCookies(true); 3554 if(c.ATVI_VISITOR_ID) return c.ATVI_VISITOR_ID; 3555 3556 var date = new Date(); 3557 var anonId = "anon-" + date.getTime() + "-" + Math.random(); 3558 3559 date.setTime(date.getTime() + 5 * 356 * 24 * 60 * 60000); 3560 ATVI.utils.setCookie("ATVI_VISITOR_ID", anonId, date); 3561 3562 return anonId; 3563 }; 3564 3565 3566 $(function() { 3567 ana.init(); 3568 }); 3569 3570})(jQuery, ATVI); 3571 3572var ATVI = ATVI || {}; 3573 3574(function($, ATVI) { 3575 3576 let a = ATVI.tagging = {}; 3577 3578 let init = function() { 3579 3580 if (!digitalData || !dataLayer) return; 3581 var d = digitalData.page; 3582
3583 ////////////////////////////////////// 3584 3585 // CTA LINK ANALYTICS CLICK HANDLER 3586 3587 ////////////////////////////////////// 3588 3589 /** 3590 Give the class name .atvi-cta-item to any <a> or <button> element that will act as an interactable CTA link/button. 3591 This class is automatically added to the ATVI CTA component's <a> and <button> tags 3592 **/ 3593 3594 //Get all elements with .atvi-cta-item class except those with .atvi-exempt-analytics class 3595 let ctaItems = $(".atvi-cta-item:not(.atvi-exempt-analytics)"); 3596 3597 ctaItems.each(function() { 3598 3599 var $el = $(this); 3600 3601 $el.on("click", function() { 3602 3603 //Get href value. If item is not a link, then it's a button 3604 let curHref = $(this).attr("href") || 'button'; 3605 3606 //Build url with https: and domain name in front 3607 let fullHref = (curHref.startsWith("https:") || curHref == 'button') ? curHref : window.location.origin + curHref; 3608 3609 //Check if link is social platform link 3610 var socialPlatform = ''; 3611 3612 if(fullHref.includes("facebook.com")) socialPlatform = "facebook"; 3613 else if(fullHref.includes("twitter.com")) socialPlatform = "twitter"; 3614 else if(fullHref.includes("instagram.com")) socialPlatform = "instagram"; 3615 else if(fullHref.includes("youtube.com")) socialPlatform = "youtube"; 3616 else if(fullHref.includes("tiktok.com")) socialPlatform = "tiktok"; 3617 else if(fullHref.includes("linkedin.com")) socialPlatform = "linkedin"; 3618 else if(fullHref.includes("discord.gg")) socialPlatform = "discord"; 3619 else if(fullHref.includes("twitch.tv")) socialPlatform = "twitch"; 3620 else if(fullHref.includes("reddit.com")) socialPlatform = "reddit"; 3621 3622 3623 //If data-extext exists, then set cta name to this english cta name. If not defined, then use the inner text of cta element 3624 let ctaName = $(this).attr("data-entext") ? $(this).attr("data-entext").replace(":", " ") : $(this).text().trim().replace(":", " "); //text in cta 3625 3626 //Get closest parent element with class .atvi-module-container[data-analytics-container] 3627 let parentModule = ($(this).closest(".atvi-module-container[data-analytics-container]").length > 0) ? $(this).closest(".atvi-module-container[data-analytics-container]") : $(this).closest(".atvi-module-container[id]"); //get closest element that has data-analytics-container or .atvi-module-container element that has ID attribute 3628 3629 //Get module name from either the data-analytics-container attribute or the id attribute or by default it will be atvi-module 3630 let moduleName = parentModule.data("analytics-container") || parentModule.attr("id") || "atvi-module"; 3631 3632 //If this button is a video, let's get the title 3633 let videoTitle = $(this).attr("data-youtube-title"); 3634 3635 //If socialPlatform is empty string, then this is a regular CTA link or button 3636 if(socialPlatform == '') { 3637 3638 //If CTA button opens a video modal 3639 if(videoTitle != null && videoTitle != '') { 3640 3641 dataLayer.push({ 3642 event: 'interaction', 3643 action: moduleName + ":" + ctaName, 3644 category: 'interaction:' + d.pageInfo.pageName, 3645 label: fullHref, 3646 video_title: videoTitle, 3647 video_provider: "youtube", 3648 module: moduleName 3649 }); 3650 3651 } 3652 3653 //Else it's a regular link or button 3654 else { 3655 3656 dataLayer.push({ 3657 event: 'interaction', 3658 action: moduleName + ":" + ctaName, 3659 category: 'interaction:' + d.pageInfo.pageName, 3660 label: fullHref, 3661 module: moduleName 3662 }); 3663 3664 } 3665 } 3666 3667 //Else this is a social link 3668 else { 3669 3670 dataLayer.push({ 3671 3672 event: "social", 3673 category: "social", 3674 action: socialPlatform, 3675 label: fullHref 3676 3677 }); 3678 3679 } 3680 3681 }); 3682 3683 }); 3684
3685 //////////////////////////////////// 3686 3687 // MODULE ANALYTICS SCROLL HANDLER 3688 3689 //////////////////////////////////// 3690 3691 //select all elements that have a data-analytics-container attribute 3692 let containers = document.querySelectorAll("*[data-analytics-container]"); 3693 3694 //if we find at least 1 element, create an observer for the elements 3695 if(containers.length > 0) createObserver(containers, handleCallback, {threshold: 0.5}); 3696 3697 }; 3698 3699 let createObserver = function(selectors, callback, options = {}) { 3700 3701 //create new intersection observer instance 3702 let observer = new IntersectionObserver(callback, options); 3703 3704 //for each selector, create an observer 3705 selectors.forEach( (selector) => { 3706 observer.observe(selector); 3707 }); 3708 }; 3709 3710 const handleCallback = (entries) => { 3711 entries.forEach( (entry) => { 3712 //if target passes half way in viewport 3713 if (entry.intersectionRatio >= 0.5) { 3714 const { target } = entry; 3715 3716 //call updateScrollDataLayer method and pass the data-analytics-container value 3717 updateScrollDataLayer($(target).data("analytics-container")); 3718 } 3719 }); 3720 }; 3721 3722 let updateScrollDataLayer = function(module) { 3723 3724 //if dataDigital or dataLayer do not exist, then stop execution of rest of code 3725 var url = window.location.href; 3726 var d = digitalData.page, obj = {}; 3727 3728 //create analytics object using predefined values 3729 obj.event = "scroll"; 3730 obj.category = "scroll"; 3731 obj.action = d.pageInfo.pageName; 3732 obj.label = module; 3733 3734 //append object to dataLayer 3735 dataLayer.push(obj); 3736 3737 }; 3738 3739 3740 $(init); 3741 3742 3743})(jQuery,ATVI); 3744 3745 3746// touch 3747 3748ATVI.touch = {}; 3749(function($, ATVI) { 3750 3751 var touch = ATVI.touch; 3752 var touchDist = ATVI.browser.isPhone ? 35 : 60; 3753 3754 touch.onSimpleHorizontal = function($el, opts) { 3755 3756 var h = opts.hammer || Hammer($el[0], { swipe_velocity: opts.swipeVelocity || .2 }); 3757 3758 h.on("swipeleft swiperight dragleft dragright dragend dragstart", function(ev) { 3759 var t = ev.type, dx = Math.abs(ev.deltaX), dy = Math.abs(ev.deltaY) + .1, rat = dx / dy, dt = ev.deltaTime; 3760 3761 if(t != "dragstart" && t != "dragend") { 3762 ev.preventDefault(); 3763 } 3764 3765 if(t == "dragleft" && opts.dragLeft) opts.dragLeft(ev); 3766 if(t == "dragright" && opts.dragRight) opts.dragRight(ev); 3767 if(t == "dragstart" && opts.dragStart) opts.dragStart(ev); 3768 if(t == "dragend" && opts.dragEnd) opts.dragEnd(ev); 3769 3770 if((t == "dragleft" && dx > touchDist && rat > 2 && dt < 700) || t == "swipeleft") { 3771 if(opts.swipeLeft) opts.swipeLeft(ev); 3772 //ev.stopDetect(); 3773 } 3774 if((t == "dragright" && dx > touchDist && rat > 2 && dt < 700) || t == "swiperight") { 3775 if(opts.swipeRight) opts.swipeRight(ev); 3776 //ev.stopDetect(); 3777 } 3778 }); 3779 3780 return { 3781 hammerObj: h 3782 }; 3783 }; 3784 3785})(jQuery, ATVI); 3786 3787 3788// country codes 3789ATVI.countryCodes = {}; 3790(function() { 3791 3792 ATVI.countryCodes = { 3793 "af" : "Afghanistan", 3794 "al" : "Albania", 3795 "dz" : "Algeria", 3796 "as" : "American Samoa", 3797 "ad" : "Andorra", 3798 "ao" : "Angola", 3799 "ag" : "Antigua and Barbuda", 3800 "ar" : "Argentina", 3801 "am" : "Armenia", 3802 "aw" : "Aruba", 3803 "au" : "Australia", 3804 "at" : "Austria", 3805 "az" : "Azerbaijan", 3806 "bs" : "Bahamas", 3807 "bh" : "Bahrain", 3808 "bd" : "Bangladesh", 3809 "bb" : "Barbados", 3810 "by" : "Belarus", 3811 "be" : "Belgium", 3812 "be-fr" : "Belgium French", 3813 "bz" : "Belize", 3814 "bj" : "Benin", 3815 "bm" : "Bermuda", 3816 "bt" : "Bhutan", 3817 "bo" : "Bolivia", 3818 "ba" : "Bosnia and Herzegovina", 3819 "bw" : "Botswana", 3820 "bv" : "Bouvet Island", 3821 "br" : "Brazil", 3822 "io" : "British Indian Ocean Territory", 3823 "bn" : "Brunei Daarussalam", 3824 "bg" : "Bulgaria", 3825 "bf" : "Burkina Faso", 3826 "bi" : "Burundi", 3827 "kh" : "Cambodia", 3828 "cm" : "Cameroon", 3829 "ca" : "Canada", 3830 "ca-fr" : "Le Canada Français", 3831 "cv" : "Cape Verde", 3832 "ky" : "Cayman Islands", 3833 "cf" : "Central AFrican Republic", 3834 "td" : "Chad", 3835 "cl" : "Chile", 3836 "cn" : "ç¹é«ä¸æ", 3837 "cn-s" : "ç®ä½ä¸æ", 3838 "cx" : "Christmas Island", 3839 "cc" : "Cocos Islands", 3840 "co" : "Colombia", 3841 "km" : "Comoros", 3842 "cg" : "Congo", 3843 "cd" : "The Democratic Republic of Congo", 3844 "ck" : "Cook Islands", 3845 "cr" : "Costa Rica", 3846 "ci" : "Côte d'Ivoire", 3847 "hr" : "Croatia", 3848 "cu" : "Cuba", 3849 "cy" : "Cypress", 3850 "cz" : "Czech Republic", 3851 "dk" : "Danmark", 3852 "dj" : "Djibouti", 3853 "dm" : "Dominica", 3854 "do" : "Dominican Republic", 3855 "ec" : "Ecuador", 3856 "eg" : "Egypt", 3857 "sv" : "El Salvador", 3858 "gq" : "Equatorial Guinea", 3859 "er" : "Eritrea", 3860 "ee" : "Estonia", 3861 "et" : "Ethiopia", 3862 "fk" : "Falkland Islands", 3863 "fo" : "Faroe Islands", 3864 "fj" : "Fiji", 3865 "fi" : "Suomi", 3866 "fr" : "France", 3867 "gf" : "French Guiana", 3868 "pf" : "French Polynesia", 3869 "tf" : "French Southern Territories", 3870 "ga" : "Gabon", 3871 "gm" : "Gambia", 3872 "ge" : "Georgia", 3873 "de" : "Deutschland", 3874 "gh" : "Ghana", 3875 "gi" : "Gibraltar", 3876 "gr" : "Greece", 3877 "gl" : "Greenland", 3878 "gd" : "Grenada", 3879 "gp" : "Guadaloupe", 3880 "gu" : "Guam", 3881 "gt" : "Guatemala", 3882 "gn" : "Guinea", 3883 "gw" : "Guinea-Bissau", 3884 "gy" : "Guyana", 3885 "ht" : "Haiti", 3886 "hm" : "Heard Island and Mcdonald Islands", 3887 "hn" : "Honduras", 3888 "hk" : "Hong Kong", 3889 "hk-s" : "Hong Kong ç®ä½ä¸æ", 3890 "hu" : "Hungary", 3891 "is" : "Iceland", 3892 "in" : "India", 3893 "id" : "Indonesia", 3894 "ir" : "Iran", 3895 "iq" : "Iraq", 3896 "ie" : "Ireland", 3897 "il" : "Israel", 3898 "it" : "Italia", 3899 "jm" : "Jamaica", 3900 "jp" : "æ¥æ¬", 3901 "jo" : "Jordan", 3902 "kz" : "Kazakhstan", 3903 "ke" : "Kenya", 3904 "ki" : "Kiribati", 3905 "kp" : "Korea ì¡°ì 민주주ìì¸ë¯¼ê³µíêµ", 3906 "kr" : "ëí민êµ", 3907 "xk" : "Kosovo", 3908 "kw" : "Kuwait", 3909 "kg" : "Kyrgyzstan", 3910 "la" : "Laos", 3911 "lv" : "Latvia", 3912 "lb" : "Lebanon", 3913 "ls" : "Lesotho", 3914 "lr" : "Liberia", 3915 "ly" : "Libyan Arab Jamahiriya", 3916 "li" : "Liechtenstein", 3917 "lt" : "Lithuania", 3918 "lu" : "Luxembourg", 3919 "lu-de" : "Luxemburg", 3920 "lu-fr" : "Luxembourg", 3921 "mo" : "Macao", 3922 "mk" : "Macedonia", 3923 "mg" : "Madagascar", 3924 "mw" : "Malawi", 3925 "my" : "Malaysia", 3926 "mv" : "Maldives", 3927 "ml" : "Mali", 3928 "mt" : "Malta", 3929 "mh" : "Marshall Islands", 3930 "mq" : "Martinique", 3931 "mu" : "Mauritius", 3932 "yt" : "Mayotte", 3933 "mx" : "México", 3934 "fm" : "Micronesia", 3935 "md" : "Moldova", 3936 "mc" : "Monaco", 3937 "mn" : "Mongolia", 3938 "me" : "Montenegro", 3939 "ms" : "Montserrat", 3940 "ma" : "Morocco", 3941 "mz" : "Mozambique", 3942 "mm" : "Myanmar", 3943 "na" : "Namibia", 3944 "nr" : "Nauru", 3945 "np" : "Nepal", 3946 "nl" : "Netherlands", 3947 "an" : "Netherlands Antilles", 3948 "nc" : "New Caledonia", 3949 "nz" : "New Zealand", 3950 "ni" : "Nicaragua", 3951 "ne" : "Niger", 3952 "ng" : "Nigeria", 3953 "nu" : "Niue", 3954 "nf" : "Norfolk Islands", 3955 "mp" : "Northern Mariana Islands", 3956 "no" : "Norge", 3957 "om" : "Oman", 3958 "pk" : "Pakistan", 3959 "pw" : "Palau", 3960 "ps" : "Palestinian Territory", 3961 "pa" : "Panama", 3962 "pg" : "Papua New Guinea", 3963 "py" : "Paraguay", 3964 "pe" : "Peru", 3965 "ph" : "Philippines", 3966 "pn" : "Pitcairn", 3967 "pl" : "Polska", 3968 "pl-en" : "Poland", 3969 "pt" : "Portugal", 3970 "pr" : "Puerto Rico", 3971 "qa" : "Qatar", 3972 "re" : "Réunion", 3973 "ro" : "Romania", 3974 "ru" : "РоÑÑиÌÑ", 3975 "rw" : "Rwanda", 3976 "sh" : "Saint Helena", 3977 "kn" : "Saint Kitts and Nevis", 3978 "lc" : "Saint Lucia", 3979 "pm" : "Saint Pierre and Miquelon", 3980 "vc" : "Saint Vincent and the Grenadines", 3981 "ws" : "Samoa", 3982 "sm" : "San Marino", 3983 "st" : "Sao Tome and Principe", 3984 "sa" : "Saudi Arabia", 3985 "sn" : "Senegal", 3986 "rs" : "Serbia", 3987 "sc" : "Seychelles", 3988 "sl" : "Sierra Leone", 3989 "sg" : "Singapore", 3990 "sk" : "Slovakia", 3991 "si" : "Slovenia", 3992 "sb" : "Solomon Islands", 3993 "so" : "Somalia", 3994 "za" : "South Africa", 3995 "gs" : "South Georgia and the South Sandwich Islands", 3996 "es" : "España", 3997 "lk" : "Sri Lanka", 3998 "sd" : "Sudan", 3999 "sr" : "Suriname", 4000 "sj" : "Svalbard and Jan Mayen", 4001 "sz" : "Swaziland", 4002 "se" : "Sverige", 4003 "ch" : "Switzerland", 4004 "ch-de" : "Schweizerische Eidgenossenschaft", 4005 "ch-fr" : "Confédération Suisse", 4006 "ch-it" : "Confederazione Svizzera", 4007 "ch-ro" : "Confederaziun Svizra", 4008 "sy" : "Syrian Arab Republic", 4009 "tw" : "Taiwan", 4010 "tj" : "Tajikistan", 4011 "tz" : "Tanzania", 4012 "th" : "Thailand", 4013 "tl" : "Timor-Leste", 4014 "tg" : "Togo", 4015 "tk" : "Tokelau", 4016 "to" : "Tonga", 4017 "tt" : "Trinidad and Tobago", 4018 "tn" : "Tunisia", 4019 "tr" : "Turkey", 4020 "tm" : "Turkmenistan", 4021 "tc" : "Turks and Caicos Islands", 4022 "tv" : "Tuvalu", 4023 "ug" : "Uganda", 4024 "ua" : "Ukraine", 4025 "ua-ru" : "Ukraine - Russian", 4026 "ae" : "United Arab Emirates", 4027 "gb" : "United Kingdom", 4028 "us" : "United States", 4029 "um" : "United States Minor Outlying Islands", 4030 "uy" : "Uruguay", 4031 "uz" : "Uzbekistan", 4032 "vu" : "Vanuatu", 4033 "ve" : "Venezuela", 4034 "vn" : "Viet Nam", 4035 "vg" : "British Virgin Islands", 4036 "vi" : "U.S. Virgin Islands", 4037 "wf" : "Wallis and Futuna", 4038 "eh" : "Western Sahara", 4039 "ye" : "Yemen", 4040 "zm" : "Zambia", 4041 "zw" : "Zimbabwe" 4042 }; 4043 4044})(); 4045var ATVI = ATVI || {}; 4046 4047(function($, ATVI) { 4048 4049 var ld = ATVI.localeDetector = {}, 4050 headers = [{id: 'x-activision-countrycode', type: 'country'}, {id: 'X-Activision-Regioncode', type: 'region'}]; 4051 4052 ld.country; 4053 ld.region; 4054 4055 ld.requestXCode = function() { 4056 var request = new XMLHttpRequest(); 4057 request.open('GET', window.location.href); 4058 request.onreadystatechange = function() { 4059 if(this.readyState == this.HEADERS_RECEIVED) { 4060 var i; 4061 for (i = 0; i < headers.length; i++) { 4062 var d = request.getResponseHeader(headers[i].id) || ""; 4063 ld[headers[i].type] = d.toLowerCase(); 4064 } 4065 ld.fireEvent(); 4066 } 4067 }; 4068 request.send(); 4069 }; 4070 4071 ld.fireEvent = function() { 4072 var e = new CustomEvent('localeDetectionReady'); 4073 document.dispatchEvent(e); 4074 }; 4075 4076 ld.getCountry = function(cb) { 4077 if (ld.country && cb) cb(ld.country); 4078 else { 4079 document.addEventListener('localeDetectionReady', function() { 4080 cb(ld.country); 4081 }); 4082 } 4083 }; 4084 4085 ld.getRegion = function(cb) { 4086 if (ld.region && cb) cb(ld.region); 4087 else { 4088 document.addEventListener('localeDetectionReady', function() { 4089 cb(ld.region); 4090 }); 4091 } 4092 }; 4093 4094 ld.requestXCode(); 4095 4096})(jQuery, ATVI); 4097ATVI.modal = {}; 4098 4099(function($, ATVI) { 4100 4101 var m = ATVI.modal; 4102 4103 var class_bodyOpenModal = 'modal-open', 4104 class_modalOpen = 'active'; 4105 4106 var init = function() { 4107 m.$modals = $('.atvi-modal'); 4108 m.addHandlers(); 4109 }; 4110 4111 m.addHandlers = function() { 4112 m.$modals.each(function() { 4113 var $thisModal = $(this), 4114 $closeButton = $thisModal.find('.button.close, .close-button'), 4115 $bg = $thisModal.find('.background-container'), 4116 $handles = $closeButton.add($bg); 4117 $handles.on('click', function(e) { 4118 e.preventDefault(); 4119 m.closeModal($thisModal); 4120 }); 4121 }); 4122 }; 4123 4124 m.openModal = function($wrapper, ms) { 4125 var $b = $('body'), 4126 ms = (ms) ? ms : 300, 4127 $modals = (m.$modals.length) ? m.$modals : $('.atvi-modal'); 4128 if ($b.hasClass(class_bodyOpenModal)) { 4129 $b.removeClass(class_bodyOpenModal); 4130 $modals.removeClass(class_modalOpen); 4131 setTimeout(function() { 4132 $b.addClass(class_bodyOpenModal); 4133 $wrapper.addClass(class_modalOpen); 4134 }, ms); 4135 } else { 4136 $b.addClass(class_bodyOpenModal); 4137 $wrapper.addClass(class_modalOpen); 4138 } 4139 }; 4140 4141 m.closeModal = function($wrapper) { 4142 var $b = $('body'), 4143 $modals = (m.$modals.length) ? m.$modals : $('.atvi-modal'); 4144 $b.removeClass(class_bodyOpenModal); 4145 $modals.removeClass(class_modalOpen); 4146 }; 4147 4148 $(init); 4149 4150})(jQuery, ATVI); 4151(function($, ATVI) { 4152 4153 var ld = ATVI.localeDetector, 4154 noShowArr = ['us', 'ca', 'mx'], 4155 targetSitesArr = ['www.activision.com', 4156 'www.callofduty.com', 4157 'www.tonyhawkthegame.com', 4158 'www.crashbandicoot.com', 4159 'www.sekirothegame.com', 4160 'www.spyrothedragon.com'], 4161 devSitesArr = [...targetSitesArr.map(site => 'preview'+site.substring(3))], 4162 hostname = window.location.hostname; 4163 4164 4165 var init = function() { 4166 if (ld.country && noShowArr.indexOf(ld.country) == -1) showEulaBanner(); 4167 else { 4168 document.addEventListener('localeDetectionReady', function() { 4169 if (noShowArr.indexOf(ld.country) == -1) showEulaBanner(); 4170 }); 4171 } 4172 }; 4173 4174 var showEulaBanner = function() { 4175 4176 if (typeof ATVI.utils.getCookie('atvi-eula-update') == 'undefined') { 4177 var $el = $('.eula-banner-module'); 4178 if ($el.length) { 4179 $el.addClass('show'); 4180 $el.find('.close-modal').on('click', function() { 4181 $el.removeClass('show'); 4182 $(this).attr("tabindex","-1");
4183 setCookie('atvi-eula-update'); 4184 }); 4185 } 4186 } 4187 }; 4188 4189 var setCookie = function(cookieName) { 4190 ATVI.utils.setCookie(cookieName, true, {expireDate: (3600 * 24 * 365)}); 4191 }; 4192 4193 // only use on select sites 4194 /*if (targetSitesArr.indexOf(hostname) > -1 || devSitesArr.indexOf(hostname) > -1) { 4195 $(init); 4196 }*/ 4197 4198})(jQuery, ATVI); 4199(function () { 4200 4201 let init = function () { 4202 4203 const ld = ATVI.localeDetector; 4204 const region = ld?.region; 4205 /*const user = ssobar?.user; 4206 const userInfo = user?.userInfo;*/ 4207 4208 const teenRegions = [ 4209 'ct', 'nj', 'de', 'co', 'ca', 'tn', 'nh', 'ia', 'tx', 'mt', 4210 'va', 'fl', 'or', 'ut', 'ne', 'ny', 'mn', 'md', 'in', 'ky', 'ri' 4211 ]; 4212 4213 const isTeenRegion = region && teenRegions.includes(region); 4214 4215 4216 const isTeenUser = (ATVI.utils.userInfo && ATVI.utils.userInfo.isChild == false) ? true : false; 4217 const isChildUser = (ATVI.utils.userInfo && ATVI.utils.userInfo.isChild == true) ? true : false; 4218 4219 const shouldRejectCookies = (isTeenRegion && isTeenUser) || (!isTeenRegion && isChildUser); 4220 4221 if (shouldRejectCookies) { 4222 rejectCookies(); 4223 } 4224 }; 4225 4226 let rejectCookies = function () { 4227 // Reject all non-essential cookies 4228 OneTrust.RejectAll(); 4229 4230 // Disable toggles 4231 document.querySelectorAll('.ot-tgl label').forEach((label) => { 4232 label.style.pointerEvents = 'none'; 4233 label.style.opacity = '0.5'; 4234 }); 4235 }; 4236 4237 //$(window).on("load", init); 4238 4239})(); 4240(function() { 4241 4242 var init = function() { 4243 4244 $(".cf-icon-toggle").on("click", function() { 4245 4246 $(this).next(".cf-modal").show(); 4247 4248 }); 4249 4250 $(".cf-modal-close").on("click", function() { 4251 4252 $(this).closest(".cf-modal").hide(); 4253 4254 }); 4255 4256 }; 4257 4258 $(init); 4259 4260})();
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.