PageSourceSearch

https://www.cordishotels.com/etc.clientlibs/cq/testandtarget/clien….ACSHASHa22efedf7e7bfad40ecfe59978aed7e2.js

js cordishotels.com collected 2026-10-02 10:58:39 UTC 24,705 bytes, 655 lines download raw bytes

1/*******************************************************************************
2 * ADOBE CONFIDENTIAL
3 * __________________
4 *
5 * Copyright 2016 Adobe Systems Incorporated
6 * All Rights Reserved.
7 *
8 * NOTICE:  All information contained herein is, and remains
9 * the property of Adobe Systems Incorporated and its suppliers,
10 * if any.  The intellectual and technical concepts contained
11 * herein are proprietary to Adobe Systems Incorporated and its
12 * suppliers 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
18if (!window.CQ_Analytics) {
19    window.CQ_Analytics = {};
20}
21
22(function ($, ns) {
23
24    ns.mboxes = ns.mboxes || [];
25
26    var atjsIntegrator = function ($, ns) {
27
28        /* -- INIT code -- */
29
30        /**
31         * The regular expression to detect the context path used
32         * on the server using the URL of this script.
33         * @private
34         * @readonly
35         * @type RegExp
36         */
37        var SCRIPT_URL_REGEXP = /^(?:http|https):\/\/[^/]+(\/.*)\/(?:etc\.clientlibs|etc(\/.*)*\/clientlibs|libs(\/.*)*\/clientlibs|apps(\/.*)*\/clientlibs|etc\/designs).*\.js(\?.*)?$/;
38
39        var instance = {};
40
41        if (this.constructor === atjsIntegrator.prototype) {
42            throw "This is a singleton!";
43        }
44
45        if (atjsIntegrator.instance) {
46            return atjsIntegrator.instance;
47        }
48
49        atjsIntegrator.instance = instance;
50
51        var _isDebugMode = window.location.href.indexOf("debug-mbox-calls=1") !== -1;
52
53        function _debug(message) {
54            if (_isDebugMode) {
55                console.log(message);
56            }
57        };
58
59        var _contextPath = _detectContextPath();
60
61        function _detectContextPath() {
62            try {
63                if (window.CQURLInfo) {
64                    return CQURLInfo.contextPath || "";
65                } else {
66                    var scripts = document.getElementsByTagName("script");
67                    for (var i = 0; i < scripts.length; i++) {
68                        var result = SCRIPT_URL_REGEXP.exec(scripts[i].src);
69                        if (result) {
70                            return result[1];
71                        }
72                    }
73                }
74            } catch (e) {
75            }
76            return "";
77        };
78
79        /* -- BEGIN PRIVATE AREA -- */
80
81        /**
82         * Adds a parameter to the specified URL. The parameter name and value
83         * will be URL-endcoded.
84         * 
85         * @param url {String}
86         *                url The URL
87         * @param name {String}
88         *                name The name of the parameter
89         * @param value {String/String[]}
90         *                value The value of the parameter
91         * @return {String} The URL with the new parameter
92         */
93        function _addParameter(url, name, value) {
94            if (value && value instanceof Array) {
95                for (var i = 0; i < value.length; i++) {
96                    url = _addParameter(url, name, value[i]);
97                }
98                return url;
99            }
100            var separator = url.indexOf("?") === -1 ? "?" : "&";
101            var hashIdx = url.indexOf("#");
102            if (hashIdx < 0) {
103                return url + separator + encodeURIComponent(name) + "=" + encodeURIComponent(value);
104            } else {
105                var hash = url.substring(hashIdx);
106                url = url.substring(0, hashIdx);
107                return url + separator + encodeURIComponent(name) + "=" + encodeURIComponent(value) + hash;
108            }
109        }
110
111        /**
112         * Returns the value of the parameter with the specified name
113         * in the URL. Only the first value will be considered.
114         * Values will be URL-decoded.
115         * @static
116         * @param {String} url The URL
117         * @param {String} name The name of the parameter
118         * @return {String} The value
119         */
120        function _getParameter(url, name) {
121            var params = _getParameters(url, name);
122            return params != null ? params[0] : null;
123        }
124
125        /**
126         * Returns the values of the parameters with the specified name
127         * in the URL. Values will be URL-decoded.
128         * @static
129         * @param {String} url The URL
130         * @param {String} name The name of the parameter
131         * @return {String[]} The values
132         */
133        function _getParameters(url, name) {
134            var values = [];
135            var queryIdx = url.indexOf("?");
136            var hashIdx = url.indexOf("#");
137            if (!name || queryIdx === -1) {
138                return null;
139            }
140            name = encodeURIComponent(name);
141            if (hashIdx !== -1) {
142                url = url.substring(0, hashIdx);
143            }
144            var query = url.substring(queryIdx + 1);
145            if (query.indexOf(name) === -1) {
146                return null;
147            }
148            var queryPts = query.split("&");
149            for (var i = 0; i < queryPts.length; i++) {
150                var paramPts = queryPts[i].split("=");
151                if (paramPts[0] === name) {
152                    values.push(paramPts.length > 1 ? decodeURIComponent(paramPts[1]) : "");
153                }
154            }
155            return values.length > 0 ? values : null;
156        }
157
158        /**
159         * Makes sure the specified relative URL starts with the context path
160         * used on the server. If an absolute URL is passed, it will be returned
161         * as-is.
162         * @static
163         * @param {String} url The URL
164         * @return {String} The externalized URL
165         */
166        function _externalize(url) {
167            try {
168                if (url.indexOf("/") === 0 && _contextPath && url.indexOf(_contextPath + "/") !== 0) {
169                    url = _contextPath + url;
170                }
171            } catch (e) {
172            }
173            return url;
174        }
175
176        /**
177         * Requests the specified URL from the server using GET. The request
178         * will be synchronous.
179         * 
180         * @param url {String}
181         *                url The URL to request
182         * @return {Mixed} The response object or, if the request is
183         *         asynchronous, the transaction ID
184         */
185        function _get(url) {
186            try {
187                var request = $.ajax({
188                    type: "GET",
189                    url: _externalize(url),
190                    async: false,
191                    externalize: false,
192                    encodePath: false,
193                    hook: false
194                });
195
196                if (!request) return null;
197
198                return request;
199            } catch (e) {
200                return null;
201            }
202        }
203
204        /**
205         * Appends the default ambit to the specified {@code path}.
206         * The function assumes the brand on the 3rd segment of the path
207         * (i.e /content/campaigns/brand).
208         *
209         * @param {String} path Resource path
210         */
211        function _appendAmbitSegment(path) {
212            return path.replace(/(\/content\/campaigns\/.*?)\/(.*)/, "$1/master/$2");
213        }
214
215        function _isAuthorEditor() {
216            var topPath = CQ.shared.HTTP.getPath(top.document.location.href);
217            //support for IE11
218            var userAgent = navigator ? navigator.userAgent.toLowerCase() : "other";
219            if (userAgent.indexOf('trident/') > 0) {
220                var rv = userAgent.indexOf('rv:');
221                if(parseInt(userAgent.substring(rv + 3, userAgent.indexOf('.', rv)), 10) == '11')
222                    return topPath.indexOf("/editor.html/") > -1;
223            }
224            return topPath.includes("/editor.html/");
225        }
226
227        function _addModeParameter(path) {
228            // if possible, force WCM mode as disabled to prevent edit decorations from being applied
229            var wcmmode = CQ.shared.HTTP.getParameter(document.location.href, 'wcmmode');
230            if (_isAuthorEditor()) {
231                wcmmode = "disabled";
232            }
233            if (wcmmode && wcmmode.length > 0) {
234                path = CQ.shared.HTTP.addParameter(path, 'wcmmode', wcmmode);
235            }
236            return path;
237        }
238
239        function _pullContent(path, mboxName) {
240
241            path = _addModeParameter(path);
242
243            var proxyUrl = window.targetGlobalSettings.currentPagePath + ".targetoffer.html" + path;
244
245            // pull in the content
246            var response = _get(proxyUrl);
247            var isOk = (response && response.status && response.status === 200);
248            var hasBody = (response && response.responseText && response.responseText.length > 0);
249
250            var _mboxId = 0;
251            if (isOk && hasBody) {
252                var target = document.getElementById(mboxName);
253                var outputWritten = false;
254                // if a target is found, process
255                if (target) {
256                    // empty the target div first.
257                    while (target.firstChild) {
258                        target.removeChild(target.firstChild);
259                    }
260
261                    // look for the wrapper div which tracks clicks
262                    var childDivs = target.getElementsByTagName('div');
263                    if (childDivs.length === 1) {
264                        target = childDivs[0];
265                    }
266
267                    var scriptwrapper = document.createElement('div');
268                    scriptwrapper.innerHTML = response.responseText;
269                    target.appendChild(scriptwrapper);
270                    var scripts = target.getElementsByTagName('script');
271                    for (var i = 0; i < scripts.length; i++) {
272                        eval(scripts[i].text);
273                    }
274
275                    outputWritten = true;
276
277                    var parentElement = target.parentElement;
278                    if (parentElement) {
279                        var event = document.createEvent("CustomEvent");
280                        event.initEvent("target-dom-loaded", true, false);
281                        event.mboxName = mboxName;
282                        parentElement.dispatchEvent(event);
283                    }
284                }
285
286                // CQ-15679 - fallback in case we don't find a target div
287                if (!outputWritten) {
288                    document.write(response.responseText);
289                }
290            }
291        }
292
293        function _callMboxUpdate() {
294            for (var i = 0; i < ns.mboxes.length; i++) {
295                var updateArgs = {};
296
297                if (Array.isArray(ns.mboxes[i].staticParameters)) {
298                    ns.mboxes[i].staticParameters.map(function(val,idx){
299                        var parts = val.split("=");
300                        if (parts.length === 2) {
301                            updateArgs[parts[0]] = parts[1];
302                        }
303                    });
304                }
305
306                for (var j = 0; j < CQ_Analytics.mboxes[i].mappings.length; j++) {
307                    var profileprefix = "";
308                    var param = CQ_Analytics.mboxes[i].mappings[j].param;
309                    var keypath = '/' + ns.mboxes[i].mappings[j].ccKey.replace('.', '/');
310                    if (ns.mboxes[i].isProfile.indexOf(param) > -1) {
311                        /* we should always apply the prefix, to prevent parameter name collisions */
312                        /*if (!param.match(/^profile\..*$/)) {*/
313                        profileprefix = "profile.";
314                        /*}*/
315                    }
316                    var paramValue =  ns.DataProvider.replaceVariables(_getContextVariable(keypath));
317                    updateArgs[profileprefix + param] = typeof paramValue !== "undefined" ? paramValue : "";
318                }
319
320                if (ns.mboxes[i].includeResolvedSegments && ns.SegmentMgr) {
321                    var resolvedSegments = ns.SegmentMgr.getResolved();
322                    if (resolvedSegments.length > 0) {
323                        updateArgs["profile._cq_.resolvedSegments"] = "|" + ns.SegmentMgr.getResolved().join("|") + ("|");
324                    }
325                }
326
327                /* space out the first call, which is probably the global mbox, by 100 ms,
328                 * to give T&T time to process the profile and use it in the next update calls
329                 */
330                (function (mboxName, args) {
331                    setTimeout(function () {
332                        CQ_Analytics.TestTarget.updateMboxContent(mboxName, args)
333                    }, (i > 0 ? 100 : 0));
334                })(ns.mboxes[i].name, updateArgs);
335            }
336        }
337
338        function _addMappings(mappingsJsonArray) {
339            for (var idx = 0; idx < mappingsJsonArray.length; idx++) {
340                var mapKey = mappingsJsonArray[idx]["ccKey"];
341                if (!instance.mappings[mapKey]) {
342                    instance.mappings[mapKey] = {};
343                }
344            }
345        }
346
347        /**
348         * Leverages both ClientContext and ContextHub to fetch the value of a variable
349         * @param keypath
350         */
351        function _getContextVariable(keypath) {
352            var value        = undefined,
353                contextValue = undefined;
354            if (window.ContextHub) {
355                contextValue = ContextHub.get(keypath);
356            } else {
357                contextValue = ns.ClientContext.get(keypath);
358            }
359            if (contextValue) {
360                if (Array.isArray(contextValue)) {
361                    value = contextValue.join(",");
362                } else if (typeof contextValue !== "object") {
363                    value = contextValue;
364                }
365            }
366            return value;
367        }
368
369        /* Returns an Array of property names used in
370        * CQ_Analytics.mboxes mappings. Returns empty Array if none
371        * found.
372        */
373        function _getMappedProperties() {
374            var properties = [];
375            if (window.CQ_Analytics
376                && window.CQ_Analytics.TestTarget
377                && window.CQ_Analytics.TestTarget.mappings) {
378                for (var mappedProp in window.CQ_Analytics.TestTarget.mappings) {
379                    properties.push(mappedProp);
380                }
381            }
382            return properties;
383        }
384
385        /**
386         * Returns true if the mbox calls are to me made in simulation mode ( WCM preview and edit modes )
387         */
388        function _isInSimulationMode() {
389            var layerName = _getAuthorLayerName();
390             return _isEdit(layerName) || _isPreview(layerName) || _isSimulation();
391        }
392
393        function _isSimulation() {
394            // use CQ.WCM when available
395            if (typeof CQ !== "undefined") {
396                if (CQ.WCM && CQ.utils && CQ.utils.WCM) {
397                    return CQ.WCM.isPreviewMode() || CQ.utils.WCM.isEditMode();
398                }
399            }
400            // fallback to reading the cookies directly
401            var $COOKIE = (document.cookie || '').split(/;\s*/).reduce(function(re, c) {
402                var tmp = c.match(/([^=]+)=(.*)/);
403                if (tmp) re[tmp[1]] = unescape(tmp[2]);
404                return re;
405            }, {});
406            return (typeof $COOKIE["wcmmode"] === "undefined"
407                || $COOKIE["wcmmode"] === "preview"
408                || $COOKIE["wcmmode"] === "edit");
409        }
410
411        function _getAuthorLayerName() {
412            var layer = document.querySelector('[class*="aem-AuthorLayer"]');
413            return layer ? layer.className.match("aem-AuthorLayer-[^ ]+")[0] : null;
414        }
415
416        function _isPreview(layerName) {
417            return layerName === "aem-AuthorLayer-Preview";
418        }
419
420        function _isEdit(layerName) {
421            return layerName === "aem-AuthorLayer-Edit";
422        }
423
424        /**
425         * Forces an mbox update if either of CQ.WCM.isPreviewMode() or CQ.utils.WCM.isEditMode() is true.
426         */
427        function _forceMboxUpdate() {
428            if (_isInSimulationMode()) {
429                _callMboxUpdate();
430            }
431        }
432
433        /* --- END PRIVATE AREA -- */
434
435        /* --- BEGIN PUBLIC AREA -- */
436
437        instance.registeredCHListeners = {};
438
439        instance.usedStoresLoaded = false;
440
441        instance.defaults = {};
442
443        instance.mappings = [];
444
445        instance.maxProfileParams = 200;
446
447        /**
448         * Fetches the resource from provided path and writes the
449         * response to the document or the mbox Element if
450         *
451         * <ul>
452         * <li>response status code is 200</li>
453         * <li>response has a body with length > 0</li>
454         * </ul>
455         *
456         * Uses a synchronous call for requesting the resource. If a WCM mode is defined this
457         * call forces the resource to be rendered with WCM mode disabled.
458         *
459         * @static
460         * @param {String} path Path to document/node to request.
461         * @param {String} mboxName The name of the mbox that issued the request
462         * @param {String} version API version indicator
463         */
464        instance.pull = function (path, mboxName, version) {
465
466            // if version parameter omitted, assume path without ambit segment
467            if (typeof version === 'undefined') {
468                path = _appendAmbitSegment(path);
469            }
470
471            _pullContent(path, mboxName);
472        };
473
474        instance.displayOffer = function(mboxName, params) {
475            adobe.target.getOffer({
476                "mbox": mboxName,
477                "params": params,
478                "success": function (response) {
479                    adobe.target.applyOffer({
480                        "mbox": mboxName,
481                        "selector": "#" + mboxName,
482                        "offer": response
483                    })
484                },
485                "error": function (status, response) {
486                    console.error(status, response);
487                    $('#' + mboxName).css('visibility', 'visible');
488                }
489            });
490        };
491
492        /**
493         * Updates the content of an mbox with the offer from Adobe Target
494         * @param mboxName the name of the mbox
495         * @param params the call parameters passed as a JS object - {paramName: paramValue}
496         */
497        instance.updateMboxContent = function(mboxName, params) {
498            _debug("Updating content for mbox " + mboxName);
499
500            if (_isAuthorEditor()) {
501                // wait for the Author layers to render so we can accurately determine the mode we are in
502                var layerName = _getAuthorLayerName();
503                if (layerName) {
504                    _isEdit(layerName) ? instance.signalDefaultOffer(mboxName) : instance.displayOffer(mboxName, params);
505                } else {
506                    setTimeout(function(){instance.updateMboxContent(mboxName, params);}, 100);
507                }
508            } else {
509                instance.displayOffer(mboxName, params);
510            }
511        }
512
513        instance.registerMboxUpdateCalls = function () {
514            if (typeof window.CQ_Analytics !== "undefined"
515                && window.CQ_Analytics.TestTarget.mappings) {
516                _debug("[Target][init] Registering Mbox update calls");
517                var mappedProperties = _getMappedProperties();
518
519                if (mappedProperties.length > 0) {
520                    instance.registerContextHubListeners();
521                } else {
522                    _callMboxUpdate();
523                }
524            }
525        };
526
527        instance.registerContextHubListeners = function () {
528            if (!window.ContextHub) {
529                return;
530            }
531
532            var mappedProperties = _getMappedProperties();
533            var listenKeys = [];
534
535            for (var mappingIdx = 0; mappingIdx < mappedProperties.length; mappingIdx++) {
536                var mappedProperty = mappedProperties[mappingIdx];
537                var storeName = mappedProperty.split(".")[0];
538                var listenKey = "/" + mappedProperty.replace(".", "/");
539
540                // check if store is in CH
541                var contextHubStore = ContextHub.get(storeName);
542
543                if (contextHubStore
544                    && !instance.registeredCHListeners[storeName]) {
545                    instance.registeredCHListeners[storeName] = true;
546                    listenKeys.push(listenKey);
547
548                    _debug("[Target][CH] - Listening for updates on " + listenKey + " CH");
549                }
550            }
551
552            if (listenKeys.length > 0) {
553                // bind to context hub to listen for property updates
554                ContextHub.bind(listenKeys,
555                    function successHandler(data) {
556                        _debug("[Target][CH][registerContextHubListeners] All properties available, triggering update!");
557                        _callMboxUpdate();
558                        instance.usedStoresLoaded = true;
559                    },
560                    function defaultHandler(data) {
561                        _debug("[Target][CH][registerContextHubListeners] Not all properties available, triggering update!");
562                        if (!instance.usedStoresLoaded) {
563                            _callMboxUpdate();
564                        }
565                    }, 500);
566            }
567        };
568
569        /**
570         * Adds a new mboxDefinition to the CQ_Analytics.mboxes array
571         *
572         * <p>Removes any mbox definition with the same mbox id prior to adding the passed
573         * mboxDefinition.</p>
574         *
575         * @return {Boolean} true if an mbox was replaced, false otherwise
576         */
577        instance.addMbox = function (mboxDefinition) {
578            var replaced = false,
579                alreadyDefined = false;
580
581            if (!CQ_Analytics.mboxes) {
582                CQ_Analytics.mboxes = [];
583            }
584            for (var i = 0; i < CQ_Analytics.mboxes.length; i++) {
585
586                var mbox = CQ_Analytics.mboxes[i];
587                //  cleanup existing mbox
588                if (mbox.id === mboxDefinition.id) {
589                    CQ_Analytics.mboxes.splice(i, 1);
590                    replaced = true;
591                    alreadyDefined = mbox.defined;
592                    break;
593                }
594            }
595            mboxDefinition.defined = alreadyDefined;
596            ns.mboxes.push(mboxDefinition);
597
598            _addMappings(mboxDefinition.mappings);
599
600            return replaced;
601        };
602
603        /**
604         * Triggers an update of all the registered mboxes
605         *
606         * <p>Delays the update requests based on the <tt>delay</tt> parameter so that multiple update requests
607         * are clumped together.</p>
608         *
609         * @param delay {Integer} the delay in milliseconds to apply to the reload, defaults to 500
610         */
611        instance.triggerUpdate = function (delay) {
612
613            if (typeof delay === "undefined")
614                delay = 500;
615
616            if (!instance.reloadRequested) {
617                instance.reloadRequested = true;
618                setTimeout(function () {
619                    _forceMboxUpdate();
620                    instance.reloadRequested = false;
621                }, delay);
622            }
623        };
624
625        /**
626         * Signals that the default offer was received from Target.
627         * This function is called by the Target offer itself.
628         * @param mboxName
629         */
630        instance.signalDefaultOffer = function(mboxName) {
631            if (typeof instance.defaults[mboxName] === 'undefined') {
632                if (console) { console.log("The default offer path was not found in the internal map for mbox " + mboxName)}
633                return;
634            }
635
636            var defaultContentPath = instance.defaults[mboxName];
637
638            _pullContent(defaultContentPath, mboxName);
639            $('#'+mboxName).css('visibility', 'visible');
640        };
641
642
643        return instance;
644    };
645
646    ns.TestTarget = atjsIntegrator($, ns);
647
648    // register for mode change event so we can switch to default content in EDIT mode
649    top.$(top.document).on("editor-frame-mode-changed", function() {
650        // This may be called while the page is refreshed so we need to check if we have a valid CQ_Analytics.TestTarget
651        if (CQ_Analytics && CQ_Analytics.TestTarget)
652            CQ_Analytics.TestTarget.triggerUpdate();
653});
654
655})($, window.CQ_Analytics);

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.