PageSourceSearch

https://www.jojomamanbebe.com/scripts/bundles/platmodheadercommon_…P-MH1oDtG4Ne3g7rsdO947_JJNM1?v=2026.916.2.1

js jojomamanbebe.com collected 2026-09-30 06:04:59 UTC 572,256 bytes, 12,934 lines download raw bytes

1/* MinifyError
2(11247,15-16): run-time error JS1010: Expected identifier: .
3(11247,15-16): run-time error JS1195: Expected expression: .
4(11935,15-16): run-time error JS1010: Expected identifier: [
5 */
6/*
7 * Author: James Bhatt
8 * Date: 2019-11-15
9 * Description: Collection of formatters for prices.
10 * Changes:
11 *
12 * Notes:
13 *
14 * Version: 0.1
15 */
16var PriceFormatters = /** @class */ (function () {
17    function PriceFormatters(currencyPosition, currencySymbol) {
18        this.defaultCurrencySymbol = "";
19        this.defaultCurrencyPosition = "left";
20        this.LEFT_WITH_SPACE = "leftwithspace";
21        this.LEFT = "left";
22        this.RIGHT_WITH_SPACE = "rightwithspace";
23        this.RIGHT = "right";
24        this.defaultCurrencyPosition = currencyPosition || "left";
25        this.defaultCurrencySymbol = currencySymbol || "";
26        this.defaultFormatter = this.getCurrencyFormatter(currencyPosition, currencySymbol);
27    }
28    PriceFormatters.prototype.getCurrencyFormatter = function (currencyPosition, currencySymbol) {
29        if (!currencyPosition || currencyPosition == "") {
30            currencyPosition = this.defaultCurrencyPosition;
31        }
32        if (!currencySymbol || currencySymbol == "") {
33            currencySymbol = this.defaultCurrencySymbol;
34        }
35        switch (currencyPosition) {
36            case this.LEFT_WITH_SPACE: {
37                return function (value) {
38                    return [currencySymbol, value.trim()].join(" ");
39                };
40            }
41            case this.RIGHT_WITH_SPACE: {
42                return function (value) {
43                    return [value.trim(), currencySymbol].join(" ");
44                };
45            }
46            case this.LEFT: {
47                return function (value) {
48                    return [currencySymbol, value.trim()].join("");
49                };
50            }
51            case this.RIGHT: {
52                return function (value) {
53                    return [value.trim(), currencySymbol].join("");
54                };
55            }
56        }
57        // Default to LEFT
58        return function (value) {
59            return [currencySymbol, value.trim()].join("");
60        };
61    };
62    PriceFormatters.prototype.formatPrice = function (price) {
63        return this.formatPriceWithFormatter(price, this.defaultFormatter);
64    };
65    PriceFormatters.prototype.formatPriceWithFormatter = function (price, formatter) {
66        if (!price || price.length == 0 || !formatter) {
67            return '';
68        }
69        return this.doFormat(price, formatter);
70    };
71    PriceFormatters.prototype.formatPriceWithSymbol = function (price, currencyPosition, currencySymbol) {
72        if (!price || price.length == 0) {
73            return '';
74        }
75        var formatter = this.getCurrencyFormatter(currencyPosition, currencySymbol);
76        return this.doFormat(price, formatter);
77    };
78    PriceFormatters.prototype.removeMultiplePriceSymbols = function (priceWithCurrency, currencyPosition, symbolToRemove) {
79        //quickly bail if not a price range
80        if (priceWithCurrency.indexOf("-") == -1) {
81            return priceWithCurrency;
82        }
83        var result = priceWithCurrency;
84        var regex = new RegExp(symbolToRemove, "g");
85        var occurrences = (priceWithCurrency.match(regex) || []).length;
86        if (occurrences > 1) {
87            if (currencyPosition.indexOf(this.RIGHT) > -1) {
88                if (currencyPosition == this.RIGHT_WITH_SPACE) {
89                    symbolToRemove = " " + symbolToRemove;
90                }
91                var firstIndex = priceWithCurrency.indexOf(symbolToRemove);
92                result = priceWithCurrency.substring(0, firstIndex - 1) + priceWithCurrency.substring(firstIndex + symbolToRemove.length);
93            }
94            else if (currencyPosition.indexOf(this.LEFT) > -1) {
95                if (currencyPosition == this.LEFT_WITH_SPACE) {
96                    symbolToRemove = symbolToRemove + " ";
97                }
98                var lastIndex = priceWithCurrency.lastIndexOf(symbolToRemove);
99                result = priceWithCurrency.substring(0, lastIndex) + priceWithCurrency.substring(lastIndex + symbolToRemove.length);
100            }
101        }
102        return result;
103    };
104    PriceFormatters.prototype.doFormat = function (price, formatter) {
105        var split = price.split('-');
106        var result = '';
107        for (var idx = 0; idx < split.length; idx++) {
108            //add a dash if there's more than 1 item in the array
109            if (idx > 0) {
110                result += ' - ';
111            }
112            result += formatter(split[idx]);
113        } //end each
114        return result;
115    };
116    return PriceFormatters;
117}());
118//# sourceMappingURL=Pricing.js.map;
119var ModularPDPHelper;
120(function (ModularPDPHelper) {
121    //URL Related
122    var PROTOCOL = window.location.protocol;
123    var HOST = window.location.host;
124    var PATH_NAME = window.location.pathname;
125    var HREF = window.location.href;
126    var URL_ORIGIN = PROTOCOL + "//" + Next.Settings.Channel.SiteUrl.split("//")[1];
127    var URL_PATH_NAME = getUrlPathName();
128    var URL_SEGMENTS = URL_PATH_NAME.split('/');
129    var URL_SEGMENTS_COUNT = URL_SEGMENTS.length;
130    var HASH = window.location.hash;
131    var IS_REFERRER_SPREAD = HASH.indexOf("/referrer=spread") >= 0;
132    var UrlSegments = /** @class */ (function () {
133        function UrlSegments() {
134        }
135        return UrlSegments;
136    }());
137    ModularPDPHelper.UrlSegments = UrlSegments;
138    function isUrlInOldFormat() {
139        //Detect PDP URL in old format (Eg: /style/st211319#548308 or /g8316s12#649138)
140        //Style and shot old URLs with spread page checks
141        return (URL_PATH_NAME.indexOf("style/") >= 0 && URL_SEGMENTS_COUNT == 3 && HASH && !IS_REFERRER_SPREAD) || (URL_SEGMENTS_COUNT == 2 && HASH && !IS_REFERRER_SPREAD)
142            ? true
143            : false;
144    }
145    ModularPDPHelper.isUrlInOldFormat = isUrlInOldFormat;
146    function isUrlInNewFormat() {
147        return (URL_PATH_NAME.indexOf("style/") >= 0 && URL_SEGMENTS_COUNT == 4) || (URL_PATH_NAME.indexOf("style/") < 0 && URL_SEGMENTS_COUNT == 3)
148            ? true
149            : false;
150    }
151    ModularPDPHelper.isUrlInNewFormat = isUrlInNewFormat;
152    function getNewUrlWithoutHash(urlCheckArguments) {
153        var itemNumber = urlCheckArguments.itemNumber || getItemNumber();
154        itemNumber = getItemNumberWithoutDash(itemNumber);
155        var urlWithoutHash = HREF.substring(0, HREF.indexOf("#"));
156        //New url
157        var newUrl = urlWithoutHash + "/" + itemNumber;
158        if (!urlCheckArguments.includeOrigin) {
159            newUrl = newUrl.replace(URL_ORIGIN, "");
160        }
161        if (!urlCheckArguments.includeStyle) {
162            newUrl = newUrl.replace("/style", "");
163        }
164        if (urlCheckArguments.replaceLastSegment) {
165            var url = URL_PATH_NAME.replace("/style", "");
166            var urlPathSegments = getSegmentOptions(url);
167            urlPathSegments.segments[urlPathSegments.segmentsCount - 1] = itemNumber;
168            newUrl = urlPathSegments.segments.join('/');
169        }
170        return newUrl;
171    }
172    ModularPDPHelper.getNewUrlWithoutHash = getNewUrlWithoutHash;
173    function getNewUrlPathName(url, itemNumber) {
174        var urlPathSegments = getSegmentOptions(url);
175        urlPathSegments.segments[urlPathSegments.segmentsCount] = itemNumber;
176        return urlPathSegments.segments.join('/');
177    }
178    ModularPDPHelper.getNewUrlPathName = getNewUrlPathName;
179    function getNewUrlWithHash(newHash) {
180        var newUrl = "", index = 0;
181        var formattedHash = newHash;
182        if (newHash.indexOf("/") >= 0) {
183            formattedHash = newHash.substring(0, newHash.indexOf("/"));
184        }
185        //New url format
186        if (isUrlPathNameInNewFormat()) {
187            index = URL_SEGMENTS_COUNT - 1;
188        }
189        //Old url format
190        else if (isUrlPathNameInOldFormat()) {
191            index = URL_SEGMENTS_COUNT;
192        }
193        URL_SEGMENTS[index] = formattedHash.replace("#", "");
194        newUrl = URL_SEGMENTS.join("/") + newHash;
195        return newUrl;
196    }
197    ModularPDPHelper.getNewUrlWithHash = getNewUrlWithHash;
198    function updateUrlProperties(isShortUrl, firstSegment, secondSegment) {
199        URL_SEGMENTS = [];
200        if (isShortUrl) {
201            URL_SEGMENTS[1] = firstSegment;
202            URL_SEGMENTS[2] = secondSegment;
203            PATH_NAME = "/" + firstSegment + "/" + secondSegment;
204        }
205        else {
206            URL_SEGMENTS[1] = "style";
207            URL_SEGMENTS[2] = firstSegment;
208            URL_SEGMENTS[3] = secondSegment;
209            PATH_NAME = "/style/" + firstSegment + "/" + secondSegment;
210        }
211        URL_SEGMENTS_COUNT = URL_SEGMENTS.length;
212        URL_PATH_NAME = PATH_NAME;
213    }
214    ModularPDPHelper.updateUrlProperties = updateUrlProperties;
215    function isUrlPathNameInNewFormat(pathName, urlSegmentsCount) {
216        var pathName = pathName || URL_PATH_NAME;
217        var urlSegmentsCount = urlSegmentsCount || URL_SEGMENTS_COUNT;
218        return (pathName.indexOf("style/") >= 0 && urlSegmentsCount == 4) || (pathName.indexOf("style/") < 0 && urlSegmentsCount == 3);
219    }
220    ModularPDPHelper.isUrlPathNameInNewFormat = isUrlPathNameInNewFormat;
221    function isUrlPathNameInOldFormat(pathName, urlSegmentsCount) {
222        var pathName = pathName || URL_PATH_NAME;
223        var urlSegmentsCount = urlSegmentsCount || URL_SEGMENTS_COUNT;
224        return (pathName.indexOf("style/") >= 0 && urlSegmentsCount == 3) || (pathName.indexOf("style/") < 0 && urlSegmentsCount == 2);
225    }
226    ModularPDPHelper.isUrlPathNameInOldFormat = isUrlPathNameInOldFormat;
227    function checkAndAddSlashBeforeUrl(url) {
228        return url.indexOf('/') != 0 ? '/' + url : url;
229    }
230    ModularPDPHelper.checkAndAddSlashBeforeUrl = checkAndAddSlashBeforeUrl;
231    function getItemNumber() {
232        var itemNumber = HASH.replace("#", "");
233        if (itemNumber.indexOf("/") >= 0) {
234            itemNumber = itemNumber.substring(0, itemNumber.indexOf("/"));
235        }
236        return itemNumber;
237    }
238    ModularPDPHelper.getItemNumber = getItemNumber;
239    function getItemNumberWithoutDash(itemNumber) {
240        return itemNumber.replace(/-/g, "");
241    }
242    ModularPDPHelper.getItemNumberWithoutDash = getItemNumberWithoutDash;
243    function getSegmentOptions(pathName) {
244        var urlSegments = pathName.split('/');
245        var segments = new UrlSegments();
246        segments.segments = urlSegments;
247        segments.segmentsCount = urlSegments.length;
248        return segments;
249    }
250    ModularPDPHelper.getSegmentOptions = getSegmentOptions;
251    function getUrlPathName() {
252        var urlWithoutHash = PROTOCOL + "//" + HOST + PATH_NAME;
253        return urlWithoutHash.replace(URL_ORIGIN, "");
254    }
255    ModularPDPHelper.getUrlPathName = getUrlPathName;
256    function transformShotJsonShortenedNames(shot) {
257        if (shot.Media !== null && shot.Media !== undefined) {
258            shot.Media = mapMediaItems(shot.Media);
259        }
260        if (shot.Styles !== null && shot.Styles !== undefined) {
261            shot.Styles.forEach(function (style) {
262                if (style.Fits !== null && style.Fits !== undefined) {
263                    style.Fits.forEach(function (fit) {
264                        if (fit.Items !== null && fit.Items !== undefined) {
265                            fit.Items.forEach(function (item) {
266                                if (item.Media !== null && item.Media !== undefined) {
267                                    item.Media = mapMediaItems(item.Media);
268                                }
269                                if (item.Options !== null && item.Options !== undefined) {
270                                    item.Options = mapOptions(item.Options);
271                                }
272                            });
273                        }
274                    });
275                }
276            });
277        }
278    }
279    ModularPDPHelper.transformShotJsonShortenedNames = transformShotJsonShortenedNames;
280    function mapOptions(options) {
281        options = options.map(function (_a) {
282            var Number = _a.Nmb, Name = _a.Nm, StockStatus = _a.SSt, Price = _a.Prc, SplitSizes = _a.SplSz, FitSizes = _a.FitSz, MarkdownType = _a.MdT, SizeType = _a.SzTyp;
283            return ({
284                Number: Number,
285                Name: Name,
286                StockStatus: StockStatus,
287                Price: Price,
288                SplitSizes: SplitSizes,
289                FitSizes: FitSizes,
290                MarkdownType: MarkdownType,
291                SizeType: SizeType
292            });
293        });
294        return options;
295    }
296    function mapMediaItems(mediaItems) {
297        mediaItems = mediaItems.map(function (_a) {
298            var name = _a.nm, level = _a.lvl, imageType = _a.imgTyp, shotType = _a.shTyp, webType = _a.wbTyp, outlet = _a.outl, pageNo = _a.pgNo, id = _a.id, alsoItemLevel = _a.alLvl;
299            return ({
300                name: name,
301                level: level,
302                imageType: imageType,
303                shotType: shotType,
304                webType: webType,
305                outlet: outlet,
306                pageNo: pageNo,
307                id: id,
308                alsoItemLevel: alsoItemLevel
309            });
310        });
311        return mediaItems;
312    }
313})(ModularPDPHelper || (ModularPDPHelper = {}));
314//# sourceMappingURL=modularpdphelper.js.map;
315/*!
316 * @overview es6-promise - a tiny implementation of Promises/A+.
317 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
318 * @license   Licensed under MIT license
319 *            See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE
320 * @version   3.0.2
321 */
322
323(function(){"use strict";function lib$es6$promise$utils$$objectOrFunction(x){return typeof x==="function"||typeof x==="object"&&x!==null}function lib$es6$promise$utils$$isFunction(x){return typeof x==="function"}function lib$es6$promise$utils$$isMaybeThenable(x){return typeof x==="object"&&x!==null}var lib$es6$promise$utils$$_isArray;if(!Array.isArray){lib$es6$promise$utils$$_isArray=function(x){return Object.prototype.toString.call(x)==="[object Array]"}}else{lib$es6$promise$utils$$_isArray=Array.isArray}var lib$es6$promise$utils$$isArray=lib$es6$promise$utils$$_isArray;var lib$es6$promise$asap$$len=0;var lib$es6$promise$asap$$toString={}.toString;var lib$es6$promise$asap$$vertxNext;var lib$es6$promise$asap$$customSchedulerFn;var lib$es6$promise$asap$$asap=function asap(callback,arg){lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len]=callback;lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len+1]=arg;lib$es6$promise$asap$$len+=2;if(lib$es6$promise$asap$$len===2){if(lib$es6$promise$asap$$customSchedulerFn){lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush)}else{lib$es6$promise$asap$$scheduleFlush()}}};function lib$es6$promise$asap$$setScheduler(scheduleFn){lib$es6$promise$asap$$customSchedulerFn=scheduleFn}function lib$es6$promise$asap$$setAsap(asapFn){lib$es6$promise$asap$$asap=asapFn}var lib$es6$promise$asap$$browserWindow=typeof window!=="undefined"?window:undefined;var lib$es6$promise$asap$$browserGlobal=lib$es6$promise$asap$$browserWindow||{};var lib$es6$promise$asap$$BrowserMutationObserver=lib$es6$promise$asap$$browserGlobal.MutationObserver||lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver;var lib$es6$promise$asap$$isNode=typeof process!=="undefined"&&{}.toString.call(process)==="[object process]";var lib$es6$promise$asap$$isWorker=typeof Uint8ClampedArray!=="undefined"&&typeof importScripts!=="undefined"&&typeof MessageChannel!=="undefined";function lib$es6$promise$asap$$useNextTick(){return function(){process.nextTick(lib$es6$promise$asap$$flush)}}function lib$es6$promise$asap$$useVertxTimer(){return function(){lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush)}}function lib$es6$promise$asap$$useMutationObserver(){var iterations=0;var observer=new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush);var node=document.createTextNode("");observer.observe(node,{characterData:true});return function(){node.data=iterations=++iterations%2}}function lib$es6$promise$asap$$useMessageChannel(){var channel=new MessageChannel;channel.port1.onmessage=lib$es6$promise$asap$$flush;return function(){channel.port2.postMessage(0)}}function lib$es6$promise$asap$$useSetTimeout(){return function(){setTimeout(lib$es6$promise$asap$$flush,1)}}var lib$es6$promise$asap$$queue=new Array(1e3);function lib$es6$promise$asap$$flush(){for(var i=0;i<lib$es6$promise$asap$$len;i+=2){var callback=lib$es6$promise$asap$$queue[i];var arg=lib$es6$promise$asap$$queue[i+1];callback(arg);lib$es6$promise$asap$$queue[i]=undefined;lib$es6$promise$asap$$queue[i+1]=undefined}lib$es6$promise$asap$$len=0}function lib$es6$promise$asap$$attemptVertx(){try{var r=require;var vertx=r("vertx");lib$es6$promise$asap$$vertxNext=vertx.runOnLoop||vertx.runOnContext;return lib$es6$promise$asap$$useVertxTimer()}catch(e){return lib$es6$promise$asap$$useSetTimeout()}}var lib$es6$promise$asap$$scheduleFlush;if(lib$es6$promise$asap$$isNode){lib$es6$promise$asap$$scheduleFlush=lib$es6$promise$asap$$useNextTick()}else if(lib$es6$promise$asap$$BrowserMutationObserver){lib$es6$promise$asap$$scheduleFlush=lib$es6$promise$asap$$useMutationObserver()}else if(lib$es6$promise$asap$$isWorker){lib$es6$promise$asap$$scheduleFlush=lib$es6$promise$asap$$useMessageChannel()}else if(lib$es6$promise$asap$$browserWindow===undefined&&typeof require==="function"){lib$es6$promise$asap$$scheduleFlush=lib$es6$promise$asap$$attemptVertx()}else{lib$es6$promise$asap$$scheduleFlush=lib$es6$promise$asap$$useSetTimeout()}function lib$es6$promise$$internal$$noop(){}var lib$es6$promise$$internal$$PENDING=void 0;var lib$es6$promise$$internal$$FULFILLED=1;var lib$es6$promise$$internal$$REJECTED=2;var lib$es6$promise$$internal$$GET_THEN_ERROR=new lib$es6$promise$$internal$$ErrorObject;function lib$es6$promise$$internal$$selfFulfillment(){return new TypeError("You cannot resolve a promise with itself")}function lib$es6$promise$$internal$$cannotReturnOwn(){return new TypeError("A promises callback cannot return that same promise.")}function lib$es6$promise$$internal$$getThen(promise){try{return promise.then}catch(error){lib$es6$promise$$internal$$GET_THEN_ERROR.error=error;return lib$es6$promise$$internal$$GET_THEN_ERROR}}function lib$es6$promise$$internal$$tryThen(then,value,fulfillmentHandler,rejectionHandler){try{then.c
323all(value,fulfillmentHandler,rejectionHandler)}catch(e){return e}}function lib$es6$promise$$internal$$handleForeignThenable(promise,thenable,then){lib$es6$promise$asap$$asap(function(promise){var sealed=false;var error=lib$es6$promise$$internal$$tryThen(then,thenable,function(value){if(sealed){return}sealed=true;if(thenable!==value){lib$es6$promise$$internal$$resolve(promise,value)}else{lib$es6$promise$$internal$$fulfill(promise,value)}},function(reason){if(sealed){return}sealed=true;lib$es6$promise$$internal$$reject(promise,reason)},"Settle: "+(promise._label||" unknown promise"));if(!sealed&&error){sealed=true;lib$es6$promise$$internal$$reject(promise,error)}},promise)}function lib$es6$promise$$internal$$handleOwnThenable(promise,thenable){if(thenable._state===lib$es6$promise$$internal$$FULFILLED){lib$es6$promise$$internal$$fulfill(promise,thenable._result)}else if(thenable._state===lib$es6$promise$$internal$$REJECTED){lib$es6$promise$$internal$$reject(promise,thenable._result)}else{lib$es6$promise$$internal$$subscribe(thenable,undefined,function(value){lib$es6$promise$$internal$$resolve(promise,value)},function(reason){lib$es6$promise$$internal$$reject(promise,reason)})}}function lib$es6$promise$$internal$$handleMaybeThenable(promise,maybeThenable){if(maybeThenable.constructor===promise.constructor){lib$es6$promise$$internal$$handleOwnThenable(promise,maybeThenable)}else{var then=lib$es6$promise$$internal$$getThen(maybeThenable);if(then===lib$es6$promise$$internal$$GET_THEN_ERROR){lib$es6$promise$$internal$$reject(promise,lib$es6$promise$$internal$$GET_THEN_ERROR.error)}else if(then===undefined){lib$es6$promise$$internal$$fulfill(promise,maybeThenable)}else if(lib$es6$promise$utils$$isFunction(then)){lib$es6$promise$$internal$$handleForeignThenable(promise,maybeThenable,then)}else{lib$es6$promise$$internal$$fulfill(promise,maybeThenable)}}}function lib$es6$promise$$internal$$resolve(promise,value){if(promise===value){lib$es6$promise$$internal$$reject(promise,lib$es6$promise$$internal$$selfFulfillment())}else if(lib$es6$promise$utils$$objectOrFunction(value)){lib$es6$promise$$internal$$handleMaybeThenable(promise,value)}else{lib$es6$promise$$internal$$fulfill(promise,value)}}function lib$es6$promise$$internal$$publishRejection(promise){if(promise._onerror){promise._onerror
323(promise._result)}lib$es6$promise$$internal$$publish(promise)}function lib$es6$promise$$internal$$fulfill(promise,value){if(promise._state!==lib$es6$promise$$internal$$PENDING){return}promise._result=value;promise._state=lib$es6$promise$$internal$$FULFILLED;if(promise._subscribers.length!==0){lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish,promise)}}function lib$es6$promise$$internal$$reject(promise,reason){if(promise._state!==lib$es6$promise$$internal$$PENDING){return}promise._state=lib$es6$promise$$internal$$REJECTED;promise._result=reason;lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection,promise)}function lib$es6$promise$$internal$$subscribe(parent,child,onFulfillment,onRejection){var subscribers=parent._subscribers;var length=subscribers.length;parent._onerror=null;subscribers[length]=child;subscribers[length+lib$es6$promise$$internal$$FULFILLED]=onFulfillment;subscribers[length+lib$es6$promise$$internal$$REJECTED]=onRejection;if(length===0&&parent._state){lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish,parent)}}function lib$es6$promise$$internal$$publish(promise){var subscribers=promise._subscribers;var settled=promise._state;if(subscribers.length===0){return}var child,callback,detail=promise._result;for(var i=0;i<subscribers.length;i+=3){child=subscribers[i];callback=subscribers[i+settled];if(child){lib$es6$promise$$internal$$invokeCallback(settled,child,callback,detail)}else{callback(detail)}}promise._subscribers.length=0}function lib$es6$promise$$internal$$ErrorObject(){this.error=null}var lib$es6$promise$$internal$$TRY_CATCH_ERROR=new lib$es6$promise$$internal$$ErrorObject;function lib$es6$promise$$internal$$tryCatch(callback,detail){try{return callback(detail)}catch(e){lib$es6$promise$$internal$$TRY_CATCH_ERROR.error=e;return lib$es6$promise$$internal$$TRY_CATCH_ERROR}}function lib$es6$promise$$internal$$invokeCallback(settled,promise,callback,detail){var hasCallback=lib$es6$promise$utils$$isFunction(callback),value,error,succeeded,failed;if(hasCallback){value=lib$es6$promise$$internal$$tryCatch(callback,detail);if(value===lib$es6$promise$$internal$$TRY_CATCH_ERROR){failed=true;error=value.error;value=null}else{succeeded=true}if(promise===value){lib$es6$promise$$internal$$reject(promise,lib$es6$promise$$internal$$cannotReturnOwn());return}}else{value=detail;succeeded=true}if(promise._state!==lib$es6$promise$$internal$$PENDING){}else if(hasCallback&&succeeded){lib$es6$promise$$internal$$resolve(promise,value)}else if(failed){lib$es6$promise$$internal$$reject(promise,error)}else if(settled===lib$es6$promise$$internal$$FULFILLED){lib$es6$promise$$internal$$fulfill(promise,value)}else if(settled===lib$es6$promise$$internal$$REJECTED){lib$es6$promise$$internal$$reject(promise,value)}}function lib$es6$promise$$internal$$initializePromise(promise,resolver){try{resolver(function resolvePromise(value){lib$es6$promise$$internal$$resolve(promise,value)},function rejectPromise(reason){lib$es6$promise$$internal$$reject(promise,reason)})}catch(e){lib$es6$promise$$internal$$reject(promise,e)}}function lib$es6$promise$enumerator$$Enumerator(Constructor,input){var enumerator=this;enumerator._instanceConstructor=Constructor;enumerator.promise=new Constructor(lib$es6$promise$$internal$$noop);if(enumerator._validateInput(input)){enumerator._input=input;enumerator.length=input.length;enumerator._remaining=input.length;enumerator._init();if(enumerator.length===0){lib$es6$promise$$internal$$fulfill(enumerator.promise,enumerator._result)}else{enumerator.length=enumerator.length||0;enumerator._enumerate();if(enumerator._remaining===0){lib$es6$promise$$internal$$fulfill(enumerator.promise,enumerator._result)}}}else{lib$es6$promise$$internal$$reject(enumerator.promise,enumerator._validationError())}}lib$es6$promise$enumerator$$Enumerator.prototype._validateInput=function(input){return lib$es6$promise$utils$$isArray(input)};lib$es6$promise$enumerator$$Enumerator.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")};lib$es6$promise$enumerator$$Enumerator.prototype._init=function(){this._result=new Array(this.length)};var lib$es6$promise$enumerator$$default=lib$es6$promise$enumerator$$Enumerator;lib$es6$promise$enumerator$$Enumerator.prototype._enumerate=function(){var enumerator=this;var length=enumerator.length;var promise=enumerator.promise;var input=enumerator._input;for(var i=0;promise._state===lib$es6$promise$$internal$$PENDING&&i<length;i++){enumerator._eachEntry(input[i],i)}};lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry=function(entry,i){var enumerator=this;var c=enumerator._instanceConstructor;if(lib$es6$promise$utils$$isMaybeThenable(entry)){if(entry.constructor===c&&entry._state!==lib$es6$promise$$internal$$PENDING){entry._onerror=null;enumerator._settledAt(entry._state,i,entry._result)}else{enumerator._willSettleAt(c.resolve(entry),i)}}else{enumerator._remaining--;enumerator._result[i]=entry}};lib$es6$promise$enumerator$$Enumerator.prototype._settledAt=function(state,i,value){var enumerator=this;var promise=enumerator.promise;if(promise._state===lib$es6$promise$$internal$$PENDING){enumerator._remaining--;if(state===lib$es6$promise$$internal$$REJECTED){lib$es6$promise$$internal$$reject(promise,value)}else{enumerator._result[i]=value}}if(enumerator._remaining===0){lib$es6$promise$$internal$$fulfill(promise,enumerator._result)}};lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt=function(promise,i){var enumerator=this;lib$es6$promise$$internal$$subscribe(promise,undefined,function(value){enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED,i,value)},function(reason){enumerator._settledAt(lib$es6$promise$$internal$$REJECTED,i,reason)})};function lib$es6$promise$promise$all$$all(entries){return new lib$es6$promise$enumerator$$default(this,entries).promise}var lib$es6$promise$promise$all$$default=lib$es6$promise$promise$all$$all;function lib$es6$promise$promise$race$$race(entries){var Constructor=this;var promise=new Constructor(lib$es6$promise$$internal$$noop);if(!lib$es6$promise$utils$$isArray(entries)){lib$es6$promise$$internal$$reject(promise,new TypeError("You must pass an array to race."));return promise}var length=entries.length;function onFulfillment(value){lib$es6$promise$$internal$$resolve(promise,value)}function onRejection(reason){lib$es6$promise$$internal$$reject(promise,reason)}for(var i=0;promise._state===lib$es6$promise$$internal$$PENDING&&i<length;i++){lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]),undefined,onFulfillment,onRejection)}return promise}var lib$es6$promise$promise$race$$default=lib$es6$promise$promise$race$$race;function lib$es6$promise$promise$resolve$$resolve(object){var Constructor=this;if(object&&typeof object==="object"&&object.constructor===Constructor){return object}var promise=new Constructor(lib$es6$promise$$internal$$noop);lib$es6$promise$$internal$$resolve(promise,object);return promise}var lib$es6$promise$promise$resolve$$default=lib$es6$promise$promise$resolve$$resolve;function lib$es6$promise$promise$reject$$reject(reason){var Constructor=this;var promise=new Constructor(lib$es6$promise$$internal$$noop);lib$es6$promise$$internal$$reject(promise,reason);return promise}var lib$es6$promise$promise$reject$$default=lib$es6$promise$promise$reject$$reject;var lib$es6$promise$promise$$counter=0;function lib$es6$promise$promise$$needsResolver(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function lib$es6$promise$promise$$needsNew(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object c
323onstructor cannot be called as a function.")}var lib$es6$promise$promise$$default=lib$es6$promise$promise$$Promise;function lib$es6$promise$promise$$Promise(resolver){this._id=lib$es6$promise$promise$$counter++;this._state=undefined;this._result=undefined;this._subscribers=[];if(lib$es6$promise$$internal$$noop!==resolver){if(!lib$es6$promise$utils$$isFunction(resolver)){lib$es6$promise$promise$$needsResolver()}if(!(this instanceof lib$es6$promise$promise$$Promise)){lib$es6$promise$promise$$needsNew()}lib$es6$promise$$internal$$initializePromise(this,resolver)}}lib$es6$promise$promise$$Promise.all=lib$es6$promise$promise$all$$default;lib$es6$promise$promise$$Promise.race=lib$es6$promise$promise$race$$default;lib$es6$promise$promise$$Promise.resolve=lib$es6$promise$promise$resolve$$default;lib$es6$promise$promise$$Promise.reject=lib$es6$promise$promise$reject$$default;lib$es6$promise$promise$$Promise._setScheduler=lib$es6$promise$asap$$setScheduler;lib$es6$promise$promise$$Promise._setAsap=lib$es6$promise$asap$$setAsap;lib$es6$promise$promise$$Promise._asap=lib$es6$promise$asap$$asap;lib$es6$promise$promise$$Promise.prototype={constructor:lib$es6$promise$promise$$Promise,then:function(onFulfillment,onRejection){var parent=this;var state=parent._state;if(state===lib$es6$promise$$internal$$FULFILLED&&!onFulfillment||state===lib$es6$promise$$internal$$REJECTED&&!onRejection){return this}var child=new this.constructor(lib$es6$promise$$internal$$noop);var result=parent._result;if(state){var callback=arguments[state-1];lib$es6$promise$asap$$asap(function(){lib$es6$promise$$internal$$invokeCallback(state,child,callback,result)})}else{lib$es6$promise$$internal$$subscribe(parent,child,onFulfillment,onRejection)}return child},"catch":function(onRejection){return this.then(null,onRejection)}};function lib$es6$promise$polyfill$$polyfill(){var local;if(typeof global!=="undefined"){local=global}else if(typeof self!=="undefined"){local=self}else{try{local=Function("return this")()}catch(e){throw new Error("polyfill failed because global object is unavailable in this environment")}}var P=local.Promise;if(P&&Object.prototype.toString.call(P.resolve())==="[object Promise]"&&!P.cast){return}local.Promise=lib$es6$promise$promise$$default}var lib$es6$promise$polyfill$$default=lib$es6$promise$polyfill$$polyfill;var lib$es6$promise$umd$$ES6Promise={Promise:lib$es6$promise$promise$$default,polyfill:lib$es6$promise$polyfill$$default};if(typeof define==="function"&&define["amd"]){define(function(){return lib$es6$promise$umd$$ES6Promise})}else if(typeof module!=="undefined"&&module["exports"]){module["exports"]=lib$es6$promise$umd$$ES6Promise}else if(typeof this!=="undefined"){this["ES6Promise"]=lib$es6$promise$umd$$ES6Promise}lib$es6$promise$polyfill$$default()}).call(this);;
324
325/* USAGE:
326    $(document).on("featureSettingsReady", function () {
327        if (Next.FeatureManager.FeatureSettings.RecentlyViewed.IsEnabled) {
328            // feature setting dependent logic here..
329        }
330    });
331*/
332
333var FeatureSettingsLoaded = false;
334
335$(document).ready(function () {
336    // set up namespacing
337    if (typeof window.Next === "undefined") window.Next = {};
338    if (typeof window.Next.FeatureManager === "undefined") window.Next.FeatureManager = {};
339
340    Next.FeatureManager.FeatureSettings = (function () {        
341        var host = (window.location.protocol == "http:" ? Next.Settings.Channel.SiteUrl : Next.Settings.Channel.SecureSiteUrl) + '/';
342        $.ajax({
343            url: host + "FeatureSettings/GetClientFeatures",
344            type: "GET",
345            dataType: "json",
346            success: function (data) {
347                Next.FeatureManager.FeatureSettings = data;
348            },
349            error: function (jqXhr, textStatus, errorThrown) {
350                if (window.console && console.log) {
351                    console.log(errorThrown);
352                }
353            },
354            complete: function () {
355                FeatureSettingsLoaded = true;
356                $(document).trigger("featureSettingsReady");
357            }
358        });
359
360        var defaultSettings = {
361            RecentlyViewed: {
362                IsEnabled: true,
363                DisplayCounter: false,
364                DisplayInFooter: true,
365                DisplayInPage: true,
366                DisplayInSecureFooter: false,
367                DisplayViewAllLink: false,
368                EnableAdditions: true,
369                InPageDisabledPageTypes: [
370                    // ENABLED: evoucher, homepage, shoppingbag, shot, sofashot
371                    "brands",
372                    "branddirectory",
373                    "classic",
374                    "classicstorefront",
375                    "collection",
376                    "complete",
377                    "delivery",
378                    "department",
379                    "footer",
380                    "item",
381                    "login",
382                    "meganav",
383                    "myaccount",
384                    "pageframe",
385                    "payment",
386                    "primary",
387                    "quickshop",
388                    "returns",
389                    "search",
390                    "singleitem",
391                    "spread",
392                    "spreadonly",
393                    "spread_carousel",
394                    "storefront",
395                    "story",
396                    "subcollection",
397                    "undefined"
398                ],
399                ToolbarDisabledPageTypes: []
400            },
401            Search: {
402                BaseAddress: "http://localhost:62161",
403                SuggestionsEnabled: true,
404                RecentSearchesSaved: 5
405            }
406        };
407
408        return defaultSettings;
409    })();
410});
411
412
413
414;
415// ---------------------------------------------------------------------------------
416// Personalisation JS Library
417// ---------------------------------------------------------------------------------
418/// <reference path="typings/jquery/jquery.d.ts" />
419// ---------------------------------------------------------------------------------
420// Personalisation Module 
421// ---------------------------------------------------------------------------------
422var Personalisation;
423(function (Personalisation) {
424    //#region Constants, Variables & Properties -------------------------------
425    // Constants (psuedo)
426    var PERSONALISATION_DATASTORAGE_KEYNAME = "PersonalisationEntity";
427    // Local variables
428    var _personalisationEntity = null;
429    // Public variables
430    Personalisation.isReady = false;
431    Personalisation.isLocalStorageSupported = false;
432    //#endregion
433    //#region Initialisation --------------------------------------------------
434    function initState() {
435        // iOS browsing in private mode can show localstorage as available but will throw exceptions when calling get/set item data
436        Personalisation.isLocalStorageSupported = false;
437        // Replace console.log with an empty function if browser has disabled or not support it.
438        // Thus stopping further console.log errors.
439        window['console'] = window['console'] || {};
440        window['console']['log'] = window['console']['log'] || function () { };
441        try {
442            if ("localStorage" in window && window.localStorage && typeof (localStorage) !== "undefined") {
443                localStorage.setItem("__tmp_localstoragetest", '1');
444                localStorage.getItem("__tmp_localstoragetest");
445                localStorage.removeItem("__tmp_localstoragetest");
446            }
447            Personalisation.isLocalStorageSupported = true;
448        }
449        catch (error) {
450            Personalisation.isLocalStorageSupported = false;
451        }
452        // InitState function will try to retrieve personalisation entity object from client first (localstorage), 
453        // otherwise will attempt to get from personalisation service on server and if not returned will then
454        // create a new local entity. At this stage it will not be saved to LocalStorage or server until a data item 
455        // is set (added)
456        if (_personalisationEntity == null) {
457            clientGetObject(); // Attempt to get entity from localstorage
458            if (_personalisationEntity == null) {
459                // If no personalisation data in localstorage then attempt to get from server...
460                // If data is returned then it will have updated _personalisationEntity
461                apiGetObject().then(function () {
462                    // If '_personalisationEntity' still null then create blank entity with visitor id only
463                    if (_personalisationEntity == null) {
464                        _personalisationEntity = new PersonalisationEntity();
465                        _personalisationEntity.VisitorId = getVisitorId();
466                    }
467                    Personalisation.isReady = true;
468                    console.log("Personalisation client is ready");
469                })['catch'](function () {
470                    // If '_personalisationEntity' still null then create blank entity with visitor id only
471                    if (_personalisationEntity == null) {
472                        _personalisationEntity = new PersonalisationEntity();
473                        _personalisationEntity.VisitorId = getVisitorId();
474                    }
475                    Personalisation.isReady = true;
476                    console.log("Personalisation client is ready");
477                });
478                return; // Return so that we process no further and leave to promise callbacks
479            }
480        }
481        Personalisation.isReady = true;
482        console.log("Personalisation client is ready");
483    }
484    Personalisation.initState = initState;
485    //#endregion 
486    //#region Public Functions ------------------------------------------------
487    function itemGet(key) {
488        if (_personalisationEntity == null) {
489            clientGetObject(); // Attempt to get entity from localstorage
490        }
491        if (_personalisationEntity != null) {
492            // Check expiry value
493            if (_personalisationEntity.Expiry != null) {
494                if (_personalisationEntity.Expiry < new Date()) {
495                    // Expire (remove) personalisation entity (client side only)
496                    verifyClientObject();
497                    return null;
498                }
499            }
500            // Return item value
501            if (_personalisationEntity.Data[key] != null) {
502                return _personalisationEntity.Data[key];
503            }
504            else {
505                return null;
506            }
507        }
508        else {
509            return null;
510        }
511    }
512    Personalisation.itemGet = itemGet;
513    function itemSet(key, value) {
514        if (_personalisationEntity == null) {
515            clientGetObject(); // Attempt to get entity from localstorage
516            // If no personalisation data then create entity object
517            if (_personalisationEntity == null) {
518                _personalisationEntity = new PersonalisationEntity();
519                _personalisationEntity.VisitorId = getVisitorId();
520            }
521        }
522        // Ensure VisitorId is populated
523        if (_personalisationEntity.VisitorId == null || _personalisationEntity.VisitorId === "") {
524            _personalisationEntity.VisitorId = getVisitorId();
525        }
526        if (value != null) {
527            _personalisationEntity.Data[key] = value;
528            _personalisationEntity.Expiry = new Date(new Date().getTime() + PersonalisationExpiryInMinutes * 60000);
529        }
530        else {
531            delete _personalisationEntity.Data[key];
532        }
533        clientSetObject();
534    }
535    Personalisation.itemSet = itemSet;
536    // GET the PersonalisationEntity object (_personalisationEntity) from server for visitor
537    function apiGetObject() {
538        if (PersonalisationClientOnly === true)
539            return Promise.reject("501"); // reject promise with 501 Not Implemented?
540        var promise = new Promise(function (resolve, reject) {
541            var visitorId = getVisitorId();
542            if (visitorId != null && visitorId != "") {
543                $.ajax({
544                    method: "GET",
545                    url: PersonalisationApiUrl + "/visitor/" + visitorId
546                })
547                    .done(function (data, statusText, xhr) {
548                    var status = xhr.status;
549                    if (status >= 200 && status < 300 || status === 304) {
550                        var getPersonalisationDataResponse = data;
551                        _personalisationEntity = getPersonalisationDataResponse.PersonalisationEntity;
552                        // Update localStorage
553                        clientSetObject();
554                        // Resolve promise
555                        resolve(data);
556                    }
557                    else {
558                        // We only see success as data being returned (i.e 200 - not 404 etc) - therefore will reject promise
559                        // Reject promise
560                        reject(status);
561                    }
562                })
563                    .fail(function (jqXHR, textStatus, errorThrown) {
564                    console.warn("Personalisation API GET call failed");
565                    // Reject promise
566                    reject(jqXHR.status);
567                });
568            }
569            else {
570                reject("No VisitorID supplied");
571            }
572        });
573        return promise;
574    }
575    Personalisation.apiGetObject = apiGetObject;
576    // POST the current PersonalisationEntity object (_personalisationEntity) to server for visitor
577    function apiSetObject() {
578        if (PersonalisationClientOnly === true)
579            return;
580        // Simple fire and forget call to Personalisation API
581        $.ajax({
582            method: "POST",
583            headers: {
584                'Accept': 'application/json',
585                'Content-Type': 'application/json'
586            },
587            url: PersonalisationApiUrl + "/visitor",
588            dataType: 'json',
589            processData: false,
590            data: JSON.stringify(_personalisationEntity)
591        });
592    }
593    //#endregion
594    //#region Private Functions ------------------------------------------------
595    // Get the personalisation entity for current visitor from local storage. 
596    // If it does not exist then an attempt is made to the Personalisation API
597    function clientGetObject() {
598        // Verify client object (inc. check expiry)
599        verifyClientObject();
600        if (Personalisation.isLocalStorageSupported) {
601            if (localStorage.getItem(PERSONALISATION_DATASTORAGE_KEYNAME) !== null) {
602                _personalisationEntity = JSON.parse(localStorage.getItem(PERSONALISATION_DATASTORAGE_KEYNAME));
603            }
604        }
605        else {
606            // TODO: Fallback for non-localstorage support?
607        }
608    }
609    // Save the personalisation entity for current visitor in local storage and call function to save to Personalisation API. 
610    function clientSetObject() {
611        if (Personalisation.isLocalStorageSupported) {
612            // Store on client in LocalStorage...
613            localStorage.setItem(PERSONALISATION_DATASTORAGE_KEYNAME, JSON.stringify(_personalisationEntity));
614            // Update server
615            apiSetObject();
616        }
617        else {
618            // TODO: Fallback for non-localstorage support?
619        }
620    }
621    // Expire personalisation entity
622    function verifyClientObject() {
623        // Check if expired?... If it has then only removes from localstorage (not server).
624        if (Personalisation.isLocalStorageSupported) {
625            if (localStorage.getItem(PERSONALISATION_DATASTORAGE_KEYNAME) !== null) {
626                var perEntity = localStorage.getItem(PERSONALISATION_DATASTORAGE_KEYNAME);
627                // Check expiry value
628                if (perEntity.Expiry != null) {
629                    if (_personalisationEntity.Expiry < new Date()) {
630                        // Remove personalisation entity (client side only)
631                        localStorage.removeItem(PERSONALISATION_DATASTORAGE_KEYNAME);
632                        return null;
633                    }
634                }
635            }
636        }
637    }
638    // Get VisitorId
639    function getVisitorId() {
640        // We are unable to access VisitorID direct from cookie as NextVisitor cookie has HttpOnly attribute
641        // VisitorID is made available to every page using shared layout as var 'PersonalisationVisitorID'
642        // (It is also available VisitorID from NextBasket although this is not available immediately)
643        if (typeof NextBasket != "undefined")
644            return NextBasket.VisitorID;
645        else
646            return null;
647        // TODO: Can't use the old PersonalisationVisitorID property as this would be cached on Akamai (the devil) for all users with wrong ID.
648        //return PersonalisationVisitorID;
649    }
650    Personalisation.getVisitorId = getVisitorId;
651    //#endregion
652    //#region Interfaces & Classes --------------------------------------------
653    /// <summary>
654    /// PersonalisationEntity class. Represents the server side personalisation entity
655    /// </summary>
656    var PersonalisationEntity = /** @class */ (function () {
657        function PersonalisationEntity() {
658            this.Data = {};
659        }
660        return PersonalisationEntity;
661    }());
662    //#endregion
663})(Personalisation || (Personalisation = {}));
664// Initialise Personalisation module...
665Personalisation.initState();
666//# sourceMappingURL=personalisation.js.map;
667/* eslint-disable */
668var HContextArray = new Array(); // Define Horizontal Context Array (for detecting changes in department, and the direction in which the transition should move)
669var DynamicResources = new Array(); // Define an array to store the dynamically added resources for the current page, so they can be removed when we leave the page asynchronously
670var PreviousPageResources;
671var PageURLInput = String(window.location.pathname) + String(window.location.search); // Drop the current page url in to a variable - used to detect context changes when triggering back functionality
672var siteAssetsUrl; // This is the URL that is used to request further assests such as CSS and JS on the fly - Set by the header.xsl code
673var PageType;
674var OverrideWithSecureFooter = (OverrideWithSecureFooter == null) ? false : OverrideWithSecureFooter;
675var PageTransitionLock = false;
676var preventReplaceState = false; // This is true if we don't want to replace state when leaving this page
677var PagePopped = false; // This is true if the popstate has been triggered for this page load
678var PagePoppedData = null; // This will contain history object data if the page is popped
679
680var mouseOverHeader = false;
681var liveSpreadPageIndex; // There are conditions where the header needs to know if the mouse is still over them. This variable is used to determine that. It should be set on mouseover/mouseenter, and cleared on mouseout/mouseleave as required.
682
683var ScriptsLoadedCallback = null; // Store the ScriptsLoadedCallback as a null function. This will get updated by indiviual pages and cleared after it has been called (this saves us from the browser keeping hold of the previous pages ScriptsLoadedCallback function and causing double init issues)
684var PageVisibleCallback = null; // Store the PageVisibleCallback as a null function. This will get updated by indiviual pages and cleared after it has been called (this saves us from the browser keeping hold of the previous pages PageVisibleCallback function and causing double init issues)
685
686var ThirdPartiesEnabled = false;
687
688var GomezEnabled;
689var GomezPageTagEnabled;
690var GomezPageId;
691var gomez; 
692
693var connectionSpeed = 0;
694
695var isTouchEnabled = false;
696var isMSPointerDevice = false;
697
698var MainSiteURL = window.location.host;
699
700var isErrorPage = false;
701var isSocialPLPPage = false;
702
703var rvScrollOffset = 0; //stores item scroller offset. This will be useful in Footer.js to i
703dentify document click
704
705var currentKey = null
706
707window.console = window.console || { log: function (_) { } };
708window._AutofillCallbackHandler = window._AutofillCallbackHandler || function () { }
709
710var jqueryUpgradeEnabledOnPage = jqueryUpgradeEnabledOnPage || false;
711
712if (console && console.log) {
713    console.log('\n                                    t\n       n nnnnn    eeeee   xx     xx ttttt\n       nn     n  e     e   xx   xx  t\n       n      n eeeeeeeee    xxx    t\n       n      n  e         xx   xx  t   t\n       n      n   eeeeee  xx     xx  ttt\n\n                S  Y  S  T  E  M  S\n\nThanks for looking! Our systems teams develop and\nmanage the IT that supports our entire enterprise.\nAnd we\'re recruiting now.\n\nHave a look at https://careers.next.co.uk/head-office/\n\n');
714}
715
716if ((typeof (navigator.maxTouchPoints) == 'undefined')) {
717    if ((typeof (window.ontouchstart) != 'undefined')) {
718        isTouchEnabled = true;
719    }
720    else if (navigator.msMaxTouchPoints > 0) { //IE10 on touch device supports this 
721        isTouchEnabled = true;
722        isMSPointerDevice = true;
723    }
724}
725else if (navigator.maxTouchPoints > 0) {
726    isTouchEnabled = true;
727    isMSPointerDevice = true;
728}
729
730var enableTouchFunctions = false;
731
732if (isTouchEnabled) {
733    enableTouchFunctions = true;
734}
735
736if (/\bMSIE 6/.test(navigator.userAgent) && !window.opera) {
737
738    if (window.location.pathname != '/browser-update') {
739        window.location = '/browser-update';
740    }
741}
742
743var isIpad = false;
744var isIOS = false;
745var iOS = 0;
746
747if (navigator.userAgent.indexOf('iPad') != -1) {
748    isIpad = true;
749
750    if (/OS [2-4]_\d(_\d)? like Mac OS X/i.test(navigator.userAgent)) {
751        //Treat 2 - 4 as just 4
752        iOS = 4;
753    } else if (/CPU like Mac OS X/i.test(navigator.userAgent)) {
754        iOS = 1;
755    } else {
756        //Set to 5 for all iOS 5 and above
757        iOS = 5;
758    }
759}
760
761if (navigator.userAgent.indexOf('iPad') != -1
762    || navigator.userAgent.indexOf('iPhone') != -1
763    || navigator.userAgent.indexOf('iPod') != -1) {
764    isIOS = true;
765    ConsoleLog("iOs detected");
766}
767
768// The documentState is a JSON object that contains params that are specific to the page.
769// These will be appended to the path as querystring params when transitioning and used on page load. 
770// If a variable name begins with 'hidden', it will not be used as a querystring param
771// The hashtag variable is reserved & placed at the end of the querystring
772// e.g. { spreadview: true, hiddenSearchbreadcrumb: '<div>secret</div>', hashtag: '123456x50' } Will be output as /path?speadview=true#123456x50
773// The following methods can be used to manage documentState: getDocStateParamValue(Name), addParamToDocState(Name, Value), getDocStateString(documentState)
774var documentState = {};                                                                                                                                                     // Declare global to store current document state
775
776try {
777    if (typeof window.history.replaceState != "undefined") {  																								// If we're navigating the site rather than clicking back or forward
778        window.history.replaceState({ "url": window.location.href, "title": document.title, "DocState": documentState, "scrollPoint": $(window).scrollTop() }, document.title, window.location.href); 			        // On load, attempt to replace the last state object on the history stack with one that is populated with the relevent transition data (although in all likely hood this will just insert a new item)
779    }
780} catch (e) {
781    ConsoleLog('Unable to replace history state');
782}
783
784/* - Global Event Handlers - */
785
786/* - Window Focus Detection - */
787window.onfocus = onFocus;
788window.onblur = onBlur;
789
790// Chrome detect as variable
791var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
792// isolated Chrome hack for window focus
793$(window).on("click", function () {
794    if (is_chrome) {
795        $(window).trigger("focus");
796    }
797});
798
799function AddMouseEarTouchEvents() {
800    $(".MouseEar").on('touchstart', function () {
801        $(this).addClass('hover');
802    });
803
804    $(".MouseEar").on('touchend', function () {
805        var $ear = $(this);
806        setTimeout(function () {
807            $ear.removeClass('hover');
808        }, 250);
809    });
810}
811
812$(document).ready(function () {
813    AddMouseEarTouchEvents();
814
815    if (!Next.Settings.UI.PlpDesktopJumpinessFix) {
816        setPagePositioning();
817    } 
818
819    //Start timing requests - this is used in LoadHTMLContent in ajax.js
820    lastRequest = new Date().getTime();
821
822    //Look in current content page params - if it exists, we have fully loaded a new page (not from loadHTML ajax)
823    //Update SEO and breadcrumb here
824
825    //Update breadcrumb/SEO
826    if ($(".CurrentContent #PageParams").length) {
827
828        var BCHTML = $(".CurrentContent #PageParams #BreadcrumbWrapper").html();
829
830        if (BCHTML != null && BCHTML.length) {
831            UpdateBreadcrumbTrail(BCHTML);
832        }
833        //Remove page params from page
834        $(".CurrentContent #PageParams").remove();
835    }
836
837    LoadGomezScripts();
838
839    SetupFallbackFor
839ChannelisedLogos();
840});
841
842function onBlur() {
843    if ($("body").hasClass("Focus")) {
844        $("body").removeClass("Focus");
845    }
846};
847
848function onFocus() {
849    //Need to check viewport size here as well as the user may have resized window while in a different tab
850    if (!Next.Settings.UI.PlpDesktopJumpinessFix) {
851        setPagePositioning();
852    } 
853   
854    if (!$("body").hasClass("Focus")) {
855        $("body").addClass("Focus");
856    }
857};
858
859var addSpreadToHistory = true;
860var trackSpreadClick = true;
861var previousPageGrid = false;
862var hideScrollBars = false;
863window.onpopstate = function (stackstate) {
864
865
866    if ($("body").css("overflow") == "hidden" && !hideScrollBars) {
867        $("body").css("overflow", "visible");
868    }
869
870    $("#SuperZoomBoxDiv > a").trigger("click");
871
872    // Fired when user clicks forward or back buttons in browser, or when window.history.back() or .forward() is used. WARNING: Chrome incorrectly fires this event handler on load too. This should be catered for by the replace state above.
873    PagePopped = true;
874    preventReplaceState = true;
875
876    if (stackstate.state == null) { // stackstate tends to only be null on initial vist page OR if we have done a full page reload, ie F5 or transitioning to another page without using AJAX.
877        if (!window.location.pathname.substring(0, PageURLInput.length) == PageURLInput + "#") {
878            LoadHTMLContent(window.location.href, window.title, "", false, 0, {}); // in either instance, we need to reload the relevant content.
879        }
880    } else {
881
882        // The stackstate will come in handy for some pages...
883        PagePoppedData = stackstate.state;
884
885        if (previousPageGrid) {
886            previousPageGrid = false;
887        }
888
889        if (stackstate.state.url != null) {
890            //If the state object has a url property
891            LoadHTMLContent(stackstate.state.url, stackstate.state.title, "", false, stackstate.state.scrollPoint, stackstate.state.DocState); // Load the content defined by the history object - as we're going back or forward in the history stack at this point, the 4th param is set to false to prevent a new history item being inserted in the stack.
892        }
893    }
894}
895
896window.onload = function (event) { // Fired on initial page load or when user hits refresh or F5.
897    $(window).trigger("focus");
898    positionMouseEars(); // Check to see if the footer is in the correct state for the document's initial scroll position. The transition param allows the toolbar to animate in gracefully.
899}
900
901window.onscroll = function (event) {
902
903    if (!$(".ContentArea").hasClass("HideOverflow")) {
904        resizeContentArea();
905    }
906}
907
908window.onresize = function (event) { // Fired when the user resizes their browser window
909    resizeContentArea();
910    positionMouseEars();
911    if (!Next.Settings.UI.PlpDesktopJumpinessFix) {
912        setPagePositioning();
913    } 
914}
915
916$(document).on("keydown", function (event) {
917    switch (event.keyCode) {
918        case 27:
919            if (typeof ModalPopup === 'object') {
920                ModalPopup.close();
921            }
922            break;
923    }
924});
925
926$(document).on("keyup", function (event) {
927    switch (event.keyCode) {
928        case 37:
929            if ($(".MouseEar.Left.Active a")) {
930                try {
931                    $(".MouseEar.Left.Active a")[0].trigger("click");
932                } catch (e) {
933                }
934            }
935            break;
936        case 39:
937            if ($(".MouseEar.Right.Active a")) {
938                try {
939                    $(".MouseEar.Right.Active a")[0].trigger("click");
940                } catch (e) {
941                }
942            }
943            break;
944    }
945});
946
947/* - SEO / Social Media - */
948function updateSeo(seoTitle, seoDescription, seoKeywords, seoRobots, seoCanonical) {
949    var defaultTitle = "Next Official Site: Shop for Clothes, Shoes, Electricals, Homeware & More";
950    var defaultDescription = "next.co.uk - shop online for the latest fashion for women, men, children and homeware. Next day delivery and free returns available.";
951    var defaultKeywords = "Next,next.co.uk,Next Directory,Next Flowers,Next Electrics,fashion,clothes,womens,mens,childrens,home,furniture";
952    var defaultRobots = "";
953
954    if ((window.Next && Next.Settings)) {
955        defaultTitle = Next.Settings.Channel.SEOTitle;
956        defaultDescription = Next.Settings.Channel.SEODescription;
957        defaultKeywords = Next.Settings.Channel.SEOKeywords;
958        defaultRobots = Next.Settings.Channel.SEORobots;
959    }
960
961    var headEl = $("head");
962
963    function createOrGetMeta(name, value) {
964        if (value != "") {
965            var el = $("meta[name='" + name + "']");
966            if (el != null) {
967                el.attr("content", value);
968            } else {
969                headEl.append($("<meta />").attr("name", name).attr("value", value));
970            }
971        }
972    }
973
974    function createOrGetCanonical(value) {
975        if (value != "") {
976            var el = $("link[rel='canonical']");
977            if (el != null) {
978                el.attr("rel", "canonical").attr("href", value)
979            } else {
980                headEl.append($("<link />").attr("rel", "canonical").attr("href", value));
981            }
982        }
983    }
984
985    seoTitle = seoTitle || defaultTitle;
986    seoDescription = seoDescription || defaultDescription;
987    seoKeywords = seoKeywords || defaultKeywords;
988    seoRobots = seoRobots || defaultRobots;
989
990    createOrGetMeta("title", seoTitle);
991    createOrGetMeta("description", seoDescription);
992    createOrGetMeta("keywords", seoKeywords);
993    createOrGetMeta("robots", seoRobots);
994    createOrGetCanonical(seoCanonical);
995
996    document.title = seoTitle;
997}
998
999/* - Dynamic Resource Management - */
1000function InsertScript(scriptSrc) { // Dynamically inserts JS file references :)
1001    var headID = document.getElementsByTagName("head")[0];
1002    var newScript = document.createElement('script');
1003    newScript.type = 'text/javascript';
1004    newScript.src = scriptSrc;
1005    headID.appendChild(newScript);
1006    DynamicResources.push({ Type: "JS", Path: scriptSrc });
1007}
1008
1009function InsertCSS(cssSrc) { // Dynamically inserts CSS file references :)
1010    var headID = document.getElementsByTagName("head")[0];
1011    var cssNode = document.createElement('link');
1012    cssNode.href = cssSrc;
1013    cssNode.rel = 'stylesheet';
1014    //cssNode.media = 'screen'; // Required?
1015    headID.appendChild(cssNode);
1016    DynamicResources.push({ Type: "CSS", Path: cssSrc });
1017}
1018
1019function AddDynamicResource(type, path) {
1020    DynamicResources.push({ Type: type, Path: path });
1021}
1022
1023function checkPreloadSupported() {
1024    if(!window.isPreloadSupportedChecked) {
1025        window.isPreloadSupportedChecked = true;
1026        var relList = document.createElement('link').relList;
1027        window.isPreloadSupported = !!(relList && relList.supports && relList.supports('preload'));
1028    }
1029}
1030
1031function CreateDynamicResources() {
1032    var $ = jQuery;
1033    var Animation = createAnimation();
1034
1035    checkPreloadSupported();
1036
1037    let showBreadcrumbs = true;
1038
1039    if (window.location.pathname == "/" || window.location.pathname.toLowerCase() == Next.Settings.Channel.MainSiteAbsolutePath.toLowerCase() || !showBreadcrumbs) {
1040        if ($(".PageHeader").hasClass("Large")) {
1041            Animation = HideBreadcrumbBar(Animation);
1042        }
1043    } else {
1044        if (!$(".PageHeader").hasClass("Large")) {
1045            Animation = ShowBreadcrumbBar(Animation);
1046        }
1047    }
1048
1049    runAnimation(Animation);
1050
1051    var headID = document.getElementsByTagName("head")[0];
1052    var waitForCSS = false;
1053    var checkPreviousPageResources = false;
1054    //If previous page resources exist, we'll need to check it while we add new resources
1055    if (PreviousPageResources != null && PreviousPageResources.length) { checkPreviousPageResources = true; }
1056
1057
1058    for (var i = 0; i < DynamicResources.length; i++) { // Split in to 2 loops to force CSS to render first.
1059        waitForCSS = false;
1060        if (DynamicResources[i].Type == "CSS") {
1061            waitForCSS = true;
1062            var doInsert = true;
1063
1064            //Check if item already exists in memory from previous page
1065            if (checkPreviousPageResources) {
1066                var exInstance = $.grep(PreviousPageResources, function (n) {
1067                    return n.Path == DynamicResources[i].Path;
1068                });
1069                //If the item already exists, don't add it again
1070                if (exInstance != null && exInstance.length) {
1071                    doInsert = false;
1072                }
1073            }
1074
1075            if (doInsert) {
1076                var cssNode = document.createElement('link');
1077                cssNode.href = DynamicResources[i].Path;
1078                cssNode.rel = 'stylesheet';
1079                if( window.isPreloadSupported ) { // IE11 safety check
1080                    cssNode.rel = 'preload';
1081                    cssNode.setAttribute('as', 'style');
1082                    cssNode.setAttribute('onload', "this.rel='stylesheet';");
1083                }
1084                headID.appendChild(cssNode);
1085            }
1086        }
1087    }
1088    CreateDynamicJSResources(waitForCSS)
1089}
1090
1091function CreateDynamicJSResources(waitForCSS) {
1092
1093    if (waitForCSS == false
1094        || $(".CSSLoadDetector").css("background-color") == "rgb(255, 255, 255)"
1095        || $(".CSSLoadDetector").css("background-color") == "#ffffff"
1096        || $(".CSSLoadDetector").css("background-color") == "#fff"
1097        || $(".CSSLoadDetector").css("background-color") == "white") {
1098
1099        loadScripts(DynamicResources, 0);
1100
1101        $(".CurrentContent").removeClass("FirstLoad");
1102    } else {
1103        window.setTimeout("CreateDynamicJSResources(true)", 200);
1104    }
1105}
1106
1107//Loads scripts in sequence - in order to guarantee scripts have loaded before calling dependencies in other files
1108function loadScripts(DynamicResources, index) {
1109
1110    if (DynamicResources[index] == null || DynamicResources.length == 0) {
1111        //Completed all script loading
1112        CallDocumentLoaded();
1113        return false;
1114    }
1115
1116    //If current resource is CSS, move onto next
1117    if (DynamicResources[index].Type != "JS") {
1118
1119        loadScripts(DynamicResources, index + 1);
1120        return false;
1121    }
1122
1123    //If item already exists in memory
1124    if (PreviousPageResources != null && PreviousPageResources.length) {
1125        var exInstance = $.grep(PreviousPageResources, function (n) {
1126            return n.Path == DynamicResources[index].Path;
1127        });
1128        //If the item already exists, don't add it again
1129        if (exInstance != null && exInstance.length) {
1130
1131            loadScripts(DynamicResources, index + 1);
1132            return false;
1133        }
1134    }
1135
1136    //Create new script element
1137    var script = document.createElement("script")
1138    script.type = "text/javascript";
1139    script.defer = true;
1140
1141    //Add script load handlers - once current script has loaded, move to next. May seem slower than async loading multiple scripts but ensures we don't call non exisitent functions
1142    if (script.readyState) {  //IE
1143        script.onreadystatechange = function () {
1144            if (script.readyState == "loaded" ||
1145                script.readyState == "complete") {
1146                script.onreadystatechange = null;
1147
1148                loadScripts(DynamicResources, index + 1);
1149            }
1150        };
1151    } else {  //Others
1152        script.onload = function () {
1153
1154            loadScripts(DynamicResources, index + 1);
1155        };
1156    }
1157
1158    script.src = DynamicResources[index].Path;
1159    document.getElementsByTagName("head")[0].appendChild(script);
1160}
1161
1162//Call this once all scripts have loaded
1163function CallDocumentLoaded(ignoreScriptCallBack) {
1164
1165    //Implement this function if we need to fire scripts as soon as they are loaded
1166    //This may be during a page transition - if the scripts cause performance issues during 
1167    //a page transition, wait until the transition is finished i.e. implement PageVisibleCallback() instead
1168    if (!ignoreScriptCallBack) {
1169        if (typeof ScriptsLoadedCallback === 'function') {
1170            ScriptsLoadedCallback();
1171            ScriptsLoadedCallback = null;
1172        }
1173    }
1174
1175    //If page is transitioning, wait until that finishes
1176    if (isPageTransitioning) {
1177        window.setTimeout("CallDocumentLoaded(true)", 100);
1178        return false;
1179    }
1180
1181    try {
1182        PageVisibleCallback();
1183        PageVisibleCallback = null;
1184    }
1185    catch (ex) {
1186        //ignore - callback method not implemented
1187    }
1188
1189    AddMouseEarHoverStates();
1190
1191    if (ThirdPartiesEnabled == true && AddThisEnabled == true) {
1192        updateSocialMediaButtons(window.location.pathname);
1193    }
1194
1195    $("#PageLoadBlock").remove();
1196    if (!Next.Settings.UI.PlpDesktopJumpinessFix) {
1197        setPagePositioning();
1198    } 
1199    
1200    // reset the PagePopped flag here as the page visible callback might need it and this is the latest we can reset it
1201    PagePopped = false;
1202    PagePoppedData = null;
1203
1204    var paymentCompletePageUrl = "/secure/checkout/complete"; //Payment complete page should redirect to "Next home page"
1205    if (!PageURLInput.match(paymentCompletePageUrl + "$")) {
1206        if ($.jStorage.storageAvailable()) {
1207            var lastPageVisited = $.jStorage.get("LastPageVisited");
1208            if (typeof lastPageVisited !== 'undefined' && lastPageVisited != '') {
1209                $('ul#steps a.lastPageVisited').attr('href', lastPageVisited);
1210            }
1211        }
1212    }
1213}
1214
1215function RemoveDynamicResources() {
1216    var $ = jQuery;
1217    if ((PreviousPageResources != undefined) && (PreviousPageResources.length > 0)) {
1218        var DRObject = PreviousPageResources.shift();
1219
1220        //Check this item isn't required by current page (i.e. added to dynamic resources)
1221        if (DynamicResources != null && DynamicResources.length) {
1222            var exInstance = $.grep(DynamicResources, function (n) {
1223                return n.Path == DRObject.Path;
1224            });
1225            //If the item we're about to remove from DOM exists in the new DynamicResources, don't remove it
1226            if (exInstance != null && exInstance.length) {
1227                RemoveDynamicResources();
1228                return false;
1229            }
1230        }
1231
1232        switch (DRObject.Type) {
1233            case "JS":
1234                $($('script[src="' + DRObject.Path + '"]')[0]).remove();
1235                break;
1236            case "CSS":
1237                $($('link[href="' + DRObject.Path + '"]')[0]).remove();
1238                break;
1239        }
1240        RemoveDynamicResources();
1241    } else {
1242        isPageTransitioning = false;
1243    }
1244}
1245
1246/* - Animation Stack Handlers - */
1247function createAnimation() {
1248    var AnimationStack = new Array();
1249    return AnimationStack;
1250}
1251
1252function addToAnimation(AnimationStack, CommandText, Duration, WaitForComplete) {
1253    var StackObject
1254    if (WaitForComplete) {
1255        StackObject = { Command: CommandText, NextActionDelay: Duration + 10 };
1256    } else {
1257        StackObject = { Command: CommandText }
1258    }
1259    AnimationStack.push(StackObject);
1260}
1261
1262function runAnimation(stack) {
1263    if (stack.length > 0) {
1264        StackObject = stack.shift();
1265        eval(StackObject.Command);
1266        if (StackObject.NextActionDelay != null && StackObject.NextActionDelay != 0) {
1267            var timer = window.setTimeout(function () { runAnimation(stack) }, StackObject.NextActionDelay)
1268        } else {
1269            runAnimation(stack);
1270        }
1271    }
1272}
1273
1274/* - Document State Management - */
1275function getDocStateParamValue(Name) {
1276    if (documentState[Name] !== undefined)
1277        return documentState[Name];
1278    else
1279        return null;
1280}
1281
1282function addParamToDocState(Name, Value) {
1283    if (documentState[Name] !== undefined) {
1284        documentState[Name] = Value;
1285    }
1286    else {
1287        documentState[Name] = Value;
1288    }
1289
1290    if (window.history.replaceState) {
1291        window.history.replaceState({ "url": window.location.href, "DocState": documentState, "title": document.title, "scrollPoint": $(window).scrollTop() }, document.title, window.location.href); 			// On load, attempt to replace the last state object on the history stack with one that is populated with the relevent transition data (although in all likely hood this will just insert a new item)
1292    }
1293}
1294
1295function getDocStateString(DocState) {
1296    var docStateString = ""
1297    var hashTag = ""
1298    if (typeof DocState != "undefined" && DocState != null) {
1299        // If it is already a string, just append it
1300        if (typeof DocState === "string")
1301            docStateString = DocState;
1302        // If it is a JSON object, parse it
1303        else if (typeof DocState === "object") {
1304            jQuery.each(DocState, function (varName, varVal) {
1305                if (varName === 'hashtag')
1306                    hashTag = '#' + varVal;
1307                // If this is not a hidden variable, then add it to the docstate str
1307ing
1308                else if (varName.indexOf('hidden') !== 0)
1309                    docStateString += '&' + varName + '=' + varVal;
1310            });
1311        }
1312    }
1313
1314    return docStateString + hashTag;
1315}
1316
1317/* - Page Transitions - */
1318/* - Context Handlers - */
1319function getVTransitionContext(url) {
1320    url = String(url);
1321    var newVTransitionContext
1322    if (url == "/") {
1323        newVTransitionContext = 0;
1324    } else {
1325        newVTransitionContext = url.split(/\//g).length - 1;
1326    }
1327    return newVTransitionContext;
1328}
1329
1330function getHTransitionContext(url) {
1331    url = String(url);
1332    var newHTransitionContext
1333    if (url == "/") {
1334        newHTransitionContext = -1;
1335    } else {
1336        if (url.indexOf("/") != -1) {
1337            var urlSeg = url.split(/\//g);
1338            newHTransitionContext = HContextArray.indexOf(urlSeg[1])
1339        } else {
1340            newHTransitionContext = 1
1341        }
1342    }
1343    return newHTransitionContext;
1344}
1345
1346/* - Layout Size Handlers - */
1347function resizeContentArea() {
1348    return false;
1349}
1350
1351function ResizeContentAreaToContentV2() {
1352    return false;
1353}
1354
1355/* - CSS Dynamic Content Handlers - */
1356function scriptEnabledValidation() {
1357    var $ = jQuery;
1358    // If JS is enabled, we want to add a class to the body so that we can show/hide content in our CSS
1359    $('body').addClass('JSEnabled');
1360    //Also add browser class to body tag
1361
1362    var browserName;
1363
1364    if (jqueryUpgradeEnabledOnPage) {
1365        if (typeof (navigator.userAgent) !== 'undefined') {
1366            if (navigator.userAgent.search("webkit")) { browserName = "webkit"; }
1367            if (navigator.userAgent.search("opera")) { browserName = "opera"; }
1368            //ie11 on desktop will have this broser class name
1369            if (navigator.userAgent.search("mozilla")) { browserName = "mozilla"; }
1370            if (navigator.userAgent.search("msie") || !!document.documentMode === true) {
1371                browserName = "msie" + document.documentMode;     
1372            }
1373        }
1374    } else {
1375        if (typeof ($.browser) !== 'undefined')
1376        {
1377            if ($.browser.webkit) { browserName = "webkit"; }
1378            if ($.browser.opera) { browserName = "opera"; }
1379            if ($.browser.mozilla) { browserName = "mozilla"; }//ie11 on desktop will have this broser class name
1380            if ($.browser.msie) { browserName = "msie" + $.browser.version.split('.')[0]; }
1381        }
1382    }
1383
1384    if (navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) {//this is for IE touch device
1385        //browserName = "msie" + $.browser.version.split('.')[0];
1386        browserName = "ie11TouchDevice";
1387    }
1388    if (!(window.ActiveXObject) && "ActiveXObject" in window) {
1389        browserName = "msie11";
1390    }
1391
1392    $('body').addClass(browserName);
1393}
1394
1395scriptEnabledValidation();
1396
1397/* - Page Callback Handlers - */
1398
1399function PageTransitionComplete() {
1400    try {
1401        PageVisibleCallback();
1402        PageVisibleCallback = null;
1403    }
1404    catch (ex) {
1405        //ignore - callback method not implemented
1406    }
1407}
1408
1409/* - Mouse Ear Logic - */
1410function ShowMouseEarHover(params, forcePopUp) {
1411
1412    if (isIpad) {
1413        RemoveMouseEarHover(params.element);
1414        return false;
1415    }
1416
1417    var $ = jQuery;
1418    if (!params.img) {
1419
1420        RemoveMouseEarHover(params.element);
1421        return false;
1422
1423    }
1424
1425    var mouseEar = params.element;
1426
1427    //If mouse ear already has an associated pop up image, return false
1428    if ($(mouseEar).find(".MouseEarHoverPopUp").length) {
1429        return false;
1430    }
1431
1432    $(mouseEar).addClass("hasPopUp");
1433
1434    //Create wrapper element
1435    var hoverEl = $("<div />");
1436    $(hoverEl).addClass("MouseEarHoverPopUp");
1437
1438    if (params.title) {
1439        $(hoverEl).append($("<h5>").text(params.title));
1440    }
1441
1442    //Create pointer arrow element
1443    //Create pointer arrow element for older browsers which don't support psuedo elements (:before/:after)
1444    if ($("body").hasClass("msie8")) {
1445        var arrow = $("<div />");
1446        $(arrow).addClass("MouseEarHoverArrow");
1447        $(hoverEl).append(arrow);
1448    }
1449
1450    //Create image shadow inset wrapper
1451    var imgWrap = $("<div />");
1452    $(imgWrap).addClass("MouseEarImg");
1453
1454    //Create image path
1455    var imgPath = cdnURL + "/common/items/default/default/sitemaps/" + params.sitemap + params.img;
1456    //Load the image - make sure the image is loaded before animating into view
1457    var img = $("<img/>").attr('src', imgPath).load(function () {
1458
1459        $(imgWrap).append(img);
1460
1461        //Append image to wrapper element
1462        $(hoverEl).append(imgWrap);
1463
1464        //Create text node
1465        var textNode = $("<h5 />");
1466        var elName = params.name;
1467        $(textNode).html(elName);
1468        $(hoverEl).append(textNode);
1469
1470        //Hide element
1471        $(hoverEl).css("opacity", 0);
1472        //Add it to the page
1473        $(mouseEar).append(hoverEl);
1474
1475        //Animate element into view based on which mouse ear it is related to
1476        if ($(mouseEar).hasClass("Right")) {
1477
1478            var animations = {
1479                opacity: 1
1480            };
1481            animations[Next.Settings.CSS.right] = "-=" + 20;
1482
1483            $(hoverEl).animate(animations, 300, 'easeOutBack');
1484        }
1485
1486        if ($(mouseEar).hasClass("Left")) {
1487
1488            var animations = {
1489                opacity: 1
1490            };
1491            animations[Next.Settings.CSS.left] = "-=" + 20;
1492
1493            $(hoverEl).animate(animations, 300, 'easeOutBack');
1494        }
1495
1496    });
1497}
1498
1499//Change contents of open pop-up as user pages while mouse is still over the mouseEar
1500function UpdateMouseEarHover(params) {
1501    var $ = jQuery;
1502    var mouseEar = params.element;
1503
1504    if (!params.img) {
1505        RemoveMouseEarHover(mouseEar);
1506        return false;
1507    }
1508
1509    var popUp = $(mouseEar).find(".MouseEarHoverPopUp");
1510
1511    if (popUp.length == 0) {
1512        ShowMouseEarHover(params, true);
1513        return false;
1514    }
1515
1516    //Create image path
1517    var imgPath = cdnURL + "/common/items/default/default/sitemaps/" + params.sitemap + params.img;
1518
1519    $(popUp).find("h5").empty();
1520    $(popUp).find("h5").html(params.name);
1521
1522    //Load the image
1523    var img = $("<img/>").attr('src', imgPath).load(function () {
1524        $(popUp).find(".MouseEarImgShadow img").first().replaceWith(img);
1525    });
1526}
1527
1528function RemoveMouseEarHover(mouseEar) {
1529
1530    var $ = jQuery;
1531    //Animate element away from parent mouse ear based on position of mouse ear then remove from DOM
1532    if ($(mouseEar).hasClass("Right")) {
1533
1534        var animations = {
1535            opacity: 0
1536        };
1537        animations[Next.Settings.CSS.right] = "+=" + 20;
1538
1539        $(mouseEar).find(".MouseEarHoverPopUp")
1540            .animate(animations, 300, 'easeInBack', function () {
1541                $(mouseEar).removeClass("hasPopUp");
1542                $(this).remove();
1543            });
1544    }
1545
1546    if ($(mouseEar).hasClass("Left")) {
1547
1548        var animations = {
1549            opacity: 0
1550        };
1551        animations[Next.Settings.CSS.left] = "+=" + 20;
1552
1553        $(mouseEar).find(".MouseEarHoverPopUp")
1554            .animate(animations, 300, 'easeInBack', function () {
1555                $(mouseEar).removeClass("hasPopUp");
1556                $(this).remove();
1557            });
1558    }
1559}
1560
1561function ClearMouseEarStates() {
1562
1563    $("div.MouseEar").each(function () {
1564        $(this).unbind('mouseenter').unbind('mouseleave');
1565    });
1566}
1567
1568//Limit mouse ear position to 1280 width - anything beyoned that, the mouse ears will be fixed
1569function positionMouseEars() {
1570    var $ = jQuery;
1571    if ($(window).width() > 1280) {
1572        $("body").addClass("LimitWidth");
1573
1574    } else {
1575        $("body").removeClass("LimitWidth");
1576    }
1577}
1578
1579//Add hover states for spread mouse ears
1580function AddSpreadHoverStates() {
1581
1582    var $ = jQuery;
1583
1584    //Clear out any mouse ears from previous pages
1585    $(".MouseEar.Right.Proxy").remove();
1586    $(".MouseEar.Left.Proxy").remove();
1587
1588    var $mouseEarRight = $(".MouseEar.Right");
1589    var $mouseEarLeft = $(".MouseEar.Left");
1590
1591    //Make new spread mouse ears visible
1592    $mouseEarRight.addClass("visible");
1593    $mouseEarLeft.addClass("visible");
1594    //Unbind any existing hover event handlers
1595    $mouseEarRight.off('hover');
1596    $mouseEarLeft.off('hover');
1597    //If Right mouse ear has a next page image preview, build hover state
1598    if ($mouseEarRight.attr("data-img").length) {
1599
1600        var paramsRight = {
1601            element: $mouseEarRight,
1602            img: $mouseEarRight.attr("data-img"),
1603            sitemap: $mouseEarRight.attr("data-sitemap"),
1604            name: $mouseEarRight.attr("data-name"),
1605            title: "Coming Next"
1606        };
1607        //Create mouseEar hover event handler
1608        $mouseEarRight.hover(function () { ShowMouseEarHover(paramsRight); }, function () { RemoveMouseEarHover($mouseEarRight); });
1609        //And close pop up on click
1610        $mouseEarRight.on("click", function () { RemoveMouseEarHover($mouseEarRight); });
1611    }
1612    else if ($mouseEarRight.hasClass("hasPopUp"))
1613        $mouseEarRight.mouseout(function () { RemoveMouseEarHover($mouseEarRight); })
1614
1615    //Same as above for left mouse ear
1616    if ($mouseEarLeft.attr("data-img").length) {
1617
1618        var paramsLeft = {
1619            element: $mouseEarLeft,
1620            img: $mouseEarLeft.attr("data-img"),
1621            sitemap: $mouseEarLeft.attr("data-sitemap"),
1622            name: $mouseEarLeft.attr("data-name")
1623        };
1624
1625        $mouseEarLeft.hover(function () { ShowMouseEarHover(paramsLeft); }, function () { RemoveMouseEarHover($mouseEarLeft); });
1626        $mouseEarLeft.on("click", function () { RemoveMouseEarHover($mouseEarLeft); });
1627    }
1628    else if ($mouseEarLeft.hasClass("hasPopUp"))
1629        $mouseEarLeft.mouseout(function () { RemoveMouseEarHover($mouseEarLeft); })
1630
1631    //Move mouse ears (first time round) to outer wrapper to prevent animations overlapping ears
1632    if (!$mouseEarLeft.hasClass("spreadEar")) {
1633        $mouseEarLeft.addClass("spreadEar");
1634        $(".ContentArea").prepend($mouseEarLeft);
1635    }
1636
1637    if (!$mouseEarRight.hasClass("spreadEar")) {
1638        $mouseEarRight.addClass("spreadEar");
1639        $(".ContentArea").prepend($mouseEarRight);
1640    }
1641
1642    return false;
1643}
1644
1645//Create hover event handlers for mouse ears
1646function AddMouseEarHoverStates() {
1647    var $ = jQuery;
1648    //If we're in a Spread page, handle mouse ears separately 
1649    if ($(".SpreadsPage").length) {
1650        AddSpreadHoverStates();
1651        return false;
1652    }
1653
1654    //Clean up spread MouseEars
1655    $(".MouseEar.Left.spreadEar").remove();
1656    $(".MouseEar.Right.spreadEar").remove();
1657
1658    //Hide incoming/new MouseEars
1659    $(".MouseEar.Right").removeClass("visible");
1660    $(".MouseEar.Left").removeClass("visible");
1661
1662    var hasNewLeft = false;
1663    var hasNewRight = false;
1664    var hasLeftProxy = false;
1665    var hasRightProxy = false;
1666
1667    //Check we already have a mouse ear to handle hover/click events
1668    if ($(".ContentArea div.MouseEar.Left.Proxy").length) {
1669        hasLeftProxy = true;
1670    }
1671
1672    if ($(".ContentArea div.MouseEar.Right.Proxy").length) {
1673        hasRightProxy = true;
1674    }
1675    //Check incoming page has a left and right mouse ear
1676    if ($(".CurrentContent div.MouseEar.Left").length) {
1677        hasNewLeft = true;
1678    } else {
1679        //Incoming page has no left mouse ear, remove any exisitng Left mouseEar
1680        $(".ContentArea div.MouseEar.Left.Proxy").remove();
1681    }
1682
1683    if ($(".CurrentContent div.MouseEar.Right").length) {
1684        hasNewRight = true;
1685    } else {
1686        $(".ContentArea div.MouseEar.Right.Proxy").remove();
1687    }
1688    //Add hover event handlers for each mouse ear
1689    $(".CurrentContent div.MouseEar").each(function () {
1690
1691        var mouseEar = $(this);
1692        var params = {
1693            element: $(this),
1694            img: $(this).attr("data-img"),
1695            sitemap: $(this).attr("data-sitemap"),
1696            name: $(this).attr("data-name")
1697        };
1698
1699        if ($(this).hasClass("Left") && hasLeftProxy) {
1700
1701            var leftProxy = $(".ContentArea div.MouseEar.Left.Proxy");
1702            $(leftProxy).off('hover');
1703            params.element = leftProxy;
1704
1705            $(leftProxy).attr("data-img", $(this).attr("data-img"));
1706            $(leftProxy).attr("data-sitemap", $(this).attr("data-sitemap"));
1707            $(leftProxy).attr("data-name", $(this).attr("data-name"));
1708
1709            $(leftProxy).hover(function () { ShowMouseEarHover(params); }, function () { RemoveMouseEarHover(leftProxy); });
1710
1711            $(leftProxy).find("a").attr("href", $(this).find("a").attr("href"));
1712            $(leftProxy).find("a").attr("onclick", $(this).find("a").attr("onclick"));
1713
1714            if ($(this).hasClass("Active")) {
1715                $(leftProxy).removeClass("Inactive");
1716                $(leftProxy).addClass("Active");
1717            }
1718
1719            if ($(this).hasClass("Inactive")) {
1720                $(leftProxy).removeClass("Active");
1721                $(leftProxy).addClass("Inactive");
1722            }
1723
1724
1725            if ($(leftProxy).hasClass("hasPopUp")) {
1726                UpdateMouseEarHover(params);
1727            }
1728        }
1729
1730        if ($(this).hasClass("Left") && !hasLeftProxy) {
1731            $(this).hover(function () { ShowMouseEarHover(params); }, function () { RemoveMouseEarHover(mouseEar); });
1732            $(this).addClass("Proxy");
1733            $(".ContentArea").prepend(this);
1734        }
1735
1736        if ($(this).hasClass("Right") && hasRightProxy) {
1737
1738            var RightProxy = $(".ContentArea div.MouseEar.Right.Proxy");
1739            $(RightProxy).off('hover');
1740            params.element = RightProxy;
1741            $(RightProxy).attr("data-img", $(this).attr("data-img"));
1742            $(RightProxy).attr("data-sitemap", $(this).attr("data-sitemap"));
1743            $(RightProxy).attr("data-name", $(this).attr("data-name"));
1744
1745            $(RightProxy).hover(function () { ShowMouseEarHover(params); }, function () { RemoveMouseEarHover(RightProxy); });
1746
1747            $(RightProxy).find("a").attr("href", $(this).find("a").attr("href"));
1748            $(RightProxy).find("a").attr("onclick", $(this).find("a").attr("onclick"));
1749
1750
1751            if ($(this).hasClass("Active")) {
1752                $(RightProxy).removeClass("Inactive");
1753                $(RightProxy).addClass("Active");
1754            }
1755
1756            if ($(this).hasClass("Inactive")) {
1757                $(RightProxy).removeClass("Active");
1758                $(RightProxy).addClass("Inactive");
1759            }
1760
1761
1762            if ($(RightProxy).hasClass("hasPopUp")) {
1763                UpdateMouseEarHover(params);
1764            }
1765        }
1766
1767        if ($(this).hasClass("Right") && !hasRightProxy) {
1768            $(this).hover(function () { ShowMouseEarHover(params); }, function () { RemoveMouseEarHover(mouseEar); });
1769            $(this).addClass("Proxy");
1770            $(".ContentArea").prepend(this);
1771        }
1772    });
1773}
1774
1775$(function () {
1776    var $document = $(document),
1777        left = 0,
1778        scrollTimer = 0;
1779
1780    // Detect horizontal scroll start and stop.
1781    $document.on("scroll", function () {
1782        var docLeft = $document.scrollLeft();
1783        if (left !== docLeft && !isTouchEnabled) {
1784            var self = this, args = arguments;
1785            if (!scrollTimer) {
1786                // We've not yet (re)started the timer: It's the beginning of scrolling.
1787                startHScroll.apply(self, args);
1788            }
1789            window.clearTimeout(scrollTimer);
1790            scrollTimer = window.setTimeout(function () {
1791                scrollTimer = 0;
1792                // Our timer was never stopped: We've finished scrolling.
1793                stopHScroll.apply(self, args);
1794            }, 100);
1795            left = docLeft;
1796        }
1797    });
1798
1799    // Horizontal scroll started - Make header absolutely positioned.
1800    function startHScroll() {
1801        console.log("Scroll Start");
1802        $(".PageHeader")
1803            // Clear out any left-positioning set by stopHScroll.
1804            .css("left", "")
1805            .each(function () {
1806                var $this = $(this),
1807                    pos = $this.offset();
1808                // Preserve our current vertical position...
1809                $this.css("top", pos.top)
1810            })
1811            // ...before making it absolutely positioned.
1812            .css("position", "absolute");
1813    }
1814
1815    // Horizontal scroll stopped - Make header float again.
1816    function stopHScroll() {
1817        var leftScroll = $(window).scrollLeft();
1818        console.log("Scroll Stop");
1819        $(".PageHeader")
1820            // Clear out any top-positioning set by startHScroll.
1821            .css("top", "")
1822            .each(function () {
1823                var $this = $(this),
1824                    pos = $this.position();
1825                // Preserve our current horizontal position, munus the scroll position...
1826                $this.css("left", pos.left - leftScroll);
1827            })
1828            // ...before making it fixed positioned.
1829            .css("position", "fixed");
1830    }
1831});
1832
1833function isTouchDevice() {
1834    var deviceAgent = navigator.userAgent.toLowerCase();
1835
1836    var isTouch = Modernizr.touch ||
1837        (deviceAgent.match(/(iphone|ipod|ipad)/) ||
1838            deviceAgent.match(/(android)/) ||
1839            deviceAgent.match(/(iemobile)/) ||
1840            deviceAgent.match(/iphone/i) ||
1841            deviceAgent.match(/ipad/i) ||
1842            deviceAgent.match(/ipod/i) ||
1843            deviceAgent.match(/blackberry/i) ||
1844            deviceAgent.match(/bada/i));
1845
1846    return isTouch;
1847}
1848
1849function setPagePositioning() {
1850    var $ = jQuery;
1851
1852    if (isTouchEnabled) {
1853        // New header is always fixed
1854          $(".PageHeader").css({
1855            "position": "fixed",
1856            "width": "100%",
1857            "min-width": "1000px"
1858        });
1859
1860
1861        $('body').addClass("isTouchDevice");
1862    }
1863    else {
1864        $(".PageHeader").css({
1865            "position": "fixed",
1866            "width": "100%",
1867            "min-width": "1000px"
1868        });
1869    }
1870}
1871
1872/* - Generic Session Variable Methods - */
1873var ClientTempSessionVariables = {};    // This is a local store of the Session Variables that will save us from going to the Server each time we want to get a value
1874var UseLocalStorage = true;             // Config switch to use either Local Storage on the browser or use the Server side Session Storage Objects
1875
1876function UpdateSessionVariable(variableName, newValue, forceServerPost, successCallback, errorCallback) {
1877	
1878	if (UseLocalStorage && !forceServerPost) {
1879        $.jStorage.set(variableName, newValue);
1880
1881        if (successCallback)
1882            successCallback();
1883    }
1884    else {
1885        if ((forceServerPost !== null && forceServerPost !== undefined && forceServerPost) || ClientTempSessionVariables === null || ClientTempSessionVariables === undefined || ClientTempSessionVariables[variableName] === null || ClientTempSessionVariables[variableName] === undefined || (ClientTempSessionVariables[variableName] !== newValue)) {
1886            // Build the URL used to set Session Variables
1887            var reqUrl = ''
1888            if (typeof baseURL != 'undefined')
1889                reqUrl = baseURL;
1890            reqUrl += "/session/AddVariable";
1891
1892			// if a json object is passed as newValue then convert to string and post to the session controller
1893            if (typeof newValue == "object") {newValue = JSON.stringify(newValue)}
1894            
1895        	// Send the request
1896            $.ajax({
1897                url: reqUrl,
1898                data: { name: variableName, value: newValue },
1899                type: "POST",
1900                cache: false,
1901                async: true,
1902                timeout: 10000,
1903                dataType: "json",
1904                xhrFields: { withCredentials: true },
1905                crossDomain: true,
1906                success: function (data, textStatus, jqXHR) {
1907                    checkAndRedirectForAjaxError(jqXHR, false, 'Global.js: UpdateSessionVariable');
1908                    // Update the temporary client-side session variables
1909                    ClientTempSessionVariables = data
1910
1911                    if (successCallback)
1912                        successCallback(data, textStatus, jqXHR);
1913                },
1914                error: function (jqXHR, textStatus, errorThrown) {
1915                    if (errorCallback)
1916                        errorCallback(jqXHR, textStatus, errorThrown);
1917                }
1918            });
1919        }
1920    }
1921}
1922
1923function GetSessionVariable(variableName, forceServerGet, successCallback, errorCallback) {
1924    if (UseLocalStorage) {
1925        if (successCallback)
1926            successCallback($.jStorage.get(variableName));
1927        else
1928            return $.jStorage.get(variableName);
1929    }
1930    else {
1931        // If we need to force a refresh or the variable doesn't exist in the jQuery temp ClientTempSessionVariables store, then refresh it
1932        if (forceServerGet || ClientTempSessionVariables === null || ClientTempSessionVariables === undefined || ClientTempSessionVariables[variableName] === null || ClientTempSessionVariables[variableName] === undefined) {
1933            var reqUrl = ''
1934            if (typeof baseURL != 'undefined')
1935                reqUrl = baseURL;
1936            reqUrl += "/session/GetVariables";
1937
1938            $.ajax({
1939                url: reqUrl,
1940                type: "POST",
1941                cache: false,
1942                async: true,
1943                timeout: 5000,
1944                dataType: "json",
1945                xhrFields: { withCredentials: true },
1946                crossDomain: true,
1947                success: function (data, textStatus, jqXHR) {
1948                    checkAndRedirectForAjaxError(jqXHR, false, 'Global.js: GetSessionVariable');
1949                    ClientTempSessionVariables = data;
1950                    // Return the value if it exists
1951                    if (ClientTempSessionVariables !== null && ClientTempSessionVariables !== undefined && ClientTempSessionVariables[variableName] !== undefined) { // Allow this to return a null value as it is valid
1952                        if (successCallback)
1953                            successCallback(ClientTempSessionVariables[variableName], data, textStatus, jqXHR);
1954                    }
1955                    else {
1956                        if (errorCallback)
1957                            errorCallback(jqXHR, textStatus);
1958                    }
1959                },
1960                error: function (jqXHR, textStatus, errorThrown) {
1961                    if (errorCallback)
1962                        errorCallback(jqXHR, textStatus, errorThrown);
1963                }
1964            });
1965        }
1966        else {
1967            // Return the value if it exists
1968            if (successCallback)
1969                successCallback(ClientTempSessionVariables[variableName]);
1970        }
1971    }
1972}
1973
1974/* - Continue Shopping Methods - */
1975function UpdateContinueShopping(shoppableUrl) {
1976    var newValue;
1977
1978    if (typeof shoppableUrl != "undefined")
1979        newValue = shoppableUrl;
1980    else
1981        newValue = window.location.href;
1982
1983    // Check the current value and update it if the values are different
1984    GetSessionVariable(
1985        "ContinueShopping",
1986        false,
1987        function (UrlReturned) { // SUCCESS CALLBACK
1988            var allowUpdate = true;
1989
1990            // Don't bother re-adding it if it was the last one to be added
1991            if (UrlReturned != null && UrlReturned != undefined && UrlReturned == newValue) {
1992                allowUpdate = false;
1993            }
1994
1995            if (allowUpdate) {
1996            	UpdateContinueShoppingAndShoppingHistory(newValue);
1997            }
1998        },
1999        function () { // ERROR CALLBACK
2000            // Just update it anyway on error (there is an issue with the Get, so Setting it is safer than ignoring it)
2001            UpdateContinueShoppingAndShoppingHistory(newValue);
2002        }
2003    );
2004}
2005
2006function UpdateContinueShoppingAndShoppingHistory(newValue) {
2007    UpdateSessionVariable('ContinueShopping', newValue);
2008
2009    // If we are using LocalStorage, then we need to manually update the ShoppingHistory too 
2010    // Note this is replicating server-side logic that is in place in the non-LocalStorage version of this method
2011    if (UseLocalStorage) {
2012        GetSessionVariable(
2013            "ShoppingHistory",
2014            false,
2015            function (returnedHistory) {
2016                var tempHistory = [];
2017                if (returnedHistory !== null) {
2018                    tempHistory = returnedHistory;
2019                }
2020                tempHistory.push(newValue);
2021
2022                // We only want to keep a small history, so get rid of the first item
2023                if (tempHistory.length > 2)
2024                    tempHistory.shift();
2025
2026                UpdateSessionVariable("ShoppingHistory", tempHistory);
2027            }
2028        );
2029    }
2030
2031}
2032
2033function ContinueShopping(boolSuppressTransition) {
2034
2035    // Try to get hold of the Continue Shopping Session Variable, if it doesn't exist, then take the user to the homepage
2036
2037    var suppressTransition = true;
2038    if (boolSuppressTransition != undefined)
2039        suppressTransition = boolSuppressTransition;
2040
2041    // Default to the Base Url if it is available, otherwise default it to the root
2042    var urlToLoad = '/';
2043    if (typeof siteBaseUrl != 'undefined') {
2044        urlToLoad = siteBaseUrl;
2045    }
2046
2047    GetSessionVariable(
2048        "ContinueShopping",
2049        false,
2050        function (UrlReturned) { // SUCCESS CALLBACK
2051
2052            if (UrlReturned != null && UrlReturned != undefined)
2053                urlToLoad = UrlReturned;
2054            LoadContinueShoppingUrl(urlToLoad, suppressTransition)
2055        },
2056        function () { // ERROR CALLBACK
2057            LoadContinueShoppingUrl(urlToLoad, suppressTransition)
2058        }
2059    );
2060}
2061
2062function LoadContinueShoppingUrl(urlToLoad, suppressTransition) {
2063    // Check whether the path is going to load up in HTTPS and force it to load in HTTP
2064    if (urlToLoad.indexOf('http:') < 0) {
2065        // First check whether this is an absolute path in HTTPS
2066        if (urlToLoad.indexOf('https:') == 0) {
2067            if (typeof siteBaseUrl != 'undefined') {
2068                var fullUrlToLoad = new UrlHelper(urlToLoad);
2069                urlToLoad = siteBaseUrl + fullUrlToLoad.Path() + fullUrlToLoad.Query() + fullUrlToLoad.Hash();
2070            }
2071            else
2072                urlToLoad = 'http' + urlToLoad.substring(5);
2073        }
2074        // Otherwise, it must be a relative path, so check if we are in HTTPS and change it accordingly
2075        else if (window.location.protocol === 'https:') {
2076            if (typeof siteBaseUrl != 'undefined')
2077                urlToLoad = siteBaseUrl + urlToLoad;
2078            else {
2079                var fullUrlToLoad = new UrlHelper(urlToLoad);
2080                fullUrlToLoad.Protocol('http:');
2081                urlToLoad = fullUrlToLoad.FullUrl();
2082            }
2083        }
2084    }
2085
2086    if (NextBasket
2087        && NextBasket.Data
2088        && NextBasket.Data.FromLabelWebsite) {
2089        urlToLoad = "/transfer/out/label";
2090    }
2091
2092    if (suppressTransition)
2093        window.location = urlToLoad;
2094    else
2095        LoadHTMLContent(urlToLoad);
2096}
2097
2098function ShopMore() {
2099    ContinueShopping(true);
2100    return false;
2101}
2102
2103
2104/* - General Helpers - */
2105function UrlHelper(urlToProcess) {
2106    this._protocol = '',
2107        this._host = '',
2108        this._port = '',
2109        this._path = '',
2110        this._query = '',
2111        this._hash = '';
2112    this._rawUrl = '';
2113
2114    if (urlToProcess != undefined) {
2115        var urlLeftToProcess = urlToProcess;
2116        var indexTemp = 0;
2117
2118        this._rawUrl = urlLeftToProcess;
2119
2120        // Protocol & Host
2121
2122        if (urlLeftToProcess.substring(0, 4) == 'http') {
2123            var slashSplit = urlLeftToProcess.split('/');
2124            this._protocol = slashSplit[0];
2125            this._host = slashSplit[2].split(':')[0].split('?')[0].split('#')[0];
2126            if (slashSplit[2].split(':').length > 1)
2127                this._port = slashSplit[2].split(':')[1].split('?')[0].split('#')[0];
2128            urlLeftToProcess = urlLeftToProcess.substring(this._protocol.length + 2 + this._host.length + 1 + this._port.length);
2129        }
2130
2131        if (urlLeftToProcess.substring(0, 1) == '/')
2132            urlLeftToProcess = urlLeftToProcess.substring(1);
2133
2134        // Path
2135
2136        indexTemp = urlLeftToProcess.indexOf('?');
2137        if (indexTemp > 0) {
2138            this._path = urlLeftToProcess.substring(0, indexTemp);
2139            urlLeftToProcess = urlLeftToProcess.substring(indexTemp);
2140        }
2141        else {
2142            indexTemp = urlLeftToProcess.indexOf('#');
2143            if (indexTemp > 0) {
2144                this._path = urlLeftToProcess.substring(0, indexTemp);
2145                urlLeftToProcess = urlLeftToProcess.substring(indexTemp);
2146            }
2147            else {
2148                this._path = urlLeftToProcess;
2149                urlLeftToProcess = '';
2150            }
2151        }
2152
2153        if (urlLeftToProcess.substring(0, 1) == '?')
2154            urlLeftToProcess = urlLeftToProcess.substring(1);
2155
2156        // Query & Hash
2157
2158        indexTemp = urlLeftToProcess.indexOf('#');
2159        if (indexTemp > 0) {
2160            this._query = urlLeftToProcess.substring(0, indexTemp);
2161            urlLeftToProcess = urlLeftToProcess.substring(indexTemp);
2162            if (urlLeftToProcess.substring(0, 1) == '#')
2163                this._hash = urlLeftToProcess.substring(1);
2164            urlLeftToProcess = '';
2165        }
2166        else {
2167            this._query = urlLeftToProcess;
2168            urlLeftToProcess = '';
2169        }
2170
2171
2172    }
2173
2174    this.Protocol = function (newval) {
2175        if (newval == undefined) {
2176            if (this._protocol == '')
2177                return window.location.protocol + '//';
2178            else
2179                return this._protocol + '//';
2180        }
2181        else {
2182            this._protocol = newval;
2183        }
2184    }
2185
2186    this.Host = function (newval) {
2187        if (newval == undefined) {
2188            if (this._host == '')
2189                return window.location.hostname;
2190            else
2191                return this._host;
2192        }
2193        else {
2194            this._host = newval;
2195        }
2196    }
2197
2198    this.Port = function (newval) {
2199        if (newval == undefined) {
2200            if (this._port == '') {
2201                if (window.location.port == '')
2202                    return '';
2203                else
2204                    return ':' + window.location.port;
2205            }
2206            else
2207                return ':' + this._port;
2208        }
2209        else {
2210            this._port = newval;
2211        }
2212    }
2213
2214    this.Path = function (newval) {
2215        if (newval == undefined) {
2216            if (this._path == '')
2217                return '';
2218            else
2219                return '/' + this._path;
2220        }
2221        else {
2222            this._path = newval;
2223        }
2224    }
2225
2226    this.Query = function (newval) {
2227        if (newval == undefined) {
2228            if (this._query == '')
2229                return '';
2230            else
2231                return '?' + this._query;
2232        }
2233        else {
2234            this._query = newval;
2235        }
2236    }
2237
2238    this.Hash = function (newval) {
2239        if (newval == undefined) {
2240            if (this._hash == '')
2241                return '';
2242            else
2243                return '#' + this._hash;
2244        }
2245        else {
2246            this._hash = newval;
2247        }
2248    }
2249
2250    this.FullUrl = function () {
2251        return this.Protocol() + this.Host() + this.Port() + this.Path() + this.Query() + this.Hash();
2252    }
2253
2254    this.ServerUrl = function () {
2255        return this.Protocol() + this.Host() + this.Port() + this.Path() + this.Query();
2256    }
2257
2258    this.AddQueryParam = function (name, value) {
2259        this._query += '&' + name + '=' + value;
2260    }
2261}
2262
2263function GetQueryStringValue(name) {
2264    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
2265    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
2266        results = regex.exec(location.search);
2267    return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
2268}
2269
2270function ConsoleLog(obj) {
2271    if (window.console && console.log) {
2272        console.log(obj);
2273    }
2274}
2275
2276function ScrollToPoint(scrollPoint) {
2277    if (scrollPoint != 'undefined' && scrollPoint != null && (parseInt(scrollPoint) > 100))
2278        $('html, body').animate({ scrollTop: scrollPoint }, 400);
2279}
2280
2281// Check's if an 500 error has occurred during an AJAX call and if so to track it and redirect the user to a friendly error page
2282function checkAndRedirectForAjaxError(jqXHR, initGaAccount, label) {
2283    if (jqXHR.getResponseHeader('X-Error500Initiated') == 'True') {
2284        if (initGaAccount == true) {
2285            GoogleAnalytics(GAAccount);
2286        }
2287        TrackGAEvent('500 AJAX - Internal Server Error', jqXHR.getResponseHeader('X-Error500Message'), label);
2288
2289        var RedirectError = false;
2290
2291        if (RedirectError) {
2292            // Redirect to the error page if we are not on an error page
2293            if (window.location.href.indexOf('error') === -1 || isErrorPage == false) {
2294                window.location = '/error';
2295            }
2296        }
2297        else {
2298
2299            var errorDom = $(jqXHR.responseText);
2300            $('.CurrentContent').html(errorDom.find('.CurrentContent').html()).addClass('dynamicLoadError');
2301
2302            // Execute the JavaScript in the the Error Page response
2303            errorDom.filter('script').each(function () {
2304                if (this.className != "monetate-tag") {
2305                    $.globalEval(this.text || this.textContent || this.innerHTML || '');
2306                }
2307            });
2308
2309            resizeContentArea();
2310        }
2311    }
2312}
2313
2314function SetupFallbackForChannelisedLegalWarningLogos() {
2315    $(".channelisedLegalWarningLogo").on('error', function () {
2316
2317        if (Next.Settings.Channel.CountryCode === "GB") {
2318            $(this).closest('p').remove();
2319        }
2320        else {
2321            var nextSpacerRow = $(this).closest('tr').next('tr.lwTableSpacingRow');
2322            var prevSpacerRow = $(this).closest('tr').prev('tr.lwTableSpacingRow');
2323            var lwTable = $(this).closest('table');
2324            var lwTableRowCount = lwTable.find('tr').length;
2325
2326            if (lwTableRowCount === 1) {
2327                lwTable.remove();
2328            } else {
2329                if (nextSpacerRow.html()) {
2330                    nextSpacerRow.remove();
2331                } else if (prevSpacerRow.html()) {
2332                    prevSpacerRow.remove();
2333                }
2334
2335                $(this).closest('tr').remove();
2336            }
2337        }
2338        $(this).unbind('error');
2339    });
2340
2341    
2342    if (jqueryUpgradeEnabledOnPage) {
2343        $(".channelisedLegalWarningLogo").on("load", function () {
2344            $(".legalWarningLogos").show();
2345        });
2346
2347    } else {
2348        $(".channelisedLegalWarningLogo").load(function () {
2349            $(".legalWarningLogos").show();
2350        });
2351
2352    }
2353}
2354
2355function AddLegalWarningLogoImage(styleCopy, url, imageName, imageDesc) {
2356
2357    var $legalWarningLogos = styleCopy.find("#legalWarningLogos");
2358
2359    // check to see if the image has already been added...   
2360    var $img = $legalWarningLogos.find("img[src$='" + url + "'][class='channelisedLegalWarningLogo']");
2361
2362    if ($img.length === 0) {
2363        $legalWarningLogos.append("<p><img class=\"channelisedLegalWarningLogo\" src='" + url + "' alt='" + imageName + "' />" + imageDesc + "</p>");
2364    }
2365}
2366
2367function SetupFallbackForChannelisedLogos() {
2368    $(".channelisedLogo").on('error', function () {
2369        $(this).closest('tr').remove();
2370        $(this).unbind('error');
2371    });
2372
2373    $(".channelisedLogo").on("load", function () {
2374        $(".logos").show();
2375    });
2376}
2377
2378function AddLogoImage(styleCopy, URL, imageName, imageDesc) {
2379
2380    $logos = styleCopy.find("#logos");
2381    $logosTable = $logos.find("table");
2382
2383    // check to see if the image has already been added...   
2384    $img = $logosTable.find("img[src$='" + URL + "'][class='channelisedLogo']");
2385
2386    if ($img.length == 0) {
2387        $logosTable.append("<tr><td class='img'><img class=\"channelisedLogo\" src='" + URL + "' alt='" + imageName + "' /></td><td><div class='description'>" + imageDesc + "</div></td></tr>");
2388    }
2389}
2390
2391function LoadGomezScripts() {
2392    if (GomezEnabled) {
2393        // Create a gomez variable that will be used once the script has loaded
2394        if (GomezPageTagEnabled && pageLoadStart && GomezPageId) {
2395            gomez = { gs: pageLoadStart, acctId: 'FDA173', pgId: GomezPageId, grpId: 'Vision' };
2396            if (typeof (GomezGroupId2) == 'string') {
2397                gomez.grpId2 = GomezGroupId2;
2398            }
2399        }
2400
2401        // UNCOMMENT BELOW FOR GOMEZ DEBUG LOGGING
2402        /*
2403        // Log whatever detail we have
2404        ConsoleLog("Loading Gomez Tag...");
2405        ConsoleLog(gomez);
2406
2407        // Log the time to load so far
2408        var timeToLoad = new Date().getTime();
2409        timeToLoad = timeToLoad - pageLoadStart;
2410        ConsoleLog("Time To Load So Far: " + timeToLoad)
2411        */
2412
2413        // Append the gomez script to the page - if we do this any earlier than the footer or doc ready, then we may not have enough params from the page to load the tag
2414        var docHeadID = document.getElementsByTagName("head")[0];
2415        var newGomezScript = document.createElement('script');
2416        newGomezScript.type = 'text/javascript';
2417        newGomezScript.src = siteAssetsUrl + '/Scripts/Gomez.js?v1';
2418        docHeadID.appendChild(newGomezScript);
2419    }
2420}
2421
2422function GoBackOrClose() {
2423    var canGoBack = false;
2424    var ua = navigator.userAgent || navigator.vendor || window.opera;
2425
2426    if (Next.Settings.UI.IsSocialPLPEnabled && ((ua.indexOf("FBAN") > -1) || (ua.indexOf("FBAV") > -1))) {
2427        if (window.location.href.indexOf('frm_sclp') > -1) {
2428            var __sclPlpUrl = window.location.href.split('#')[0] + '?frm_sclp';
2429            location.replace(__sclPlpUrl);
2430
2431            return;
2432        }
2433    }
2434
2435    $(window).on('beforeunload', function () {
2436        canGoBack = true;
2437    });
2438
2439    window.history.back();
2440
2441    window.setTimeout(function () {
2442        if (!canGoBack) { window.close(); }
2443    }, 200);
2444
2445}
2446
2447/*
2448* ----------------------------- JSTORAGE -------------------------------------
2449* Simple local storage wrapper to save data on the browser side, supporting
2450* all major browsers - IE6+, Firefox2+, Safari4+, Chrome4+ and Opera 10.5+
2451*
2452* Copyright (c) 2010 Andris Reinman, [email protected]
2453* Project homepage: www.jstorage.info
2454*
2455* Licensed under MIT-style license:
2456*
2457* Permission is hereby granted, free of charge, to any person obtaining a copy
2458* of this software and associated documentation files (the "Software"), to deal
2459* in the Software without restriction, including without limitation the rights
2460* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2461* copies of the Software, and to permit persons to whom the Software is
2462* furnished to do so, subject to the following conditions:
2463*
2464* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2465* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2466* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2467* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2468* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2469* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2470* SOFTWARE.
2471*/
2472
2473/**
2474* $.jStorage
2475*
2476* USAGE:
2477*
2478* jStorage requires Prototype, MooTools or jQuery! If jQuery is used, then
2479* jQuery-JSON (http://code.google.com/p/jquery-json/) is also needed.
2480* (jQuery-JSON needs to be loaded BEFORE jStorage!)
2481*
2482* Methods:
2483*
2484* -set(key, value[, options])
2485* $.jStorage.set(key, value) -> saves a value
2486*
2487* -get(key[, default])
2488* value = $.jStorage.get(key [, default]) ->
2489*    retrieves value if key exists, or default if it doesn't
2490*
2491* -deleteKey(key)
2492* $.jStorage.deleteKey(key) -> removes a key from the storage
2493*
2494* -flush()
2495* $.jStorage.flush() -> clears the cache
2496*
2497* -storageObj()
2498* $.jStorage.storageObj() -> returns a read-ony copy of the actual storage
2499*
2500* -storageSize()
2501* $.jStorage.storageSize() -> returns the size of the storage in bytes
2502*
2503* -index()
2504* $.jStorage.index() -> returns the used keys as an array
2505*
2506* -storageAvailable()
2507* $.jStorage.storageAvailable() -> returns true if storage is available
2508*
2509* -reInit()
2510* $.jStorage.reInit() -> reloads the data from browser storage
2511*
2512* <value> can be any JSON-able value, including objects and arrays.
2513*
2514**/
2515
2516(function ($) {
2517    if (!$ || !($.toJSON || Object.toJSON || window.JSON)) {
2518        throw new Error("jQuery, MooTools or Prototype needs to be loaded before jStorage!");
2519    }
2520
2521    var
2522        /* This is the object, that holds the cached values */
2523        _storage = {},
2524
2525        /* Actual browser storage (localStorage or globalStorage['domain']) */
2526        _storage_service = { jStorage: "{}" },
2527
2528        /* DOM element for older IE versions, holds userData behavior */
2529        _storage_elm = null,
2530
2531        /* How much space does the storage take */
2532        _storage_size = 0,
2533
2534        /* function to encode objects to JSON strings */
2535        json_encode = $.toJSON || Object.toJSON || (window.JSON && (JSON.encode || JSON.stringify)),
2536
2537        /* function to decode objects from JSON strings */
2538        json_decode = $.evalJSON || (window.JSON && (JSON.decode || JSON.parse)) || function (str) {
2539            return String(str).evalJSON();
2540        },
2541
2542        /* which backend is currently used */
2543        _backend = false,
2544
2545        /* Next check for TTL */
2546        _ttl_timeout,
2547
2548        /**
2549        * XML encoding and decoding as XML nodes can't be JSON'ized
2550        * XML nodes are encoded and decoded if the node is the value to be saved
2551        * but not if it's as a property of another object
2552        * Eg. -
2553        *   $.jStorage.set("key", xmlNode);        // IS OK
2554        *   $.jStorage.set("key", {xml: xmlNode}); // NOT OK
2555        */
2556        _XMLService = {
2557
2558            /**
2559            * Validates a XML node to be XML
2560            * based on jQuery.isXML function
2561            */
2562            isXML: function (elm) {
2563                var documentElement = (elm ? elm.ownerDocument || elm : 0).documentElement;
2564                return documentElement ? documentElement.nodeName !== "HTML" : false;
2565            },
2566
2567            /**
2568            * Encodes a XML node to string
2569            * based on http://www.mercurytide.co.uk/news/article/issues-when-working-ajax/
2570            */
2571            encode: function (xmlNode) {
2572                if (!this.isXML(xmlNode)) {
2573                    return false;
2574                }
2575                try { // Mozilla, Webkit, Opera
2576                    return new XMLSerializer().serializeToString(xmlNode);
2577                } catch (E1) {
2578                    try {  // IE
2579                        return xmlNode.xml;
2580                    } catch (E2) { }
2581                }
2582                return false;
2583            },
2584
2585            /**
2586            * Decodes a XML node from string
2587            * loosely based on http://outwestmedia.com/jquery-plugins/xmldom/
2588            */
2589            decode: function (xmlString) {
2590                var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) ||
2591                    (window.ActiveXObject && function (_xmlString) {
2592                        var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
2593                        xml_doc.async = 'false';
2594                        xml_doc.loadXML(_xmlString);
2595                        return xml_doc;
2596                    }),
2597                    resultXML;
2598                if (!dom_parser) {
2599                    return false;
2600                }
2601                resultXML = dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml');
2602                return this.isXML(resultXML) ? resultXML : false;
2603            }
2604        };
2605
2606    ////////////////////////// PRIVATE METHODS ////////////////////////
2607
2608    /**
2609    * Initialization function. Detects if the browser supports DOM Storage
2610    * or userData behavior and behaves accordingly.
2611    * @returns undefined
2612    */
2613    function _init() {
2614        /* Check if browser supports localStorage */
2615        var localStorageReallyWorks = false;
2616        if ("localStorage" in window) {
2617            try {
2618                window.localStorage.setItem('_tmptest', 'tmpval');
2619                localStorageReallyWorks = true;
2620                window.localStorage.removeItem('_tmptest');
2621            } catch (BogusQuotaExceededErrorOnIos5) {
2622                // Thanks be to iOS5 Private Browsing mode which throws
2623                // QUOTA_EXCEEDED_ERRROR DOM Exception 22.
2624            }
2625        }
2626        if (localStorageReallyWorks) {
2627            try {
2628                if (window.localStorage) {
2629                    _storage_service = window.localStorage;
2630                    _backend = "localStorage";
2631                }
2632            } catch (E3) { /* Firefox fails when touching localStorage and cookies are disabled */ }
2633        }
2634        /* Check if browser supports globalStorage */
2635        else if ("globalStorage" in window) {
2636            try {
2637                if (window.globalStorage) {
2638                    _storage_service = window.globalStorage[window.location.hostname];
2639                    _backend = "globalStorage";
2640                }
2641            } catch (E4) { /* Firefox fails when touching localStorage and cookies are disabled */ }
2642        }
2643        /* Check if browser supports userData behavior */
2644        else {
2645            _storage_elm = document.createElement('link');
2646            if (_storage_elm.addBehavior) {
2647
2648                /* Use a DOM element to act as userData storage */
2649                _storage_elm.style.behavior = 'url(#default#userData)';
2650
2651                /* userData element needs to be inserted into the DOM! */
2652                document.getElementsByTagName('head')[0].appendChild(_storage_elm);
2653
2654                _storage_elm.load("jStorage");
2655                var data = "{}";
2656                try {
2657                    data = _storage_elm.getAttribute("jStorage");
2658                } catch (E5) { }
2659                _storage_service.jStorage = data;
2660                _backend = "userDataBehavior";
2661            } else {
2662                _storage_elm = null;
2663                return;
2664            }
2665        }
2666
2667        _load_storage();
2668
2669        // remove dead keys
2670        _handleTTL();
2671    }
2672
2673    /**
2674    * Loads the data from the storage based on the supported mechanism
2675    * @returns undefined
2676    */
2677    function _load_storage() {
2678        /* if jStorage string is retrieved, then decode it */
2679        if (_storage_service.jStorage) {
2680            try {
2681                _storage = json_decode(String(_storage_service.jStorage));
2682            } catch (E6) { _storage_service.jStorage = "{}"; }
2683        } else {
2684            _storage_service.jStorage = "{}";
2685        }
2686        _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
2687    }
2688
2689    /**
2690    * This functions provides the "save" mechanism to store the jStorage object
2691    * @returns undefined
2692    */
2693    function _save() {
2694        try {
2695            _storage_service.jStorage = json_encode(_storage);
2696            // If userData is used as the storage engine, additional
2697            if (_storage_elm) {
2698                _storage_elm.setAttribute("jStorage", _storage_service.jStorage);
2699                _storage_elm.save("jStorage");
2700            }
2701            _storage_size = _storage_service.jStorage ? String(_storage_service.jStorage).length : 0;
2702        } catch (E7) { /* probably cache is full, nothing is saved this way*/ }
2703    }
2704
2705    /**
2706    * Function checks if a key is set and is string or numberic
2707    */
2708    function _checkKey(key) {
2709        if (!key || (typeof key != "string" && typeof key != "number")) {
2710            throw new TypeError('Key name must be string or numeric');
2711        }
2712        if (key == "__jstorage_meta") {
2713            throw new TypeError('Reserved key name');
2714        }
2715        return true;
2716    }
2717
2718    /**
2719    * Removes expired keys
2720    */
2721    function _handleTTL() {
2722        var curtime, i, TTL, nextExpire = Infinity, changed = false;
2723
2724        clearTimeout(_ttl_timeout);
2725
2726        if (!_storage.__jstorage_meta || typeof _storage.__jstorage_meta.TTL != "object") {
2727            // nothing to do here
2728            return;
2729        }
2730
2731        curtime = +new Date();
2732        TTL = _storage.__jstorage_meta.TTL;
2733        for (i in TTL) {
2734            if (TTL.hasOwnProperty(i)) {
2735                if (TTL[i] <= curtime) {
2736                    delete TTL[i];
2737                    delete _storage[i];
2738                    changed = true;
2739                } else if (TTL[i] < nextExpire) {
2740                    nextExpire = TTL[i];
2741                }
2742            }
2743        }
2744
2745        // set next check
2746        if (nextExpire != Infinity) {
2747            _ttl_timeout = setTimeout(_handleTTL, nextExpire - curtime);
2748        }
2749
2750        // save changes
2751        if (changed) {
2752            _save();
2753        }
2754    }
2755
2756
2757    ////////////////////////// PUBLIC INTERFACE /////////////////////////
2758
2759    $.jStorage = {
2760        /* Version number */
2761        version: "0.1.7.0",
2762
2763        /**
2764        * Sets a key's value.
2765        *
2766        * @param {String} key - Key to set. If this value is not set or not
2767        *              a string an exception is raised.
2768        * @param {Mixed} value - Value to set. This can be any value that is JSON
2769        *              compatible (Numbers, Strings, Objects etc.).
2770        * @param {Object} [options] - possible options to use
2771        * @param {Number} [options.TTL] - optional TTL value
2772        * @returns the used value
2773        */
2774        set: function (key, value, options) {
2775            _checkKey(key);
2776
2777            options = options || {};
2778
2779            if (_XMLService.isXML(value)) {
2780                value = { _is_xml: true, xml: _XMLService.encode(value) };
2781            } else if (typeof value == "function") {
2782                value = null; // functions can't be saved!
2783            } else if (value && typeof value == "object") {
2784                // clone the object before saving to _storage tree
2785                value = json_decode(json_encode(value));
2786            }
2787            _storage[key] = value;
2788
2789            if (!isNaN(options.TTL)) {
2790                this.setTTL(key, options.TTL);
2791                // also handles saving
2792            } else {
2793                _save();
2794            }
2795            return value;
2796        },
2797
2798        /**
2799        * Looks up a key in cache
2800        *
2801        * @param {String} key - Key to look up.
2802        * @param {mixed} def - Default value to return, if key didn't exist.
2803        * @returns the key value, default value or <null>
2804        */
2805        get: function (key, def) {
2806            _checkKey(key);
2807            if (key in _storage) {
2808                if (_storage[key] && typeof _storage[key] == "object" &&
2809                    _storage[key]._is_xml &&
2810                    _storage[key]._is_xml) {
2811                    return _XMLService.decode(_storage[key].xml);
2812                } else {
2813                    return _storage[key];
2814                }
2815            }
2816            return typeof (def) == 'undefined' ? null : def;
2817        },
2818
2819        /**
2820        * Deletes a key from cache.
2821        *
2822        * @param {String} key - Key to delete.
2823        * @returns true if key existed or false if it didn't
2824        */
2825        deleteKey: function (key) {
2826            _checkKey(key);
2827            if (key in _storage) {
2828                delete _storage[key];
2829                // remove from TTL list
2830                if (_storage.__jstorage_meta &&
2831                    typeof _storage.__jstorage_meta.TTL == "object" &&
2832                    key in _storage.__jstorage_meta.TTL) {
2833                    delete _storage.__jstorage_meta.TTL[key];
2834                }
2835                _save();
2836                return true;
2837            }
2838            return false;
2839        },
2840
2841        /**
2842        * Sets a TTL for a key, or remove it if ttl value is 0 or below
2843        *
2844        * @param {String} key - key to set the TTL for
2845        * @param {Number} ttl - TTL timeout in milliseconds
2846        * @returns true if key existed or false if it didn't
2847        */
2848        setTTL: function (key, ttl) {
2849            var curtime = +new Date();
2850            _checkKey(key);
2851            ttl = Number(ttl) || 0;
2852            if (key in _storage) {
2853
2854                if (!_storage.__jstorage_meta) {
2855                    _storage.__jstorage_meta = {};
2856                }
2857                if (!_storage.__jstorage_meta.TTL) {
2858                    _storage.__jstorage_meta.TTL = {};
2859                }
2860
2861                // Set TTL value for the key
2862                if (ttl > 0) {
2863                    _storage.__jstorage_meta.TTL[key] = curtime + ttl;
2864                } else {
2865                    delete _storage.__jstorage_meta.TTL[key];
2866                }
2867
2868                _save();
2869
2870                _handleTTL();
2871                return true;
2872            }
2873            return false;
2874        },
2875
2876        /**
2877        * Deletes everything in cache.
2878        *
2879        * @return true
2880        */
2881        flush: function () {
2882            _storage = {};
2883            _save();
2884            return true;
2885        },
2886
2887        /**
2888        * Returns a read-only copy of _storage
2889        *
2890        * @returns Object
2891        */
2892        storageObj: function () {
2893            function F() { }
2894            F.prototype = _storage;
2895            return new F();
2896        },
2897
2898        /**
2899        * Returns an index of all used keys as an array
2900        * ['key1', 'key2',..'keyN']
2901        *
2902        * @returns Array
2903        */
2904        index: function () {
2905            var index = [], i;
2906            for (i in _storage) {
2907                if (_storage.hasOwnProperty(i) && i != "__jstorage_meta") {
2908                    index.push(i);
2909                }
2910            }
2911            return index;
2912        },
2913
2914        /**
2915        * How much space in bytes does the storage take?
2916        *
2917        * @returns Number
2918        */
2919        storageSize: function () {
2920            return _storage_size;
2921        },
2922
2923        /**
2924        * Which backend is currently in use?
2925        *
2926        * @returns String
2927        */
2928        currentBackend: function () {
2929            return _backend;
2930        },
2931
2932        /**
2933        * Test if storage is available
2934        *
2935        * @returns Boolean
2936        */
2937        storageAvailable: function () {
2938            return !!_backend;
2939        },
2940
2941        /**
2942        * Reloads the data from browser storage
2943        *
2944        * @returns undefined
2945        */
2946        reInit: function () {
2947            var new_storage_elm, data;
2948            if (_storage_elm && _storage_elm.addBehavior) {
2949                new_storage_elm = document.createElement('link');
2950
2951                _storage_elm.parentNode.replaceChild(new_storage_elm, _storage_elm);
2952                _storage_elm = new_storage_elm;
2953
2954                /* Use a DOM element to act as userData storage */
2955                _storage_elm.style.behavior = 'url(#default#userData)';
2956
2957                /* userData element needs to be inserted into the DOM! */
2958                document.getElementsByTagName('head')[0].appendChild(_storage_elm);
2959
2960                _storage_elm.load("jStorage");
2961                data = "{}";
2962                try {
2963                    data = _storage_elm.getAttribute("jStorage");
2964                } catch (E5) { }
2965                _storage_service.jStorage = data;
2966                _backend = "userDataBehavior";
2967            }
2968
2969            _load_storage();
2970        }
2971    };
2972
2973    // Initialize jStorage
2974    _init();
2975
2976})(window.$ || window.jQuery);
2977
2978
2979// ------- Helper -------------
2980var Helpers = {
2981    RoundToHalf: function (value) {
2982        //<summary>Converts decimal to nearest half value (e.g 4.3=4.5, 5.1=5)</summary>
2983
2984        var converted = parseFloat(value); // Make sure we have a number 
2985        var decimal = (converted - parseInt(converted, 10));
2986        //Set to Math.floor to match value returned by search provider
2987        decimal = Math.floor(decimal * 10);
2988        if (decimal == 5) { return (parseInt(converted, 10) + 0.5); }
2989        if ((decimal < 3) || (decimal > 7)) {
2990            return Math.round(converted);
2991        } else {
2992            return (parseInt(converted, 10) + 0.5);
2993        }
2994    },
2995    FormatDate: function (JavascriptDateTime) {
2996
2997        var dateString = JavascriptDateTime.substring(0, 10);
2998
2999        var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
2999November", "December"]
3000
3001        var dateArr = dateString.split('-');
3002        var year = dateArr[0];
3003
3004        var monthString = dateArr[1];
3005        var monthInt = parseInt(monthString, 10);
3006        var monthIndex = monthInt - 1;
3007
3008        var month = monthNames[monthIndex];
3009        var day = dateArr[2];
3010
3011        var dateJSON =
3012        {
3013            "day": day,
3014            "month": month,
3015            "year": year
3016        }
3017
3018        return dateJSON;
3019    }
3020}
3021
3022// ------- Helper -------------
3023var Helpers = {
3024    RoundToHalf: function (value) {
3025        //<summary>Converts decimal to nearest half value (e.g 4.3=4.5, 5.1=5)</summary>
3026
3027        var converted = parseFloat(value); // Make sure we have a number 
3028        var decimal = (converted - parseInt(converted, 10));
3029
3030        //Set to Math.floor to match value returned by search provider
3031        decimal = Math.floor(decimal * 10);
3032        if (decimal == 5) { return (parseInt(converted, 10) + 0.5); }
3033        if ((decimal < 3) || (decimal > 7)) {
3034            return Math.round(converted);
3035        } else {
3036            return (parseInt(converted, 10) + 0.5);
3037        }
3038    },
3039    FormatDate: function (JavascriptDateTime) {
3040
3041        var dateString = JavascriptDateTime.substring(0, 10);
3042
3043        var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
3043November", "December"]
3044
3045        var dateArr = dateString.split('-');
3046        var year = dateArr[0];
3047
3048        var monthString = dateArr[1];
3049        var monthInt = parseInt(monthString, 10);
3050        var monthIndex = monthInt - 1;
3051
3052        var month = monthNames[monthIndex];
3053        var day = dateArr[2];
3054
3055        var dateJSON =
3056        {
3057            "day": day,
3058            "month": month,
3059            "year": year
3060        }
3061
3062        return dateJSON;
3063
3064    },
3065    FormatCurrencyAndPrice: function (currencySymbol, currencyPosition, price) {
3066        switch (currencyPosition) {
3067            case 'left':
3068                return currencySymbol + price;
3069            case 'right':
3070                return price + currencySymbol;
3071            case 'leftwithspace':
3072                return currencySymbol + ' ' + price;
3073            case 'rightwithspace':
3074                return price + ' ' + currencySymbol;
3075            default:
3076                return currencySymbol + price;
3077        }
3078    }
3079}
3080
3081var GlobalURLHelper = {
3082    SetRedirectUrl: function (url) {
3083
3084        if (url.length < 1) {
3085            return url;
3086        }
3087
3088        var MainSiteAbsolutePath = Next.Settings.Channel.MainSiteAbsolutePath;
3089
3090        //check first character of url
3091        var firstUrlChar = url.charAt(0)
3092
3093        if (firstUrlChar !== '/') {
3094            url = '/' + url;
3095        }
3096
3097        if (MainSiteAbsolutePath == '/') {
3098            return url;
3099
3100        } else
3101            return url = MainSiteAbsolutePath + url;
3102    }
3103}
3104
3105var Button = {
3106    Vars: {
3107        Classes: {
3108            Loading: "loading"
3109        }
3110    },
3111    UpdateUI: function ($btn, settings) {
3112
3113        var _this = this;
3114
3115        if (settings.loading) {
3116
3117            var btnWidth = $btn.width();
3118
3119            $btn.width(btnWidth)
3120                .addClass(_this.Vars.Classes.Loading);
3121        }
3122        else if (settings.loading == false) {
3123
3124            $btn.removeClass(_this.Vars.Classes.Loading)
3125                .css("width", "");
3126        }
3127
3128    }
3129}
3130
3131var Next = Next || {};
3132Next.NextTrial = {
3133    Init: function (trialEnabled) {
3134        this.Vars.TrialEnabled = trialEnabled;
3135        this.Vars.TrialImgPath = "/content/co-uk/images/trial/";
3136        this.Vars.TrialImgAltTxt = "Northern Ireland Only | FREE next day delivery to home on orders over &pound;50&#42;. All deliveries and returns to store are FREE. Returns collected from your home cost &pound;1.99. &#42; Subject to stock, and courier availability. Product exceptions apply see full Terms and Conditions.";
3137        this.Vars.TrialRefundTxt = 'All deliveries and returns to store are free. Returns collected from your home cost &pound;2.50. Subject to stock, and courier availability. Product exceptions apply, see full <a href=\"/terms" target=\"_blank\"><u>Terms and Conditions</u></a>.';
3138        this.Vars.TrialInitialised = true;
3139        this.Vars.TrialCookieName = 'Next-TL';
3140    },
3141
3142    Vars: {
3143        TrialEnabled: null,
3144        TrialImgPath: null,
3145        TrialInitialised: false
3146    },
3147
3148    InitRecursiveCheck: function (f) {
3149        if (!this.Vars.TrialInitialised) {
3150            setTimeout(function () {
3151                f();
3152            }, 600);
3153            return false;
3154        }
3155        else {
3156            return true;
3157        }
3158    },
3159
3160    trackGa: function () {
3161        var _this = this;
3162        var trialId = _this.getTrialCookieKeyValue(_this.Vars.TrialCookieName, 'id');
3163        var urlPath = window.location.pathname.toLowerCase();
3164
3165        if (!Next.NextTrial.InitRecursiveCheck(_this.trackGa)) {
3166            return false;
3167        }
3168
3169        if (_this.getTrialCookie(_this.Vars.TrialCookieName) != null) {
3170            if (urlPath == "/") {
3171                TrackGAEvent('Trial', trialId, 'NI Homepage', 0);
3172            } else if (urlPath == "/shoppingbag") {
3173                TrackGAEvent('Trial', trialId, 'NI Shoppingbag', 0);
3174            } else if (urlPath == "/quickshop") {
3175                TrackGAEvent('Trial', trialId, 'NI Quickshop', 0);
3176            } else if (urlPath == "/delivery/") {
3177                TrackGAEvent('Trial', trialId, 'NI Delivery', 0);
3178            }
3179        }
3180    },
3181
3182
3183    getTrialCookie: function (name) {
3184        var nameEQ = name + "=";
3185        var ca = document.cookie.split(';');
3186        for (var i = 0; i < ca.length; i++) {
3187            var c = ca[i];
3188            while (c.charAt(0) == ' ') c = c.substring(1, c.length);
3189            if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
3190        }
3191        return null;
3192    },
3193
3194    getTrialCookieKeyValue: function (cookieName, keyName) {
3195        var _this = this;
3196        var nextTrialCookie = _this.getTrialCookie(cookieName);
3197        if (nextTrialCookie != null) {
3198            var splitVars = nextTrialCookie.split("&");
3199            for (var i = 0; i < splitVars.length; i++) {
3200                var splitKvp = splitVars[i].split("=");
3201                if (splitKvp != null && splitKvp[0] == keyName)
3202                    return splitKvp[1];
3203            }
3204        }
3205        return null;
3206    },
3207
3208    getTrialHomepage: function () {
3209
3210        var _this = this;
3211        if (window.location.pathname != "/") {
3212            return false;
3213        }
3214
3215        if (!Next.NextTrial.InitRecursiveCheck(_this.getTrialHomepage)) {
3216            return false;
3217        }
3218
3219        if (_this.Vars.TrialEnabled == 'true') {
3220            if (_this.getTrialCookie(_this.Vars.TrialCookieName) != null) {
3221                var trialId = _this.getTrialCookieKeyValue('Next-TL', 'id');
3222                var trialStoreFrontUrl = window.location.href + trialId;
3223
3224                if (trialId != null) {
3225                    $.ajax({
3226                        url: trialStoreFrontUrl,
3227                        timeout: 10000,
3228                        dataType: 'html',
3229                        type: 'GET',
3230                        error: function () { },
3231                        success: function (htmlResponse, textStatus, jqXHR) {
3232                            checkAndRedirectForAjaxError(jqXHR, false, 'global.js: function getTrialHomepage');
3233                            var htmlDataResponse = $(htmlResponse);
3234                            $('.Storefront .Background').replaceWith(htmlDataResponse.find('.Storefront .Background'));
3235                            _this.trackGa();
3236                        },
3237                        complete: function (jqXHR, errorThrown) {
3238                            if (errorThrown == 'timeout') {
3239
3240                            }
3241                        }
3242                    })
3243                }
3244            }
3245        }
3246    },
3247
3248    getTrialShopBanner: function () {
3249        var _this = this;
3250
3251        if (!Next.NextTrial.InitRecursiveCheck(_this.getTrialShopBanner)) {
3252            return false;
3253        }
3254
3255        var trialImgPath = _this.Vars.TrialImgPath;
3256        var trialImgAltTxt = _this.Vars.TrialImgAltTxt;
3257        var shoppingBagImgPath;
3258
3259        var oBanner = $('.ContentArea .trialShopBanner');
3260        if (_this.Vars.TrialEnabled == 'true') {
3261            if (_this.getTrialCookie('Next-TL') != null) {
3262
3263                var trialId = _this.getTrialCookieKeyValue('Next-TL', 'id');
3264                if (trialId != null) {
3265                    if (oBanner.length) {
3266                        shoppingBagImgPath = MainSiteURL + trialImgPath + trialId + '/shop.jpg';
3267                        oBanner.html("<img src='" + shoppingBagImgPath + "' alt='" + trialImgAltTxt + "' />");
3268                        _this.trackGa();
3269                    }
3270                }
3271            }
3272        }
3273    },
3274
3275    getTrialCheckoutBanner: function () {
3276        var _this = this;
3277        var MainSiteURLSecure = window.location.protocol + "//" + window.location.host;
3278
3279        if (!Next.NextTrial.InitRecursiveCheck(_this.getTrialCheckoutBanner)) {
3280            return false;
3281        }
3282
3283        var trialImgPath = _this.Vars.TrialImgPath;
3284        var trialImgAltTxt = _this.Vars.TrialImgAltTxt;
3285        var checkoutImgPath;
3286
3287        var oBanner = $('#deliveryForm .trialCheckoutBanner');
3288        if (_this.Vars.TrialEnabled == 'true') {
3289            if (_this.getTrialCookie('Next-TL') != null) {
3290
3291                var trialId = _this.getTrialCookieKeyValue('Next-TL', 'id');
3292                if (trialId != null) {
3293                    if (oBanner.length) {
3294                        checkoutImgPath = MainSiteURLSecure + trialImgPath + trialId + '/checkout.jpg';
3295                        oBanner.html("<img src='" + checkoutImgPath + "' alt='" + trialImgAltTxt + "' />");
3296                        _this.trackGa();
3297                    }
3298                }
3299            }
3300        }
3301    },
3302
3303    getTrialCheckoutRefundTxt: function () {
3304        var _this = this;
3305
3306        if (!Next.NextTrial.InitRecursiveCheck(_this.getTrialCheckoutRefundTxt)) {
3307            return false;
3308        }
3309
3310        var trialImgPath = _this.Vars.TrialImgPath;
3311        var trialImgAltTxt = _this.Vars.TrialImgAltTxt;
3312        var trialRefundTxt = _this.Vars.TrialRefundTxt;
3313
3314        var oRefundTxt = $('.dBag .trialCheckoutRefundTxt');
3315        if (_this.Vars.TrialEnabled == 'true') {
3316            if (_this.getTrialCookie('Next-TL') != null) {
3317
3318                var trialId = _this.getTrialCookieKeyValue('Next-TL', 'id');
3319                if (trialId != null) {
3320                    if (oRefundTxt.length) {
3321                        oRefundTxt.html(trialRefundTxt);
3322                    }
3323                }
3324            }
3325        }
3326    }
3327}
3328
3329$(function () {
3330    var urlPath = window.location.pathname.toLowerCase();
3331    if (typeof NextTrialEnabled !== "undefined") {
3332        Next.NextTrial.Init(NextTrialEnabled);
3333    }
3334});
3335
3336function isValidDomain(domain) {
3337	return domain.split(".").length > 2;
3338}
3339
3340function getValidDomain() {
3341    var siteUrl = Next.Settings.Channel.SiteUrl;
3342
3343    var domains = ["next"];
3344    var strippedDownUrl = "";
3345
3346    for (var i = 0; i < domains.length; ++i) {
3347        var domainVal = domains[i];
3348        var regex = new RegExp("^.*" + domainVal + "")
3349        strippedDownUrl = (siteUrl.replace(regex, domainVal)).replace(/(?=\/)(.*)/, '');
3350
3351        if (isValidDomain(strippedDownUrl)) {
3352            return strippedDownUrl;
3353        }
3354    }
3355    
3356    return "";
3357}
3358
3359function generateAlternativeCookiePolicy(site, link, showFull) {
3360
3361    var returnString = "";
3362    var cookiePolicyClass = !showFull ? "altCookiePolicySmall" : "";
3363
3364    var isUK = Next.Settings.Channel.CountryCode === 'GB';
3365    var isChildsPlay = site === "Childsplay";
3366    var isFromNext = window.location.href.toLowerCase().indexOf('?fromnext') > 0;
3367    var directToCP = isChildsPlay && !isFromNext ? " cp-direct" : "";
3368
3369    returnString += "<div id='alternativeCookiePolicy' class='col-sm-10 " + cookiePolicyClass + directToCP + "'>";
3370
3371    if (showFull) {
3372        var cookiePolicyHeaderText;
3373        var sectionImg1Class, sectionImg2Class, sectionImg3Class, sectionImg4Class;
3374        var section1Text, section2Text, section3Text, section4Text;
3375        var section1Hide, section2Hide;
3376
3377        sectionImg1Class = "sharedBag";
3378        sectionImg2Class = "nextUnlimited";
3379        sectionImg3Class = "spreadCosts";
3380        sectionImg4Class = "backArrow";
3381
3382        section1Hide = false;
3383        section2Hide = false;
3384
3385        switch (site) {
3386            case "Childsplay":
3387                sectionImg1Class = "luxuryBrands";
3388                sectionImg2Class = "sharedBag";
3389                cookiePolicyHeaderText = "Childsplay Clothing";
3390                section1Text = "Luxury Kids Brands from Moncler to Versace";
3391                section2Text = "Shared Shopping Bag across Next and Childsplay";
3392                section3Text = "Pay Using your Next Pay Account*";
3393                section4Text = "Easily Navigate Back to Next";
3394                section2Hide = !Next.Settings.Channel.StateConvergence.IsEnabled;
3395                break;
3396        }
3397
3398        var sectionHiddenFormatClass = section1Hide || section2Hide ? "sectionHiddenFormat " : "";
3399
3400        returnString += "<div class='altCookiePolicyHeader'>";
3401        if (!isChildsPlay) {
3402            returnString += "<span class='altCookiePolicyHeaderText'>Welcome to <span class='altCookiePolicyHeaderLogo'></span>" + cookiePolicyHeaderText + "</span>";
3403        } else {
3404            returnString += "<span class='altCookiePolicyHeaderText'>Welcome to " + cookiePolicyHeaderText + "</span>";
3405        }
3406        returnString += "<span class='altCookiePolicyClose'></span>";
3407        returnString += "</div>";
3408
3409        returnString += "<div id='altCookiePolicySections'>";
3410        if (!section1Hide) {
3411            returnString += "<div class='" + sectionHiddenFormatClass + "altCookiePolicySection'><span class='altCookiePolicySectionImage " + sectionImg1Class + "'></span><span class='altCookiePolicySectionText'>" + section1Text + "</span></div>";
3412        }
3413        if (!section2Hide) {
3414            returnString += "<div class='" + sectionHiddenFormatClass + "altCookiePolicySection'><span class='altCookiePolicySectionImage " + sectionImg2Class + "'></span><span class='altCookiePolicySectionText'>" + section2Text + "</span></div>";
3415        }
3416
3417        returnString += "<div class='" + sectionHiddenFormatClass + "altCookiePolicySection'><span class='altCookiePolicySectionImage " + sectionImg3Class + "'></span><span class='altCookiePolicySectionText'>" + section3Text + "</span></div>";
3418        returnString += "<div class='" + sectionHiddenFormatClass + "altCookiePolicySection'><span class='altCookiePolicySectionImage " + sectionImg4Class + "'></span><span class='altCookiePolicySectionText'>" + section4Text + "</span></div>";
3419
3420        returnString += "</div>";
3421    }
3422  
3423    returnString += "<div id='altCookiePolicyLegal'" + (isChildsPlay && isFromNext ? " class='from-next'" : "") + ">";
3424
3425    if (!isChildsPlay || (isChildsPlay && isFromNext && isUK)) {
3426        returnString += "<span class='altCookieNextPayTerms'>*29.9% APR Representative Variable. Credit subject to status.</span>";
3427    }
3428
3429    returnString += " We use cookies to provide you with the best possible experience. By continuing to use our site, you agree to our use of cookies. <a href='" + link + "' target='_blank'>Find out more</a> about managing your cookie settings.<span class='altCookiePolicyClose'></span></div>"
3430
3431
3432    returnString += "</div>";
3433
3434    return returnString;
3435}
3436
3437$(document).ready(function () {
3438    //Moved before userConsentManagementEnabled check.
3439    if (!Next.Settings.Channel.PlatModGoogleAnalyticsSDK) {
3440        $('#platform_modernisation_header').on('click',
3441            'a,\
3442         button,\
3443         [data-testid="header-small-screen-search"]>[role="link"],\
3444         [data-testid="country-selector-select-menu"] li',
3445            function () {
3446                if (currentKey) {
3447                    currentKey = null
3448                    return
3449                }
3450
3451                var $this = $(this)
3452                var testId = $this.data("testid")
3453                if (testId &&
3454                    (testId == "header-search-bar-clear-text-button" ||
3455                        testId == "header-search-bar-button")) {
3456                    var variant2 = $this.closest('[data-testid$="screen-search"]').find('[data-testid="header-search-bar-text-input"]').val();
3457                    TrackPlatModLinkID($this, null, variant2)
3458                    return
3459                }
3460
3461                TrackPlatModLinkID($this);
3462            }
3463        );
3464
3465        $('#platform_modernisation_header').on('keypress', '.header-adaptive-search form [data-testid="header-search-bar-text-input"]', function (e) {
3466            if (e.which == 13) {
3467                currentKey = 13
3468                var $this = $(this)
3469                TrackPlatModLinkID($this, null, $this.val(), $this.data('ga-enter-event'));
3470            }
3471        });
3472    }
3473
3474    if (!Next.Settings.Channel.EnableModernisedConsentCookie) {
3475        var enabled = "true"; // Toggle for UK channels only
3476        if (Next.Settings.Channel.CountryCode !== 'GB') eraseCookie('NextConsentCookie');// This deletes the UK Consent Cookie if an International customer has it.
3477        var siteUrl = Next.Settings.Channel.SiteUrl;
3478        var nextConsentCookie = (Next.Settings.Channel.CountryCode === 'GB') ? readCookie('NextConsentCookie') : readCookie('NextDirectConsentCookie');
3479        var aLink = (Next.Settings.Channel.CountryCode === 'GB') ? siteUrl + "/privacy" : siteUrl + "/privacypolicy";
3480        var ukChannels = Next.Settings.Channel.ChannelId === "NEXT_GB" || Next.Settings.Channel.ChannelId === "NXTA_GB" || Next.Settings.Channel.ChannelId === "NXTB_GB" || Next.Settings.Channel.ChannelId === "NXTD_GB";
3481        var fromNextCookieName = Next.Settings.Cookie.BackToNextCookieName;
3482        var isFromNext = readCookie(fromNextCookieName) === "True";
3483        var isChildsPlay = Next.Settings.Channel.ChannelTheme === "Childsplay";
3484        var userConsentManagementEnabled = Next.Settings.Channel.UserConsentManagement.Enabled;
3485
3486        if (userConsentManagementEnabled === true) {
3487            return;
3488        }
3489        else if ((enabled == "true" && ukChannels) || Next.Settings.UI.CookiePolicyPopup) {
3490            if (nextConsentCookie == null) {
3491                var cookiePopUp = "";
3492                if (Next.Settings.Channel.EnableAltCookiePolicy) {
3493                    if (isFromNext || isChildsPlay) {
3494                        cookiePopUp = generateAlternativeCookiePolicy(Next.Settings.Channel.ChannelTheme, aLink, true);
3495                    } else {
3496                        cookiePopUp = generateAlternativeCookiePolicy(Next.Settings.Channel.ChannelTheme, aLink, false);
3497                    }
3498
3499                } else {
3500                    cookiePopUp = '<div class="CookieConsent hide-in-app-mode"><p style="font-weight:600">' + nxt.jstranslations.cookiepolicy.header + '</p><div class="CookieConsentCross"></div><p>' + nxt.jstranslations.cookiepolicy.messagebody1 + ' <br/> <a id="aFindOutMore" href="' + aLink + '" target="_blank" style="text-decoration:underline">' + nxt.jstranslations.cookiepolicy.messagebody2 + '</a> ' + nxt.jstranslations.cookiepolicy.messagebody3 + '</p ></div > ';
3501                }
3502                $("body").append(cookiePopUp);
3503
3504                var d = new Date();
3505                d.setTime(d.getTime() + (365 * 24 * 60 * 60 * 1000)); //1 years expiry time
3506                var expires = "expires=" + d.toUTCString();
3507                var domain = getValidDomain(); // strip URL down to just next domain e.g. https://account.next.de/de -> .next.de
3508                // If domain computed is not correct just use the configured domain
3509                if (!isValidDomain(domain)) {
3510                    domain = Next.Settings.Channel.CookieDomainName;
3511                }
3512                var cookieData = (Next.Settings.Channel.CountryCode === 'GB') ? "NextConsentCookie=" : "NextDirectConsentCookie=";
3513                cookieData += "AllowCookiesFromNext=True;path=/;" + expires + ";domain=" + domain;
3514                document.cookie = cookieData;
3515            }
3516        }
3517
3518        $('.CookieConsent').on("click", function (event) {
3519            if (event.target.toString() != aLink) {
3520
3521                $('.CookieConsent').hide();
3522            }
3523        });
3524        $('.altCookiePolicyClose').on("click", function (e) {
3525            $("#alternativeCookiePolicy").hide();
3526        })
3527    }
3528});
3529;
3530//define a global namespace for nxt - this will be used in all js file requiring translation.
3531var nxt = window.nxt || {};
3532
3533(function ($, nx) {   
3534
3535    /*
3536     * formats a JS string using string interpolation similar to string.Format in .Net
3537     * Usage:
3538     * var param1 = 3;
3539     * var param2 = "shopping bag";
3540     * var message = nxt.stringFormat("You have {0} items in your {1}", param1, param2);
3541     */    
3542    nx.stringFormat = function (string) {
3543        var args = arguments;
3544        return string.replace(/{(\d+)}/g, function (match, index) {
3545            var pos = parseInt(index) + 1;
3546            return args[pos] < 0 ? args[pos] || Math : args[pos];
3547        });
3548    };
3549
3550    
3551
3552    //initialise
3553    nxt.jstranslations = nxt.jsData.next.jscontent;
3554
3555})(window.jQuery, nxt);;
3556var FontLoader = {
3557    Init: function () {
3558
3559        var _this = this;
3560
3561        WebFont.load({
3562            timeout: 2000,
3563            custom: {
3564                families: ['azo-sans']
3565            },
3566            fontactive: function () {
3567                
3568                _this.FontLoadComplete();
3569
3570            },
3571            fontinactive: function () {
3572
3573                _this.FontLoadComplete();
3574
3575            }
3576        });
3577
3578    },
3579    FontLoadComplete: function () {
3580
3581        if (typeof setNavItemWidths === "function") {
3582            setNavItemWidths();
3583        }
3584
3585    }
3586}
3587
3588$(function () {
3589    FontLoader.Init();
3590});;
3591var Next = Next || {};
3592Next.UI = Next.UI || {};
3593Next.UI.CustomDropDown = {
3594    Init: function () {
3595
3596        if (Next.Settings.UI.CustomDropdownEnabled) {
3597
3598            $("select[data-customdropdown='true']:visible").each(function(i, v) {
3599
3600                var $this = $(this);
3601                if (!$this.data("dropkick")) {
3602                    $this.dropkick();
3603                }
3604
3605            });
3606        }
3607
3608    }
3609}
3610
3611$(function () {
3612    Next.UI.CustomDropDown.Init();
3613});;
3614
3615/* - Functions -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
3616/* - Site Chrome / Layout ------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
3617/* - Prototype Code ----------------------------------------------------------------------------------------------------------------------------------------------------------------*/
3618
3619var xhr = null;
3620var isPageTransitioning = null;
3621var isSpreadTransitioning = null;
3622var isDragging = false;
3623var globalPageReferrer = document.referrer;
3624var globalPageLocation = document.location.href;
3625var lastRequest = null;
3626
3627function toggleFixedProductViewer() {																									// Check to see if the footer is in the correct state for the document's scroll position.
3628    if ($("ProductViewer")) {
3629        var PVB = $(document).scrollTop() + $(".ProductViewer").height() + 130; 														// (VPB = View Port Bottom) Calculates the position of the bottom of the users browser viewport on the document
3630        var FTB = $(".FooterPromotions").position().top; 			 																	// (FTB = Footer Toolbar Bottom) Calculates the position of the bottom of the footer toolbar, when not fixed and in document flow
3631        if (PVB < FTB) {																												// If the View Port Bottom Position is less than the normal position of the bottom of the footer toolbar when it's in the document flow (ie the toolbar would be out of view) then
3632            if (parseInt($(".PageHeader").height()) == 48 && $(document).scrollTop() >= 32) {
3633                pinProductViewer()																											// Pin the Footer Toolbar to the bottom of the browser chrome
3634            } else {
3635                releaseProductViewer();
3636            }
3637        } else {																														// Otherwise (ie the toolbar would be fully in view
3638            releaseProductViewer("Bottom"); 																										// Unpin the toolbar from the browser chrome, and drop it back in to the document flow.
3639        }
3640    }
3641}
3642
3643function pinProductViewer() {
3644    /*
3645    if ($(".ProductViewer").hasClass("Top")) {
3646    $(".ProductViewer").removeClass("Top");
3647    }																										
3648    */
3649    if ($(".ProductViewer").hasClass("Bottom")) {
3650        $(".ProductViewer").removeClass("Bottom");
3651    }
3652    if (!$(".ProductViewer").hasClass("Fixed")) {
3653        $(".ProductViewer").addClass("Fixed");
3654    } else {
3655        $(".ProductViewer").removeAttr("style");
3656    }
3657}
3658
3659function releaseProductViewer(className) {
3660    /*
3661    if ($(".ProductViewer").hasClass("Top")) {
3662    $(".ProductViewer").removeClass("Top");
3663    }																										
3664    */
3665    if ($(".ProductViewer").hasClass("Fixed")) {
3666        $(".ProductViewer").removeClass("Fixed");
3667    }
3668
3669    if (className == "Bottom" && !$(".ProductViewer").hasClass("Bottom")) {
3670        $(".ProductViewer").addClass("Bottom");
3671    }
3672    $(".ProductViewer").removeAttr("style");
3673}
3674
3675/* - Page / Data Handlers ----------------------------------------------------------------------------------------------------------------------------------------------------------*/
3676
3677function LoadHTMLFragment(Path, Parameters, TargetElement) {
3678    //  alert("Remove This Call!");
3679    $.get(Path, Parameters, function (data) { document.getElementById(TargetElement).innerHTML = data; });
3680}
3681
3682// Method:      LoadHTMLContent
3683// Description: This is the main method called by pages when a link is clicked
3684//              It will check whether the link is the current page, whether another page is already loading and also whether the browser can use the HTML5 History Object (Pushstate)
3685//              If it passes these checks then it will load the respective data and kick off a transition
3686// Params:
3687//              Path:               [REQUIRED] String - The URL of the content to be loaded - e.g. '/women'
3688//              Title:              [OPTIONAL] String - The title of the conent to be loaded (used for history object) - e.g. 'Next.co.uk - Women'
3689//              Transition:         [OPTIONAL] String - This will override the default transition UP/DOWN/LEFT/RIGHT - e.g. 'RIGHT'
3690//              AddToHistory:       [OPTIONAL] Boolean - This will determine whether the history stack needs to be updated - e.g. true
3691//              ScrollPoint:        [OPTIONAL] Integer - This will scroll the document to the specified point after loading - e.g. 0
3692//              DocState:           [OPTIONAL] JSON - This is an object that contains querystring params that are specific to the page. These will be appended to the path and used on page load. If a variable name begins with 'hidden', it will not be appended to the path and the hashtag variable is reserved & placed at the end of the querystring - e.g. { spreadview: true, hiddenSearchbreadcrumb: '<div>secret</div>', hashtag: '123456x50' }
3693//              FormData:           [OPTIONAL] JSON - If form data (page params) needs to be sent with the $.get request, it can be specified here - e.g. { w: 'dress' }
3694//              CompletionCallback: [OPTIONAL] Function - Once the transition is complete, this method will be called - e.g. function() { ConsoleLog('Page has loaded...'); }
3695
3696function LoadHTMLContent(Path, Title, Transition, AddToHistory, ScrollPoint, DocState, FormData, CompletionCallback) {
3697
3698    if (typeof mobileDragged !== 'undefined' || typeof isDragStopping !== 'undefined') {
3699        if (mobileDragged || isDragStopping) {
3700            return false;
3701        }
3702    }
3703
3704
3705    var $ = jQuery;
3706    var allowTransition = true;
3707
3708    // Check whether the parent of the DOM element that called this has a class "Inactive"
3709    // This is mainly for Mouse Ears, where the user is on the last Spread in a Department and they select the Right Mouse Ear to load up a malformed sread page
3710    if ((this.event != undefined) && this.event.srcElement && this.event.srcElement.parentNode && this.event.srcElement.parentNode.parentNode) {
3711        var srcWrapper = this.event.srcElement.parentNode.parentNode;
3712        if ($(srcWrapper).hasClass("Inactive")) {
3713            return false;
3714        }
3715    }
3716
3717    //This ensures, no matter what happens, we don't lock the UI for more than 2 seconds
3718    //In theory this wont be needed but acts as a fallback should something go wrong
3719    var newRquest = new Date().getTime();
3720    if (lastRequest != null) {
3721        if ((newRquest - lastRequest) > 2000) {
3722            isPageTransitioning = false;
3723        }
3724    }
3725    lastRequest = newRquest;
3726
3727    //$("section.BreadcrumbNavigation div.Content a.ContinueShopping").remove(); // this will remove 'continue shopping' link from all other pages - Raj
3728
3729    //Check if we're loading an external URL - external URLs should be loaded in a new window
3730    if (Path.indexOf(location.hostname) == -1 && Path.indexOf("http://") == 0) {
3731        window.open(Path, "_blank");
3732        return false;
3733    }
3734
3735    //If page is transitioning, ignore request
3736    if (isPageTransitioning || isDragging) {
3737        return false;
3738    }
3739
3740    //This is for browsers that support pushState - if the user loads a page by manipulating the url or clicks on a standard link 
3740with no onclick event
3741    //the browser will fully load the requested page. If the user then hits the back button the loadHTML content will fire at the same time as a full refresh,
3742    //effectively requesting the same content twice. This stops a transition happening on the same page AFTER the content has loaded.
3743    //Previously, this only comapred the Path element, but it has been modified to compare the full url as it was causing issues on the search page when consecutive searches were made
3744    var newUrl = new UrlHelper(Path);
3745    var currUrl = new UrlHelper(PageURLInput);
3746
3747    if (newUrl.ServerUrl() == currUrl.ServerUrl()) {
3748        isPageTransitioning = false;
3749        return false;
3750    }
3751
3752    $("section.BreadcrumbNavigation div.Content a.ContinueShopping").remove(); // this will remove 'continue shopping' link from all other pages - Raj
3753
3754    // If we are on an error page, then we should not transition to the next page as the DOM may be in a bad state
3755    if (window.location.pathname.indexOf('error') > -1) {
3756        allowTransition = false;
3757    }
3758
3759    // Temporary solution to force lipsy homepage to be loaded without transitions - this is required until the storefronts are moved into the MVC architechure
3760    if ((newUrl.Path() == '/lipsy') || (newUrl.Path() == '/lipsy/')) {
3761        allowTransition = false;
3762    }
3763
3764    // Check if the DocState was passed in and make it blank if it wasn't
3765    if (typeof DocState === "undefined") {
3766        DocState = {};
3767    }
3768
3769    //Check we're not passing in the full URL the same as current location
3770    if (location.href == Path && !PagePopped) {
3771        isPageTransitioning = false;
3772        return false;
3773    }
3774
3775    globalPageReferrer = globalPageLocation;
3776    globalPageLocation = Path;
3777
3778    // Disable all transitions except spread to grid and grid to spread.
3779    if (Transition != 'SPREADTOGRID' && Transition != 'GRIDTOSPREAD') {
3780        allowTransition = false;
3781    }
3782
3783    /* ASP pages do not contain ContentArea, so transitions cannot be used for them. */
3784    if (allowTransition && typeof window.history.pushState != "undefined" && document.getElementById("ContentArea") != null) {
3785
3786        //Clean up path - remove http://domain
3787        var siteURL = window.location.protocol + "//" + window.location.host;
3788        Path = Path.replace(siteURL, '');
3789
3790        //Kill hero carousel from home page if it still exists
3791        if (typeof cInterval != "undefined") {
3792            try {
3793                clearInterval(cInterval);
3794                cInterval = null;
3795            } catch (ex) { }
3796        }
3797
3798        //Kill any current async page requests.
3799        //The only time this can happen is if the user has clicked a link again before the previous xhr request has completed
3800        //As soon as the xhr succeeds we will be transitioning the page so this wont apply.
3801        //This just allows the user the click something else if the request is taking too long
3802        if (xhr != null) {
3803            xhr.abort();
3804            xhr = null;
3805        }
3806
3807        //Store outgoing page's resource array (jscript and css) so we can remove them from header when transition is complete
3808        PreviousPageResources = DynamicResources;
3809        DynamicResources = new Array();
3810        var backTransition;
3811        var forwardTransition = Transition;
3812        var currentPageURL = window.location.pathname;
3813
3814        var addToHistory = true;
3815        if (AddToHistory == false) {
3816            addToHistory = false;
3817            currentPageURL = PageURLInput;
3818            //currentPageURL = Path;
3819            //ConsoleLog(PageURLInput);
3820        }
3821
3822        // Figure out what transition we need to use
3823        var currentHContext = getHTransitionContext(currentPageURL);
3824
3825        var currentVContext = getVTransitionContext(currentPageURL);
3826        var newHContext = getHTransitionContext(Path);
3827        var newVContext = getVTransitionContext(Path);
3828        var productPageURLPattern = /^\/[xgXG](l)?(L)?\d{2}\d+[sS]\d+$/gi;
3829
3830        var productPageTransition = false;
3831        if (currentPageURL.search(productPageURLPattern) != -1 || Path.search(productPageURLPattern) != -1) {
3832            productPageTransition = true;
3833        }
3834
3835        if (Transition == null || Transition == "") {
3836            if (Path == "/") {																									// Homepage Handler
3837                forwardTransition = "DOWN"; 																					// Moving to the homepage is always a DOWN
3838            } else {
3839                if (currentHContext == -1) {																					// Currently on a root level page (ie homepage), all transitions are UP
3840                    if (currentPageURL.search(productPageURLPattern) != -1) {
3841                        forwardTransition = "DOWN";
3842                    } else {
3843                        if (newVContext < currentVContext) {
3844                            forwardTransition = "DOWN";
3845                        } else if (newVContext > currentVContext) {
3846                            forwardTransition = "UP";
3847                        } else {
3848                            forwardTransition = "LEFT";
3849                        }
3850                        //If next page is a product page, regardless of where we are, animate up
3851                        if (Path.search(productPageURLPattern) != -1) {
3852                            forwardTransition = "UP";
3853                        }
3854                    }
3855                } else if (currentHContext > newHContext) {																		// Changing Department RIGHT
3856                    if (Path.search(productPageURLPattern) != -1) {
3857                        forwardTransition = "UP";
3858                    } else {
3859                        forwardTransition = "RIGHT";
3860                    }
3861                } else if (currentHContext < newHContext) {																		// Changing Department LEFT
3862                    forwardTransition = "LEFT";
3863                } else if (currentHContext == newHContext) {																	// Within the same Department
3864                    if (currentVContext > newVContext) {																		// Current Vertical Context is higher in Context Tree than New Vertical Context
3865                        forwardTransition = "DOWN";
3866                    } else if (currentVContext < newVContext) {																	// Current Vertical Context is lower in Context Tree than New Vertical Context
3867                        forwardTransition = "UP";
3868                    } else if (currentVContext == newVContext) {																// Current Vertical Context is same as New Vertical Context (Maybe a different horizontal context)
3869                        //forwardTransition = "UP";
3870                        return false; 																							// At the same vertical Context Level - Should be horizontal transition?
3871                    }
3872                }
3873            }
3874        }
3875
3876        //Shopping bag
3877        if (Path.toLowerCase() == "/shoppingbag") {
3878            forwardTransition = "UP";
3879        }
3880        if (currentPageURL.toLowerCase() == "/shoppingbag") {
3881            forwardTransition = "DOWN";
3882        }
3883
3884        // Build up the request and get the content from the server
3885        if (Path != currentPageURL || addToHistory == false) {
3886            // We are about to build up the request path, but we need to get rid of the hash temporarily so we can append some querystring params
3887            // If we don't do this then we will end up with a malformed request and this causes issues when we go from a redirected product page with hashtag to a spread view and back again
3888            var hashSplit = Path.split('#');
3889            var reqPath = hashSplit[0];
3890
3891            // Add contentonly=true so that we are not pulling back the header and footer
3892            if (reqPath.toLowerCase().indexOf("?") >= 0)
3893                reqPath += '&';
3894            else
3895                reqPath += '?';
3896            reqPath += "contentonly=true";
3897
3898            // Build up a docstate string that we can append to the Url
3899            var docStateString = getDocStateString(DocState);
3900
3901            // Add the docstate string
3902            if (docStateString !== '') {
3903                if (docStateString.charAt(0) === '?')
3904                    reqPath += docStateString.replace('?', '&');
3905                else if (docStateString.charAt(0) === '&' || docStateString.charAt(0) === '#')
3906                    reqPath += docStateString;
3907                else
3908                    reqPath += '&' + docStateString;
3909            }
3910
3911            // If the original path already had a hash on it, add it back on
3912            if (hashSplit.length > 1) {
3913                // If the getDocStateString brought back a hashtag, then replace it with the original
3914                if (reqPath.indexOf('#') > -1) {
3915                    reqPath = reqPath.substring(0, reqPath.indexOf('#'));
3916                }
3917                reqPath += '#' + hashSplit[1];
3918            }
3919
3920            // Get the form data defined if it isn't
3921            var formData = ""
3922            if (typeof FormData != "undefined" && FormData != null) {
3923                formData = FormData;
3924            }
3925
3926            // Send the request
3927            xhr = $.ajax({
3928                type: "GET",
3929                url: reqPath,
3930                timeout: 5000,
3931                data: formData,
3932                success: function (data, textStatus, jqXHR) { // 200 (and non cross domain 301 redirects)
3933                    checkAndRedirectForAjaxError(jqXHR, false, 'AJAXv1.js: LoadHTMLContent');
3934                    if (jqXHR.getResponseHeader('X-RequestUrl') != null) {
3935                        // We cannot detect whether there was a redirect (e.g. 301) as the browser handles this and gets the redirect content before bubbling anything back up to the JavaScript
3936                        // So lets check if our custom header with the requested url on the actual server matches the url that we sent in the initial request
3937                        try {
3938                            var serverRequestUrl = jqXHR.getResponseHeader('X-RequestUrl');
3939                            var clientUrl = new UrlHelper(reqPath);
3940                            var serverUrl = new UrlHelper(serverRequestUrl);
3941                            if (clientUrl.ServerUrl() !== serverUrl.ServerUrl()) {
3942                                // If they are different, reload the page with the original URL so that we are redirected with a hashtag
3943                                window.location = Path;
3944                                return false;
3945                            }
3946                        }
3947                        catch (exp) {
3948                            // Let it carry on and transition
3949                        }
3950                    }
3951
3952                    TransitionHandler("success", data, forwardTransition, Path, addToHistory, ScrollPoint, DocState, CompletionCallback);
3953                },
3954                error: function (data) { // 404 etc (and cross domain 301 redirects which are handled in the TransitionHandler)
3955                    TransitionHandler("error", data, forwardTransition, Path, addToHistory, ScrollPoint, DocState, CompletionCallback);
3956                }
3957            });
3958        }
3959        return false;
3960    } else {
3961        //Browser doesn't support pushstate, load page the 'traditional' way.
3962        isPageTransitioning = false;
3963
3964        var isMsie = jqueryUpgradeEnabledOnPage ? navigator.userAgent.toLowerCase().indexOf('msie') > -1 : $.browser.msie;
3965
3966        if (isMsie && Path.substr(0, 4) != ('http') && Path.charAt(0) != '/') {
3967            Path = "/" + Path;
3968        }
3969
3970        //Check if there's a hash param in the docstate
3971        if (DocState['hashtag'] !== undefined && DocState['hashtag'] !== null && DocState['hashtag'] != "") {
3972            window.location = Path + '#' + DocState['hashtag'];
3973        } else {
3974            window.location = Path;
3975            var _pattern = /[#][0-9][_][0-9]/;
3976            if (Next.Settings.UI.HorizontalFiltersEnabled && bcSearchBy != undefined && (bcSearchBy == "category" || bcSearchBy == "keyword") && (_pattern.test(Path))) {
3977                window.location.reload();
3978            }
3979        }
3980        return false;
3981    }
3982}
3983
3984function TransitionHandler(type, data, forwardTransition, Path, addToHistory, ScrollPoint, DocState, CompletionCallback) {
3985    var $ = jQuery;
3986    //Could change animation interval here
3987    //The default is 13 - giving a smooth, approx 75 fps
3988    //But - this might kill some browsers. By increasing the interval between 'frames' we decrease the fps 
3989    //potentially improving performance but a less smooth transition.
3990    //Setting the interval to 40 gives an approximate fps of 24 - shouldn't really go any lower than that.
3991    //jQuery.fx.interval = 20;
3992
3993    //No need to track users aborting the rerquest,
3994    //Just cancel
3995    if (data.statusText == "abort") {
3996        isPageTransitioning = false;
3997        xhr = null;
3998        return false;
3999    }
4000
4001    //Set the transition lock before we bind anything to the page as scripts contained in the incoming data
4002    //may need to fire after the transtion finishes - this prevents those scripts firing until we want them to
4003    isPageTransitioning = true;
4004    var Title
4005    Path = Path.toLowerCase();
4006
4007    switch (type) {
4008        case "success":
4009            TrackGAPageView(Path);
4010            $(".NextContent").html(data);
4011            xhr = null;
4012            break;
4013        case "error":
4014            var StatusCode = "" + data.status
4015            var Details = "";
4016
4017            if (data.statusText == "timeout") {
4018                StatusCode = "408";
4019            }
4020
4021            switch (StatusCode) {
4022                case "404":
4023                    StatusCode += " - File Not Found"
4024                    Details = "Referrer: " + window.location.href;
4025                    break;
4026                case "408":
4027                    TrackGAEvent(StatusCode + " - " + data.statusText, Path, Details, 0);
4028                    xhr.abort();
4029                    xhr = null;
4030                    isPageTransitioning = false;
4031                    return false;
4032                    break;
4033                case "500":
4034                    Details = data.responseText
4035                    break;
4036            }
4037
4038            TrackGAEvent(StatusCode + " - " + data.statusText, Path, Details, 0);
4039
4040            if (data.responseText != "") {
4041                $(".NextContent").html(data.responseText);
4042            } else {
4043                // If we hit any cross domain redirect issues or the request is malformed, then we need to reload the page
4044                // We catch this instance with the status code 0. 
4045                // The browser will make the initial request, get a 301, try to get the redirect url and hit a permission denyed if it is cross domain, then it will return a 0 instead of a 301
4046                if (data.status === 0)
4047                    window.location = Path;
4048                return false;
4049            }
4050            break;
4051    }
4052
4053
4054
4055    //Check if we are currently on a spread page and the user has navigated to a spread in the same dept
4056    //If so, we need to trigger the spread animation instead
4057    if ($(".CurrentContent .SpreadsPage").length && $(".NextContent .SpreadsPage").length) {
4058
4059        var nextSpread = $(".NextContent .Spread");
4060        var nextDept = $(".NextContent .SpreadsPage #hdnDeptName").val();
4061        var curDept = $(".CurrentContent .SpreadsPage #hdnDeptName").val();
4062        var nextPage = $(".NextContent .SpreadsPage .ImageLayer").attr("data-page");
4063        var nextBook = $(".NextContent .SpreadsPage .ImageLayer").attr("data-book");
4064        var nextOccurrence = $(".NextContent .SpreadsPage .ImageLayer").attr("data-occurrence");
4065
4066        $(".NextContent").html("");
4067        //If we're in the same dept
4068        if (nextDept == curDept) {
4069            //Target the item in the current carousel we need to click to load incoming spread
4070            var targetCarouselLI = $(".CurrentContent .SpreadsPage li[data-page='" + nextPage + "'][data-book='" + nextBook + "'][data-occurrence='" + nextOccurrence + "']");
4071            $(targetCarouselLI).find("a").first().click();
4072            //Scroll carousel to display selected carousel item
4073            scrollThumbNailBar($(targetCarouselLI).offset().left, targetCarouselLI, true);
4074
4075        } else {
4076            //Else - we're navigating between spread pages of different departments
4077            ////            //Load the new spread carousel
4078            ////            LoadSpreadCarousel(nextDept);
4079            //Update attributes on current spread - this allows us to target the correct carousel item once the carousel has loaded
4080            $(".ImageLayer").attr("data-page", nextPage);
4081            $(".ImageLayer").attr("data-book", nextBook);
4082            $(".ImageLayer").attr("data-occurrence", nextOccurrence);
4083            $(".ImageLayer").attr("data-reloadContent", true);
4084            $(".CurrentContent .SpreadsPage #hdnDeptName").val(nextDept);
4085            initCarousel(nextDept);
4086            ////            initPage();
4087
4088        }
4089        //Return false here as we've passed transitioning over to the spread transition handler (via a carousel click).
4090        return false;
4091    }
4092
4093    //Update breadcrumb/SEO
4094    if ($(".NextContent #PageParams").length) {
4095        var BCHTML = $(".NextContent #PageParams #BreadcrumbWrapper").html();
4096        if (BCHTML.length) {
4097            UpdateBreadcrumbTrail(BCHTML);
4098        }
4099
4100        var seoTitle = $(".NextContent #PageParams #seoTitle").val();
4101        var seoDescription = $(".NextContent #PageParams #seoDescription").val();
4102        var seoKeywords = $(".NextContent #PageParams #seoKeywords").val();
4103        var seoRobots = $(".NextContent #PageParams #seoRobots").val();
4104        var seoCanonical = $(".NextContent #PageParams #seoCanonical").val();
4105
4106        updateSeo(seoTitle, seoDescription, seoKeywords, seoRobots, seoCanonical);
4107
4108        //Remove page params from page
4109        $(".NextContent #PageParams").remove();
4110
4111    }
4112
4113    if (addToHistory && !preventReplaceState) {																											// If we're navigating the site rather than clicking back or forward
4114        window.history.replaceState({ "url": window.location.href, "DocState": documentState, "title": document.title, "scrollPoint": $(window).scrollTop() }, document.title, window.location.href); 			// On load, attempt to replace the last state object on the history stack with one that is populated with the relevent transition data (although in all likely hood this will just insert a new item)
4115    }
4116
4117    var Animation = createAnimation()
4118
4119    var siteURL = window.location.protocol + "//" + window.location.host;
4120    var relPath = Path.replace(siteURL, '');
4121
4122    if (relPath == "/") {
4123        $(".PageHeader").addClass("home");
4124        if ($(".PageHeader").hasClass("Large")) {
4125            addToAnimation(Animation, '$("footer.ToolBar").animate({bottom: -50}, 1000);', 0, false);
4126            addToAnimation(Animation, '$("#SpreadsGridTitle").fadeOut(350);', 0, false);
4127            addToAnimation(Animation, '$(".PageHeader .BreadcrumbNavigation").fadeOut(350);', 350, true);
4128            //addToAnimation(Animation, '$(".HeaderSpacer").animate({ "height": "-=' + $(".BreadcrumbNavigation").height() + 'px" }, 250);', 250, true);
4129            addToAnimation(Animation, '$(".PageHeader").removeClass("Large")', 0, false);
4130            //addToAnimation(Animation, '$(".HeaderSpacer").removeClass("Large")', 0, false);
4131            //addToAnimation(Animation, '$(".HeaderSpacer").removeAttr("style")', 0, false);
4132        }
4133    } else {
4134        $(".PageHeader").removeClass("home");
4135        if (!$(".PageHeader").hasClass("Large")) {
4136            addToAnimation(Animation, '$("footer.ToolBar").animate({bottom: 0}, 1000);', 0, false);
4137            addToAnimation(Animation, '$(".PageHeader").addClass("Large")', 0, false);
4138            //addToAnimation(Animation, '$(".HeaderSpacer").animate({ "height": "+=' + $(".BreadcrumbNavigation").height() + 'px" }, 250);', 250, true);
4139            //addToAnimation(Animation, '$(".HeaderSpacer").addClass("Large")', 0, false);
4140            //addToAnimation(Animation, '$(".HeaderSpacer").removeAttr("style")', 0, false);
4141            addToAnimation(Animation, '$(".PageHeader .BreadcrumbNavigation").fadeIn(650);', 150, true);
4142        }
4143    }
4144
4145
4146
4147    addToAnimation(Animation, 'PageTransition' + forwardTransition + '(' + ScrollPoint + ')', 0, false);
4148    if (typeof CompletionCallback != "undefined")
4149        addToAnimation(Animation, CompletionCallback, 0, true);
4150
4151
4152    runAnimation(Animation);
4153
4154    //If hash value was passed, add this to path
4155    if (DocState['hashtag'] !== undefined && DocState['hashtag'] !== null) {
4156        Path += '#' + DocState['hashtag'];
4157    }
4158
4159    //eval("PageTransition" + forwardTransition + "(" + ScrollPoint + ")");
4160    if (addToHistory) {
4161        var historyObject
4162        //if (Transition == null || Transition == "") {
4163        historyObject = { "url": Path, "title": Title, "DocState": DocState, "scrollPoint": ScrollPoint }
4164        //} else {
4165        //    historyObject = { "url": Path, "title": Title, "transition": Transition }
4166        //}
4167        window.history.pushState(historyObject, Title, Path);
4168    }
4169    //document.title = Title;
4170    PageURLInput = Path;
4171    preventReplaceState = false;
4172
4173}
4174
4175function LoadSpread(Path, Title, Transition, AddToHistory, ScrollPoint, DocState) {
4176
4177    var $ = jQuery;
4178
4179    // Check whether the parent of the DOM element that called this has a class "Inactive"
4180    // This is mainly for Mouse Ears, where the user is on the last Spread in a Department and they select the Right Mouse Ear to load up a malformed sread page
4181    if ((this.event != undefined) && this.event.srcElement && this.event.srcElement.parentNode && this.event.srcElement.parentNode.parentNode) {
4182        var srcWrapper = this.event.srcElement.parentNode.parentNode;
4183        if ($(srcWrapper).hasClass("Inactive")) {
4184            return false;
4185        }
4186    }
4187
4188    // If there is a hash at the end of the Url, strip it off
4189    if (Path.indexOf('#', Path.length - 1) !== -1) {
4190        Path = Path.substring(0, Path.length - 1)
4191    }
4192
4193    //Check we're not passing in the full URL the same as current location
4194    if (location.href == Path && !PagePopped) {
4195        return false;
4196    }
4197
4198    // This prevents the spread from being loaded twice when Chrome incorrectly fires onpopstate on page load.
4199    var newUrl = new UrlHelper(Path);
4200    var currUrl = new UrlHelper(PageURLInput);
4201    if (newUrl.ServerUrl() == currUrl.ServerUrl()) {
4202        return false;
4203    }
4204
4205    if (typeof window.history.pushState != "undefined") {
4206
4207        //Prevents spread locking completely
4208        var newRquest = new Date().getTime();
4209        if (lastRequest != null) {
4210            if ((newRquest - lastRequest) > 1500) {
4211                isSpreadTransitioning = false;
4212            }
4213        }
4214        lastRequest = newRquest;
4215
4216
4217        //Prevent using building up a stack of clicks/transtions
4218        if (isSpreadTransitioning) {
4219            return false;
4220        }
4221        //Set isSpreadTransitioning to true - indicates we're in a spread transition
4222        isSpreadTransitioning = true;
4223
4224        var currentPageURL = window.location.pathname;
4225        var siteURL = window.location.protocol + "//" + window.location.host;
4226
4227        Path = Path.replace(siteURL, '');
4228
4229
4230
4231        if (PageTransitionLock == false) {
4232            PageTransitionLock = true;
4233            var backTransition;
4234            var forwardTransition = Transition;
4235
4236            var addToHistory = true;
4237            if (AddToHistory == false) {
4238                addToHistory = false;
4239                currentPageURL = PageURLInput;
4240            }
4241
4242            // Check if the DocState was passed in and make it blank if it wasn't
4243            if (typeof DocState === "undefined") {
4244                DocState = {};
4245            }
4246
4247            if (Path != currentPageURL || addToHistory == false) {
4248                // Add contentonly=true so that we are not pulling back the header and footer
4249                var reqPath = Path;
4250                if (reqPath.toLowerCase().indexOf("?") >= 0)
4251                    reqPath += '&';
4252                else
4253                    reqPath += '?';
4254                reqPath += "contentonly=true&spreadonly=true";
4255
4256                // Build up a docstate string that we can append to the Url
4257                var docStateString = getDocStateString(DocState);
4258
4259                // Add the docstate string
4260                if (docStateString !== '') {
4261                    if (docStateString.charAt(0) === '?')
4262                        reqPath += docStateString.replace('?', '&');
4263                    else if (docStateString.charAt(0) === '&' || docStateString.charAt(0) === '#')
4264                        reqPath += docStateString;
4265                    else
4266                        reqPath += '&' + docStateString;
4267                }
4268
4269                var request = $.get(reqPath);
4270                request.success(function (data) {
4271
4272                    Path = Path.toLowerCase();
4273                    TrackGAPageView(Path);
4274
4275                    $(".NextSpread").html(data);
4276
4277                    //Update breadcrumb/SEO
4278                    if ($(".NextSpread #PageParams").length) {
4279                        var BCHTML = $(".NextSpread #PageParams #BreadcrumbWrapper").html();
4280                        if (BCHTML.length) {
4281                            UpdateBreadcrumbTrail(BCHTML);
4282                        }
4283
4284
4285                        var seoTitle = $(".NextSpread #PageParams #seoTitle").val();
4286                        var seoDescription = $(".NextSpread #PageParams #seoDescription").val();
4287                        var seoKeywords = $(".NextSpread #PageParams #seoKeywords").val();
4288                        var seoRobots = $(".NextSpread #PageParams #seoRobots").val();
4289                        var seoCanonical = $(".NextSpread #PageParams #seoCanonical").val();
4290
4291                        updateSeo(seoTitle, seoDescription, seoKeywords, seoRobots, seoCanonical);
4292
4293
4294                        //Remove page params from page
4295                        $(".NextSpread #PageParams").remove();
4296
4297                    }
4298
4299                    if (addToHistory) {																										// If we're navigating the site rather than clicking back or forward
4300                        window.history.replaceState({ "url": window.location.href, "spreadView": true, "DocState": documentState, "title": document.title, "scrollPoint": $(window).scrollTop() }, document.title, window.location.href); 			// On load, attempt to replace the last state object on the history stack with one that is populated with the relevent transition data (although in all likely hood this will just insert a new item)
4301                        //ConsoleLog(documentState);
4302                    }
4303
4304                    if (Title == '')
4305                        Title = seoTitle;
4306
4307                    SpreadTransition(forwardTransition === "LEFT");
4308
4309                    if (addToHistory) {
4310                        var historyObject
4311                        if (Transition == null || Transition == "") {
4312                            historyObject = { "url": Path, "title": Title, "spreadView": true, "DocState": DocState, "scrollPoint": ScrollPoint }
4313                        } else {
4314                            historyObject = { "url": Path, "title": Title, "transition": Transition, "spreadView": true, "DocState": DocState, "scrollPoint": ScrollPoint }
4315                        }
4316                        window.history.pushState(historyObject, Title, Path);
4317                    }
4318                    document.title = Title;
4319                    PageURLInput = Path;
4320
4321                    UpdateContinueShopping(Path)
4322                });
4323                request.error(function (data) { // 404, 500 Response => To Error Page
4324                    isSpreadTransitioning = false;
4325                    PageTransitionLock = false;
4326                    TransitionHandler("error", data, forwardTransition, Path, addToHistory, ScrollPoint, DocState);
4327                });
4328            } else {
4329                isSpreadTransitioning = false;
4330                PageTransitionLock = false;
4331            }
4332        }
4333        return false;
4334    } else {
4335
4336        var siteURL = window.location.protocol + "//" + window.location.host;
4337
4338        Path = Path.replace(siteURL, '');
4339
4340        window.location.pathname = Path;
4341    }
4342}
4343
4344
4345/* - Transition Handlers / Definitions ---------------------------------------------------------------------------------------------------------------------------------------------*/
4346
4347
4348/* Available easings ----------------------------------------------------
4349linea, swing, jswing, easeInQuad, easeOutQuad, easeInOutQuad, easeInCubic, 
4350easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, 
4351easeInQuint, easeOutQuint, easeInOutQuint, easeInSine, easeOutSine, easeInOutSine, 
4352easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, 
4353easeInElastic, easeOutElastic, easeInOutElastic, easeInBack, easeOutBack, easeInOutBack, 
4354easeInBounce, easeOutBounce, easeInOutBounce
4355*/
4356
4357
4358var pageTransitionSpeed = 800;
4359var leftRightTransitionSpeed = 900;
4360var pageTransitionEasing = 'easeOutCirc';
4361var pageTransitionEasingIn = 'easeInQuint';
4362var fadeContent = false;
4363
4364//TODO - Need to decide whether fading next content in is required
4365//In chrome it can give the appearance of a smoother transition, firefox maybe not 
4366//if ($.browser.mozilla == true) {
4367//    fadeContent = false;
4368// 
4369//}
4370
4371//Set page up correctly for any transition
4372function PreparePageForTransition(scrollToTop) {
4373    var $ = jQuery;
4374
4375    $(window).scrollTop(0);
4376
4377    if (fadeContent) {
4378        $(".NextContent").css("position", "absolute").css("opacity", "0").css("display", "block");
4379    } else {
4380        $(".NextContent").css("position", "absolute").css("display", "block");
4381    }
4382    $("#ContentArea").removeAttr("style").removeClass("HideOverflow");
4383
4384    $(".ToolBar").css("position", "fixed");
4385
4386    var newContentHeight = $(".NextContent").height();
4387    var ViewportHeight = $(window).height();
4388
4389    $(".NextContent").height(ViewportHeight);
4390
4391}
4392
4393function PageTransitionGRIDTOSPREAD(scrollPoint) {
4394    var $ = jQuery;
4395    var imageLoadCalled = false;
4396    PreparePageForTransition();
4397
4398    // Load page and image so we can get the image position/size
4399    $(".NextContent").css("top", 0).css("left", 0).css("opacity", 0);
4400
4401    var $spreadImg = $(".NextContent .ImageLayer img");
4402    var onSpreadImageLoad = function () {
4403        if (Next.Settings.Channel.IsInnovationDesktopSpreadQuickView) {
4404            if (imageLoadCalled) {
4405                return false;
4406            }
4407            imageLoadCalled = true;
4408        }
4409        var imgOffset = $spreadImg.offset();
4410        var spreadDimensions = {
4411            top: imgOffset.top,
4412            left: imgOffset.left,
4413            width: $spreadImg.width(),
4414            height: $spreadImg.height()
4415        };
4416
4417        var animateElement = $spreadImg.clone();
4418        $spreadImg.css("opacity", 0);
4419
4420        var $gridImg = $("a.selectedGrid img");
4421        var gridImgOffset = $gridImg.offset();
4422
4423        $(".CurrentContent").animate({ opacity: 0 }, 700);
4424
4425        $(animateElement).css("position", "absolute")
4426           .css("top", gridImgOffset.top)
4427           .css("left", gridImgOffset.left)
4428           .width($gridImg.width())
4429           .height($gridImg.height())
4430           .css("border", "none").css("margin", "").css("z-index", "1000");
4431
4432        $(".NextContent").after(animateElement);
4433
4434        $(animateElement).animate(spreadDimensions, 800, "easeOutExpo");
4435
4436        setTimeout(function () {
4437            $(".NextContent").animate({ opacity: 1 }, 600, pageTransitionEasing, function () {
4438                $(".NextContent .ImageLayer").find("img").css("opacity", 1);
4439                $(animateElement).remove()
4440                PageTransitionTidy();
4441            });
4442        }, 20)
4443    };
4444    $spreadImg.load(function () {
4445        onSpreadImageLoad();
4446    });
4447    //Cached images and the “load” event issue--http://mikefowler.me/journal/2014/04/22/cached-images-load-event
4448    if (Next.Settings.Channel.IsInnovationDesktopSpreadQuickView && $spreadImg.length > 0 && isIOS) {
4449        var spreadImageElement = $spreadImg[0];
4450        if (spreadImageElement.complete) {
4451            onSpreadImageLoad();
4452        }
4453    }
4454}
4455
4456function PageTransitionSPREADTOGRID(scrollPoint) {
4457    var $ = jQuery;
4458    PreparePageForTransition();
4459    $(".NextContent").css("top", 0).css("left", 0).css("opacity", 0);
4460    $(".CurrentContent .NextSpread").remove();
4461    var srcPage = $(".CurrentContent .CurrentSpread .ImageLayer").attr("data-page");
4462    var $spreadImage = $(".CurrentContent .CurrentSpread .ImageLayer img");
4463   
4464    var srcImg = $spreadImage.clone();
4465    var $targetImg = $(".NextContent img[data-page='" +srcPage + "']");
4466
4467    var targetParent = $targetImg.parent();
4468    $(targetParent).addClass("StorySelected");
4469
4470    var srcOffset = $spreadImage.offset();
4471
4472    srcImg.css("position", "absolute")
4473    srcImg.offset(srcOffset);
4474    srcImg.height($spreadImage.height());
4475    srcImg.css("z-index", 1);
4476    $(".NextContent").after(srcImg);
4477
4478    $spreadImage.animate({ opacity: 0 }, 200, function () {
4479        var $img = $(".StorySelected img");
4480        var imgOffset;
4481        if ($img.length > 0) {
4482            imgOffset = $img.offset();
4483            $(srcImg).animate({
4484                top: imgOffset.top,
4485                left: imgOffset.left,
4486                width: $img.width(),
4487                height: $img.height()
4488            }, 600, "easeOutExpo");
4489        }
4490
4491        $(".Controller").hide();
4492
4493        $(".NextContent").animate({ opacity: 1 }, 600, "easeInExpo", function () {
4494            PageTransitionTidy();
4495            var $storySel = $(".StorySelected");
4496            $(srcImg).remove();
4497            // Only scroll if necessary to bring image into view.
4498            if ($storySel.length > 0) {
4499                $("body,html").animate({ scrollTop: $storySel.offset().top + 250 - $(window).height() }, 200);
4500            }
4501        });
4502    });
4503}
4504
4505function PageTransitionGRIDLEFT(scrollPoint) {
4506    var $ = jQuery;
4507    PreparePageForTransition();
4508    var ViewportHeight = $(window).height();
4509    $(".NextContent").css("top", 0).css("left", 0).css("opacity", 1).css("background-color", "transparent");
4510    $(".NextContent .SpreadsGridTitle").css("opacity", 0);
4511
4512    $(".NextContent .SpreadGridSection").height(ViewportHeight).css("background-color", "#fff"); ;
4513
4514    $(".NextContent .SpreadGridSection").offset({ left: $(".NextContent .SpreadGridSection").offset().left + 970 });
4515    $(".NextContent .SpreadGridSection").animate({
4516        left: "-=" + 970
4517    }, 900, "easeOutExpo", function () {
4518        $(".NextContent .SpreadGridSection").css("height", "");
4519        PageTransitionTidy();
4520
4521    });
4522
4523    //    $(".CurrentContent .SpreadGridSection").animate({
4524    //        left: "-=" + 970
4525    //    }, 700, "easeOutExpo");
4526
4527    $(".NextContent .SpreadsGridTitle").animate({ opacity: 1 }, 700);
4528    $(".CurrentContent .SpreadsGridTitle").animate({ opacity: 0 }, 700);
4529
4530
4531}
4532
4533
4534function PageTransitionGRIDRIGHT(scrollPoint) {
4535    var $ = jQuery;
4536    PreparePageForTransition();
4537    var ViewportHeight = $(window).height();
4538    $(".NextContent").css("top", 0).css("left", 0).css("opacity", 1).css("background-color", "transparent").css("z-index", 100);
4539    $(".NextContent .SpreadsGridTitle").css("opacity", 0);
4540    $(".NextContent .SpreadGridSection").offset({ left: $(".NextContent .SpreadGridSection").offset().left });
4541
4542
4543
4544    $(".CurrentContent .SpreadGridSection").css("background-color", "#fff").css("z-index", 101).css("height", ViewportHe
4544ight);
4545
4546    //    $(".NextContent .SpreadGridSection").animate({
4547    //        left: "+=" + 970
4548    //    }, 700, "easeOutExpo");
4549
4550    $(".CurrentContent .SpreadGridSection").animate({
4551        left: "+=" + 970
4552    }, 900, pageTransitionEasingIn, function () {
4553        PageTransitionTidy();
4554        ScrollToPoint(scrollPoint);
4555    });
4556
4557    $(".NextContent .SpreadsGridTitle").animate({ opacity: 1 }, 700);
4558    $(".CurrentContent .SpreadsGridTitle").animate({ opacity: 0 }, 700);
4559
4560}
4561
4562function PageTransitionUP(scrollPoint) {
4563    var $ = jQuery;
4564    PreparePageForTransition();
4565    var ViewportHeight = $(window).height();
4566    var HeaderHeight = $(".PageHeader").height();
4567    $(".NextContent").css("top", ViewportHeight).css("left", "0px");
4568    var animateJSON;
4569
4570    if (fadeContent) {
4571        animateJSON = {
4572            top: "-=" + ViewportHeight,
4573            opacity: 1
4574        };
4575    } else {
4576        animateJSON = {
4577            top: "-=" + ViewportHeight
4578        };
4579
4580    }
4581
4582    $(".NextContent").animate(animateJSON, pageTransitionSpeed, pageTransitionEasing, function () {
4583        PageTransitionTidy();
4584        ScrollToPoint(scrollPoint);
4585    });
4586}
4587
4588function PageTransitionDOWN(scrollPoint) {
4589    var $ = jQuery;
4590    PreparePageForTransition();
4591    var ViewportHeight = $(window).height();
4592    var HeaderHeight = $(".PageHeader").height();
4593    var ContentViewportHeight = ViewportHeight - HeaderHeight;
4594    var newContentHeight = $(".NextContent").height();
4595    var newContentPositon = 0 - newContentHeight;
4596
4597    $(".CurrentContent").css("z-index", "1000")
4598                        .css("position", "absolute")
4599                        .css("overflow", "hidden")
4600                        .height(ViewportHeight);
4601
4602    $(".NextContent").css("top", "0px")
4603                        .css("left", "0px")
4604                        .css("opacity", "1");
4605    var animateJSON;
4606
4607    if (fadeContent) {
4608        animateJSON = {
4609            top: "+=" + ViewportHeight,
4610            opacity: 0
4611        };
4612    } else {
4613        animateJSON = {
4614            top: "+=" + ViewportHeight
4615        };
4616    }
4617
4618    $(".CurrentContent").animate(animateJSON, pageTransitionSpeed, pageTransitionEasingIn, function () {
4619        PageTransitionTidy();
4620        ScrollToPoint(scrollPoint);
4621    });
4622}
4623
4624//Page transition for going BACK - content transtions to the right, user clicked on LEFT mouse ear
4625function PageTransitionRIGHT(scrollPoint) {
4626    var $ = jQuery;
4627    PinMouseEars();
4628    PreparePageForTransition();
4629
4630
4631
4632    var tempClip = $("<div />");
4633    $(tempClip).addClass("tempClip");
4634    $(tempClip).height($(window).height());
4635    $(tempClip).append($(".NextContent"));
4636    $(tempClip).append($(".CurrentContent"));
4637    $("#ContentArea").append(tempClip);
4638
4639    $(".NextContent .TitleBar").first().addClass("newTitle");
4640    $(".CurrentContent .TitleBar").first().addClass("newTitle");
4641
4642    if ($(".NextContent .TitleBar").length) {
4643        $(".NextContent .TitleBar").parent().css("margin-top", 48);
4644    }
4645
4646    if ($(".CurrentContent .TitleBar").length) {
4647        $(".CurrentContent .TitleBar").parent().css("margin-top", 48);
4648    }
4649
4650    var ViewportHeight = $(window).height();
4651    var ViewportWidth = $(window).width();
4652    var HeaderHeight = $(".PageHeader").height();
4653    var ContentViewportHeight = ViewportHeight - HeaderHeight;
4654    var newContentHeight = $(".NextContent").height();
4655    var newContentWidth = $(".NextContent").width();
4656    var newContentPositon = 0 - 976;
4657    $(".NextContent").css("left", 0).css("width", 976).css("top", "0px").css("z-index", 100);
4658    $(".CurrentContent").css("left", 0).css("width", 976).css("top", "0px").css("position", "absolute").css("z-index", 101).css("height", ViewportHeight);
4659    var animateJSON;
4660    if (fadeContent) {
4661        animateJSON = {
4662            left: "+=" + 976,
4663            opacity: 1
4664        };
4665    } else {
4666        animateJSON = {
4667            left: "+=" + 976
4668        };
4669    }
4670
4671    //$(".NextContent").animate(animateJSON, pageTransitionSpeed, pageTransitionEasing);
4672
4673    $(".CurrentContent").animate(animateJSON, leftRightTransitionSpeed, 'easeInCubic', function () {
4674        var cnt = $(".tempClip").contents()
4675        $(".tempClip").replaceWith(cnt);
4676
4677        PageTransitionTidy();
4678        ScrollToPoint(scrollPoint);
4679
4680    });
4681
4682    $(".NextContent .TitleBar").first().animate({ opacity: 1 }, 300);
4683
4684}
4685
4686function PageTransitionLEFT(scrollPoint) {
4687    var $ = jQuery;
4688    PinMouseEars();
4689
4690    PreparePageForTransition();
4691
4692    var tempClip = $("<div />");
4693
4694    $(tempClip).addClass("tempClip");
4695    $(tempClip).height($(window).height());
4696    $(tempClip).append($(".NextContent"));
4697    $(tempClip).append($(".CurrentContent"));
4698    $("#ContentArea").append(tempClip);
4699    $(".NextContent .TitleBar").first().addClass("newTitle");
4700    $(".CurrentContent .TitleBar").first().addClass("newTitle");
4701
4702    if ($(".NextContent .TitleBar").length) {
4703        $(".NextContent .TitleBar").parent().css("margin-top", 48);
4704    }
4705
4706    if ($(".CurrentContent .TitleBar").length) {
4707        $(".CurrentContent .TitleBar").parent().css("margin-top", 48);
4708    }
4709
4710
4711    $("body").css("overflow-x", "hidden");
4712    var ViewportHeight = $(window).height();
4713    var ViewportWidth = $(window).width();
4714    var HeaderHeight = $(".PageHeader").height();
4715    var ContentViewportHeight = ViewportHeight - HeaderHeight;
4716    var newContentHeight = $(".NextContent").height();
4717    var newContentWidth = $(".NextContent").width();
4718    var newContentPositon = ViewportWidth;
4719    $(".NextContent").css("left", 976).css("width", 976).css("top", "0px").css("height", ViewportHeight);
4720    $(".CurrentContent").css("left", 0).css("width", 976).css("top", "0px").css("position", "absolute");
4721
4722
4723
4724    var animateJSON;
4725    if (fadeContent) {
4726        animateJSON = {
4727            left: "-=" + 976,
4728            opacity: 1
4729        };
4730    } else {
4731        animateJSON = {
4732            left: "-=" + 976
4733        };
4734    }
4735
4736    $(".NextContent").animate(animateJSON, leftRightTransitionSpeed, pageTransitionEasing, function () {
4737        var cnt = $(".tempClip").contents()
4738        $(".tempClip").replaceWith(cnt);
4739
4740        PageTransitionTidy();
4741        ScrollToPoint(scrollPoint);
4742    });
4743
4744    //$(".CurrentContent").animate(animateJSON, pageTransitionSpeed, pageTransitionEasing);
4745
4746    $(".NextContent .TitleBar").first().animate({ opacity: 1 }, 300);
4747
4748}
4749
4750
4751
4752function PinMouseEars() {
4753
4754    return false;
4755    var oldContent = $(".CurrentContent");
4756    var newContent = $(".NextContent");
4757
4758    var oldMouseEarLeft = $(".CurrentContent").find(".MouseEar.Left");
4759    var oldMouseEarRight = $(".CurrentContent").find(".MouseEar.Right");
4760
4761    var newMouseEarLeft = $(".NextContent").find(".MouseEar.Left");
4762    var newMouseEarRight = $(".NextContent").find(".MouseEar.Right");
4763
4764    var omeLPOS = $(oldMouseEarLeft).offset();
4765    var omeRPOS = $(oldMouseEarRight).offset();
4766
4767    $(oldMouseEarLeft).css("position", "fixed").css("left", "0px").css("top", omeLPOS.top);
4768    $(oldMouseEarRight).css("position", "fixed").css("right", "0px").css("top", omeRPOS.top);
4769
4770    $(newMouseEarLeft).css("position", "fixed").css("left", "0px").css("top", omeLPOS.top).css("opacity", "0");
4771    $(newMouseEarRight).css("position", "fixed").css("right", "0px").css("top", omeRPOS.top).css("opacity", "0");
4772
4773    $(oldMouseEarLeft).animate({ opacity: 0 }, 700);
4774    $(oldMouseEarRight).animate({ opacity: 0 }, 700);
4775
4776    $(newMouseEarLeft).animate({ opacity: 1 }, 700);
4777    $(newMouseEarRight).animate({ opacity: 1 }, 700);
4778
4779
4780}
4781
4782/////////////Spread transitions
4783// Copied  into htmlSpreadCanvas.js
4784function SpreadTransition(left) {
4785    var $ = jQuery;
4786
4787    // Is spread expanded?
4788    var $exp = $(".SpreadsPage .Expanded:visible");
4789    if ($exp.length) {
4790
4791        doAnimation(function () {
4792            var src = $(".ImageLayer img").attr("src");
4793            var $img = $exp.find("img");
4794            $img.attr("src", src);
4795        });
4796
4797    } else {
4798
4799        // Transition Data
4800        var ContentViewportWidth = $(".SpreadCarousel").width();
4801        var currentSpreadOffset = $(".CurrentSpread").offset();
4802
4803        var targetOffset;
4804        if (left) 
4805            targetOffset = "-=" + currentSpreadOffset.left + ContentViewportWidth;
4806         else 
4807            targetOffset = "+=" + ContentViewportWidth;
4808        
4809        $(".NextSpread").offset({ left: currentSpreadOffset.left }).css("z-index", 100);
4810        $(".CurrentSpread").css("z-index", 101);
4811        $(".NextSpread .ImageLayer img").load(function () {
4812            $(".CurrentSpread").animate({ left: targetOffset }, 700, 'easeInSine', doAnimation);
4813        });
4814
4815    }
4816
4817    function doAnimation(callback) {
4818        var Animation = createAnimation();
4819        Animation = SpreadTransitionUpdateNavigationAids(Animation)
4820        Animation = SpreadTransitionClearDown(Animation);
4821        runAnimation(Animation, callback);
4822        isSpreadTransitioning = false;
4823        PageTransitionLock = false;
4824    }
4825}
4826
4827//function SpreadTransitionLEFT() {
4828//    SpreadTransition(true);
4829//}
4830
4831//function SpreadTransitionRIGHT() {
4832//    SpreadTransition(false);
4833//}
4834
4835function SpreadTransitionUpdateNavigationAids(Animation) {
4836    var $ = jQuery;
4837    addToAnimation(Animation, 'ClearMouseEarStates();', 0, true);
4838
4839    if ($(".BreadcrumbTrail").html() != "") {
4840        // addToAnimation(Animation, '$(".Breadcrumbs").html($(".NextSpread .BreadcrumbTrail .Breadcrumbs").html())', 0, false);
4841    }
4842
4843    if ($(".NextSpread .NextPageURL").val() == "") {
4844        addToAnimation(Animation, '$(".MouseEar.Right").addClass("Inactive").removeClass("Active");', 0, false);
4845        addToAnimation(Animation, '$(".MouseEar.Right a")[0].href = "#";', 0, false);
4846    } else {
4847        addToAnimation(Animation, '$(".MouseEar.Right").addClass("Active").removeClass("Inactive");', 0, false);
4848        addToAnimation(Animation, '$(".MouseEar.Right a")[0].href = $(".NextSpread .NextPageURL").val();', 0, false); //
4849    }
4850
4851    if ($(".NextSpread .PreviousPageURL").val() == "") {
4852        addToAnimation(Animation, '$(".MouseEar.Left").addClass("Inactive").removeClass("Active");', 0, false);
4853        addToAnimation(Animation, '$(".MouseEar.Left a")[0].href = "#";', 0, false);
4854    } else {
4855        addToAnimation(Animation, '$(".MouseEar.Left").addClass("Active").removeClass("Inactive");', 0, false);
4856        addToAnimation(Animation, '$(".MouseEar.Left a")[0].href = $(".NextSpread .PreviousPageURL").val();', 0, false);
4857
4858    }
4859
4860    if ($(".NextSpread .NextPageIMG").val() == "") {
4861        addToAnimation(Animation, '$(".MouseEar.Right").attr("data-img","");', 0, false);
4862    } else {
4863        addToAnimation(Animation, '$(".MouseEar.Right").attr("data-img","' + $(".NextSpread .NextPageIMG").val() + '");', 0, false);
4864    }
4865
4866    if ($(".NextSpread .PreviousPageIMG").val() == "") {
4867        addToAnimation(Animation, '$(".MouseEar.Left").attr("data-img","");', 0, false);
4868    } else {
4869        addToAnimation(Animation, '$(".MouseEar.Left").attr("data-img","' + $(".NextSpread .PreviousPageIMG").val() + '");', 0, false);
4870    }
4871
4872    if ($(".NextSpread .NextPageName").val() == "") {
4873        addToAnimation(Animation, '$(".MouseEar.Right").attr("data-name","");', 0, false);
4874    } else {
4875        addToAnimation(Animation, '$(".MouseEar.Right").attr("data-name","' + $(".NextSpread .NextPageName").val() + '");', 0, false);
4876    }
4877
4878    if ($(".NextSpread .PreviousPageName").val() == "") {
4879        addToAnimation(Animation, '$(".MouseEar.Left").attr("data-name","");', 0, false);
4880    } else {
4881        addToAnimation(Animation, '$(".MouseEar.Left").attr("data-name","' + $(".NextSpread .PreviousPageName").val() + '");', 0, false);
4882    }
4883
4884
4885    return Animation;
4886}
4887
4888function SpreadTransitionClearDown(Animation, UpdateMeta) {
4889    ConsoleLog("SpreadTransitionClearDown");
4890    var $ = jQuery;
4891    // Tidy Up Function For Page Transitions - makes sure everything is reset correctly for next time.
4892    addToAnimation(Animation, '$(".CurrentSpread").removeClass("CurrentSpread").addClass("Held");', 0, false); 					// Change Class Of CurrentContent To Held - It will ultimately become NextContent
4893    addToAnimation(Animation, '$(".NextSpread").removeClass("NextSpread").addClass("CurrentSpread");', 0, false); 				// Reassign the classes on the NextContent container to reflect it's new position (CurrentContent)
4894    addToAnimation(Animation, '$(".Held").removeClass("Held").addClass("NextSpread");', 0, true); 									// Reassign the classes on the Held container to reflect it's new position (NextContent)
4895    addToAnimation(Animation, '$(".NextSpread").html("");', 0, false);
4896
4897    addToAnimation(Animation, '$(".NextSpread").css("-webkit-transform", ""); ', 0, false);
4898    addToAnimation(Animation, '$(".CurrentSpread").css("-webkit-transform", ""); ', 0, false);
4899    addToAnimation(Animation, '$(".NextSpread").css("transform", ""); ', 0, false);
4900    addToAnimation(Animation, '$(".CurrentSpread").css("transform", ""); ', 0, false);
4901    addToAnimation(Animation, '$(".CurrentSpread").removeClass("animate"); ', 0, false);
4902    addToAnimation(Animation, '$(".NextSpread").removeClass("animate"); ', 0, false);
4903
4904
4905    addToAnimation(Animation, '$(".NextSpread").removeAttr("style");', 0, false); 													// Remove dynamically added css styles.
4906    addToAnimation(Animation, '$(".CurrentSpread").removeAttr("style");', 0, false); 												// Remove dynamically added css styles.
4907    //addToAnimation(Animation, 'PageTransitionLock = false;', 0, true);
4908
4909    addToAnimation(Animation, 'AddMouseEarHoverStates();', 0, true);
4910
4911    if (UpdateMeta) {
4912        addToAnimation(Animation, 'makeSpreadDraggable(false, true);', 0, true);
4913    } else {
4914        addToAnimation(Animation, 'makeSpreadDraggable();', 0, true);
4915    }
4916
4917    addToAnimation(Animation, 'selectCurrentSpreadThumbnail();', 0, true);
4918    addToAnimation(Animation, 'setGridViewUrl();', 0, true);
4919    
4920 
4921
4922    return Animation;
4923}
4924
4925
4926function PageTransitionTidy() {
4927    var $ = jQuery;
4928    $("body").css("overflow-x", "");
4929
4930    var oldContent = $(".CurrentContent");
4931    var newContent = $(".NextContent");
4932
4933    $(oldContent).html("").removeClass("CurrentContent")
4934                        .addClass("NextContent")
4935                        .css("position", "absolute")
4936                        .css("display", "none")
4937                        .css("opacity", "")
4938                        .css("width", "")
4939                        .css("overflow", "")
4940                        .css("z-index", "")
4941                        .css("height", "");
4942
4943    $(newContent).addClass("CurrentContent")
4944                        .removeClass("NextContent")
4945                        .css("position", "")
4946                        .css("opacity", "")
4947                        .css("width", "")
4948                        .css("top", "")
4949                        .css("left", "")
4950                        .css("height", "")
4951                        .css("background-color", "#fff");
4952
4953    $(".CurrentContent .TitleBar").parent().css("margin-top", 0);
4954
4955    $(".ProductImagery").css("position", "").css("margin-top", "");
4956    $("#ContentArea").removeAttr("style").removeClass("HideOverflow").addClass("LargeHeader");
4957
4958    AddMouseEarTouchEvents();
4959
4960    RemoveDynamicResources();
4961}
4962
4963function PageTransitionClearDown(Animation, scrollPoint) {
4964    var $ = jQuery;
4965    // Tidy Up Function For Page Transitions - makes sure everything is reset correctly for next time.
4966
4967    //Potential to do something with ContentArea here to make the transition to the scroll point better?
4968    addToAnimation(Animation, '$(".CurrentContent").removeClass("CurrentContent").addClass("Held");', 0, false); 					// Change Class Of CurrentContent To Held - It will ultimately become NextContent
4969    addToAnimation(Animation, '$(".NextContent").removeClass("NextContent").addClass("CurrentContent").addClass("Backgroun
4969dWhite");', 0, false); 				// Reassign the classes on the NextContent container to reflect it's new position (CurrentContent)
4970    addToAnimation(Animation, '$(".Held").removeClass("Held").addClass("NextContent");', 0, true); 									// Reassign the classes on the Held container to reflect it's new position (NextContent)
4971    addToAnimation(Animation, '$(".NextContent").html("");', 0, false); 																// Remove Content From NextContent Container
4972    addToAnimation(Animation, '$(".NextContent").removeAttr("style");', 0, false); 													// Remove dynamically added css styles.
4973    addToAnimation(Animation, '$(".CurrentContent").removeAttr("style");', 0, false); 												// Remove dynamically added css styles.
4974    //addToAnimation(Animation, 'ResizeContentAreaToContent(' + scrollPoint + ')', 0, false);
4975
4976    addToAnimation(Animation, 'Resize(".ContentArea", "Y", $(".CurrentContent").height() + "px", 500, "")', 500, true);                 // The content bottom is not visible, so we cna shorten the transition by just snapping it in to place.
4977    // For Toolbar
4978    //addToAnimation(Animation, 'toggleFixedFooterToolbar("transition");', 200, true);                                                    // ...and switch the footer toolbar to fixed mode.
4979
4980    addToAnimation(Animation, 'RemoveDynamicResources();', 0, false);
4981    //addToAnimation(Animation, 'PageTransitionComplete();', 0, true);
4982
4983    // addToAnimation(Animation, '$(".CurrentContent").removeClass("Backgroun
4983dWhite");', 100, true); 
4984
4985
4986    return Animation;
4987}
4988
4989function ResizeContentAreaToContent(scrollPoint) {
4990    return false;
4991    var scrolltimer = 500;
4992    var CCHeight = $(".CurrentContent").height();
4993    var CAHeight = $(".ContentArea").height();
4994    var CAMinHeight = parseInt($(".ContentArea").css('min-height'));
4995    var CAHeightDiff
4996    var timer
4997
4998    if (CCHeight >= CAHeight) {
4999        if (CAMinHeight > CAHeight) {
5000            CAHeight = CAMinHeight;
5001        }
5002        CAHeightDiff = CCHeight - CAHeight
5003        ContentResizeComplete("+", CAHeightDiff, scrolltimer, scrollPoint);
5004    } else {
5005        CAHeightDiff = CAHeight - CCHeight
5006        var newContentHeight = $(".PageHeader").height() + CCHeight + $(".FooterPromotions").height();
5007        if (newContentHeight < $(window).height()) {
5008            unPinFooterToolbar('transition');
5009            timer = window.setTimeout(function () { ContentResizeComplete("-", CAHeightDiff, scrolltimer, scrollPoint); }, 300)			// Wait for animation to complete, then continue
5010        } else {
5011            ContentResizeComplete("-", CAHeightDiff, scrolltimer, scrollPoint);
5012        }
5013    }
5014}
5015
5016function ContentResizeComplete(animationDirection, animationDistance, animationDuration, scrollPoint) {
5017
5018    //$(".ContentArea").animate({ "height": animationDirection + "=" + animationDistance + "px" }, animationDuration);
5019    timer = window.setTimeout(function () { ResetScrollPoint(scrollPoint) }, animationDuration + 10)									// Wait for animation to complete, then continue
5020}
5021
5022function ResetScrollPoint(scrollPoint) {
5023    $(".CurrentContent").scrollTop(1); 																								// Match content's scroll point to the window scrollpoint and...
5024    $(window).scrollTop(scrollPoint);
5025 																							// Reset the window's scroll point to 0 - this ensures that the new page's content starts at the top, rather than at the scroll point from the previous page!
5026}
5027
5028function ToggleExpander(target, ExpanderID) {
5029    ToggleExpanderResize(target, "Expanded");
5030
5031    if (!$(target).hasClass("Expanded")) {
5032
5033        if (!$(target).is("#CategoryViewport")) {
5034
5035            if ($(ExpanderID + "Img")) {
5036                $(ExpanderID + "Img").attr("src", $(ExpanderID + "Img").attr("src").toLowerCase().replace("down", "up"));
5037            }
5038            if ($(ExpanderID + "Text")) {
5039                $(ExpanderID + "Text").text($(ExpanderID + "Text").text().replace("More", "Less"));
5040            }
5041
5042        }
5043
5044        if ($(target).hasClass("ExpansionFinished")) {
5045
5046            if ($(ExpanderID + "Img")) {
5047                $(ExpanderID + "Img").attr("src", $(ExpanderID + "Img").attr("src").toLowerCase().replace("down", "up"));
5048            }
5049            if ($(ExpanderID + "Text")) {
5050                $(ExpanderID + "Text").text($(ExpanderID + "Text").text().replace("More", "Less"));
5051            }
5052
5053            $(target).removeClass("ExpansionFinished");
5054        }
5055
5056        addParamToDocState(target, 'Expanded');
5057    } else {
5058
5059        if ($(ExpanderID + "Img")) {
5060            $(ExpanderID + "Img").attr("src", $(ExpanderID + "Img").attr("src").toLowerCase().replace("up", "down"));
5061        }
5062        if ($(ExpanderID + "Text")) {
5063            $(ExpanderID + "Text").text($(ExpanderID + "Text").text().replace("Less", "More"));
5064        }
5065        addParamToDocState(target, '');
5066    }
5067}
5068
5069function ToggleExpanderResize(target, toggleClass) {
5070    var value
5071
5072
5073    if (!$(target).hasClass(toggleClass)) {
5074
5075        if ($(target).is("#CategoryViewport")) {
5076            var maxHeight = $(target).children().height();
5077            var unitHeight = $(target).find("article").first().height();
5078            var unitMargin = parseInt($(target).find("article").first().css("margin-top")) * 2;
5079            var curentHeight = $(target).height();
5080            var baseAdjust = parseInt($(target).css("min-height")) - (unitHeight + unitMargin);
5081            var hiddenUnitsLeft = parseInt((maxHeight - (curentHeight - baseAdjust)) / (unitHeight + unitMargin));
5082
5083            if (unitHeight * 2 > curentHeight && unitHeight * 2 <= maxHeight) {
5084
5085                //add two more rows
5086                value = curentHeight + ((unitHeight + unitMargin) * 2);
5087            }
5088            else {
5089
5090                //add more rows based on where we are in the visible and hidden grid
5091
5092                if (hiddenUnitsLeft > 3) {
5093                    hiddenUnitsLeft = 3;
5094                }
5095
5096                // calcualte the new height to show 
5097                value = curentHeight + ((unitHeight + unitMargin) * hiddenUnitsLeft);
5098            }
5099
5100            // chack to see if we are at the end of the collection
5101            if (value > maxHeight) {
5102                $(target).addClass("ExpansionFinished");
5103            }
5104
5105            if (value < maxHeight) {
5106                toggleClass = "";
5107            }
5108
5109        }
5110        else {
5111            value = $(target).children(1).height();
5112        }
5113    } else {
5114        value = parseInt($(target).css("min-height"));
5115    }
5116
5117    ResizeExpander(target, value, 500, toggleClass);
5118}
5119
5120function ResizeExpander(target, value, duration, toggleClass) {
5121    var Animation = createAnimation();
5122    var newHeight = $(".ContentArea").height() - $(target).height() + value;
5123
5124    addToAnimation(Animation, '$("' + target + '").animate({"height": "' + value + '"}, ' + duration + ')', 0, false);
5125    addToAnimation(Animation, '$(".ContentArea").animate({"height": "' + newHeight + '"}, ' + duration + ')', duration, true);
5126
5127    if (toggleClass != '') {
5128        if (!$(target).hasClass(toggleClass)) {
5129            addToAnimation(Animation, '$("' + target + '").addClass("' + toggleClass + '")', 0, false);
5130        } else {
5131            addToAnimation(Animation, '$("' + target + '").removeClass("' + toggleClass + '")', 0, false);
5132        }
5133    }
5134
5135    runAnimation(Animation);
5136}
5137
5138function ToggleResize(target, axis, toggleClass) {
5139    var newvalue
5140    var startvalue
5141
5142    if (axis == "Y") {
5143        newvalue = $("#" + target).children(1).height()
5144        startvalue = parseInt($("#" + target).css("min-height"));
5145    }
5146    if (axis == "X") {
5147        newvalue = $("#" + target).children(1).width()
5148        startvalue = parseInt($("#" + target).css("min-width"));
5149    }
5150
5151    if (!$("#" + target).hasClass(toggleClass)) {
5152        Resize("#" + target, axis, newvalue, 500, toggleClass);
5153    } else {
5154        Resize("#" + target, axis, startvalue, 500, toggleClass);
5155    }
5156}
5157
5158function Resize(target, axis, value, duration, toggleClass) {
5159    var Animation = createAnimation();
5160    var dimension
5161    switch (axis) {
5162        case "Y":
5163            dimension = "height";
5164            break;
5165        case "X":
5166            dimension = "width";
5167            break;
5168    }
5169
5170    addToAnimation(Animation, '$("' + target + '").animate({"' + dimension + '": "' + value + '"}, ' + duration + ')', duration, true);
5171
5172    if (toggleClass != '') {
5173        if (!$("" + target).hasClass(toggleClass)) {
5174            addToAnimation(Animation, '$("' + target + '").addClass("' + toggleClass + '")', 0, false);
5175        } else {
5176            addToAnimation(Animation, '$("' + target + '").removeClass("' + toggleClass + '")', 0, false);
5177        }
5178        addToAnimation(Animation, '$("' + target + '").removeAttr("style")', 0, false);
5179    }
5180
5181    //addToAnimation(Animation, 'ResizeContentAreaToContent(' + $(window).scrollTop() + ')', 0, false);
5182
5183    runAnimation(Animation);
5184}
5185
5186function ToggleView(View1, View2, Trigger, DocStateParam) {
5187    var Animation = createAnimation();
5188    var scrollTimer = 500
5189    var ToggleClass = 'Hide'
5190
5191    if ($(View1.className).hasClass(ToggleClass)) {
5192        addToAnimation(Animation, '$(".' + View2.className + '").fadeOut(' + scrollTimer + ')', scrollTimer, true);
5193        addToAnimation(Animation, '$("' + View2.className + '").addClass("FadedOut")', 0, false);
5194        addToAnimation(Animation, '$("' + View1.className + '").removeClass("' + ToggleClass + '")', 0, false);
5195        addToAnimation(Animation, '$("' + View2.className + '").addClass("' + ToggleClass + '")', 0, false);
5196        addToAnimation(Animation, '$(".' + View1.className + '").fadeIn(' + scrollTimer + ');', scrollTimer, true);
5197        addToAnimation(Animation, '$("' + View1.className + '").removeClass("FadedOut")', 0, false);
5198        addToAnimation(Animation, '$("' + View1.className + '").removeAttr("style")', 0, false);
5199        addToAnimation(Animation, '$("' + View2.className + '").removeAttr("style")', 0, false);
5200        if (Trigger.TextID && Trigger.TextID != "" && View2.trigger.text && View2.trigger.text != '') {
5201            addToAnimation(Animation, '$("#' + Trigger.TextID + '").text("' + View2.trigger.text + '")', 0, false);
5202        }
5203
5204        if (DocStateParam != '') {
5205            if (View1.DocStateValue) {
5206                addParamToDocState(DocStateParam, View1.DocStateValue)
5207            } else {
5208                addParamToDocState(DocStateParam, '')
5209            }
5210        }
5211    } else {
5212        addToAnimation(Animation, '$(".' + View1.className + '").fadeOut(' + scrollTimer + ')', scrollTimer, true);
5213        addToAnimation(Animation, '$("' + View1.className + '").addClass("FadedOut")', 0, false);
5214        addToAnimation(Animation, '$("' + View2.className + '").removeClass("Hide")', 0, false);
5215        addToAnimation(Animation, '$("' + View1.className + '").addClass("Hide")', 0, false);
5216        addToAnimation(Animation, '$(".' + View2.className + '").fadeIn(' + scrollTimer + ')', scrollTimer, true);
5217        addToAnimation(Animation, '$("' + View2.className + '").removeClass("FadedOut")', 0, false);
5218        addToAnimation(Animation, '$("' + View1.className + '").removeAttr("style")', 0, false);
5219        addToAnimation(Animation, '$("' + View2.className + '").removeAttr("style")', 0, false);
5220        if (Trigger.TextID && Trigger.TextID != "" && View1.trigger.text && View1.trigger.text != '') {
5221            addToAnimation(Animation, '$("#' + Trigger.TextID + '").text("' + View1.trigger.text + '")', 0, false);
5222        }
5223        if (DocStateParam != '') {
5224            if (View2.DocStateValue) {
5225                addParamToDocState(DocStateParam, View2.DocStateValue)
5226            } else {
5227                addParamToDocState(DocStateParam, '')
5228            }
5229        }
5230    }
5231
5232    runAnimation(Animation);
5233}
5234
5235/*function ZoomTarget(e) {
5236if ($(".ProductViewer").hasClass("ShowZoom")) {
5237} else {
5238return false;
5239}
5240}*/
5241;
5242var StateConvergence = /** @class */ (function () {
5243    function StateConvergence() {
5244    }
5245    StateConvergence.prototype.GetStateConvergenceCookie = function () {
5246        var cookieName = Next.Settings.Channel.StateConvergence.CookieName;
5247        var cookieValue = {};
5248        var stateConvergenceCookie = readCookie(cookieName);
5249        if (stateConvergenceCookie != null) {
5250            var splitVars = stateConvergenceCookie.split("&");
5251            for (var i = 0; i < splitVars.length; i++) {
5252                var splitKvp = splitVars[i].split("=");
5253                if (splitKvp != null) {
5254                    cookieValue[splitKvp[0]] = splitKvp[1];
5255                }
5256            }
5257        }
5258        return cookieValue;
5259    };
5260    StateConvergence.prototype.GetAgentId = function () {
5261        var cookieAgentIdKey = Next.Settings.Channel.StateConvergence.CookieAgentIDKey;
5262        var cookieValue = this.GetStateConvergenceCookie();
5263        return cookieValue[cookieAgentIdKey];
5264    };
5265    StateConvergence.prototype.GetConvergedFlag = function () {
5266        var cookieConvergedFlagKey = Next.Settings.Channel.StateConvergence.CookieConvergedFlagKey;
5267        var cookieValue = this.GetStateConvergenceCookie();
5268        return cookieValue[cookieConvergedFlagKey] === "True";
5269    };
5270    StateConvergence.prototype.StripTrailingForwardSlash = function (url) {
5271        var lastForwardSlashIndex = url.lastIndexOf("/");
5272        var lastIndexOfUrl = url.length - 1;
5273        var output;
5274        if (lastForwardSlashIndex === lastIndexOfUrl) {
5275            output = url.substring(0, lastForwardSlashIndex);
5276        }
5277        else {
5278            output = url;
5279        }
5280        return output;
5281    };
5282    StateConvergence.prototype.FromEndpoint = function (endpoint, agentId) {
5283        var formattedEndpoint = this.StripTrailingForwardSlash(endpoint);
5284        var formattedOrigin = this.StripTrailingForwardSlash(window.location.origin);
5285        if (formattedEndpoint !== formattedOrigin) {
5286            var pixelEndpoint = endpoint + "/StateConvergence/Pixel/" + agentId;
5287            var pixelImage = new Image();
5288            pixelImage.src = pixelEndpoint;
5289        }
5290    };
5291    StateConvergence.prototype.Execute = function () {
5292        var convergedFlag = this.GetConvergedFlag();
5293        if (convergedFlag) {
5294            return;
5295        }
5296        var convergedDomains = Next.Settings.Channel.StateConvergence.Domains;
5297        var agentId = this.GetAgentId();
5298        if (agentId && convergedDomains.length) {
5299            for (var i = 0; i < convergedDomains.length; i++) {
5300                var endpoint = convergedDomains[i];
5301                this.FromEndpoint(endpoint, agentId);
5302            }
5303        }
5304    };
5305    return StateConvergence;
5306}());
5307var NextStateConvergence = new StateConvergence();
5308//# sourceMappingURL=StateConvergenceCommon.js.map;
5309// globals we reference
5310// todo supply interface for consumers, rather than letting them randomly add to our data structure?
5311var rebuildDataLayer = true;
5312var setUpGA = true;
5313var itemNumberAdded = "";
5314var guestAccountConverted = false;
5315var platmodCommon;
5316(function (platmodCommon) {
5317    var w = window;
5318    var NextUnlimitedModel = /** @class */ (function () {
5319        function NextUnlimitedModel() {
5320            this.IsEnabled = false;
5321            this.IsExistingNUCustomer = false;
5322            this.ShowAlreadyNUCustomerBanner = false;
5323            this.ShowBelowMinimumOrderValueBanner = false;
5324            this.AmountToSatisfyMinimumOrderValue = "";
5325            this.ShowAlreadyNUCustomerNURemovedAlert = false;
5326            this.NextUnlimitedItemNumbers = [];
5327        }
5328        NextUnlimitedModel.prototype.Update = function (data) {
5329            this.IsEnabled = data.IsEnabled;
5330            this.IsExistingNUCustomer = data.IsExistingNUCustomer;
5331            this.ShowAlreadyNUCustomerBanner = data.ShowAlreadyNUCustomerBanner;
5332            this.ShowBelowMinimumOrderValueBanner = data.ShowBelowMinimumOrderValueBanner;
5333            this.AmountToSatisfyMinimumOrderValue = data.AmountToSatisfyMinimumOrderValue;
5334            this.ShowAlreadyNUCustomerNURemovedAlert = data.ShowAlreadyNUCustomerNURemovedAlert;
5335            if (data.ItemNumbersWithoutHyphen && data.ItemNumbersWithoutHyphen.length > 0) {
5336                this.NextUnlimitedItemNumbers = data.ItemNumbersWithoutHyphen;
5337            }
5338        };
5339        return NextUnlimitedModel;
5340    }());
5341    var NextBasketData = /** @class */ (function () {
5342        function NextBasketData() {
5343            this.Version = 0;
5344            this.ItemCount = 0;
5345        }
5346        return NextBasketData;
5347    }());
5348    var SessionTransferVariables = /** @class */ (function () {
5349        function SessionTransferVariables() {
5350            this.GAAccount = '';
5351            this.GASessionId = '';
5352            this.HomeUrl = '';
5353            this.IgnoreGA = true;
5354            this.SearchUrl = '';
5355            this.ShoppingBagUrl = '';
5356            this.GAEnabledForGTM = false;
5357            this.GAAccountForGTM = '';
5358        }
5359        return SessionTransferVariables;
5360    }());
5361    var Basket = /** @class */ (function () {
5362        function Basket() {
5363            this.VisitorID = '';
5364            this.SessionID = '';
5365            this.Data = new NextBasketData();
5366            this.NotifyChange = [];
5367            this.NotifyError = [];
5368            this.Loaded = false;
5369            this.UsingKeepAlive = false;
5370            this.KeepAlivePollTime = 60000;
5371            this.HostURL = "";
5372            this.InboundQueue = [];
5373            this.OutboundQueue = [];
5374            this.ItemsWaiting = false;
5375            this.NotifyWaiting = false;
5376            this.SessionTransferVariables = new SessionTransferVariables();
5377            this.NextUnlimited = new NextUnlimitedModel();
5378            this.RoamingProfileId = "";
5379            this.BrowseOnlyMode = false;
5380            this.MobilePMeterAnimationEnabled = Next.Settings.Channel.BagIconShutterAnimation;
5381            this.TriggerMobilePMeterAnimation = false;
5382            this.DesktopPMeterAnimationEnabled = Next.Settings.Channel.BagIconShutterAnimation;
5383            this.TriggerDesktopPMeterAnimation = false;
5384            // todo pass baseUrl to ctor
5385            // Use baseURL if it exists (used by AccountPortal to post to MVC app).
5386            if (typeof baseURL != 'undefined') {
5387                this.HostURL = baseURL;
5388            }
5389            // the header is not there at this point so we don't want to do this
5390            // Load -> LoadSuccess calls UpdateBagUI anyway
5391            //this.UpdateBagUI(this);
5392        }
5393        Basket.prototype.SubscribeToEvents = function () {
5394            var _this = this;
5395            if (typeof w.subjects !== "undefined") {
5396                w.subjects["$ SHOPPING_BAG_GET_CALLBACK"].subscribe(function (eventResponse) {
5397                    var jqXHR = {
5398                        getResponseHeader: function () { return false; },
5399                        status: eventResponse.status
5400                    };
5401                    if (eventResponse.success) {
5402                        var data = eventResponse.data;
5403                        if (data.redirect === "true") {
5404                            _this.ConfirmRedirectModal(data.cancelUrl);
5405                        }
5406                        else {
5407                            _this.LoadSuccess(data, eventResponse.textStatus, jqXHR, 'load');
5408                        }
5409                    }
5410                    else {
5411                        _this.LoadError(jqXHR, eventResponse.textStatus, null, 'load');
5412                    }
5413                });
5414            }
5415        };
5416        // these methods should be overridden in the logically-concrete subclass (this class is logically abstract, but we do not enforced that to keep things simple)
5417        //todo enforce these are overridden?
5418        Basket.prototype.UpdateBagUI = function (basket) { };
5419        Basket.prototype.PriceDial = function (bag) { };
5420        Basket.prototype.Notify = function (messageObj) { };
5421        Basket.prototype.DisplayRebuildNotification = function (messageObj) { };
5422        Basket.prototype.NotifyItemAdded = function (itemObj) { };
5423        Basket.prototype.NotifyGAAccount = function (GAAccountToUse, GASessionId, GAEnabled) { };
5424        Basket.prototype.NotifyGAAccountForGTM = function (GAAccountForGTM, GASessionIdForGTM, GAEnabledForGTM) { };
5425        //Executes bag actions
5426        Basket.prototype.ExecuteBagAction = function (actionParams) {
5427            var _this = this;
5428            if (this.SessionID == '') {
5429                return;
5430            }
5431            var eventId = Date.now().toString();
5432            switch (actionParams.actionPath) {
5433                case "bag/add":
5434                    var addBagSubscription = w.subjects["$ SHOPPING_BAG_ADD_CALLBACK"].subscribe(function (eventResponse) {
5435                        if (eventId === eventResponse.eventId) {
5436                            _this.EventCallbackHandler(eventResponse, actionParams, addBagSubscription);
5437                        }
5438                    });
5439                    var addBagEventData = {
5440                        eventId: eventId,
5441                        id: actionParams.postData.id,
5442                        optionNumber: actionParams.postData.option,
5443                        chain: actionParams.postData.chain,
5444                        quantity: actionParams.postData.quantity,
5445                        modalItemUrl: actionParams.postData.modalItemUrl,
5446                        saleClearanceSofaImage: actionParams.postData.SaleClearanceSofaImage,
5447                        itemNumberAdded: itemNumberAdded
5448                    };
5449                    w.subjects["$ SHOPPING_BAG_ADD"].next(addBagEventData);
5450                    return;
5451                case "bag/AddCist":
5452                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_CIST_CALLBACK"].subscribe(function (eventResponse) {
5453                        if (eventId === eventResponse.eventId) {
5454                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5455                        }
5456                    });
5457                    var addCistEventData = {
5458                        eventId: eventId,
5459                        id: actionParams.postData.id,
5460                        optionNumber: actionParams.postData.option,
5461                        chain: actionParams.postData.chain,
5462                        quantity: actionParams.postData.quantity,
5463                        cistStoreId: actionParams.postData.ciststoreid,
5464                    };
5465                    w.subjects["$ SHOPPING_BAG_ADD_CIST"].next(addCistEventData);
5466                    return;
5467                case "bag/addevoucher":
5468                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_EVOUCHER_CALLBACK"].subscribe(function (eventResponse) {
5469                        if (eventId === eventResponse.eventId) {
5470                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5471                        }
5472                    });
5473                    var addEvoucherEventData = {
5474                        eventId: eventId,
5475                        id: actionParams.postData.id,
5476                        option: actionParams.postData.option,
5477                        optionNumber: actionParams.postData.option,
5478                        eVoucherTo: actionParams.postData.eVoucherTo,
5479                        eVoucherFrom: actionParams.postData.eVoucherFrom,
5480                        eVoucherEmail: actionParams.postData.eVoucherEmail,
5481                        eVoucherMessage: actionParams.postData.eVoucherMessage,
5482                        ecardDeliveryDate: actionParams.postData.ecardDeliveryDate,
5483                    };
5484                    w.subjects["$ SHOPPING_BAG_ADD_EVOUCHER"].next(addEvoucherEventData);
5485                    return;
5486                case "bag/addgiftcard":
5487                    var addGCSubscription = w.subjects["$ SHOPPING_BAG_ADD_GIFT_CARD_CALLBACK"].subscribe(function (eventResponse) {
5488                        if (eventId === eventResponse.eventId) {
5489                            _this.EventCallbackHandler(eventResponse, actionParams, addGCSubscription);
5490                        }
5491                    });
5492                    var addGiftCardEventData = {
5493                        eventId: eventId,
5494                        id: actionParams.postData.id,
5495                        amountOption: actionParams.postData.amountOption,
5496                        firstName: actionParams.postData.firstName,
5497                        lastName: actionParams.postData.lastName,
5498                        addressLine1: actionParams.postData.addressLine1,
5499                        addressLine2: actionParams.postData.addressLine2,
5500                        addressLine3: actionParams.postData.addressLine3,
5501                        addressLine4: actionParams.postData.addressLine4,
5502                        addressLine5: actionParams.postData.addressLine5,
5503                        postCode: actionParams.postData.postCode,
5504                        message: actionParams.postData.message,
5505                        deliveryDate: actionParams.postData.deliveryDate,
5506                        deliveryOption: actionParams.postData.deliveryOption,
5507                        deliveryCharge: actionParams.postData.deliveryCharge,
5508                        mediacode: actionParams.postData.mediacode
5509                    };
5510                    w.subjects["$ SHOPPING_BAG_ADD_GIFT_CARD"].next(addGiftCardEventData);
5511                    return;
5512                case "bag/addlinkeditem":
5513                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_LINKED_ITEM_CALLBACK"].subscribe(function (eventResponse) {
5514                        if (eventId === eventResponse.eventId) {
5515                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5516                        }
5517                    });
5518                    var addLinkedItemEventData = {
5519                        eventId: eventId,
5520                        id: actionParams.postData.id,
5521                        optionNumber: actionParams.postData.option,
5522                        linkedItemId: actionParams.postData.linkeditem,
5523                        linkedItemOption: actionParams.postData.linkeditemoption,
5524                        itemNumberAdded: itemNumberAdded
5525                    };
5526                    w.subjects["$ SHOPPING_BAG_ADD_LINKED_ITEM"].next(addLinkedItemEventData);
5527                    return;
5528                case "bag/addmultiple":
5529                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_MULTIPLE_CALLBACK"].subscribe(function (eventResponse) {
5530                        if (eventId === eventResponse.eventId) {
5531                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5532                        }
5533                    });
5534                    var addMultipleEventData = {
5535                        eventId: eventId,
5536                        data: actionParams.postData.data,
5537                        pageUrl: actionParams.postData.pageurl,
5538                        deliveryWeeks: actionParams.postData.deliveryweeks,
5539                        isGrouped: actionParams.postData.grouped,
5540                        groupType: actionParams.postData.groupType
5541                    };
5542                    w.subjects["$ SHOPPING_BAG_ADD_MULTIPLE"].next(addMultipleEventData);
5543                    return;
5544                case "bag/addwarranty":
5545                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_WARRANTY_CALLBACK"].subscribe(function (eventResponse) {
5546                        if (eventId === eventResponse.eventId) {
5547                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5548                        }
5549                    });
5550                    var addWarrantyEventData = {
5551                        eventId: eventId,
5552                        id: actionParams.postData.id,
5553                        optionNumber: actionParams.postData.option,
5554                        warrantyId: actionParams.postData.warranty,
5555                        warrantyOptionNumber: actionParams.postData.warrantyoptionno,
5556                    };
5557                    w.subjects["$ SHOPPING_BAG_ADD_WARRANTY"].next(addWarrantyEventData);
5558                    return;
5559                case "bag/remove":
5560                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_REMOVE_CALLBACK"].subscribe(function (eventResponse) {
5561                        if (eventId === eventResponse.eventId) {
5562                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5563                        }
5564                    });
5565                    var removeEventData = {
5566                        eventId: eventId,
5567                        id: actionParams.postData.id,
5568                        customItemType: actionParams.postData.customItemType
5569                    };
5570                    w.subjects["$ SHOPPING_BAG_REMOVE"].next(removeEventData);
5571                    return;
5572                case "bag/reject":
5573                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_REJECT_CALLBACK"].subscribe(function (eventResponse) {
5574                        if (eventId === eventResponse.eventId) {
5575                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5576                        }
5577                    });
5578                    var rejectEventData = {
5579                        eventId: eventId,
5580                        id: actionParams.postData.id,
5581                    };
5582                    w.subjects["$ SHOPPING_BAG_REJECT"].next(rejectEventData);
5583                    return;
5584                case "bag/accept":
5585                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ACCEPT_CALLBACK"].subscribe(function (eventResponse) {
5586                        if (eventId === eventResponse.eventId) {
5587                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5588                        }
5589                    });
5590                    var acceptEventData = {
5591                        eventId: eventId,
5592                        id: actionParams.postData.id,
5593                    };
5594                    w.subjects["$ SHOPPING_BAG_ACCEPT"].next(acceptEventData);
5595                    return;
5596                case "bag/addSample":
5597                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_ADD_SAMPLE_CALLBACK"].subscribe(function (eventResponse) {
5598                        if (eventId === eventResponse.eventId) {
5599                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5600                        }
5601                    });
5602                    var addSampleEventData = {
5603                        eventId: eventId,
5604                        items: actionParams.postData.items,
5605                    };
5606                    w.subjects["$ SHOPPING_BAG_ADD_SAMPLE"].next(addSampleEventData);
5607                    return;
5608                case "bag/removeSample":
5609                    var addCistSubscription = w.subjects["$ SHOPPING_BAG_REMOVE_SAMPLE_CALLBACK"].subscribe(function (eventResponse) {
5610                        if (eventId === eventResponse.eventId) {
5611                            _this.EventCallbackHandler(eventResponse, actionParams, addCistSubscription);
5612                        }
5613                    });
5614                    var removeSampleEventData = {
5615                        eventId: eventId,
5616                        id: actionParams.postData.id,
5617                    };
5618                    w.subjects["$ SHOPPING_BAG_REMOVE_SAMPLE"].next(removeSampleEventData);
5619                    return;
5620                default:
5621                    var jqXHR = {
5622                        getResponseHeader: function () { return false; },
5623                        status: "Error"
5624                    };
5625                    console.log("ERROR UNHANDLED BAG EVENT - " + actionParams.actionPath);
5626                    this.LoadError(jqXHR, "500", "ERROR UNHANDLED BAG EVENT - " + actionParams.actionPath, actionParams.actionType, actionParams.callBack, actionParams.dataLoadCallback);
5627                    break;
5628            }
5629        };
5630        Basket.prototype.EventCallbackHandler = function (eventResponse, actionParams, subscription) {
5631            console.log("SHOPPING_BAG_CALLBACK", actionParams, eventResponse);
5632            var jqXHR = {
5633                getResponseHeader: function () { return false; },
5634                status: eventResponse.status
5635            };
5636            if (eventResponse.success) {
5637                if (this.MobilePMeterAnimationEnabled) {
5638                    this.TriggerMobilePMeterAnimation = true;
5639                }
5640                if (this.DesktopPMeterAnimationEnabled) {
5641                    this.TriggerDesktopPMeterAnimation = true;
5642                }
5643                this.LoadSuccess(eventResponse.data, eventResponse.textStatus, jqXHR, actionParams.actionType, actionParams.loadBasketPage, actionParams.callBack, actionParams.dataLoadCallback);
5644            }
5645            else {
5646                this.LoadError(jqXHR, eventResponse.textStatus, null, actionParams.actionType, actionParams.callBack, actionParams.dataLoadCallback);
5647            }
5648            subscription.unsubscribe();
5649        };
5650        //All bag actions are passed here and added to the queue of actions
5651        Basket.prototype.AddBagAction = function (actionParams) {
5652            //Add action to inbound queue
5653            this.InboundQueue.push(actionParams);
5654            //If ItemsWaiting is set to false, we have not yet begun to process the items in the Inbound queue
5655            //Need to kick it off here
5656            if (!this.ItemsWaiting) {
5657                this.ItemsWaiting = true;
5658                //Get (and remove) first item from queue and send it off to be processed
5659                //In most cases we will be using the item we just added but if user has clicked 'add' multiple times,
5660                //we can loop through the items one by one
5661                var firstAction = this.InboundQueue.shift();
5662                this.ExecuteBagAction(firstAction);
5663            }
5664            if (!Next.Settings.Channel.PlatModGoogleAnalyticsSDK) {
5665                if (actionParams.postData != undefined) {
5666                    if (actionParams.actionType != undefined && (actionParams.actionType === "add" || actionParams.actionType === "addEvoucher" || actionParams.actionType === "addgiftcard")) {
5667                        var products = "";
5668                        var itemNumber = "";
5669                        var sku = "";
5670                        if (actionParams.postData.id != undefined) {
5671                            itemNumber = actionParams.postData.id;
5672                            if (itemNumber.lastIndexOf("-") === -1) {
5673                                itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5674                            }
5675                            else if (itemNumber.lastIndexOf("-") === 7) {
5676                                itemNumber = itemNumber.substring(0, 7);
5677                            }
5678                            if (actionParams.postData.option != undefined) {
5679                                sku = itemNumber + "-" + actionParams.postData.option;
5680                            }
5681                            else {
5682                                sku = itemNumber + "-01";
5683                            }
5684                            products = '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5685                            if (actionParams.postData.linkeditem != undefined) {
5686                                itemNumber = actionParams.postData.linkeditem;
5687                                if (itemNumber.lastIndexOf("-") === -1) {
5688                                    itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5689                                }
5690                                else if (itemNumber.lastIndexOf("-") === 7) {
5691                                    itemNumber = itemNumber.substring(0, 7);
5692                                }
5693                                if (actionParams.postData.linkeditemoption != undefined) {
5694                                    sku = itemNumber + "-" + actionParams.postData.linkeditemoption;
5695                                }
5696                                else {
5697                                    sku = itemNumber + "-01";
5698                                }
5699                                products = products + "," + '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5700                            }
5701                            if (actionParams.postData.warranty != undefined) {
5702                                itemNumber = actionParams.postData.warranty;
5703                                if (itemNumber.lastIndexOf("-") === -1) {
5704                                    itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5705                                }
5706                                else if (itemNumber.lastIndexOf("-") === 7) {
5707                                    itemNumber = itemNumber.substring(0, 7);
5708                                }
5709                                if (actionParams.postData.warrantyoptionno != undefined) {
5710                                    sku = itemNumber + "-" + actionParams.postData.warrantyoptionno;
5711                                }
5712                                else {
5713                                    sku = itemNumber + "-01";
5714                                }
5715                                products = products + "," + '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5716                            }
5717                        }
5718                        else if (actionParams.postData.data != undefined) {
5719                            var jsonData = JSON.parse(actionParams.postData.data);
5720                            if (jsonData != undefined && jsonData.Items != undefined && jsonData.Items.length > 0) {
5721                                for (var j = 0; j < jsonData.Items.length; j++) {
5722                                    if (jsonData.Items[j].id != undefined) {
5723                                        itemNumber = jsonData.Items[j].id;
5724                                        if (itemNumber.lastIndexOf("-") === -1) {
5725                                            itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5726                                        }
5727                                        else if (itemNumber.lastIndexOf("-") === 7) {
5728                                            itemNumber = itemNumber.substring(0, 7);
5729                                        }
5730                                        if (jsonData.Items[j].option != undefined) {
5731                                            sku = itemNumber + "-" + jsonData.Items[j].option;
5732                                        }
5733                                        else {
5734                                            sku = itemNumber + "-01";
5735                                        }
5736                                    }
5737                                    if (products !== "") {
5738                                        products = products + ",";
5739                                    }
5740                                    products = products + '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5741                                    if (jsonData.Items[j].linkeditem != undefined) {
5742                                        itemNumber = jsonData.Items[j].linkeditem;
5743                                        if (itemNumber.lastIndexOf("-") === -1) {
5744                                            itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5745                                        }
5746                                        else if (itemNumber.lastIndexOf("-") === 7) {
5747                                            itemNumber = itemNumber.substring(0, 7);
5748                                        }
5749                                        if (jsonData.Items[j].linkeditemoption != undefined) {
5750                                            sku = itemNumber + "-" + jsonData.Items[j].linkeditemoption;
5751                                        }
5752                                        else {
5753                                            sku = itemNumber + "-01";
5754                                        }
5755                                        products = products + "," + '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5756                                    }
5757                                    if (jsonData.Items[j].warranty != undefined) {
5758                                        itemNumber = jsonData.Items[j].warranty;
5759                                        if (itemNumber.lastIndexOf("-") === -1) {
5760                                            itemNumber = itemNumber.substring(0, 3) + "-" + itemNumber.substring(3, 6);
5761                                        }
5762                                        else if (itemNumber.lastIndexOf("-") === 7) {
5763                                            itemNumber = itemNumber.substring(0, 7);
5764                                        }
5765                                        if (jsonData.Items[j].warrantyoptionno != undefined) {
5766                                            sku = itemNumber + "-" + jsonData.Items[j].warrantyoptionno;
5767                                        }
5768                                        else {
5769                                            sku = itemNumber + "-01";
5770                                        }
5771                                        products = products + "," + '{"prod_id": "' + itemNumber + '", "sku": "' + sku + '"}';
5772                                    }
5773                                }
5774                            }
5775                        }
5776                        var productsAdded = JSON.parse('[' + products + ']');
5777                        var bloomReachPixelEnabled = false;
5778                        var bloomReachSofaSku = "";
5779                        var bloomReachSofaId = "";
5780                        if (dataLayer != undefined && dataLayer.length > 0) {
5781                            for (var j = 0; j < dataLayer.length; j++) {
5782                                if (dataLayer[j].products_added_into_bag != undefined) {
5783                                    dataLayer.splice(j, 1);
5784                                }
5785                                if (dataLayer[j].br_pixel_enabled != undefined) {
5786                                    bloomReachPixelEnabled = dataLayer[j].br_pixel_enabled === "true";
5787                                }
5788                                if (dataLayer[j].br_sofa_sku != undefined && dataLayer[j].br_sofa_id != undefined) {
5789                                    bloomReachSofaSku = dataLayer[j].br_sofa_sku;
5790                                    bloomReachSofaId = dataLayer[j].br_sofa_id;
5791                                }
5792                            }
5793                            if (bloomReachPixelEnabled) {
5794                                var brProducts = products.replace(/-/g, "");
5795                                if (bloomReachSofaId !== "" && bloomReachSofaSku !== "") {
5796                                    brProducts = '{"prod_id": "' + bloomReachSofaId + '", "sku": "' + bloomReachSofaSku + '"}';
5797                                }
5798                                brProducts = JSON.parse('[' + brProducts + ']');
5799                                dataLayer.push({ "event": "BloomReachProductsAddedIntoBag", "br_products_added_into_bag": brProducts });
5800                            }
5801                            dataLayer.push({ "event": "ProductsAddedIntoBag", "products_added_into_bag": productsAdded });
5802                            if (Next.Settings.Channel.Promotions.Sampling && actionParams.actionPath === "bag/addSample") {
5803                                dataLayer.push({
5804                                    event: 'Sampling',
5805                                    Sampling: {
5806                                        Category: 'Sampling',
5807                                        Action: 'Banner',
5808                                        Label: 'Sampling_ribbon_add_to_bag'
5809                                    }
5810                                });
5811                            }
5812                        }
5813                    }
5814                    if (window.monetateQ && typeof monetateEnabled != 'undefined' && monetateEnabled) {
5815                        if (actionParams.actionType != undefined && (actionParams.actionType === "remove")) {
5816                            window.monetateQ.push(["addCategories", ['RemovedFromBag']]);
5817                        }
5818                    }
5819                }
5820            }
5821        };
5822        Basket.prototype.ItemRemove = function (itemID, customItemType) {
5823            RebuildDataLayer();
5824            var actionParams = {
5825                actionPath: "bag/remove",
5826                postData: { id: itemID, customItemType: customItemType },
5827                actionType: "remove",
5828                loadBasketPage: false
5829            };
5830            this.AddBagAction(actionParams);
5831        };
5832        Basket.prototype.ItemReject = function (itemID) {
5833            RebuildDataLayer();
5834            var actionParams = {
5835                actionPath: "bag/reject",
5836                postData: { id: itemID },
5837                actionType: "reject",
5838                loadBasketPage: false
5839            };
5840            this.AddBagAction(actionParams);
5841        };
5842        Basket.prototype.ItemAccept = function (itemID) {
5843            RebuildDataLayer();
5844            var actionParams = {
5845                actionPath: "bag/accept",
5846                postData: { id: itemID },
5847                actionType: "accept",
5848                loadBasketPage: false
5849            };
5850            this.AddBagAction(actionParams);
5851        };
5852        Basket.prototype.ItemAddSample = function (items) {
5853            RebuildDataLayer();
5854            var actionParams = {
5855                actionPath: "bag/addSample",
5856                postData: { items: items },
5857                actionType: "addSample",
5858                loadBasketPage: false
5859            };
5860            this.AddBagAction(actionParams);
5861        };
5862        Basket.prototype.ItemRemoveSample = function (itemID) {
5863            RebuildDataLayer();
5864            var actionParams = {
5865                actionPath: "bag/removeSample",
5866                postData: { id: itemID },
5867                actionType: "removeSample",
5868                loadBasketPage: false
5869            };
5870            this.AddBagAction(actionParams);
5871        };
5872        Basket.prototype.CustomAction = function (data, customActionId) {
5873            RebuildDataLayer();
5874            var actionParams = {
5875                actionPath: "customAction",
5876                postData: {
5877                    customActionId: customActionId,
5878                    data: data
5879                },
5880                actionType: "customAction",
5881                loadBasketPage: false
5882            };
5883            this.AddBagAction(actionParams);
5884        };
5885        Basket.prototype.ItemAdd = function (itemID, optionNo, quantity, chain, loadBasketPage, callBack, SaleClearanceS
5885ofaImage, modalItemUrl, originatesFromQbtTray, basePagePdpItemNumber) {
5886            if (SaleClearanceSofaImage === void 0) { SaleClearanceSofaImage = ""; }
5887            if (modalItemUrl === void 0) { modalItemUrl = ""; }
5888            if (originatesFromQbtTray === void 0) { originatesFromQbtTray = false; }
5889            if (basePagePdpItemNumber === void 0) { basePagePdpItemNumber = ""; }
5890            RebuildDataLayer();
5891            //Build action paramters
5892            var actionParams = {
5893                actionPath: "bag/add",
5894                postData: { id: itemID, option: optionNo, chain: chain, quantity: quantity, modalItemUrl: modalItemUrl, SaleClearanceSofaImage: SaleClearanceSofaImage },
5895                actionType: "add",
5896                loadBasketPage: loadBasketPage,
5897                callBack: callBack
5898            };
5899            SaveCurrentLocation();
5900            itemNumberAdded = itemID;
5901            if (originatesFromQbtTray && basePagePdpItemNumber != "") {
5902                itemNumberAdded = basePagePdpItemNumber;
5903            }
5904            if (this.MobilePMeterAnimationEnabled) {
5905                this.TriggerMobilePMeterAnimation = true;
5906            }
5907            if (this.DesktopPMeterAnimationEnabled) {
5908                this.TriggerDesktopPMeterAnimation = true;
5909            }
5910            //Pass to AddBagAction method
5911            this.AddBagAction(actionParams);
5912        };
5913        Basket.prototype.ItemAddCist = function (itemID, optionNo, quantity, chain, loadBasketPage, callBack, branchId) {
5914            RebuildDataLayer();
5915            //Build action paramters
5916            var actionParams = {
5917                actionPath: "bag/AddCist",
5918                postData: { id: itemID, option: optionNo, chain: chain, quantity: quantity, ciststoreid: branchId },
5919                actionType: "add",
5920                loadBasketPage: loadBasketPage,
5921                callBack: callBack
5922            };
5923            SaveCurrentLocation();
5924            itemNumberAdded = itemID;
5925            //Pass to AddBagAction method
5926            this.AddBagAction(actionParams);
5927        };
5928        Basket.prototype.ItemAddMultiple = function (data, options, callBack, dataLoadCallback) {
5929            RebuildDataLayer();
5930            //Fallback in case some method calls are still sending a boolean (loadBasketPage) for 2nd parameter
5931            if (typeof options == "boolean") {
5932                options = {
5933                    loadBasketPage: options
5934                };
5935            }
5936            var postData = {
5937                data: $.toJSON(data),
5938                pageurl: null,
5939                deliveryweeks: null,
5940                grouped: false,
5941                groupType: null
5942            };
5943            if (options.pageurl
5944                && options.pageurl.length) {
5945                postData.pageurl = options.pageurl;
5946            }
5947            if (options.deliveryweeks != null
5948                && options.deliveryweeks.toString().length) {
5949                postData.deliveryweeks = options.deliveryweeks;
5950            }
5951            if (options.grouped
5952                && options.groupType != null
5953                && options.groupType.length) {
5954                postData.grouped = options.grouped;
5955                postData.groupType = options.groupType;
5956            }
5957            var actionParams = {
5958                actionPath: "bag/addmultiple",
5959                postData: postData,
5960                actionType: "add",
5961                loadBasketPage: options.loadBasketPage,
5962                callBack: callBack,
5963                dataLoadCallback: dataLoadCallback
5964            };
5965            SaveCurrentLocation();
5966            this.AddBagAction(actionParams);
5967        };
5968        Basket.prototype.ItemAddWarranty = function (itemID, optionNo, chain, warrantyID, warrantyOption, callBack) {
5969            RebuildDataLayer();
5970            var actionParams = {
5971                actionPath: "bag/addwarranty",
5972                postData: { id: itemID, option: optionNo, warranty: warrantyID, warrantyoptionno: warrantyOption },
5973                actionType: "add",
5974                loadBasketPage: false,
5975                callBack: callBack
5976            };
5977            itemNumberAdded = itemID;
5978            //Pass to AddBagAction method
5979            this.AddBagAction(actionParams);
5980        };
5981        // used by sofas
5982        Basket.prototype.ItemAddLinkedItem = function (itemID, optionNo, linkedID, linkedOption, quantity, loadBasketPage, callBack, originatesFromQbtTray, basePagePdpItemNumber) {
5983            if (originatesFromQbtTray === void 0) { originatesFromQbtTray = false; }
5984            if (basePagePdpItemNumber === void 0) { basePagePdpItemNumber = ""; }
5985            RebuildDataLayer();
5986            var actionParams = {
5987                actionPath: "bag/addlinkeditem",
5988                postData: { id: itemID, option: optionNo, linkeditem: linkedID, linkeditemoption: linkedOption },
5989                actionType: "add",
5990                loadBasketPage: loadBasketPage,
5991                callBack: callBack
5992            };
5993            itemNumberAdded = itemID;
5994            if (originatesFromQbtTray && basePagePdpItemNumber != "") {
5995                itemNumberAdded = basePagePdpItemNumber;
5996            }
5997            //Pass to AddBagAction method
5998            this.AddBagAction(actionParams);
5999        };
6000        Basket.prototype.ItemUpdateSize = function (itemID, optionNo, itemNumber) {
6001            var _this = this;
6002            RebuildDataLayer();
6003            var eventId = Date.now().toString();
6004            var updateSizeSubscription = w.subjects["$ SHOPPING_BAG_UPDATE_SIZE_CALLBACK"].subscribe(function (eventResponse) {
6005                if (eventId === eventResponse.eventId) {
6006                    var jqXHR = {
6007                        getResponseHeader: function () { return false; },
6008                        status: eventResponse.status
6009                    };
6010                    if (eventResponse.success) {
6011                        if (_this.MobilePMeterAnimationEnabled) {
6012                            _this.TriggerMobilePMeterAnimation = true;
6013                        }
6014                        _this.LoadSuccess(eventResponse.data, eventResponse.textStatus, jqXHR, 'addupdatesize');
6015                    }
6016                    else {
6017                        _this.LoadError(jqXHR, eventResponse.textStatus, null, 'updatesize');
6018                    }
6019                    updateSizeSubscription.unsubscribe();
6020                }
6021            });
6022            var updateSizeEventData = { eventId: eventId, id: itemID, optionNumber: optionNo, itemNumber: itemNumber };
6023            w.subjects["$ SHOPPING_BAG_UPDATE_SIZE"].next(updateSizeEventData);
6024        };
6025        Basket.prototype.ItemUpdateQuantity = function (itemID, quantity, loadBasketPage) {
6026            var _this = this;
6027            if (loadBasketPage === void 0) { loadBasketPage = true; }
6028            RebuildDataLayer();
6029            var eventId = Date.now().toString();
6030            var updateSizeSubscription = w.subjects["$ SHOPPING_BAG_UPDATE_QUANTITY_CALLBACK"].subscribe(function (eventResponse) {
6031                if (eventId === eventResponse.eventId) {
6032                    var jqXHR = {
6033                        getResponseHeader: function () { return false; },
6034                        status: eventResponse.status
6035                    };
6036                    if (eventResponse.success) {
6037                        if (_this.MobilePMeterAnimationEnabled) {
6038                            _this.TriggerMobilePMeterAnimation = true;
6039                        }
6040                        if (_this.DesktopPMeterAnimationEnabled) {
6041                            _this.TriggerDesktopPMeterAnimation = true;
6042                        }
6043                        _this.LoadSuccess(eventResponse.data, eventResponse.textStatus, jqXHR, 'updatequantity', loadBasketPage);
6044                    }
6045                    else {
6046                        _this.LoadError(jqXHR, eventResponse.textStatus, null, 'updatequantity');
6047                    }
6048                    updateSizeSubscription.unsubscribe();
6049                }
6050            });
6051            var updateSizeEventData = { eventId: eventId, id: itemID, quantity: quantity };
6052            w.subjects["$ SHOPPING_BAG_UPDATE_QUANTITY"].next(updateSizeEventData);
6053        };
6054        Basket.prototype.AddEVoucher = function (id, option, eVoucherTo, eVoucherFrom, eVoucherEmail, eVoucherMessage, ecardDeliveryDate) {
6055            RebuildDataLayer();
6056            var actionParams = {
6057                actionPath: "bag/addevoucher",
6058                postData: { id: id, option: option, eVoucherTo: eVoucherTo, eVoucherFrom: eVoucherFrom, eVoucherEmail: eVoucherEmail, eVoucherMessage: eVoucherMessage, ecardDeliveryDate: ecardDeliveryDate },
6059                actionType: "addEvoucher",
6060                loadBasketPage: false
6061            };
6062            this.AddBagAction(actionParams);
6063        };
6064        Basket.prototype.AddEVoucherMobile = function (id, option, eVoucherTo, eVoucherFrom, eVoucherEmail, eVoucherMessage, ecardDeliveryDate, callBack) {
6065            RebuildDataLayer();
6066            var actionParams = {
6067                actionPath: "bag/addevoucher",
6068                postData: { id: id, option: option, eVoucherTo: eVoucherTo, eVoucherFrom: eVoucherFrom, eVoucherEmail: eVoucherEmail, eVoucherMessage: eVoucherMessage, ecardDeliveryDate: ecardDeliveryDate },
6069                actionType: "addEvoucher",
6070                loadBasketPage: false,
6071                callBack: callBack
6072            };
6073            this.AddBagAction(actionParams);
6074        };
6075        //add gift card item to Shopping Bag
6076        Basket.prototype.AddGiftCard = function (id, amountOption, firstName, lastName, addressLine1, addressLine2, addressLine3, addressLine4, addressLine5, postCode, message, deliveryDate, deliveryOption, deliveryCharge, mediacode, callBack) {
6077            RebuildDataLayer();
6078            var actionParams = {
6079                actionPath: "bag/addgiftcard",
6080                postData: { id: id, amountOption: amountOption, firstName: firstName, lastName: lastName, addressLine1: addressLine1, addressLine2: addressLine2, addressLine3: addressLine3, addressLine4: addressLine4, addressLine5: addressLine5, postCode: postCode, message: message, deliveryDate: deliveryDate, deliveryOption: deliveryOption, deliveryCharge: deliveryCharge, mediacode: mediacode },
6081                actionType: "addgiftcard",
6082                loadBasketPage: false,
6083                callBack: callBack
6084            };
6085            this.AddBagAction(actionParams);
6086        };
6087        Basket.prototype.Load = function () {
6088            w.subjects["$ SHOPPING_BAG_GET"].next({ guestAccountConverted: guestAccountConverted });
6089        };
6090        Basket.prototype.NotifySuccess = function () {
6091            if (this.Loaded) {
6092                for (var i = 0; i < this.NotifyChange.length; i++) {
6093                    this.NotifyChange[i]();
6094                }
6095            }
6096            ;
6097        };
6098        Basket.prototype.AddItemNotify = function (resultItemArray, currentBag) {
6099            var eventResponse = {
6100                success: true,
6101                data: { ShoppingBag: currentBag },
6102                status: 200,
6103                textStatus: "OK",
6104                eventId: null
6105            };
6106            w.subjects["$ SHOPPING_BAG_ADD_CALLBACK"].next(eventResponse);
6107            this.AddItemNotifyInternal(resultItemArray, currentBag);
6108        };
6109        Basket.prototype.AddItemNotifyInternal = function (resultItemArray, currentBag) {
6110            var itemObj = {
6111                itemArray: resultItemArray,
6112                currentBag: currentBag
6113            };
6114            this.OutboundQueue.push(itemObj);
6115            if (!this.NotifyWaiting) {
6116                this.NotifyWaiting = true;
6117                // var nextNotifyItem = NextBasket.OutboundQueue.shift();
6118                var nextNotifyItem = this.OutboundQueue[0];
6119                // check if the item is a part of multibuy if so than call get multibuy
6120                //  if (NextBasket.OutboundQueue[0].itemArray[0].IsMultibuyItem)            
6121                if (this.DesktopPMeterAnimationEnabled) {
6122                    this.TriggerDesktopPMeterAnimation = true;
6123                }
6124                if (this.MobilePMeterAnimationEnabled) {
6125                    this.TriggerMobilePMeterAnimation = true;
6126                }
6127                this.NotifyItemAdded(nextNotifyItem);
6128            }
6129        };
6130        Basket.prototype.SetGAUp = function (SessionTransferVariables) {
6131            if (SessionTransferVariables != null) {
6132                this.SessionTransferVariables.IgnoreGA = SessionTransferVariables.IgnoreGA;
6133                this.SessionTransferVariables.GAAccount = SessionTransferVariables.GAAccount;
6134                this.SessionTransferVariables.GASessionId = SessionTransferVariables.GASessionId;
6135                this.SessionTransferVariables.HomeUrl = SessionTransferVariables.HomeUrl;
6136                this.SessionTransferVariables.SearchUrl = SessionTransferVariables.SearchUrl;
6137                this.SessionTransferVariables.ShoppingBagUrl = SessionTransferVariables.ShoppingBagUrl;
6138                this.SessionTransferVariables.GAEnabledForGTM = SessionTransferVariables.GAEnabledForGTM;
6139                this.SessionTransferVariables.GAAccountForGTM = SessionTransferVariables.GAAccountForGTM;
6140                this.NotifyGAAccount(this.SessionTransferVariables.GAAccount, this.SessionTransferVariables.GASessionId, !this.SessionTransferVariables.IgnoreGA);
6141                this.NotifyGAAccountForGTM(this.SessionTransferVariables.GAAccountForGTM, this.SessionTransferVariables.GASessionId, this.SessionTransferVariables.GAEnabledForGTM);
6142            }
6143            else {
6144                // Call GA with NOTHING so that defaults are resorted to.
6145                this.NotifyGAAccount(null, null, null);
6146                this.NotifyGAAccountForGTM(null, null, null);
6147            }
6148        };
6149        Basket.prototype.convertProductGender = function (gender) {
6150            if (gender) {
6151                if (gender.toLowerCase().indexOf("boy") != -1)
6152                    return "Men";
6153                if (gender.toLowerCase().indexOf("girl") != -1)
6154                    return "Women";
6155            }
6156            else {
6157                gender = '';
6158            }
6159            return gender;
6160        };
6161        // callback - this is more visual, it is triggered once the notification is shown
6162        // dataLoadCallback - this is triggered as soon as we have data
6163        Basket.prototype.LoadSuccess = function (data, textStatus, jqXHR, actionType, loadBasketPage, callBack, dataLoadCallback) {
6164            // Call the GA setup routine
6165            if (setUpGA) {
6166                if (data != null && data.ShoppingBag != null) {
6167                    this.SetGAUp(data.ShoppingBag.SessionTransferVariables);
6168                }
6169                else {
6170                    this.SetGAUp(null);
6171                }
6172            }
6173            checkAndRedirectForAjaxError(jqXHR, false, 'ShoppingBagCommon.js: ' + actionType);
6174            if (dataLoadCallback) {
6175                dataLoadCallback(true);
6176            }
6177            if (this.SessionID === '')
6178                this.SessionID = data.SessionID;
6179            if (this.VisitorID === '')
6180                this.VisitorID = data.VisitorID;
6181            if (this.RoamingProfileId === '')
6182                this.RoamingProfileId = data.RoamingProfileId;
6183            this.BrowseOnlyMode = data.BrowseOnlyMode;
6184            //Check if RedirectURL has a value, and HTTP redirect the user to that value
6185            if (data.Variables && data.Variables.RedirectURL) {
6186                window.location.replace(data.Variables.RedirectURL);
6187            }
6188            if (actionType === "load"
6189                && typeof CountryRedirect === 'object') {
6190                //Initalise CountryRedirect object and pass in data from response
6191                CountryRedirect.Init(data.CountryRedirect);
6192                $(document).trigger("NextBasket_Load");
6193            }
6194            if (actionType === "load" && typeof NextBasketState !== 'undefined')
6195                NextBasketState.SetNextBasketDataOnPageLoad(data.ShoppingBag);
6196            if (Next.Settings.Channel.IsNextUnlimitedEnabled) {
6197                if (((actionType === "remove") || (actionType === "removegroup") || (actionType === "updatequantity") || (actionType === "addupdatesize") || (Next.Settings.Mobile.IsShoppingbagDrawerEnabled && actionType === "load")) && typeof data.NextUnlimited === "object") {
6198                    this.NextUnlimited.Update(data.NextUnlimited);
6199                }
6200            }
6201            //First need to start the next action waiting to be sent (if one exists)
6202            if (this.InboundQueue.length) {
6203                //Get next action and send to be executed
6204                var nextAction = this.InboundQueue.shift();
6205                this.ExecuteBagAction(nextAction);
6206            }
6207            else {
6208                //Else - all items are processed
6209                this.ItemsWaiting = false;
6210                // Now we know we are on the last item, lets handle any errors
6211                this.NotifyErrors();
6212            }
6213            var hasOutOfStockItems = false;
6214            if (Next.Settings.Channel.Promotions.GWP && typeof gwpShoppingBagBanners !== 'undefined') {
6215                gwpShoppingBagBanners.refresh(data.ShoppingBag);
6216            }
6217            if (Next.Settings.Channel.Promotions.Sampling && window.location.href.indexOf("shoppingbag") > -1
6218                && typeof SamplingRibbon !== 'undefined' && typeof SamplingBanner !== 'undefined') {
6219                SamplingRibbon.create(data.ShoppingBag);
6220                SamplingBanner.create(data.ShoppingBag);
6221            }
6222            if (Next.Settings.Channel.EnableFlowers && window.location.href.indexOf("shoppingbag") > -1) {
6223                if (typeof data.ShoppingBag !== 'undefined' && typeof data.ShoppingBag.Items !== 'undefined' && !data.ShoppingBag.Items.some(function (i) { return i.FulfilmentType === 'F'; })) {
6224                    var flowersInfoBox = document.querySelectorAll('.flowersInfoBox');
6225                    flowersInfoBox.forEach(function (item) {
6226                        item.remove();
6227                    });
6228                }
6229            }
6230            if (Next.Settings.Channel.EnableFlowers && typeof FlowerItem !== 'undefined') {
6231                FlowerItem.ManageTimeoutForFlowerItem(data.ShoppingBag);
6232            }
6233            if (Next.Settings.Channel.ShoppingBagBannersSettings.ShoppingBagBanners.Enabled && window.location.href.indexOf("shoppingbag") > -1 && typeof ContentDeliverySdkInitializer !== 'undefined') {
6234                ContentDeliverySdkInitializer.refreshContentDeliverySdk(data.ShoppingBag);
6235            }
6236            switch (actionType) {
6237                case "add":
6238                case "addEvoucher":
6239                case "addSample":
6240                case "addgiftcard":
6241                    //                this.Data = data.Bag;
6242                    (actionType == "addEvoucher" || actionType == "addgiftcard") ? this.Data = data.Bag : this.Data = data.ShoppingBag;
6243                    //this.Data = data.ShoppingBag;
6244                    this.Loaded = true;
6245                    var newItemArr = [];
6246                    // TODO: Filter out feet
6247                    if (data.ItemStates != null) {
6248                        for (var i = 0; i < data.ItemStates.length; i++) {
6249                            if (data.ItemStates[i].State === "A" || data.ItemStates[i].State === "R") {
6250                                newItemArr.push(data.ItemStates[i].Item);
6251                                //FB 162345 - this functionality is not currently required as we do not want subsequent redirect from Clearance
6252                                //if (data.ItemStates[i].Item.StockStatus === "soldout")
6253                                //    hasOutOfStockItems = true;
6254                            }
6255                        }
6256                    }
6257                    if (Next.Settings.Channel.ShoppingBagBannersSettings.ShoppingBagBanners.Enabled &&
6258                        dataLayer != undefined &&
6259                        newItemArr.length > 0) {
6260                        this.pushAddtoBagClickToDataLayer(newItemArr);
6261                    }
6262                    if (Next.Settings.Channel.Promotions.GWP && newItemArr.length > 1) {
6263                        var freeGift = newItemArr.find(function (item) { return item.IsFreeGiftItem; });
6264                        if (freeGift !== undefined) {
6265                            newItemArr[0].TriggeredFreeGift = true;
6266                            newItemArr[0].FreeGiftTitle = freeGift.Description;
6267                            if (dataLayer != null && Next.Settings.Channel.Promotions.GWP) {
6268                                dataLayer.push({
6269                                    event: 'GWP',
6270                                    GWP: {
6271                                        Label: 'gwp_pdp_add_to_bag',
6272                                        Action: 'PDP',
6273                                        Category: 'Gift With Purchase'
6274                                    }
6275                                });
6276                            }
6277                        }
6278                    }
6279                    this.Data.LatestItem = newItemArr;
6280                    if (actionType === "addEvoucher") {
6281                        hasOutOfStockItems = false;
6282                    }
6283                    //var curBag = data.Bag;
6284                    var curBag;
6285                    (actionType == "addEvoucher" || actionType == "addgiftcard") ? curBag = data.Bag : curBag = data.ShoppingBag;
6286                    // If we are displaying the basket page then we need to update the count and total summary in the header, otherwise we need to show the notification
6287                    if (loadBasketPage || hasOutOfStockItems)
6288                        this.PriceDial(curBag);
6289                    else
6290                        this.AddItemNotifyInternal(newItemArr, curBag);
6291                    if (this.Data.LowerLimitReached || this.Data.IsShoppingBagFull) {
6292                        // todo: this seems to be an error:
6293                        // the behaviour in this area seems to be broken in live - past a certain # of items (lowerlimit?) the notification stops and the shopping bag is only updated on loading a new page (and once per page after?) - the shopping bag page isn't loaded
6294                        //notifyItemAdded = true; // this forces the shopping bag page to be loaded - Raj
6295                        //todo: we're going to revisit this at a later date, but for now we'll load the shopping bag page
6296                        if (typeof NavigateToShoppingBag === 'function') {
6297                            NavigateToShoppingBag();
6298                        }
6299                        else {
6300                            window.location.href = Next.Settings.Channel.SiteUrl + "/shoppingbag";
6301                        }
6302                    }
6303                    break;
6304                default: // all other action types (remove, update etc) do not need to perform any specific action (currently) - Raj
6305                    var returnedData = null;
6306                    //                if (data.Bag != undefined)
6307                    //                    returnedData = data.Bag;
6308                    //                else
6309                    returnedData = data.ShoppingBag;
6310                    //var dataVersion = returnedData.Version;
6311                    this.Data = returnedData;
6312                    this.Loaded = true;
6313                    this.NotifySuccess(); // this should come first, to display total amount at the top of the page - Raj
6314                    var forcePageRefresh = false;
6315                    if (data.IgnoreBagVersion === true)
6316                        forcePageRefresh = true;
6317                    var url = window.location.pathname.toLowerCase();
6318                    if (typeof RefreshShoppingBag === 'function') {
6319                        RefreshShoppingBag(forcePageRefresh);
6320                    }
6321                    else if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1) {
6322                        $(function () {
6323                            if (typeof RefreshShoppingBag === 'function') {
6324                                RefreshShoppingBag(forcePageRefresh);
6325                            }
6326                        });
6327                    }
6328                    //Signify if the shopping bag has been recreated from a previous session and the user has not been previously notified.
6329                    if (actionType === "load" && returnedData.RecreatedFromPreviousSession && !returnedData.UserNotifiedOfSessionRecreation && returnedData.Authenticated) {
6330                        //this.Notify(returnedData);
6331                        if (this.Data.IsShoppingBagFull) {
6332                            if (typeof NavigateToShoppingBag === 'function') {
6333                                NavigateToShoppingBag();
6334                            }
6335                            else {
6336                                window.location.href = Next.Settings.Channel.SiteUrl + "/shoppingbag";
6337                            }
6338                        }
6339                        else {
6340                            this.DisplayRebuildNotification(returnedData);
6341                        }
6342                    }
6343                    break;
6344            }
6345            if (data.ShoppingBag != null && $("#promoInputShoppingBag").length > 0) {
6346                if (data.ShoppingBag.MultiBuyDiscount != null && data.ShoppingBag.MultiBuyDiscount > 0 && !Next.Settings.Channel.AllowPromoWithMultibuy || data.ShoppingBag.ItemCount == 0) {
6347                    $('#promoInputShoppingBag').hide(300);
6348                }
6349                else {
6350                    $('#promoInputShoppingBag').show(300);
6351                }
6352            }
6353            if (callBack) {
6354                var callBackParam = !(Object(callBack).name == "removeFromSaveForLater" && this.Data.IsShoppingBagFull);
6355                /*
6356                    Protocol relative SiteUrl causes the page to load faster
6357                    Therefore the page is refreshed before the item is removed from save for later
6358                    So, Feature switch for HTTPS to remove setTimeout
6359                */
6360                if (Next.Settings.Channel.HttpsEnabled) {
6361                    callBack(callBackParam);
6362                }
6363                else {
6364                    setTimeout(function () {
6365                        callBack(callBackParam);
6366                    }, 500);
6367                }
6368            }
6369            this.UpdateBagUI(this);
6370            this.saveBagCookieForVIP();
6371            if (loadBasketPage || hasOutOfStockItems)
6372                if (typeof NavigateToShoppingBag === 'function') {
6373                    NavigateToShoppingBag();
6374                }
6375                else {
6376                    var loadHtmlContentUrl = Next.Settings.Channel.HttpsEnabled ? window.location.protocol + AjaxURL() : AjaxURL();
6377                    if (Next.Settings.Channel.IsTotalPlatformLiteClient && Next.Settings.Channel.MainSiteAbsolutePath && Next.Settings.Channel.MainSiteAbsolutePath !== "/") {
6378                        loadHtmlContentUrl = AjaxURL() + Next.Settings.Channel.MainSiteAbsolutePath.replace("/", "") + "/";
6379                    }
6380                    LoadHTMLContent(loadHtmlContentUrl + 'shoppingbag', 'Shopping Bag');
6381                }
6382            var cartRows = "";
6383            var products = "";
6384            var productList = "";
6385            var itemsData = "";
6386            var position = 0;
6387            var dataLayerCurrencyCode = "GBP";
6388            var isShoppingBagPage = false;
6389            var isDeliveryPage = false;
6390            var isPaymentPage = false;
6391            var isCompletePage = false;
6392            var pageType = "";
6393            var bloomReachPixelEnabled = false;
6394            var productsAddedIntoBag = false;
6395            var productSKUs = "";
6396            monetateEnabled = false;
6397            if (!Next.Settings.Channel.PlatModGoogleAnalyticsSDK) {
6398                if (rebuildDataLayer && dataLayer != undefined && dataLayer.length > 0) {
6399                    for (var j = 0; j < dataLayer.length; j++) {
6400                        if (dataLayer[j].page_type != undefined) {
6401                            pageType = dataLayer[j].page_type;
6402                        }
6403                        else if (dataLayer[j].monetate_enabled != undefined) {
6404                            monetateEnabled = dataLayer[j].monetate_enabled === "true";
6405                        }
6406                        else if (dataLayer[j].br_pixel_enabled != undefined) {
6407                            bloomReachPixelEnabled = dataLayer[j].br_pixel_enabled === "true";
6408                        }
6409                        else if (dataLayer[j].channel_currency_code != undefined) {
6410                            dataLayerCurrencyCode = dataLayer[j].channel_currency_code;
6411                        }
6412                        else if (dataLayer[j].is_shoppingbag_page != undefined) {
6413                            isShoppingBagPage = dataLayer[j].is_shoppingbag_page === "true";
6414                        }
6415                        else if (dataLayer[j].is_delivery_page != undefined) {
6416                            isDeliveryPage = dataLayer[j].is_delivery_page === "true";
6417                        }
6418                        else if (dataLayer[j].is_payment_page != undefined) {
6419                            isPaymentPage = dataLayer[j].is_payment_page === "true";
6420                        }
6421                        else if (dataLayer[j].is_complete_page != undefined) {
6422                            isCompletePage = dataLayer[j].is_complete_page === "true";
6423                        }
6424                        else if (dataLayer[j].event != undefined) {
6425                            productsAddedIntoBag = (dataLayer[j].event === "ProductsAddedIntoBag");
6426                        }
6427                        else if (dataLayer[j].monetateCartRows != undefined) {
6428                            dataLayer.splice(j, 1);
6429                        }
6430                        else if (dataLayer[j].itemsData != undefined) {
6431                            dataLayer.splice(j, 1);
6432                        }
6433                        else if (dataLayer[j].bloomreachBasketData != undefined) {
6434                            dataLayer.splice(j, 1);
6435                        }
6436                    }
6437                }
6438                if (rebuildDataLayer && NextBasket.Data.Items != null && NextBasket.Data.Items.length > 0) {
6439                    var bloomreachBasketData = itemsData;
6440                    for (var i = 0; i < NextBasket.Data.Items.length; i++) {
6441                        if (cartRows !== "") {
6442                            cartRows = cartRows + ",";
6443                        }
6444                        var friendlyItemNumber = NextBasket.Data.Items[i].ItemNumber.substring(0, 3) + '-' + NextBasket.Data.Items[i].ItemNumber.substring(3);
6445                        var itemNumber = NextBasket.Data.Items[i].ItemNumber;
6446                        var quantity = NextBasket.Data.Items[i].Quantity;
6447                        var price = NextBasket.Data.Items[i].Price;
6448                        var name = NextBasket.Data.Items[i].Description;
6449                        var variant = NextBasket.Data.Items[i].SizeDescription;
6450                        if (bloomReachPixelEnabled) {
6451                            if (bloomreachBasketData !== "") {
6452                                bloomreachBasketData = bloomreachBasketData + ",";
6453                            }
6454                            var brItemNumber = NextBasket.Data.Items[i].ItemNumber.substring(0, 3) +
6455                                NextBasket.Data.Items[i].ItemNumber.substring(3);
6456                            var productId = "";
6457                            var sku = "";
6458                            if (NextBasket.Data.Items[i].ItemCategory === "sofas" &&
6459                                NextBasket.Data.Items[i].AlternativeDescription.split("|").length > 0) {
6460                                var sofaStyleTitle = NextBasket.Data.Items[i].AlternativeDescription.split("|")[0].trim()
6461                                    .replace(/ /g, "").toLowerCase();
6462                                productId = sofaStyleTitle + "_" + NextBasket.Data.Items[i].OptionNo;
6463                                sku = productId + "_" + NextBasket.Data.Items[i].ItemNumber;
6464                            }
6465                            else {
6466                                productId = brItemNumber;
6467                                sku = brItemNumber + NextBasket.Data.Items[i].OptionNo;
6468                            }
6469                            bloomreachBasketData = bloomreachBasketData + '{"prod_id": "' + productId + '", "sku": "' + sku + '", "name": "' + n
6469ame + '", "quantity": "' + quantity + '", "price": "' + price + '"}';
6470                        }
6471                        cartRows = cartRows + '{"productId": "' + friendlyItemNumber + '", "quantity": "' + quantity + '","unitPrice": "' + price + '","currency": "' + dataLayerCurrencyCode + '"}';
6472                        if (itemsData !== "") {
6473                            itemsData = itemsData + ",";
6474                        }
6475                        itemsData = itemsData + '{"prod_id": "' + friendlyItemNumber + '", "sku": "' + friendlyItemNumber + '-' + NextBasket.Data.Items[i].OptionNo + '", "name": "' + name + '", "quantity": "' + quantity + '", "price": "' + price + '"}';
6476                        friendlyItemNumber = friendlyItemNumber + '-';
6477                        if (products !== "") {
6478                            products = products + ",";
6479                        }
6480                        if (productList !== "") {
6481                            productList = productList + ",";
6482                        }
6483                        position = i + 1;
6484                        var ItemVariant = NextBasket.Data.Items[i].ItemNumber + '-' + NextBasket.Data.Items[i].OptionNo + ' | ' + NextBasket.Data.Items[i].SizeDescription;
6485                        var colour = NextBasket.Data.Items[i].Colour || "";
6486                        var markdownItem = NextBasket.Data.Items[i].IsDiscount ? "true" : "false";
6487                        var brand = NextBasket.Data.Items[i].ItemBrand || "";
6488                        products = products + '{"id": "' + friendlyItemNumber + '", "name": "' + name + '","price": "' + price + '","variant": "' + variant + '","position": ' + position + ', "quantity": "' + quantity + '","markdownItem":"' + markdownItem + '"}';
6489                        productList = productList + '{"id": "' + friendlyItemNumber + '", "name": "' + name + '","price": "' + price + '","brand":"' + brand + '" ,"category":"' + NextBasket.Data.Items[i].ItemCategory + '","variant": "' + ItemVariant + '","position": ' + position + ', "quantity": ' + quantity + ',"dimension21":"' + NextBasket.Data.Items[i].StockStatus + '","dimension22":"' + NextBasket.Data.Items[i].ItemCategory + '","dimension23":"' + NextBasket.Data.Items[i].Department + '","dimension24":"' + this.convertProductGender(NextBasket.Data.Items[i].Gender) + '","dimension25":"","dimension26":"' + brand + '","dimension27":"' + brand + '","dimension28":"' + colour + '","markdownItem":"' + markdownItem + '"}';
6490                        if (productSKUs !== "") {
6491                            productSKUs = productSKUs + ",";
6492                        }
6493                        productSKUs = productSKUs + friendlyItemNumber;
6494                        if (NextBasket.Data.Items[i].OptionNo != null) {
6495                            productSKUs = productSKUs + NextBasket.Data.Items[i].OptionNo;
6496                        }
6497                    }
6498                    cartRows = JSON.parse('[' + cartRows + ']');
6499                    products = JSON.parse('[' + products + ']');
6500                    itemsData = JSON.parse('[' + itemsData + ']');
6501                    productList = JSON.parse('[' + productList + ']');
6502                    if (bloomReachPixelEnabled) {
6503                        bloomreachBasketData = JSON.parse('[' + JSON.stringify(bloomreachBasketData) + ']');
6504                    }
6505                    if (firebase != undefined) {
6506                        firebase.push({ "event": "monetateCart", "monetateCartRows": cartRows });
6507                        var eeCheckoutValues;
6508                        if (isShoppingBagPage && dataLayer != undefined) {
6509                            dataLayer.push({ "event": "shoppingbag", "total_number_of_items": NextBasket.Data.Items.length, "order_total": NextBasket.Data.FinalOrderValue, "product_skus": productSKUs });
6510                            if (pageType == "shoppingBag") {
6511                                dataLayer.push({ "event": "checkout", "ecommerce": { "currencyCode": dataLayerCurrencyCode, "checkout": { "actionField": { "step": 1 }, "products": products } } });
6512                                eeCheckoutValues = { "event": "ee-checkout", "ecommerce": { "currencyCode": Next.Settings.Channel.CurrencyCode, "checkout": { "actionField": { "step": 1, "option": "" }, "products": productList } } };
6513                                EnhancedEcommerceHelper.checkAndPushtoDatalayer("ee-checkout", eeCheckoutValues);
6514                            }
6515                        }
6516                        else if (isDeliveryPage) {
6517                            firebase.push({ "event": "checkout", "ecommerce": { "currencyCode": dataLayerCurrencyCode, "checkout": { "actionField": { "step": 2 }, "products": productList } } });
6518                            // eeCheckoutValues = { "event": "ee-checkout", "ecommerce": { "currencyCode": Next.Settings.Channel.CurrencyCode, "checkout": { "actionField": { "step": 2 }, "products": productList } } };
6519                            // EnhancedEcommerceHelper.checkAndPushtoDatalayer("ee-checkout", eeCheckoutValues);
6520                        }
6521                        else if (isPaymentPage) {
6522                            firebase.push({ "event": "checkout", "ecommerce": { "currencyCode": dataLayerCurrencyCode, "checkout": { "actionField": { "step": 3 }, "products": products } } });
6523                            //  eeCheckoutValues = { "event": "ee-checkout", "ecommerce": { "currencyCode": Next.Settings.Channel.CurrencyCode, "checkout": { "actionField": { "step": 3 }, "products": productList } } };
6524                            // EnhancedEcommerceHelper.checkAndPushtoDatalayer("ee-checkout", eeCheckoutValues);
6525                        }
6526                        firebase.push({ "event": "basketData", "items": itemsData });
6527                        if (bloomReachPixelEnabled && bloomreachBasketData.length > 0) {
6528                            firebase.push({ "event": "BRBasketdata", "br_basket_data": bloomreachBasketData });
6529                        }
6530                    }
6531                }
6532                this.CheckPersonalisedItems(NextBasket.Data.Items);
6533                var pageTypeQry = (pageType === "productPage" || pageType === "BeautyproductPage" || pageType === "productPageModal" || pageType === "searchResults" || pageType === "productListPage" || pageType === "clearanceProductListPage" || pageType === "tabbedcontent" || pageType === "homeWarePDP");
6534                monetateEnabled = monetateEnabled && (!pageTypeQry || actionType === "add");
6535                if (rebuildDataLayer && (NextBasket.Data.Items == null || NextBasket.Data.Items.length === 0) && !isCompletePage) {
6536                    if (dataLayer != undefined) {
6537                        dataLayer.push({ "monetateCartRows": undefined });
6538                        if (isShoppingBagPage) {
6539                            dataLayer.push({ "items": undefined });
6540                            dataLayer.push({ "br_basket_data": undefined });
6541                            dataLayer.push({ "ecommerce": undefined });
6542                            dataLayer.push({ "event": "gtm.dom" });
6543                        }
6544                    }
6545                    if (monetateEnabled) {
6546                        window.monetateQ.push(["addCartRows", [{}]]);
6547                    }
6548                }
6549                else if (monetateEnabled && rebuildDataLayer && !isCompletePage) {
6550                    if (dataLayer != undefined && dataLayer.length > 0) {
6551                        for (var k = 0; k < dataLayer.length; k++) {
6552                            if (dataLayer[k].monetateCartRows != undefined) {
6553                                window.monetateQ.push(["addCartRows", dataLayer[k].monetateCartRows]);
6554                                if (productsAddedIntoBag) {
6555                                    window.monetateQ.push(["addCategories", ['addedToBag']]);
6556                                }
6557                                ;
6558                                break;
6559                            }
6560                        }
6561                    }
6562                }
6563                if (monetateEnabled && rebuildDataLayer) {
6564                    var deviceType = "desktop";
6565                    if (dataLayer != undefined && dataLayer.length > 0) {
6566                        if (isCompletePage) {
6567                            for (var i = 0; i < dataLayer.length; i++) {
6568                                if (dataLayer[i].monetatePurchaseRows != undefined) {
6569                                    window.monetateQ.push(["addPurchaseRows", dataLayer[i].monetatePurchaseRows]);
6570                                    break;
6571                                }
6572                            }
6573                        }
6574                        for (var i = 0; i < dataLayer.length; i++) {
6575                            if (dataLayer[i].device_type) {
6576                                deviceType = dataLayer[i].device_type;
6577                                break;
6578                            }
6579                            if (dataLayer[i].siteLayout) {
6580                                deviceType = dataLayer[i].siteLayout; //sometimes device-type isn't defined
6581                                break;
6582                            }
6583                        }
6584                    }
6585                    window.monetateQ.push(["setPageType", pageType]);
6586                    window.monetateQ.push(["addCategories", [deviceType]]);
6587                    window.monetateQ.push(["setCustomVariables", [{ name: "deviceType", value: deviceType }]]);
6588                    if (itemNumberAdded != "") {
6589                        var friendlyItemNumber = itemNumberAdded.substring(0, 3) + '-' + itemNumberAdded.substring(3);
6590                        window.monetateQ.push(["addProductDetails", JSON.parse('["' + friendlyItemNumber + '"]')]);
6591                        itemNumberAdded = "";
6592                    }
6593                    window.monetateQ.push(["trackData"]);
6594                }
6595            }
6596            else {
6597                this.CheckPersonalisedItems(NextBasket.Data.Items);
6598                if (itemNumberAdded != "") {
6599                    itemNumberAdded = "";
6600                }
6601            }
6602            rebuildDataLayer = false;
6603            if (Next.Settings.Channel.StateConvergence !== undefined && Next.Settings.Channel.StateConvergence.IsEnabled && typeof (NextStateConvergence) != "undefined") {
6604                NextStateConvergence.Execute();
6605            }
6606        };
6607        Basket.prototype.LoadError = function (jqXHR, textStatus, errorThrown, actionType, callBack, dataLoadCallback) {
6608            checkAndRedirectForAjaxError(jqXHR, false, 'ShoppingBagCommon.js: ' + actionType);
6609            this.SetGAUp(null); // Call GA with NOTHING so that defaults are resorted to.
6610            if (dataLoadCallback) {
6611                dataLoadCallback(false);
6612            }
6613            if (callBack) {
6614                callBack(false, jqXHR.status);
6615            }
6616            // First, push the error onto the NotifyError array as JSON
6617            this.NotifyError.push({ Data: jqXHR, TextStatus: textStatus, ErrorThrown: errorThrown, ActionType: actionType });
6618            //On error, there may be more items waiting to be added, move on to these items
6619            if (this.InboundQueue.length) {
6620                var nextAction = this.InboundQueue.shift();
6621                this.ExecuteBagAction(nextAction);
6622            }
6623            else {
6624                //Else - all items are processed
6625                this.ItemsWaiting = false;
6626                // Now we know we are on the last item, lets handle any errors
6627                this.NotifyErrors();
6628            }
6629        };
6630        Basket.prototype.CheckPersonalisedItems = function (items) {
6631            var personalisedGiftInBag = false;
6632            var isGiftItemInBag = false;
6633            if (items != null && items.length > 0) {
6634                for (var i = 0; i < items.length; i++) {
6635                    var currentItem = items[i];
6636                    if (currentItem.Personalisation && currentItem.Personalisation === "Y" && currentItem.FulfilmentType !== "F") {
6637                        if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled) {
6638                            if (currentItem.FulfilmentType === 'M') {
6639                                var IsCustomizableCustomItem = currentItem.CustomItemType && ["Curtain", "Blind"].indexOf(currentItem.CustomItemType.toString()) > -1;
6640                                if (IsCustomizableCustomItem) {
6641                                    personalisedGiftInBag = true;
6642                                }
6643                            }
6644                            else {
6645                                personalisedGiftInBag = true;
6646                            }
6647                        }
6648                        else {
6649                            personalisedGiftInBag = true;
6650                        }
6651                    }
6652                    if (Next.Settings.Channel.GiftCardMigration) {
6653                        var departmentType = currentItem.Department;
6654                        if (departmentType && departmentType == "GiftCard") {
6655                            isGiftItemInBag = true;
6656                        }
6657                    }
6658                }
6659            }
6660            if (this.isResponsiveShoppingBag() && (personalisedGiftInBag || isGiftItemInBag)) {
6661                $('[id=divShoppingBagPersonalisation]').css({ 'display': 'block' });
6662            }
6663            // hide top blue banner if there are no Personalised items
6664            if (!personalisedGiftInBag && !isGiftItemInBag) {
6665                $("#PersonalisedGiftsInBagMessage").hide();
6666                if (this.isResponsiveShoppingBag()) {
6667                    $('[id=divShoppingBagPersonalisation]').removeClass("show");
6668                }
6669            }
6670        };
6671        Basket.prototype.ConfirmRedirectModal = function (cancelUrl) {
6672            $("#ChannelRedirect_Form").attr("action", Next.Settings.Channel.SiteUrl + "/ChannelRedirect/ConfirmChannelChange");
6673            this.ConfirmRedirectButtonInit();
6674        };
6675        Basket.prototype.ConfirmRedirectButtonInit = function () {
6676            $(document).on('click', '#ChannelRedirect_Confirm', function () {
6677                $("#ChannelRedirect_Background").css("height", "100%");
6678                $("#ChannelRedirect_Background").fadeOut("slow");
6679            });
6680        };
6681        Basket.prototype.RegisterChange = function (func) {
6682            this.NotifyChange.push(func);
6683        };
6684        Basket.prototype.RegisterError = function (func) {
6685            this.NotifyError.push(func);
6686        };
6687        Basket.prototype.NotifyErrors = function () {
6688            if (this.NotifyError.length) {
6689                ConsoleLog('Errors were detected when receiving a shopping bag response');
6690                // Loop through each error
6691                for (var i = 0; i < this.NotifyError.length; i++) {
6692                    var gaErrorString = "Shopping Bag Error";
6693                    // If we have a 513 status code then the session has been reset the maximum number of times, lets get the new bag and take the user to the error page
6694                    if (this.NotifyError[i].Data.status === 513) {
6695                        gaErrorString = "Shopping Bag Session Expiry Error";
6696                    }
6697                    // Log the error to GA
6698                    try {
6699                        ConsoleLog(gaErrorString + ": " + this.NotifyError[i].ActionType + " - " + this.NotifyError[i].TextStatus + " - " + this.NotifyError[i].ErrorThrown);
6700                        TrackGAEvent(gaErrorString, this.NotifyError[i].ActionType, this.NotifyError[i].TextStatus + " - " + this.NotifyError[i].ErrorThrown, 0);
6701                    }
6702                    catch (er) {
6703                        //ConsoleLog('Error Logging to GA');
6704                    }
6705                }
6706                // Empty the errors no we have dealt with them
6707                this.NotifyError = [];
6708            }
6709        };
6710        //used during vip to make sure customers are given the option to complete their order when moving between sale site and main 
6710site
6711        Basket.prototype.saveBagCookieForVIP = function () {
6712            if (this.Data.ItemCount > 0) { //update cookie if items in bag
6713                var cookieData = "MainSiteBag=Quantity=" + this.Data.ItemCount + "&TotalValue=" + this.Data.OrderGoodsValue + "&SaleSiteRead=False;path=/;";
6714                document.cookie = cookieData;
6715            }
6716            else {
6717                var nextMainSiteBagCookie = readCookie('MainSiteBag');
6718                if (nextMainSiteBagCookie) { //check if cookie exists before removing
6719                    document.cookie = "MainSiteBag=;expires=" + new Date().toGMTString() + ";path=/;";
6720                }
6721            }
6722        };
6723        Basket.prototype.isResponsiveShoppingBag = function () {
6724            var url = window.location.pathname.toLowerCase();
6725            return Next.Settings.Channel.ResponsiveShoppingBagIsEnabled &&
6726                url.indexOf("/shoppingbag") > -1 &&
6727                typeof RefreshShoppingBag !== 'function';
6728        };
6729        Basket.prototype.pushAddtoBagClickToDataLayer = function (newItemArr) {
6730            var itemsForTracking = newItemArr.map(function (item) {
6731                var itemNumber = String(item.ItemNumber).replace("-", "");
6732                var itemVariant = (itemNumber + '-' + item.OptionNo + " | " + item.SizeDescription);
6733                return {
6734                    id: itemNumber,
6735                    name: item.Description,
6736                    price: item.Price,
6737                    brand: item.ItemBrand,
6738                    category: item.ItemCategory,
6739                    variant: itemVariant,
6740                    position: 1,
6741                    quantity: item.Quantity,
6742                    dimension21: item.StockStatus,
6743                    dimension22: "",
6744                    dimension23: item.Department,
6745                    dimension24: item.Gender,
6746                    dimension25: "",
6747                    dimension26: "",
6748                    dimension27: item.ItemBrand,
6749                    dimension28: item.Colour,
6750                    markdownItem: item.IsMarkedDownItem,
6751                    titleType: "standard"
6752                };
6753            });
6754            dataLayer.push({
6755                "event": "ee-addToCart",
6756                "ecommerce": {
6757                    "currencyCode": Next.Settings.Channel.CurrencyCode,
6758                    "add": {
6759                        "products": itemsForTracking
6760                    }
6761                }
6762            });
6763        };
6764        return Basket;
6765    }());
6766    platmodCommon.Basket = Basket;
6767    function SaveCurrentLocation() {
6768        //save the url in jstorage for the breadcumbs
6769        if ($.jStorage && $.jStorage.storageAvailable()) {
6770            $.jStorage.set("LastPageVisited", window.location.toString());
6771        }
6772    }
6773    function RebuildDataLayer() {
6774        rebuildDataLayer = true;
6775        setUpGA = false;
6776        if (!Next.Settings.Channel.PlatModGoogleAnalyticsSDK) {
6777            if (dataLayer != undefined && dataLayer.length > 0) {
6778                for (var j = 0; j < dataLayer.length; j++) {
6779                    if (dataLayer[j].is_shoppingbag_page != undefined) {
6780                        dataLayer.splice(j, 1);
6781                        break;
6782                    }
6783                }
6784                dataLayer.push({ "is_shoppingbag_page": "true" });
6785            }
6786        }
6787    }
6788    function ValueRange(value) {
6789        var s = "";
6790        if (isNaN(value) || value == 0)
6791            s = "0";
6792        else if (value <= 50)
6793            s = "Under £50";
6794        else if (value <= 100)
6795            s = "£50 - £100";
6796        else if (value <= 250)
6797            s = "£100 - £250";
6798        else if (value <= 500)
6799            s = "£250 - £500";
6800        else if (value <= 1000)
6801            s = "£500 - £1000";
6802        else if (value > 1000)
6803            s = "£1000+";
6804        return s;
6805    }
6806    platmodCommon.ValueRange = ValueRange;
6807})(platmodCommon || (platmodCommon = {}));
6808//# sourceMappingURL=ShoppingBagCommon.js.map;
6809var __extends = (this && this.__extends) || (function () {
6810    var extendStatics = function (d, b) {
6811        extendStatics = Object.setPrototypeOf ||
6812            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6813            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6814        return extendStatics(d, b);
6815    }
6816    return function (d, b) {
6817        extendStatics(d, b);
6818        function __() { this.constructor = d; }
6819        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
6820    };
6821})();
6822var touchDevice = isIOS || isTouchEnabled;
6823var addedToBagTranSpeed = 400;
6824var multipleAddToBagHideTimer;
6825var msVersion = navigator.userAgent.match(/MSIE ([0-9]{1,}[\.0-9]{0,})/);
6826var msie = !!msVersion;
6827var bagIsAnimating = false;
6828var accountDialogIsAnimating = false;
6829var enablePlatModUserVariables = Next.Settings.Channel.PlatModUserVariables && Next.Settings.Channel.EnableModernisedHeader;
6830var platmod;
6831(function (platmod) {
6832    var DesktopBasket = /** @class */ (function (_super) {
6833        __extends(DesktopBasket, _super);
6834        function DesktopBasket() {
6835            "use strict";
6836            var _this = _super.call(this) || this;
6837            console.log("NEW HEADER DESKTOP/SHOPPINGBAG.TS");
6838            if (!enablePlatModUserVariables) {
6839                //This method registers the new basket total and sets the value on the homepage.
6840                _this.RegisterChange(function () {
6841                    SetSoftLoggedInState();
6842                });
6843            }
6844            _this.RegisterChange(function () {
6845                // Desktop Abandoned Basket Banner
6846                if (Next.Settings.Channel.AbandondedBagHomepage) {
6847                    var abbBannerShown = window.sessionStorage.getItem('abbBannerShownKey');
6848                    if (abbBannerShown === null) {
6849                        var abbInitialVisitBasket = window.sessionStorage.getItem('abbInitialVisitBasketKey');
6850                        if ((_this.Data.ItemCount > 0) && (abbInitialVisitBasket === null)) {
6851                            if ($('#abbPlaceHolder').length) {
6852                                var abbClosed = window.sessionStorage.getItem('abbClosedKey');
6853                                if (abbClosed === null) {
6854                                    BuildAbandonedBagBannerMH();
6855                                    $('#abbCloseLink').on("click", AbandonedBagBannerCloseLinkMH);
6856                                    window.sessionStorage.setItem('abbBannerShownKey', 'true');
6857                                }
6858                            }
6859                        }
6860                        else {
6861                            window.sessionStorage.setItem('abbInitialVisitBasketKey', 'true');
6862                        }
6863                    }
6864                }
6865                // Shopping Bag Dwell Prompt
6866                if (Next.Settings.Channel.ShoppingBagReEngagement != null && Next.Settings.Channel.ShoppingBagReEngagement.Enabled) {
6867                    var setShoppingBagDwellPrompt = function (Items) {
6868                        {
6869                            if (Items.length > 0) {
6870                                var pathname = window.location.pathname;
6871                                if (pathname.indexOf('shoppingbag') > -1) {
6872                                    var shoppingBagDwellPromptDisplayed = sessionStorage.getItem("shoppingBagDwellPromptDisplayed");
6873                                    if (shoppingBagDwellPromptDisplayed === null) {
6874                                        var dwellPromptTimeoutDuration = (Math.floor(Next.Settings.Channel.ShoppingBagReEngagement.DwellPromptTimeoutSecs)) * 1000;
6875                                        var inStockItems = Items.filter(function (x) { return !Next.Settings.Channel.NextUnlimitedItems.find(function (nu) { return nu.ItemNumberWithoutHyphen === x.ItemNumber; }) && x.StockStatus === 'instock' || x.StockStatus === 'delayed'; });
6876                                        if (inStockItems.length > 0) {
6877                                            TimerEventMH(dwellPromptTimeoutDuration);
6878                                        }
6879                                    }
6880                                }
6881                            }
6882                        }
6883                    };
6884                    if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled) {
6885                        setShoppingBagDwellPrompt(NextBasket.Data.Items);
6886                    }
6887                    else {
6888                        setShoppingBagDwellPrompt(_this.Data.Items);
6889                    }
6890                }
6891            });
6892            //free delivery with next unlimited modal popup
6893            if (Next.Settings.Channel.FreeDeliveryWithNextUnlimitedEnabled) {
6894                var isNUModalActive_1 = false;
6895                $(document).on("click", "#next-unlimited-delivery", function (e) {
6896                    event.preventDefault();
6897                    if (!isNUModalActive_1) {
6898                        isNUModalActive_1 = true;
6899                        $.ajax({
6900                            url: Next.Settings.Channel.SiteUrl + "/NextUnlimitedModal/desktop",
6901                            dataType: "HTML",
6902                            type: "GET",
6903                            cache: true,
6904                            success: function (data, textStatus, jqXHR) {
6905                                isNUModalActive_1 = false;
6906                                var desktopElemModal = $(document.createElement("div"));
6907                                desktopElemModal.html(data);
6908                                $(desktopElemModal).find(".nu-modal-TCs-apply").attr("href", Next.Settings.Channel.SiteUrl + "/Unlimited");
6909                                $(desktopElemModal).find(".nu-modal-add-to-bag").attr("href", Next.Settings.Channel.SiteUrl + "/addtobag/?itemnumbers=17562401");
6910                                if (NextBasket.Data.Items.some(function (p) { return p.IsNextUnlimitedItem; }) || NextBasket.NextUnlimited.IsExistingNUCustomer) {
6911                                    $(desktopElemModal).find(".nu-modal-add-to-bag").hide();
6912                                }
6913                                var $modal = ModalPopup.init({
6914                                    width: 600,
6915                                    height: "auto",
6916                                    fixedTopPosition: "25%",
6917                                    fullyLockBackgroundScroll: true,
6918                                    modalDataSet: []
6919                                });
6920                                $modal.html($(desktopElemModal).html());
6921                                ModalPopup.show();
6922                            },
6923                            error: function (xhr, ajaxOptions, thrownError) {
6924                                isNUModalActive_1 = false;
6925                                ConsoleLog("Desktop Partial for Next Unlimited on Shopping Bag Modal did not load: " + thrownError);
6926                            }
6927                        });
6928                    }
6929                });
6930            }
6931            return _this;
6932        } //Constructor
6933        DesktopBasket.prototype.NotifyItemAdded = function (itemObj) {
6934            this.OutboundQueue.shift();
6935            this.NotifyWaiting = false;
6936        };
6937        DesktopBasket.prototype.Notify = function (returnedData) {
6938            "use strict";
6939            TrackGAEvent("Saved Shopping Bag", "Bag Recovered", "Count", 0);
6940            TrackGAEvent("Saved Shopping Bag", "Bag Quantity", returnedData.ItemCount, 0);
6941            TrackGAEvent("Saved Shopping Bag", "Bag Age", returnedData.OldShoppingBagAge, 0);
6942            TrackGAEvent("Saved Shopping Bag", "Bag Value", platmodCommon != undefined ? platmodCommon.ValueRange(returnedData.FinalOrderValue) : ValueRange(returnedData.FinalOrderValue), 0);
6943        }; //Class Functions
6944        DesktopBasket.prototype.DisplayRebuildNotification = function (returnedData) {
6945            "use strict";
6946            TrackGAEvent("Saved Shopping Bag", "Bag Recovered", "Count", 0);
6947            TrackGAEvent("Saved Shopping Bag", "Bag Quantity", returnedData.ItemCount, 0);
6948            TrackGAEvent("Saved Shopping Bag", "Bag Age", returnedData.OldShoppingBagAge, 0);
6949            TrackGAEvent("Saved Shopping Bag", "Bag Value", platmodCommon != undefined ? platmodCommon.ValueRange(returnedData.FinalOrderValue) : ValueRange(returnedData.FinalOrderValue), 0);
6950        };
6951        return DesktopBasket;
6952    }(platmodCommon.Basket)); //Class
6953    platmod.DesktopBasket = DesktopBasket;
6954    if (!enablePlatModUserVariables) {
6955        // If true, PlatMod Header will take responsibility of this function making use of the bag/get call.
6956        function SetSoftLoggedInState() {
6957            //need to check if there is a soft login state
6958            var firstName = NextBasket.Data.FirstName;
6959            var userName = NextBasket.Data.Name;
6960            if (userName || firstName) {
6961                window.sessionStorage.removeItem("RPID");
6962                window.sessionStorage.removeItem("AcctType");
6963                window.sessionStorage.removeItem("unlimitedCustomer");
6964                window.sessionStorage.setItem("RPID", NextBasket.RoamingProfileId);
6965                if (NextBasket.Data.Authenticated) {
6966                    var NextUnlimitedStatus = NextBasket.Data.NextUnlimitedStatus == 0 ? false : true;
6967                    window.sessionStorage.setItem("AcctType", NextBasket.Data.AccountType);
6968                    window.sessionStorage.setItem("unlimitedCustomer", NextUnlimitedStatus.toString());
6969                    if (firebase != undefined) {
6970                        firebase.transferWebEventToApp("authenticated", NextBasket.Data.Authenticated.toString());
6971                    }
6972                }
6973            }
6974        }
6975    }
6976})(platmod || (platmod = {}));
6977//Helper methods
6978var NextBasket = new platmod.DesktopBasket();
6979function BuildAbandonedBagBannerMH() {
6980    var abbWrapper = $("<div />");
6981    $(abbWrapper).addClass("abb-wrapper");
6982    $(abbWrapper).attr('id', 'abbWrapper');
6983    var abbContainer = $("<div />");
6984    $(abbContainer).addClass("abb-container");
6985    var abbContainerContent = $("<div />");
6986    $(abbContainerContent).addClass("abb-container-content");
6987    var abbContentWrapper = $("<div />");
6988    $(abbContentWrapper).addClass("abb-content-wrapper");
6989    // Build Image Container
6990    var abbContentImgContainer = $("<div />");
6991    $(abbContentImgContainer).addClass("abb-content-img-container");
6992    var abbBagItems = NextBasket.Data["Items"];
6993    abbBagItems.sort(function (a, b) { return b.ItemID - a.ItemID; });
6994    var abbNumBagItems = 3;
6995    if (abbBagItems.length < 3) {
6996        abbNumBagItems = abbBagItems.length;
6997    }
6998    for (var j = 0; j < abbNumBagItems; j++) {
6999        var abbImage = BuildAbandonedBagImageElementMH(abbBagItems[j]);
7000        $(abbContentImgContainer).append(abbImage);
7001    }
7002    var abbContentInfoContainer = $("<div />");
7003    $(abbContentInfoContainer).addClass("abb-content-info-container");
7004    var abbContentInfoTop = $("<div />");
7005    $(abbContentInfoTop).addClass("abb-content-info-top");
7006    var abbIconBasket = $("<div />");
7007    $(abbIconBasket).addClass("abb-icon-basket");
7008    var abbIconBasketImage = $("<div />");
7009    $(abbIconBasketImage).addClass("abb-icon-basket-image");
7010    $(abbIconBasket).append(abbIconBasketImage);
7011    var abbIconText = $("<div />");
7012    $(abbIconText).addClass("abb-icon-text");
7013    var abbIconTextPara = $("<p />");
7014    var abbBagItemCount = NextBasket.Data["ItemCount"];
7015    var abbIconTextContent = ((abbBagItemCount !== 1) ?
7016        abbBagItemCount + " Items" :
7017        abbBagItemCount + " Item") + " in your ";
7018    var abbIconTextShopBagLinkText = "Shopping Bag";
7019    var abbIconTextShopBagLinkURL = Next.Settings.Channel.SiteUrl + "/shoppingbag";
7020    var abbIconTextShopBagLink = $("<a></a>")
7021        .text(abbIconTextShopBagLinkText)
7022        .attr("href", abbIconTextShopBagLinkURL);
7023    $(abbIconTextPara).append(abbIconTextContent);
7024    $(abbIconTextPara).append(abbIconTextShopBagLink);
7025    $(abbIconText).append(abbIconTextPara);
7026    $(abbContentInfoTop).append(abbIconBasket);
7027    $(abbContentInfoTop).append(abbIconText);
7028    var abbContentInfoBot = $("<div />");
7029    $(abbContentInfoBot).addClass("abb-content-info-bot");
7030    var abbContentInfoBotPara = $("<p />");
7031    var abbContentInfoBotText = "Complete your order now before it's too late...";
7032    $(abbContentInfoBotPara).text(abbContentInfoBotText);
7033    $(abbContentInfoBot).append(abbContentInfoBotPara);
7034    $(abbContentInfoContainer).append(abbContentInfoTop);
7035    $(abbContentInfoContainer).append(abbContentInfoBot);
7036    if (abbNumBagItems == 1) {
7037        $(abbContentImgContainer).addClass("abb-content-image-1");
7038        $(abbContentInfoContainer).addClass("abb-content-info-1");
7039    }
7040    else if (abbNumBagItems == 2) {
7041        $(abbContentImgContainer).addClass("abb-content-image-2");
7042        $(abbContentInfoContainer).addClass("abb-content-info-2");
7043    }
7044    $(abbContentWrapper).append(abbContentImgContainer);
7045    $(abbContentWrapper).append(abbContentInfoContainer);
7046    $(abbContainerContent).append(abbContentWrapper);
7047    var abbCloseLinkContainer = $("<div />");
7048    $(abbCloseLinkContainer).addClass("abb-close-link-container");
7049    $(abbCloseLinkContainer).attr('id', 'abbCloseLink');
7050    var abbCloseLinkWrapper = $("<div />");
7051    $(abbCloseLinkWrapper).addClass("abb-close-link-wrapper");
7052    $(abbCloseLinkWrapper).append(abbCloseLinkContainer);
7053    // abb checkout button
7054    var abbContainerCTA = $("<div />");
7055    $(abbContainerCTA).addClass("abb-container-cta");
7056    var abbCheckoutTxt = nxt.jstranslations.shoppingbagts.checkout;
7057    var abbCheckoutLinkURL = Next.Settings.Channel.CheckoutURL;
7058    var abbCheckoutBtn = $("<a></a>").addClass("abb-btn-checkout")
7059        .text(abbCheckoutTxt)
7060        .attr("href", abbCheckoutLinkURL);
7061    $(abbContainerCTA).append(abbCloseLinkWrapper);
7062    $(abbContainerCTA).append(abbCheckoutBtn);
7063    $(abbContainer).append(abbContainerContent);
7064    $(abbContainer).append(abbContainerCTA);
7065    $(abbWrapper).append(abbContainer);
7066    $('#abbPlaceHolder').append(abbWrapper);
7067}
7068function BuildAbandonedBagImageElementMH(curItem) {
7069    var abbItemImage = $("<img />");
7070    var abbImgUrl;
7071    if (curItem.SaleClearanceSofaImage != "" && curItem.SaleClearanceSofaImage != null) {
7072        abbImgUrl = curItem.SaleClearanceSofaImage;
7073    }
7074    else {
7075        if (curItem.ItemCategory === "sofas" && curItem.LinkedItems != null) {
7076            abbImgUrl = cdnURL + "/SofaContent/Item_AddToBag/" + curItem.ItemNumber + '_' + curItem.OptionNo + (curItem.LinkedItems.length > 0 && curItem.LinkedItems[0].ItemNumber !== "" ? '_' + curItem.LinkedItems[0].ItemNumber : "") + ".jpg";
7077        }
7078        else if (curItem.ItemCategory === "diningchairs") {
7079            abbImgUrl = cdnURL + "/ChairContent/Item_AddToBag/" + curItem.ItemNumber + '_' + curItem.OptionNo;
7080            abbImgUrl += (curItem.LinkedItems.length > 0 && curItem.LinkedItems[0].ItemNumber !== "" ? '_' + curItem.LinkedItems[0].ItemNumber : "");
7081            abbImgUrl += ".jpg";
7082        }
7083        else if (curItem.ItemCategory === "beds") {
7084            abbImgUrl = cdnURL + "/BedContent/Item_AddToBag/" + curItem.ItemNumber + '_' + curItem.OptionNo;
7085            abbImgUrl += (curItem.LinkedItems.length > 0 && curItem.LinkedItems[0].ItemNumber !== "" ? '_' + curItem.LinkedItems[0].ItemNumber : "");
7086            abbImgUrl += ".jpg";
7087        }
7088        else if (curItem.Personalisation === "Y") {
7089            var abbItemContainsImage = false;
7090            // obtain personalised gifts image for shopping bag
7091            for (var i = 0; i < curItem.PersonalisationFields.length; i++) {
7092                if (curItem.PersonalisationFields[i].Field == "image") {
7093                    abbItemContainsImage = true;
7094                    abbImgUrl = curItem.PersonalisationFields[i].Value;
7095                    break;
7096                }
7097            }
7098            // obtain Custom item image for shopping bag
7099            for (var i = 0; i < curItem.CustomItemFields.length; i++) {
7100                if (curItem.CustomItemFields[i].Field == "image") {
7101                    abbItemContainsImage = true;
7102                    abbImgUrl = curItem.CustomItemFields[i].Value;
7103                    break;
7104                }
7105            }
7106            if (!abbItemContainsImage) {
7107                abbImgUrl = cdnURL + "/common/items/default/default/itemimages/altitembag/" + curItem.ItemNumber + ".jpg";
7108            }
7109        }
7110        else {
7111            abbImgUrl = cdnURL + "/common/items/default/default/itemimages/altitembag/" + curItem.ItemNumber + ".jpg";
7112        }
7113    }
7114    $(abbItemImage).attr('src', abbImgUrl);
7115    return abbItemImage;
7116}
7117function AbandonedBagBannerCloseLinkMH() {
7118    window.sessionStorage.setItem('abbClosedKey', 'true');
7119    $('#abbWrapper').remove();
7120    return false;
7121}
7122function TimerEventMH(dwellPromptTimeoutDuration) {
7123    // Set Dwell Prompt Session key
7124    sessionStorage.setItem("shoppingBagDwellPromptDisplayed", "true");
7125    // Load Dwell Prompt HTML Partial 
7126    $.ajax({
7127        url: Next.Settings.Channel.SiteUrl + "/shoppingbagprompt/desktop",
7128        dataType: "HTML",
7129        type: "GET",
7130        cache: true,
7131        success: function (data, textStatus, jqXHR) {
7132            setTimeout(function () {
7133                // Get the shopping bag items again - just in case there have been changes since timeout initiation
7134                var inStockItems = NextBasket.Data.Items.filter(function (x) { return !Next.Settings.Channel.NextUnlimitedItems.find(function (nu) { return nu.ItemNumberWithoutHyphen === x.ItemNumber; }) && x.StockStatus === 'instock' || x.StockStatus === 'delayed'; });
7135                // If the Dwell Prompt Criteria are still met try to create Dwell Prompt modal
7136                if (inStockItems.length > 0) {
7137                    var inStockItem = inStockItems[0];
7138                    var description = null;
7139                    var formattedPrice = null;
7140                    var itemNumber = null;
7141                    var imageURL = null;
7142                    if (inStockItem.Description) {
7143                        description = inStockItem.Description;
7144                    }
7145                    if (inStockItem.PriceFormatted) {
7146                        formattedPrice = inStockItem.PriceFormatted;
7147                    }
7148                    if (inStockItem.ItemNumber) {
7149                        itemNumber = inStockItem.ItemNumber;
7150                    }
7151                    if (itemNumber != null && Next.Settings.Channel.ResponsiveShoppingBagIsEnabled) {
7152                        imageURL = $(".sbm-item[data-itemnumber=" + itemNumber + "]").find(".detailed-image-url").attr("data-detailed-image-url");
7153                    }
7154                    else if ($("tr[data-itemnumber=" + itemNumber + "] > td.imageColumn > a") && itemNumber != null) {
7155                        imageURL = $("tr[data-itemnumber=" + itemNumber + "] > td.imageColumn > a").attr("href");
7156                    }
7157                    // If all required Modal data available show Dwell Prompt Modal
7158                    if (description != null && formattedPrice != null && imageURL != null) {
7159                        // Get Monetate Key - used for testing
7160                        var shoppingBagDwellPromptMonetateKey = sessionStorage.getItem("shoppingBagDwellPromptMonetateKey");
7161                        // Monetate if active, toggles Dwell Prompt by setting key to "control" to suppress or "test" to show modal
7162                        if ((shoppingBagDwellPromptMonetateKey === null) || (shoppingBagDwellPromptMonetateKey === "test")) {
7163                            // Remove any previous modals on page
7164                            if ($('.ModalPopupWrapper').length > 0) {
7165                                $('.ModalPopupWrapper').remove();
7166                                $('.ModalPopupContainer').remove();
7167                            }
7168                            var desktopElemModal = $(document.createElement('div'));
7169                            desktopElemModal.html(data);
7170                            $(desktopElemModal).find(".sb-modal-text-product").text(description);
7171                            $(desktopElemModal).find(".sb-modal-text-price").text(formattedPrice);
7172                            if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled) {
7173                                var add3_4ImageClass = $(".sbm-item[data-itemnumber=" + itemNumber + "]").find(".detailed-image-url").attr("data-image-3_4-class");
7174                                if (add3_4ImageClass.toLowerCase() === 'true') {
7175                                    $(desktopElemModal).find(".sb-modal-container").addClass("dwell-image-3-4-class");
7176                                }
7177                            }
7178                            $(desktopElemModal).find(".sb-modal-image-container").html('<img class="sb-modal-image" src="' + imageURL + '" alt="' + description + '">');
7179                            var $modal = ModalPopup.init({
7180                                width: 640,
7181                                height: "auto",
7182                                fixedTopPosition: "25%",
7183                                fullyLockBackgroundScroll: true,
7184                                modalDataSet: []
7185                            });
7186                            $modal.html($(desktopElemModal).html());
7187                            ModalPopup.show();
7188                        }
7189                    }
7190                }
7191            }, dwellPromptTimeoutDuration);
7192        },
7193        error: function (xhr, ajaxOptions, thrownError) {
7194            ConsoleLog('Desktop Partial for Dwell Prompt on Shopping Bag Modal did not load: ' + thrownError);
7195        }
7196    });
7197}
7198//# sourceMappingURL=ShoppingBag.js.map;
7199
7200var SoftwareVersion = "";
7201var HeaderTrace = "";
7202
7203// Enable support for CORS (Cross Origin Resource Sharing).
7204jQuery.support.cors = true;
7205
7206var HidePrimaryNavigation = false;
7207
7208
7209function ShowBreadcrumbBar(Animation) {
7210    addToAnimation(Animation, '$(".PageHeader .BreadcrumbNavigation").fadeIn(250);', 250, true);
7211
7212    return Animation;
7213}
7214
7215function HideBreadcrumbBar(Animation) {
7216    addToAnimation(Animation, '$(".PageHeader .BreadcrumbNavigation").fadeIn(250);', 250, true);
7217
7218    return Animation;
7219}
7220
7221function UpdateBreadcrumbTrail(BCHTML) {
7222    $("section.Breadcrumbs").html(BCHTML);
7223
7224    $("ul.Breadcrumbs li").last().addClass("lastBreadcrumb");
7225
7226    BreadcrumbResize();
7227}
7228
7229//Function determines the available space for the breadcrumb navigation, and sets a width dependant on this
7230//If there is not enough space for the full breadcrumb, then the overflow is hidden, and an ellipsis is displayed
7231function BreadcrumbResize() {
7232
7233    //Static variables
7234    var bcrumbHolderWidth = 890; //bcrumbholderwidth set to the full available space for the breadcrumb, if no socialbookmarks are displayed
7235    var SocialBookmarkWidth = 160; //variable also includes additional spacing so that the breadcrumb and socialbookmarks have space between them
7236
7237    //Element variables
7238    var $bcrumbHolder = $(".BreadcrumbsHolder");
7239    var $bcrumbList = $bcrumbHolder.find("ul.Breadcrumbs");
7240    var $bcrumbLi = $bcrumbList.find("li");
7241    var $bcrumbEllipsis = $(".BreadcrumbEllipsis");
7242
7243
7244    if (AddThisEnabled) {
7245        //AddThis is enabled, therefore reduced the bcrumbholder width by the width of the socialbookmarkwidth variable
7246        bcrumbHolderWidth = bcrumbHolderWidth - SocialBookmarkWidth;
7247    }
7248
7249    $bcrumbHolder.width(bcrumbHolderWidth);
7250
7251    //Following loop determines the total length of all the Li elements matching the $bcrumbLi variable selector.
7252    var totalLiLength = 0;
7253    $bcrumbLi.each(function (i, e) {
7254        totalLiLength += $(e).outerWidth(true) + 2; //+2 has been added as a fix for IE7. Without this, it seems the outerWidth() for IE7 can be too small.
7255    });
7256
7257
7258    //If the totalLiLength > $bcrumbholder width, then a width needs to be set on the $bcrumbList, and the ellipsis should be shown.
7259    if (totalLiLength >= $bcrumbHolder.width()) {
7260        $bcrumbList.width(totalLiLength);
7261        $bcrumbEllipsis.show();
7262    }
7263        //Else statements reverse changes made in the If statement
7264    else {
7265        $bcrumbEllipsis.hide();
7266    }
7267
7268    if (dataLayer != undefined) {
7269        var department = "";
7270        var category = "";
7271        var spread = "";
7272        var bloomreachCategoryId = "";
7273
7274        // TODO new platform mod way of tracking active department.
7275
7276        var activeDepartment = $(".Department.currentDepartment .DepartmentLink");
7277        if (activeDepartment.length) {
7278            if (activeDepartment[0].pathname != undefined) {
7279                department = activeDepartment[0].pathname.replace(/\//gi, "");
7280            }
7281        }
7282
7283        var collection = $(".spreadImageWrapper a");
7284        if (collection.length > 1) {
7285            spread = collection[1];
7286            if (spread != undefined) {
7287                var urlSplitData = spread.pathname.split("/");
7288                if (urlSplitData != undefined) {
7289                    if (urlSplitData.length > 1 && department === "") {
7290                        department = urlSplitData[1];
7291                    }
7292                    category = spread.innerText.replace(/"/gi, "");
7293                }
7294            }
7295        }
7296
7297        var breadCrumb = $("section.Breadcrumbs");
7298
7299        if (breadCrumb != undefined) {
7300            var breadCrumbList = breadCrumb.find("li");
7301            if (breadCrumbList != undefined) {
7302                breadCrumbList.each(function (i, e) {
7303                    if (i > 0) {
7304                        if (i === 1 && department === "") {
7305                            var firstLink = $(e).find("a");
7306                            department = $(e).text().replace(/"/gi, "");
7307                            if (firstLink.length) {
7308                                if (firstLink[0].pathname != undefined) {
7309                                    department = firstLink[0].pathname.replace(/\//gi, "");
7310                                }
7311                            }
7312
7313                            if (department === "search") {
7314                                category = $(e).text().replace(/"/gi, "");
7315                            }
7316                        }
7317                        if (i === 2) {
7318                            var secondLink = $(e).find("a");
7319                            if (secondLink.length) {
7320                                if (secondLink[0].innerText != undefined) {
7321                                    category = secondLink[0].innerText.replace(/"/gi, "");
7322                                }
7323                            } else {
7324                                category = $(e).text().replace(/"/gi, "");
7325                            }
7326                        }
7327                    }
7328                });
7329            }
7330        }
7331
7332        if (category === "") {
7333            category = department;
7334        }
7335
7336        var pageType = "";
7337        var bloomReachPixelEnabled = false;
7338        for (var j = 0; j < dataLayer.length; j++) {
7339            if (dataLayer[j].page_type != undefined) {
7340                pageType = dataLayer[j].page_type;
7341            }
7342            if (dataLayer[j].br_pixel_enabled != undefined) {
7343                bloomReachPixelEnabled = dataLayer[j].br_pixel_enabled === "true";
7344            }
7345        }
7346        if (!Next.Settings.Channel.PlatModGoogleAnalyticsSDK) {
7347            if (pageType !== "") {
7348                if (pageType === department + "LandingPage" || pageType === "storefront") {
7349                    dataLayer.push({ "event": "storefront", "department": department.toLowerCase(), "category": category.toLowerCase() });
7350
7351                    if (bloomReachPixelEnabled && category.toLowerCase() === "sofa collections") {
7352                        var sofaCategoryId, sofaCategory;
7353
7354                        if ($(".br_data-taxonomy-enabled").val().toLowerCase() === "true") {
7355                            sofaCategoryId = $(".br_data-sofa-cat_id").val();
7356                            sofaCategory = $(".br_data-sofa-cat").val();
7357                        }
7358                        else {
7359                            sofaCategoryId = "homehomewaresofasandchairs";
7360                            sofaCategory = "home|homeware|sofasandchairs";
7361                        }
7362
7363                        dataLayer.push({ "br_cat_id": sofaCategoryId, "br_cat": encodeURIComponent(sofaCategory) });
7364                    }
7365
7366                } else if (pageType === "spread") {
7367                    dataLayer.push({ "event": "spread", "department": department.toLowerCase(), "category": category.toLowerCase() });
7368                } else if (pageType === "productListPage" || pageType === "searchResults") {
7369
7370                    if (bloomReachPixelEnabled) {
7371                        var bloomreachCategoryId = $(".br_data-cat_id").val();
7372                        var bloomreachCategory = $(".br_data-cat").val();
7373
7374                        if (typeof bloomreachCategoryId !== "undefined" && typeof bloomreachCategory !== "undefined") {
7375                            dataLayer.push({ "br_cat_id": bloomreachCategoryId, "br_cat": encodeURIComponent(bloomreachCategory) });
7376                        }
7377                    }
7378
7379                    if (pageType === "searchResults") {
7380                        department = "search";
7381                    }
7382                    dataLayer.push({ "event": "searchlanding", "department": department.toLowerCase(), "category": category.toLowerCase() });
7383                } else if (pageType === "productPage" || pageType === "BeautyproductPage" || pageType === "productPageModal" || pageType === "homeWarePDP") {
7384
7385                    if ($("article.Style").length > 0) {
7386                        var item = $("article.Style.Selected");
7387                        var pDepartment = $(item).data("department") || "";
7388                        var departmentForDataLayer = $(item).data("departmentfordatalayer");
7389                        if (pDepartment == "NOT_IN_USE" && (departmentForDataLayer != "" && departmentForDataLayer != undefined)) {
7390                            pDepartment = departmentForDataLayer;
7391                        }
7392                        var pcategory = $(item).data("category");
7393                        dataLayer.push({ "department": pDepartment.toLowerCase(), "category": pcategory.toLowerCase() });
7394                    }
7395                    else {
7396
7397                        dataLayer.push({ "department": department.toLowerCase(), "category": category.toLowerCase() });
7398                    }
7399                  
7400                }
7401            }
7402        } else {
7403            if (window.subjects && window.subjects["$ GA_TRACK_PAGE_LOAD"]) {
7404                window.subjects["$ GA_TRACK_PAGE_LOAD"].next({ department: department, category: category })
7405            }
7406            else {
7407                console.log("Error Tracking GA Page Load")
7408            }
7409        }
7410    }
7411}
7412
7413
7414;
7415function CreateCarouselLoopTimer(CSelector, Direction, Interval) {
7416    return window.setTimeout('ChangePage("' + CSelector + '","' + Direction + '","",' + Interval + ')', Interval);
7417}
7418
7419function ChangePage(CSelector, Direction, PageIndex, AutoScroll) {
7420
7421    if (!$("body").hasClass("Focus") && AutoScroll != 0 || PageTransitionLock == true) {
7422        eval(CSelector.replace('#','') + 'Timer = CreateCarouselLoopTimer("' + CSelector + '", "+", ' + AutoScroll + ')');
7423        return false;
7424    }
7425    
7426    if (CSelector == "" || Direction == "" && PageIndex == "" ) {
7427        return false;
7428    }
7429
7430    if (!$(CSelector).hasClass("Locked")) {
7431        var currentPageIndex;
7432        var PageDirection = Direction;
7433        var MovementDirection;
7434
7435        $(CSelector + " .CControlPage").each(function (index) {
7436              
7437            if ($(CSelector + " .CControlPage:eq(" + index + ")").hasClass("Current")) {
7438                currentPageIndex = index;
7439            }
7440        });
7441
7442      
7443        if (PageIndex != "") {
7444            //PageIndex = PageIndex - 1;
7445            if (PageIndex > currentPageIndex) {
7446                PageDirection = "+";
7447            } else {
7448                PageDirection = "-";
7449            }
7450        }
7451
7452        switch (PageDirection) {
7453            case "+":
7454                MovementDirection = "-";
7455            break;
7456            case "-":
7457                MovementDirection = "+";
7458            break;
7459        }
7460
7461        var nextPageIndex
7462        if (PageIndex == "") {
7463            nextPageIndex = eval(currentPageIndex + PageDirection + "1");
7464        } else {
7465            nextPageIndex = PageIndex;
7466        }
7467
7468        if (nextPageIndex == currentPageIndex) {
7469            return false;
7470        } else {
7471            if (nextPageIndex < 0) {
7472                nextPageIndex = ($(CSelector + " .CControlPage").length -1)
7473                MovementDirection = "-";
7474            } else {
7475                if (nextPageIndex >= $(CSelector + " .CControlPage").length) {
7476                    nextPageIndex = 0;
7477                    MovementDirection = "+";
7478                }
7479            }
7480        }
7481
7482        var numPagesToMove
7483        if (nextPageIndex > currentPageIndex) {
7484            numPagesToMove = nextPageIndex - currentPageIndex;
7485        } else {
7486            numPagesToMove = (currentPageIndex - nextPageIndex);
7487        }
7488
7489        var Animation = createAnimation();
7490        addToAnimation(Animation, '$("' + CSelector + '").addClass("Locked");', 0, false);
7491
7492        addToAnimation(Animation, '$("' + CSelector + ' .CControlPage.Current").removeClass("Current")', 0, false);
7493        addToAnimation(Animation, '$("' + CSelector + ' .CControlPage:eq(' + nextPageIndex + ')").addClass("Current")', 0, false);
7494        
7495        addToAnimation(Animation, '$("' + CSelector + ' .CContent").animate({"' + Next.Settings.CSS.left + '": "' + MovementDirection + '=' + ($(CSelector).width() * numPagesToMove) + '"},500)', 500, true);
7496
7497        addToAnimation(Animation, '$("' + CSelector + '").removeClass("Locked");', 0, true);
7498        if (AutoScroll != 0) {
7499            addToAnimation(Animation, CSelector.replace('#','') + 'Timer = CreateCarouselLoopTimer("' + CSelector + '", "+", ' + AutoScroll + ')', 0, false);
7500        }
7501        runAnimation(Animation,true);
7502    }
7503}
7504
7505function CarouselCreateLoopTimer(CSelector, Direction, Interval) {
7506
7507    var options = {
7508        TargetElement: CSelector
7509    }
7510    CarouselTouch.Init(options);
7511    //AddTouch(CSelector);
7512    return window.setTimeout('CarouselChangePage("' + CSelector + '","' + Direction + '","",' + Interval + ')', Interval);
7513
7514}
7515
7516function CarouselChangePage(CSelector, Direction, PageIndex, AutoScroll) {
7517    //debugger;
7518
7519    //ConsoleLog("Change Page");
7520
7521    if (!$("body").hasClass("Focus") && AutoScroll != 0 || PageTransitionLock == true) {
7522        eval('Timer' + CSelector.replace('#', '') + ' = CarouselCreateLoopTimer("' + CSelector + '", "+", ' + AutoScroll + ')');
7523        //ConsoleLog(1);
7524        return false;
7525    }
7526
7527    
7528
7529    if (CSelector == "" || Direction == "" && PageIndex == "") {
7530        //ConsoleLog(2);
7531        return false;
7532    }
7533    if (!$(CSelector).hasClass("Locked")) {
7534
7535        var currentPageIndex;
7536        var PageDirection = Direction;
7537        var MovementDirection;
7538
7539        $(CSelector + " .PageButton").each(function (index) {
7540            if ($(CSelector + " .PageButton:eq(" + index + ")").hasClass("Current")) {
7541                currentPageIndex = index;
7542            }
7543        });
7544
7545        if (PageIndex != "") {
7546            //PageIndex = PageIndex - 1;
7547            if (PageIndex > currentPageIndex) {
7548                PageDirection = "+";
7549            } else {
7550                PageDirection = "-";
7551            }
7552        }
7553
7554        switch (PageDirection) {
7555            case "+":
7556                MovementDirection = "-";
7557                break;
7558            case "-":
7559                MovementDirection = "+";
7560                break;
7561        }
7562
7563        var nextPageIndex
7564        if (PageIndex == "") {
7565            nextPageIndex = eval(currentPageIndex + PageDirection + "1");
7566        } else {
7567            nextPageIndex = PageIndex;
7568        }
7569
7570        if (nextPageIndex == currentPageIndex) {
7571            return false;
7572        } else {
7573            if (nextPageIndex < 0) {
7574                nextPageIndex = ($(CSelector + " .PageButton").length - 1)
7575                MovementDirection = "-";
7576            } else {
7577                if (nextPageIndex >= $(CSelector + " .PageButton").length) {
7578                    nextPageIndex = 0;
7579                    MovementDirection = "+";
7580                }
7581            }
7582        }
7583
7584        var numPagesToMove
7585        if (nextPageIndex > currentPageIndex) {
7586            numPagesToMove = nextPageIndex - currentPageIndex;
7587        } else {
7588            numPagesToMove = (currentPageIndex - nextPageIndex);
7589        }
7590
7591        if (!$(CSelector).hasClass("Paused") || ($(CSelector).hasClass("Paused") && AutoScroll == 0)) {
7592            var Animation = createAnimation();
7593            addToAnimation(Animation, '$("' + CSelector + '").addClass("Locked");', 0, false);
7594
7595            addToAnimation(Animation, '$("' + CSelector + ' .PageButton.Current").removeClass("Current")', 0, false);
7596            addToAnimation(Animation, '$("' + CSelector + ' .PageButton:eq(' + nextPageIndex + ')").addClass("Current")', 0, false);
7597
7598            var NewPosition = $(CSelector).width() * nextPageIndex;
7599
7600            addToAnimation(Animation, '$("' + CSelector + ' .Pages").animate({"' + Next.Settings.CSS.left + '": "-' + NewPosition + '"},500)', 500, true);
7601
7602            addToAnimation(Animation, '$("' + CSelector + '").removeClass("Locked");', 0, true);
7603            if (AutoScroll != 0) {
7604                addToAnimation(Animation, 'Timer' + CSelector.replace('#', '') + ' = CarouselCreateLoopTimer("' + CSelector + '", "+", ' + AutoScroll + ')', 0, false);
7605            }
7606            runAnimation(Animation, true);
7607        }
7608        if ($(CSelector).hasClass("Paused") && AutoScroll != 0) {
7609            eval('Timer' + CSelector.replace('#', '') + ' = CarouselCreateLoopTimer("' + CSelector + '", "+", ' + AutoScroll + ')');
7610        }
7611    }
7612}
7613
7614function PauseCarousel(carousel) {
7615    $(carousel).addClass("Paused");
7616}
7617
7618function UnpauseCarousel(carousel) {
7619    $(carousel).removeClass("Paused");
7620}
7621
7622var CarouselTouch  = function($,undefined){
7623
7624    var _ = {
7625        Settings: {
7626            isMouseDown: false,
7627            startPosition: null,
7628            endPosition:null,
7629            TargetElement: null,
7630            TargetElementStart: null,
7631            Pages: null,
7632            PageWidth: null,
7633            Initialised:false
7634        },
7635        Init: function(options){
7636            if (_.Settings.Initialised) {
7637                return false;
7638            }
7639            _.Settings.Initialised = true;
7640            _.Settings.TargetElement = options.TargetElement;
7641            _.Settings.Pages = $(_.Settings.TargetElement).find("section.Pages");
7642            _.Settings.PageWidth = $(_.Settings.TargetElement).find("section.Pages .Page").width();
7643          
7644            _.AddTouch();
7645
7646           // This is required to swipe the carousel with mouse on desktop to test, uncomment it to enable on desktop, comment it before checking in the code
7647           //$( _.Settings.TargetElement).find("a").each(function () { 
7648           //    $(this).removeAttr("onclick").click(function () {
7649           //        return false;
7650           //    });
7651           // });
7652
7653
7654        },
7655        AddTouch: function () {
7656
7657            var config = { 
7658                touchStart: _.touchStart,
7659                touchMove: _.touchMove,
7660                touchEnd: _.touchEnd,
7661                useMouse: true
7662            }
7663
7664            $(_.Settings.TargetElement).on("mouseleave", function () {_.touchEnd() }).NXTouch(config);
7665
7666        },
7667        touchMove: function (e, NXTouchObj) {
7668            if (_.Settings.isMouseDown) {
7669                var targetLeft = _.Settings.TargetElementStart + NXTouchObj.DistanceX;
7670              
7671                if (targetLeft > 0) 
7672                    targetLeft = 0;
7673
7674                if (targetLeft < -(_.Settings.Pages.width() - _.Settings.PageWidth))
7675                    targetLeft = -(_.Settings.Pages.width() - _.Settings.PageWidth);
7676                
7677                _.Settings.Pages.css("left", targetLeft);
7678                
7679            }
7680            
7681        },
7682        touchStart:function(e, NXTouchObj){        
7683            _.Settings.isMouseDown = true;
7684            _.Settings.startPosition = NXTouchObj.X;
7685
7686            _.Settings.TargetElementStart = parseInt(_.Settings.Pages.css("left"));
7687            if (isNaN(_.Settings.TargetElementStart))
7688                _.Settings.TargetElementStart = 0;
7689        },
7690        touchEnd:function(){
7691        
7692            if (_.Settings.isMouseDown) {
7693                _.Settings.isMouseDown = false;
7694                
7695                _.Settings.endPosition = -Math.round((Math.abs(_.Settings.Pages.position().left) / _.Settings.PageWidth) * _.Settings.PageWidth);
7696                
7697                if (_.Settings.endPosition >= 0)
7698                    return false;
7699
7700                if (_.Settings.endPosition <= -(_.Settings.Pages.width() - _.Settings.PageWidth)) {
7701                    return false;
7702                }
7703
7704                var direction = '-';
7705
7706                var distanceDragged = _.Settings.endPosition % _.Settings.PageWidth;
7707
7708                //console.log('distanceDragged:'+distanceDragged)
7709                //console.log('pageWidth:' + _.Settings.PageWidth)
7710                //console.log('endPosition:' + _.Settings.endPosition)
7711                //console.log('target start:', _.Settings.TargetElementStart)
7712
7713                if (_.Settings.endPosition < _.Settings.TargetElementStart) {
7714                    direction = '+';
7715                }
7716                else
7717                {
7718                    distanceDragged = _.Settings.PageWidth - Math.abs(distanceDragged);
7719                }
7720
7721                if (Math.abs(distanceDragged) < (_.Settings.PageWidth / 4)) {                   
7722                    _.Settings.Pages.animate({ "left": _.Settings.endPosition - (distanceDragged) },300);
7723                }
7724                else {
7725                    CarouselChangePage(_.Settings.TargetElement, direction, 0, 0);
7726                }
7727
7728                //CarouselChangePage(_.Settings.TargetElement,direction, 0, 0);
7729
7730                _.Settings.isMouseDown = false;
7731            }        
7732        }    
7733    }
7734
7735
7736    return {
7737        Init: _.Init
7738    }
7739
7740
7741}(jQuery);
7742
7743
7744
7745
7746//$(function () {
7747//    AddTouch();
7748//});
7749
7750
7751;
7752var AddThisEnabled = false;
7753
7754function appendAddThis() {
7755    var container = $("<div/>").attr("class", "addthis_toolbox addthis_default_style");
7756    var facebook = $("<a/>").attr("class", "addthis_button_facebook").html(" ");
7757    var twitter = $("<a/>").attr("class", "addthis_button_twitter");
7758    var email = $("<a/>").attr("class", "addthis_button_email");
7759    var google = $("<a/>").attr("class", "addthis_button_google_plusone_share");
7760    var addThisButton = $("<a/>").attr("class", "addthis_button_compact");
7761    var addThisCounter = $("<a/>").attr("class", "addthis_counter addthis_bubble_style");
7762    var clear = $("<div/>").attr("class", "ClearBoth").html(" ");
7763    container.append(facebook, twitter, email, google, addThisButton, addThisCounter);
7764    $(".SocialBookmarks").empty();
7765    $(".SocialBookmarks").append(container, clear);
7766
7767    $.ajax({
7768        url: "https://s7.addthis.com/js/250/addthis_widget.js#domready=1&async=1",
7769        dataType: "script",
7770        success: function (d, txtStatus, xhr) {
7771            socialSuccess(d, txtStatus, xhr);
7772        },
7773        error: function (d, txtStatus, xhr) {
7774            socialError(d, txtStatus, xhr);
7775        },
7776        cache: false
7777    });
7778}
7779
7780
7781function socialError(d, txtStatus, xhr) {
7782    var data = d;
7783}
7784
7785function socialSuccess(d, txtStatus, xhr) {
7786    if (xhr.status == 200) {
7787        addthis.toolbox('#toolbox');
7788        addthis.counter('.addthis_counter');
7789        addthis.addEventListener('addthis.menu.open', AddThisMenuOpen);
7790    }
7791}
7792
7793function updateSocialMediaButtons(path) {
7794
7795    window.addthis_share = { url: "//" + window.location.host + path };
7796
7797    $("#at20mc").remove();
7798    window.addThisLoaded = false;
7799    window.addthis = null;
7800    window._atc = null;
7801    window._atd = null;
7802    window._ate = null;
7803    window._atr = null;
7804    window._atw = null;
7805    window._at_plusonecallback = null;
7806    appendAddThis();
7807}
7808
7809function AddThisMenuOpen() {
7810    //Set menu popup to fixed position so that scrolling the page persists the visibility of the popup
7811    $("#at20mc #at15s").css("position", "fixed");
7812};
7813//Recenty viewed object contains service call methods and plugin initialisation methods
7814var RecentlyViewed = {
7815    //Initialise the scroller plugin
7816    initScroller: function (selector, loadOnVisible) {
7817        //make sure we have a visitor id
7818        if (typeof NextBasket == "undefined" || NextBasket.VisitorID == "") {
7819            setTimeout(function () {
7820                RecentlyViewed.initScroller(selector, loadOnVisible);
7821            }, 100);
7822            return false;
7823        }
7824        $(selector).ItemScroller("init", NextBasket.VisitorID, loadOnVisible);
7825    },
7826    //Initialise the view all plugin
7827    initViewAll: function (selector) {
7828        //make sure we have a visitor id
7829        if (typeof NextBasket == "undefined" || NextBasket.VisitorID == "") {
7830            setTimeout(function () {
7831                RecentlyViewed.initViewAll(selector);
7832            }, 100);
7833            return false;
7834        }
7835
7836        $(selector).viewAllRecentlyViewed("init", NextBasket.VisitorID);
7837
7838    },
7839    //Get ListsURL or SecureListsURL based on protocol or HTTPS feature
7840    getListsURLOrSecureListsURL: function () {
7841        if (window.location.protocol === "https:" || Next.Settings.Channel.HttpsEnabled)
7842            return SecureListsURL;
7843        else
7844            return ListsURL;
7845    },
7846    getRecentlyViewed: function (visitorID, callback, errorCallBack) {
7847
7848
7849        //Check if recently viewed data has already been loaded - if it has, just pas that into the callback rather than making another call
7850        if (typeof recentlyViewedGlobal != "undefined" && recentlyViewedGlobal != null) {
7851            if (callback) {
7852                callback(recentlyViewedGlobal);
7853            }
7854            return;
7855        }
7856
7857        //make sure we have a visitor id
7858        if (typeof NextBasket == "undefined" || NextBasket.VisitorID == null) {
7859            setTimeout(function () {
7860                RecentlyViewed.getRecentlyViewed(visitorID, callback);
7861            }, 100);
7862            return false;
7863        }
7864
7865        var profileClientId = Next.Settings.Channel.ProfileClientId;
7866
7867        $.ajax({
7868            url: RecentlyViewed.getListsURLOrSecureListsURL() + "/recentlyviewed/get/" + visitorID,
7869            type: "POST",
7870            dataType: "json",
7871            data: { ProfileClientId: profileClientId },
7872            xhrFields: { withCredentials: true },
7873            crossDomain: true,
7874            success: function (data, textStatus, jqXHR) {
7875
7876                //Uncomment this to test the error message
7877                //                setTimeout(function () {
7878                //                    errorCallBack();
7879                //                }, 2000);
7880
7881                //                return false;
7882
7883                // data = [{ "Path": "/g38330s3", "SpreadPage": "330", "DateAdded": "2013-06-11T15:06:39.39" }, { "Path": "/g38330s4", "ItemNumber": "780-632-G38", "Size": "07", "DateAdded": "2013-06-11T15:06:21.517" }, { "Path": "/g38330s7", "SpreadPage": "330", "DateAdded": "2013-06-11T15:06:05.733"}]
7884
7885                if (callback) {
7886
7887                    if (!Next.Settings.Channel.IsMobileSite) {
7888                        data = RecentlyViewed.filterRecentlyViewedBySingleSegment(data);
7889                    }
7890
7891                    callback(data);
7892                }
7893            },
7894            error: function (xhr, ajaxOptions, thrownError) {
7895                if (errorCallBack) {
7896                    errorCallBack();
7897                }
7898            },
7899            complete: function () {
7900                RecentlyViewed.updateRecentlyViewedFooterLink(null);
7901            }
7902        });
7903    },
7904    updateRecentlyViewedFooterLink: function (element) {
7905
7906        // find the recently viewed wrapper that is generated on the page (not the pop up footer)
7907
7908
7909        element = element || $(".RecentlyViewedWrapper.inPage");
7910
7911
7912        // return if there are no in page wrappers
7913
7914        if ($(element).length === 0 || !$(element).hasClass("inPage")) {
7915            return false;
7916        }
7917
7918        var scrollTop = $(window).scrollTop();
7919        var grabPoint = $(element).offset().top - scrollTop;
7920
7921        var url = window.location.pathname.toLowerCase();
7922        if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1 && grabPoint == 0) {//fix grab point through css, "display:none"" removes element from layout, so we bring RV into view for split second, but set it's size to 0 so no flickering, then we grab point and remove the class.
7923            $(element).addClass("grabPoint");
7924            grabPoint = $(element).offset().top - scrollTop;
7925            $(element).removeClass("grabPoint")
7926        }
7927
7928        var wHeight = window.innerHeight; //$(window).height() doesn't take into account initial resizing that would happen when content would fall below min width, 1024px on desktop.
7929        var intermediateBottom = wHeight - 50;
7930        var intermediateTop = wHeight - 250;
7931        var bind = false;
7932        // The grabPoint initially calculates to zero due to browser/speed issues with rendering
7933
7934        if (grabPoint >= 0) {
7935
7936            // find the link in the footer
7937            var recentlyViewedFooterLink = $("a.recentlyViewedFooterLink");
7938
7939            // if there is a link in the footer decide how it should behave
7940
7941            if ($(recentlyViewedFooterLink).length > 0) {
7942
7943                if ((grabPoint < intermediateBottom) && (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInPage)) {
7944                    $(recentlyViewedFooterLink).addClass("disabled");
7945                    bind = true;
7946                } else {
7947                    if (!$(recentlyViewedFooterLink).hasClass("disableForPage")) {
7948                        $(recentlyViewedFooterLink).removeClass("disabled");
7949                    }
7950                }
7951
7952                if (grabPoint < intermediateBottom && grabPoint > intermediateTop) {
7953                    $(recentlyViewedFooterLink).addClass("intermediate");
7954                    bind = true;
7955                } else {
7956                    $(recentlyViewedFooterLink).removeClass("intermediate");
7957                }
7958
7959            }
7960
7961            if ((grabPoint < intermediateBottom) && (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInPage)) {
7962                $(element).addClass("BINDME");
7963            }
7964
7965        }
7966
7967        if (!$(element).hasClass("loadedInWindow")) {
7968            $(element).addClass("loadedInWindow");
7969        }
7970
7971
7972
7973        return bind;
7974
7975    },
7976    getItem: function (path, callback) {
7977
7978        $.get(path, function (data) {
7979
7980            if (callback) {
7981                callback(data);
7982            }
7983        });
7984    },
7985    addItem: function (item, callback) {
7986        if (!Next.FeatureManager.FeatureSettings.RecentlyViewed.EnableAdditions) {
7987            return false;
7988        }
7989
7990        if (!Next.Settings.Channel.RvDisplayInPage) {
7991            return false;
7992        }
7993
7994        //make sure we have a visitor id
7995        if (typeof NextBasket == "undefined" || NextBasket.VisitorID == "") {
7996            setTimeout(function () {
7997                RecentlyViewed.addItem(item, callback);
7998            }, 100);
7999            return false;
8000        }
8001
8002        var homewareIndxStartPos = item.path.indexOf('/homeware/');
8003        var styleIndxStartPos = item.path.indexOf('/style/');
8004        var lastSlashIndxStartPos = item.path.lastIndexOf('/');
8005
8006        //handle furniture url's different to url with publication_book_shot
8007        if (homewareIndxStartPos > -1) {
8008            item.path = item.path.substring(homewareIndxStartPos);
8009        }
8010        //handle style items properly (we need to keep /style in the URL)
8011        else if (styleIndxStartPos > -1) {
8012            item.path = item.path.substring(styleIndxStartPos);
8013        }
8014        else if (!Next.Settings.Channel.EnhancedStyleWithRibbonEnabled || !item.isStyleWith) {
8015            //New URL check
8016            item.path = !ModularPDPHelper.isUrlInNewFormat()
8017                ? item.path.substring(lastSlashIndxStartPos)
8018                : ModularPDPHelper.getNewUrlWithoutHash({ includeOrigin: false, includeStyle: false, itemNumber: item.itemNumber || null, replaceLastSegment: true });
8019        }
8020
8021        //Build target url
8022        var targetURL = RecentlyViewed.getListsURLOrSecureListsURL() + "/recentlyviewed/add/" + NextBasket.VisitorID;
8023        var postParams = { Path: item.path };
8024        if (item.itemNumber) {
8025            //targetURL += "&itemNumber=" + item.itemNumber;
8026            postParams.ItemNumber = item.itemNumber;
8027        }
8028
8029        //If a page number was supplied, add it to the querystring
8030        if (item.pageNumber) {
8031            //targetURL += "&SpreadPage=" + item.pageNumber;
8032            postParams.SpreadPage = item.pageNumber;
8033        }
8034
8035        if (item.Size) {
8036            //targetURL += "&size=" + item.Size;
8037            postParams.Size = item.Size;
8038        }
8039
8040        var profileClientId = Next.Settings.Channel.ProfileClientId;
8041        if (profileClientId) {
8042            postParams.ProfileClientId = profileClientId;
8043        }
8044
8045        $.ajax({
8046            url: targetURL,
8047            type: "POST",
8048            dataType: "json",
8049            data: postParams,
8050            xhrFields: { withCredentials: true },
8051            crossDomain: true,
8052            success: function (data, textStatus, jqXHR) {
8053                if (callback) {
8054                    callback(data);
8055                }
8056            },
8057            error: function (xhr, ajaxOptions, thrownError) {
8058
8059            }
8060        });
8061    },
8062    clearList: function (path, callback) {
8063
8064        var profileClientId = Next.Settings.Channel.ProfileClientId;
8065
8066        $.ajax({
8067            url: path,
8068            type: "GET",
8069            dataType: "json",
8070            xhrFields: { withCredentials: true },
8071            data: { ProfileClientId: profileClientId },
8072            crossDomain: true,
8073            success: function (data, textStatus, jqXHR) {
8074                if (callback) {
8075                    callback(data);
8076                }
8077            },
8078            error: function (xhr, ajaxOptions, thrownError) {
8079
8080            }
8081        });
8082
8083        // Disable the Recently Viewed Link in the Footer
8084        if (!$("a.recentlyViewedFooterLink").hasClass("active")) {
8085            $("a.recentlyViewedFooterLink").addClass("disabled");
8086        }
8087
8088        $("a.recentlyViewedFooterLink").addClass("disableForPage");
8089    },
8090    filterRecentlyViewedBySingleSegment: function (items) {
8091        for (var i = 0; i < items.length; i++) {
8092            var currentItem = items[i];
8093
8094            if (currentItem.Path.split("/").length == 2) {
8095                items.splice(i, 1);
8096            }
8097        }
8098        return items;
8099    }
8100};
8101
8102
8103function SetRecentlyViewedDisplay() {
8104
8105    checkForRecentlyViewedCookie();
8106
8107
8108    if (Next.FeatureManager.FeatureSettings.RecentlyViewed.IsEnabled) {
8109        //Added flagselector check to display RecentlyViewed in Footer when HTTPS is turned ON
8110        if (Next.Settings.Channel.HttpsEnabled) {
8111            if ((window.location.protocol.indexOf("https:") === 0) && (!Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInSecureFooter) && $(".PageFooter .flagSelectorContainer").length == 0) {
8112                $(".recentlyViewedFooterLink").hide();
8113            }
8114        } else {
8115            if ((window.location.protocol.indexOf("https:") === 0) && (!Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInSecureFooter)) {
8116                $(".recentlyViewedFooterLink").hide();
8117            }
8118        }
8119
8120        if (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayCounter) {
8121            $(".RVDisplayCounter").show();
8122        }
8123
8124        if (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayViewAllLink) {
8125            $(".RVDisplayViewAllLink").show();
8126        }
8127
8128        if (!Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInPage) {
8129            $(".RVDisplayInPage").hide();
8130            $(".RecentlyViewedWrapper.inPage").hide();
8131        } else {
8132            $(".RVDisplayInPage").show();
8133            $(".RecentlyViewedWrapper.inPage").show();
8134        }
8135
8136        if (!Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayInFooter) {
8137            $(".RVDisplayInFooter").hide();
8138        } else {
8139            $(".RVDisplayInFooter").show();
8140        }
8141    } else {
8142
8143        $(".recentlyViewedFooterLink").hide();
8144
8145        $(".RecentlyViewed").each(function () {
8146            $(this).hide();
8147        });
8148        $(".RVDisplayInPage").each(function () {
8149            $(this).hide();
8150        });
8151        $(".RVDisplayCounter").each(function () {
8152            $(this).hide();
8153        });
8154        $(".RVDisplayViewAllLink").each(function () {
8155            $(this).hide();
8156        });
8157        $(".RecentlyViewedWrapper").each(function () {
8158            $(this).hide();
8159        });
8160        $(".RVDisplayInFooter").each(function () {
8161            $(this).hide();
8162        });
8163    }
8164};
8165
8166//Check if any components need initialising
8167function checkForRecentlyViewedCookie() {
8168    // Check whether the ShowRecentlyViewed flag is set to true, if it is then initScroller, otherwise remove the wrapper from the DOM
8169
8170    var showInPage = true;
8171    var showFooterLink = true;
8172    var showCoachTip = true;
8173
8174    // Get the ShowRecentlyViewed flag
8175    var showRVCookie = readSplitCookie("NextSessionVariables", "ShowRecentlyViewed");
8176    if (showRVCookie == null || showRVCookie === "false") {
8177        showInPage = false;
8178        showFooterLink = false;
8179    }
8180
8181    // Disable the Footer Link if the global config says to do so
8182    if (typeof disableRecentlyViewedFooterLink != "undefined") {
8183        showFooterLink = false;
8184    }
8185
8186
8187    // Check the list of PageTypes and update the flags accordingly
8188    var disabledInPageList = Next.FeatureManager.FeatureSettings.RecentlyViewed.InPageDisabledPageTypes;
8189    var currentPageType = PageType;
8190
8191    if (typeof currentPageType === "undefined") {
8192        currentPageType = "undefined";
8193    }
8194
8195    if (currentPageType.toLowerCase() == "sale") {
8196        showInPage = false;
8197    }
8198    if (currentPageType.toLowerCase() == "socialplp") {
8199        showInPage = false;
8200    }
8201
8202    //Check current page type against list of disabled page types for in-page display
8203    if (typeof disabledInPageList != "undefined") {
8204        for (var i = 0; i < disabledInPageList.length; i++) {
8205            if (currentPageType.toLowerCase() == disabledInPageList[i].toLowerCase()) {
8206                showInPage = false;
8207            }
8208        }
8209    }
8210
8211    //Same for toolbar
8212    var disabledToolBarList = Next.FeatureManager.FeatureSettings.RecentlyViewed.ToolbarDisabledPageTypes;
8213    //Check current page type against list of disabled page types for ToolBar display
8214    if (typeof currentPageType != "undefined" && typeof disabledToolBarList != "undefined") {
8215        for (var i = 0; i < disabledToolBarList.length; i++) {
8216            if (currentPageType.toLowerCase() == disabledToolBarList[i].toLowerCase()) {
8217                showFooterLink = false;
8218            }
8219        }
8220    }
8221
8222
8223    if ($(".HomeFooter").length) {
8224        showFooterLink = false;
8225    }
8226
8227    if (showInPage) {
8228        // Init the In-Page components
8229        if ($(".RecentlyViewedWrapper").length) {
8230            $(".RecentlyViewedWrapper").each(function () {
8231                var wrapper = $(this);
8232
8233                if (wrapper.hasClass("LoadNow") && !wrapper.hasClass("inFooter")) {
8234                    if (!wrapper.hasClass("CustomPosition")) {
8235                        if ($(".CurrentContent").length) {
8236                            $(".CurrentContent").append(wrapper);
8237                        } else if ($("#ct").length) {
8238                            $("#ct").append(wrapper);
8239                        }
8240                    }
8241
8242                    RecentlyViewed.initScroller(wrapper, false);
8243
8244                }
8245
8246                if (wrapper.hasClass("loadOnVisible") && !wrapper.hasClass("inFooter")) {
8247                    if (!wrapper.hasClass("CustomPosition")) {
8248                        if ($(".CurrentContent").length) {
8249                            $(".CurrentContent").append(wrapper);
8250                        } else if ($("#ct").length) {
8251                            $("#ct").append(wrapper);
8252                        }
8253                    }
8254
8255                    RecentlyViewed.initScroller(wrapper, true);
8256
8257                }
8258
8259            });
8260        }
8261    } else {
8262        // Remove the In-Page component from the DOM
8263        $(".RecentlyViewedWrapper.inPage").remove();
8264    }
8265
8266    if (!showFooterLink) {
8267        // Disable the Recently Viewed Link in the Footer
8268        $(".recentlyViewedFooterLink").addClass("disabled").addClass("disableForPage");
8269    }
8270
8271    if (showFooterLink && showCoachTip) {
8272        setTimeout("openCoachTip()", 1000);
8273    }
8274}
8275
8276function openCoachTip() {
8277    // Display the coach tip
8278    $(".coachTip").addClass("open").animate({
8279        top: -120,
8280        opacity: 1
8281    }, 1000, "easeOutExpo");
8282}
8283
8284function closeCoachTip() {
8285
8286    var $coachTip = $(".coachTip");
8287
8288    if ($coachTip.length == 0 || !$coachTip.hasClass("open") || $coachTip.hasClass("locked")) {
8289        return false;
8290    }
8291
8292    $coachTip.addClass("locked");
8293
8294    $(".coachTip").animate({
8295        top: 40,
8296        opacity: 0
8297    }, 500, "easeInCirc", function () {
8298
8299        $(".coachTip").removeClass("open").removeClass("locked");
8300
8301    });
8302
8303}
8304
8305
8306///Helper functions/////////////////////////////////////////////////
8307
8308//Return the list of recently viewed items grouped by day
8309function groupByDate(objArray) {
8310
8311    var previousDay = null;
8312    var groupedArray = new Array();
8313    var currentGroup = null;
8314    var path = window.location.pathname;
8315    var createOlderItemsGroup = true;
8316    var now = new Date();
8317    now.setDate(now.getDate() - 15);
8318
8319    var isRTL = Next.Settings.Channel.DirectionRTL ? true : false;
8320
8321    // If RTL, then process the list from back to front as thats how we wish to display it
8322    var i = 0;
8323    if (isRTL) i = objArray.length - 1;
8324    while (i >= 0 && i < objArray.length) {
8325
8326        //Uncomment below to enable interaction list
8327        // var skipEntry = false;
8328        //        if (typeof interactionList != 'undefined') {
8329        //
8330
8331        //            if (objArray[i].ItemNumber == null && objArray[i].Path == path) {
8332        //                skipEntry = true;
8333        //            }
8334
8335        //            for (var interactionObject = 0; interactionObject < interactionList.length; interactionObject++) {
8336        //                if (objArray[i].ItemNumber == interactionList[interactionObject]) {
8337        //                    skipEntry = true;
8338        //                }
8339        //            }
8340
8341
8342        //        }
8343
8344        // if (skipEntry) continue;
8345        //Get current day
8346        var thisDay = new Date(objArray[i].DateAdded);
8347
8348        if (isNaN(thisDay)) {
8349            var dateString = objArray[i].DateAdded.split("T")[0];
8350            var dateArray = dateString.split("-");
8351            var formattedDateString = dateArray[1] + "/" + dateArray[2] + "/" + dateArray[0];
8352            thisDay = new Date(formattedDateString);
8353        }
8354
8355        //Check if we're on the first day or if this date is different to previous
8356        if ((previousDay == null || formatViewedDate(thisDay, "nn mm yy") != formatViewedDate(previousDay, "nn mm yy")) // All items under 14 days old
8357            && ((thisDay > now) || createOlderItemsGroup)) // All older items
8358        {
8359            //if it is - create a new currentGroup object and set its date to current item
8360
8361
8362            var groupDate = formatViewedDate(thisDay, "", true);
8363            currentGroup = {
8364                rawDate: objArray[i].DateAdded,
8365                date: groupDate,
8366                itemArray: new Array()
8367            }; //Add this group object to the parent array
8368            groupedArray.push(currentGroup);
8369
8370            if (thisDay < now) // All older items
8371                createOlderItemsGroup = false;
8372        }
8373        //Add this day to the current group
8374        currentGroup.itemArray.push(objArray[i]);
8375        //Reset previous day
8376        previousDay = thisDay;
8377
8378        if (isRTL) i--;
8379        else i++;
8380    }
8381
8382    return groupedArray;
8383}
8384
8385
8386//Custom date formatting function
8387function formatViewedDate(date, format, displayFriendyDates) {
8388
8389
8390    //If we're displaying friendly names e.g. Today, Yesterday etc. check that condition first
8391    if (displayFriendyDates) {
8392
8393        var matchFound = false;
8394
8395        for (var i = 0; i < 15; i++) {
8396
8397            var loopDay = new Date();
8398
8399            loopDay.setDate(loopDay.getDate() - i);
8400
8401            if (loopDay.getDate() == date.getDate() &&
8402                loopDay.getMonth() == date.getMonth() &&
8403                loopDay.getYear() == date.getYear()) {
8404                matchFound = true;
8405
8406                switch (i) {
8407                    case 0:
8408                        return "Today";
8409                        break;
8410                    case 1:
8411                        return "Yesterday";
8412                        break;
8413                    default:
8414                        return i + " Days Ago";
8415                }
8416            }
8417
8418        }
8419
8420        if (!matchFound) {
8421            return "Older";
8422        }
8423
8424    }
8425
8426    var monthNames = [
8427        "January", "February", "March", "April", "May", "June",
8428        "July", "August", "September", "October", "November", "December"
8429    ];
8430
8431    var dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
8432
8433    var dDay = dayNames[date.getDay()];
8434    var dayNumber = date.getDate();
8435    var dMonth = monthNames[date.getMonth()];
8436    var dYear = date.getYear() + 1900;
8437
8438    var ordinalString = "th";
8439
8440    if (dayNumber == 1 || dayNumber == 11 || dayNumber == 21 || dayNumber == 21) {
8441        ordinalString = "st";
8442    }
8443
8444    if (dayNumber == 2 || dayNumber == 12 || dayNumber == 22) {
8445        ordinalString = "nd";
8446    }
8447
8448    if (dayNumber == 3 || dayNumber == 13 || dayNumber == 23) {
8449        ordinalString = "rd";
8450    }
8451
8452    switch (format) {
8453
8454        case "nn mm yy":
8455            return dayNumber + " " + dMonth + " " + dYear;
8456            break;
8457        case "nn/mm/yy":
8458            return dayNumber + "/" + (date.getMonth() + 1) + "/" + dYear;
8459            break;
8460        default:
8461            return dDay + ", " + dayNumber + ordinalString + " " + (dMonth) + ", " + dYear;
8462
8463    }
8464
8465}
8466
8467function roundToHalf(value) {
8468    var converted = parseFloat(value); // Make sure we have a number
8469    var decimal = (converted - parseInt(converted, 10));
8470    //Set to Math.floor to match value returned by search provider
8471    decimal = Math.floor(decimal * 10);
8472    if (decimal == 5) {
8473        return (parseInt(converted, 10) + 0.5);
8474    }
8475    if ((decimal < 3) || (decimal > 7)) {
8476        return Math.round(converted);
8477    } else {
8478        return (parseInt(converted, 10) + 0.5);
8479    }
8480}
8481
8482
8483/////////////Plugins/////////////////////////////////////
8484
8485///viewAllRecentlyViewed Plugin////////
8486
8487(function ($) {
8488
8489    var methods = {
8490        init: function (visitorId) {
8491            //Create copy of element we're intialising as this plugin - use in nested/callback functions
8492            var $this = this;
8493            //Set scroll hanfler
8494            $(window).scroll(function () {
8495                methods.loadItemsInviewport($this);
8496            });
8497            //Call getRecentlyViewed and pass callback
8498            RecentlyViewed.getRecentlyViewed(visitorId, function (itemList) {
8499
8500
8501                //If no elements in recently viewed, stop here
8502                if (itemList.length == 0)
8503                    return false;
8504
8505                //Get formated array of items - grouped by date
8506                var groupedArray = groupByDate(itemList);
8507                //Loop through each group/day
8508                for (var i = 0; i < groupedArray.length; i++) {
8509
8510                    var thisGroup = groupedArray[i];
8511                    //Create wrapper element for this day of recently viewed items
8512                    var dayWrapper = $("<div />");
8513                    dayWrapper.addClass("dayWrapper");
8514                    //Heading for this day
8515                    var heading = $("<h2 />");
8516                    heading.text(thisGroup.date);
8517                    //Add heading to wrapper
8518                    dayWrapper.append(heading);
8519                    //Create list to display all recently viewed items for this day
8520                    var dayList = $("<ul />");
8521                    //Add the list to the wrapper
8522                    dayWrapper.append(dayList);
8523
8524                    //Loops through each recently viewed item in this list
8525                    for (var j = 0; j < thisGroup.itemArray.length; j++) {
8526
8527                        var thisDay = thisGroup.itemArray[j];
8528                        //Create li element to display item
8529                        var itemDay = $("<li />");
8530                        //Build path to item component/display
8531                        var path = siteAssetsUrl + "/singleitemview/viewall" + thisDay.Path;
8532                        //If an item number was included, add it to the querystring
8533                        if (thisDay.ItemNumber != null) {
8534                            path += "/" + thisDay.ItemNumber;
8535                        }
8536
8537                        //Set data attribute on LI
8538                        itemDay.attr("data-itempath", path);
8539                        //Set item path
8540                        var itemTargetPath = thisDay.Path;
8541
8542                        //If we're targeting a specific item
8543                        if (thisDay.ItemNumber != null) {
8544                            itemTargetPath += "#" + thisDay.ItemNumber.replace(/-/g, "");
8545                        }
8546                        //If a size was selected
8547                        if (thisDay.Size != null) {
8548                            itemTargetPath += "?o=" + thisDay.Size;
8549                        }
8550                        //Add the target path
8551                        itemDay.attr("data-itemURL", itemTargetPath);
8552                        //Check if item we're addng is in the shopping bag
8553                        if (NextBasket.Data.Items != null) {
8554                            for (var k = 0; k < NextBasket.Data.Items.length; k++) {
8555                                if (thisDay.ItemNumber != null && NextBasket.Data.Items[k].ItemNumber == thisDay.ItemNumber.replace(/-/g, "").substring(0, 6)) {
8556                                    //If it is in the shopping bag, add appropriate class
8557                                    itemDay.addClass("inBag");
8558                                }
8559                            }
8560                        }
8561                        //Add the item to the list for this day
8562                        dayList.append(itemDay);
8563
8564                    }
8565                    //Add the wrapper for this current day/item group
8566                    $this.append(dayWrapper);
8567
8568                }
8569                //Load items currently visible
8570                methods.loadItemsInviewport($this);
8571
8572            });
8573
8574        },
8575        //This method loads the data/component for any list item currently visible in the viewport
8576        loadItemsInviewport: function (element) {
8577
8578            //Get height of window and scroll position of page
8579            var wHeight = $(window).height();
8580            var scrollTop = $(window).scrollTop();
8581            //Loop through each list item in the recently viewed wrapper
8582            $(element).find("li").each(function () {
8583                //If we haven't previously bound data to it and it's not a heading item
8584                if (!$(this).hasClass("newDay") && !$(this).hasClass("visible")) {
8585                    //Check position of list item - is it visible?
8586                    if (($(this).offset().top - scrollTop) > 100 && ($(this).offset().top - scrollTop < wHeight)) {
8587                        $(this).addClass("visible");
8588                        //If so - get the item data
8589                        methods.getItemData(this);
8590                    }
8591
8592                }
8593            });
8594
8595        },
8596        getItemData: function (li) {
8597
8598            var $li = $(li);
8599
8600            var path = $li.attr("data-itempath");
8601            var url = $li.attr("data-itemURL");
8602
8603
8604            RecentlyViewed.getItem(path, function (data) {
8605
8606                var d = $(data);
8607                var img = d.find("img");
8608
8609                //This assumes the first element returned is an <a>
8610                $(d[0]).attr("href", url);
8611
8612                img.css("opacity", 0);
8613                $li.prepend(d);
8614                img.animate({ opacity: 1 }, 300);
8615                $li.addClass("databound");
8616
8617            });
8618
8619        }
8620    };
8621
8622    $.fn.viewAllRecentlyViewed = function (method) {
8623
8624        if (methods[method]) {
8625            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
8626        } else if (typeof method === "object" || !method) {
8627            return methods.init.apply(this, arguments);
8628        } else {
8629            $.error("Method " + method + " does not exist on jQuery.viewAllRecentlyViewed");
8630        }
8631
8632    };
8633
8634})(jQuery);;
8635
8636
8637/////////////Item Scroller plug-in//////////////////////
8638
8639var RVInitialized = false;
8640
8641(function ($) {
8642
8643    var _visitorId;
8644    var isTouchDown = false;
8645    var isRTL = Next.Settings.Channel.DirectionRTL ? true : false;
8646    const rvItemWidthWithMargins = 102;
8647    var maxItemsOnPage = 9;
8648    var url = window.location.pathname.toLowerCase();
8649    if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1) {
8650        maxItemsOnPage = 8;
8651    }
8652
8653
8654    var methods = {
8655        //Initialize
8656        init: function (visitorId, loadOnVisible) {
8657            //Store visitor id
8658            _visitorId = visitorId;
8659
8660
8661            //If we're only loading the data when the element becomes visible (scrolls into view)
8662            //pass to initOnVisible and exit
8663            if (loadOnVisible) {
8664                methods.initOnVisible(this);
8665                return;
8666            }
8667
8668            //Otherwise, call the bindData method
8669            methods.bindData(this);
8670
8671
8672        },
8673        //Get ListsURL or SecureListsURL based on protocol or HTTPS feature
8674        getListsURLOrSecureListsURL: function () {
8675            if (window.location.protocol === "https:" || Next.Settings.Channel.HttpsEnabled)
8676                return SecureListsURL;
8677            else
8678                return ListsURL;
8679        },
8680        windowEvents: function (element) {
8681            RecentlyViewed.updateRecentlyViewedFooterLink(element);
8682        },
8683        initOnVisible: function (element) {
8684            if (RVInitialized) {
8685                return;
8686            }
8687            //wait for recentlyviewed to finish loading
8688            var bindRecentlyViewed = setInterval(function () {
8689                if (element.hasClass("BINDME")) {
8690                    methods.bindData(element);
8691                    clearInterval(bindRecentlyViewed);                    
8692                }
8693            }, 400);
8694
8695            //for home page
8696            setTimeout(function () {
8697                RecentlyViewed.updateRecentlyViewedFooterLink(element);
8698            }, 1000);
8699
8700            //Scroll handler
8701            $(window).scroll(function () {
8702                methods.windowEvents(element);
8703            });
8704
8705            //Resize handler
8706            $(window).resize(function () {
8707                methods.windowEvents(element);
8708            });
8709
8710            RVInitialized = true;
8711        },
8712        bindData: function (element) {
8713
8714            //Local copy of the element
8715            var $this = element;
8716
8717            //Add click handler for reload button in the error message
8718            $this.find("a.reload").click(function () { methods.reload($this); return false; });
8719
8720
8721            //getRecentlyViewed - shared service call in recentlyViewed.js
8722            RecentlyViewed.getRecentlyViewed(_visitorId, function (data) {
8723
8724                //Remove the ajax loader
8725
8726
8727                $this.find(".loader").remove();
8728
8729                var itemList = data;
8730                var vLength = itemList.length;
8731                var totalWidth = 0;
8732
8733                //Get formatted array of items - grouped by date
8734                var groupedArray = groupByDate(itemList);
8735
8736                var recentlyViewedGroupWrapper = $("<div />");
8737
8738                //Loop through each group/day
8739                for (var i = 0; i < groupedArray.length; i++) {
8740
8741                    var thisGroup = groupedArray[i];
8742                    //Create wrapper element for this day of recently viewed items
8743                    var dayWrapper = $("<div />");
8744                    dayWrapper.addClass("dayWrapper");
8745                    if (isRTL) dayWrapper.addClass("RTL");
8746                    //Heading for this day
8747                    var headingText = thisGroup.date;
8748                    if (thisGroup.itemArray.length == 1) {
8749                        // headingText = formatViewedDate(new Date(thisGroup.rawDate), "nn/mm/yy", true);
8750                        headingText = thisGroup.date;
8751                    }
8752
8753                    var heading = $("<h2 />");
8754                    heading.text(headingText);
8755                    // Amend arrow direction if RTL
8756                    if (isRTL) heading.addClass("RTL");
8757                    //Add heading to wrapper
8758                    dayWrapper.append(heading);
8759                    //Create list to display all recently viewed items for this day
8760                    var dayList = $("<ul />");
8761                    //Add the list to the wrapper
8762                    dayWrapper.append(dayList);
8763
8764
8765                    //Force the width of the wrapper
8766                    if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1) {
8767                        dayWrapper.width(thisGroup.itemArray.length * rvItemWidthWithMargins - 5);
8768                        dayList.width(thisGroup.itemArray.length * rvItemWidthWithMargins - 4);
8769                        totalWidth += thisGroup.itemArray.length * rvItemWidthWithMargins - 5;
8770                    }
8771                    else {
8772                        dayWrapper.width((thisGroup.itemArray.length * 95));
8773                        dayList.width(thisGroup.itemArray.length * 95);
8774                        totalWidth += thisGroup.itemArray.length * 95;
8775                    }
8776
8777                    //Loops through each recently viewwed item in this list
8778                    for (var j = 0; j < thisGroup.itemArray.length; j++) {
8779
8780                        var thisDay = thisGroup.itemArray[j];
8781
8782                        //Create li element to display item
8783                        var itemDay = $("<li />");
8784
8785                        if (i == 0 && j == 0) {
8786                          itemDay.addClass("lastViewed");
8787                        }
8788
8789                        if (Next.Settings.Channel.ThreeFourImageManagerEnabled && (thisDay.Path && !thisDay.Path.toLowerCase().includes("/homeware/sofas"))) {
8790                          itemDay.addClass("three-four-image");
8791                        }
8792
8793                        var isTabbedPageItem = false;
8794                        if (thisDay.Path.indexOf(thisDay.ItemNumber) > -1) {
8795                            isTabbedPageItem = true;
8796                            itemDay.data("type", "tabbedItem");
8797                        }
8798
8799                        //Build path to item component/display
8800                        //var path = "/singleitemview" + thisDay.Path + "?itemView=true";
8801
8802                        if (thisDay.Path.indexOf("/style") === -1 && (thisDay.Path.substring(0, 3).toLowerCase() == '/st' || thisDay.Path.substring(0, 3).toLowerCase() == '/es')) {
8803                            thisDay.Path = '/style' + thisDay.Path;
8804                        }
8805
8806                        //Store the correct path before modifying it
8807                        var currentItemPath = thisDay.Path;
8808
8809                        //New URL check
8810                        var urlSegments = ModularPDPHelper.getSegmentOptions(thisDay.Path);
8811                        if (ModularPDPHelper.isUrlPathNameInNewFormat(thisDay.Path, urlSegments.segmentsCount)) {
8812                            //Eg: /style/g8316s12/649138 or /g8316s12/649138
8813                            urlSegments.segments.pop();
8814                            thisDay.Path = urlSegments.segments.join('/');
8815                        }
8816
8817                      var path = siteAssetsUrl + "/singleitemview/rvscroller";
8818
8819                        var seqStartIndex = thisDay.Path.indexOf("seq");
8820                        var nonSeqPath = "";
8821
8822                        if (seqStartIndex > 0) {
8823                            nonSeqPath = thisDay.Path;
8824                            var textToReplace = nonSeqPath.substring(seqStartIndex, 20);
8825                            nonSeqPath = nonSeqPath.replace(textToReplace, '');
8826                            path = path + nonSeqPath;
8827                        }
8828                        else {
8829                            path = path + thisDay.Path;
8830                        }
8831
8832
8833                        //If an item number was included, add it to the querystring
8834                        if (thisDay.ItemNumber != null && !isTabbedPageItem) {
8835                            path += "/" + thisDay.ItemNumber;
8836                        }
8837
8838                        //Set data attribute on LI
8839                        itemDay.attr("data-itempath", path);
8840
8841                        //Set item path
8842                        var itemTargetPath = currentItemPath;
8843                        if (thisDay.ItemNumber != null && Next.Settings.UI.ModularPDPNewUrlFormatEnabled && ModularPDPHelper.isUrlPathNameInOldFormat(itemTargetPath, itemTargetPath.split('/').length)) {
8844                            itemTargetPath = ModularPDPHelper.getNewUrlPathName(itemTargetPath, thisDay.ItemNumber.replace(/-/g, ''));
8845                        }
8846
8847                        if (thisDay.ItemNumber != null && !isTabbedPageItem) {
8848                            itemTargetPath += "#" + thisDay.ItemNumber.replace(/-/g, '');
8849                        }
8850
8851                        if (thisDay.Size != null) {
8852                            itemTargetPath += "?o=" + thisDay.Size;
8853                        }
8854
8855                        itemDay.attr("data-itemURL", siteBaseUrl + itemTargetPath);
8856
8857                        //Check if item we're addng is in the shopping bag
8858                        if (NextBasket.Data.Items != null) {
8859                            for (var k = 0; k < NextBasket.Data.Items.length; k++) {
8860
8861                                if (thisDay.ItemNumber) {
8862
8863                                    var inBag = false;
8864
8865                                    if (isTabbedPageItem) {
8866                                        if (thisDay.Path.indexOf(NextBasket.Data.Items[k].ItemNumber + "-" + NextBasket.Data.Items[k].OptionNo) > -1) {
8867                                            inBag = true;
8868                                        }
8869                                    }
8870                                    else if (NextBasket.Data.Items[k].ItemNumber == thisDay.ItemNumber.replace(/-/g, '').substring(0, 6)) {
8871                                        inBag = true;
8872                                    }
8873
8874                                    if (inBag == true) {
8875                                        itemDay.addClass("inBag");
8876                                    }
8877
8878                                }
8879                            }
8880                        }
8881
8882                        //Add the item to the list for this day
8883                        dayList.append(itemDay);
8884
8885                    }
8886                    //Add the wrapper for this current day/item group
8887                    //setTimeout(function () {
8888                    recentlyViewedGroupWrapper.append(dayWrapper).width(totalWidth);
8889                    // }, 5000);
8890
8891
8892                }
8893
8894                //Clear out any existing data - we may be reloading a newer set of data
8895                $this.find(".recentlyViewedGroupWrapper").empty();
8896                var temp = recentlyViewedGroupWrapper.find(".dayWrapper");
8897                $this.find(".recentlyViewedGroupWrapper").append(temp).width(totalWidth);
8898
8899                //More than 9 - fix width
8900                if (vLength > maxItemsOnPage) {
8901                    // $this.width(976);
8902                    // $this.find(".clip").width(855)
8903                    if (isRTL) {
8904                        $this.find("a.scrollNav.previous").removeClass("disabled");
8905                        $this.find("a.scrollNav.next").addClass("disabled");
8906                    } else {
8907                        $this.find("a.scrollNav.next").removeClass("disabled");
8908                        $this.find("a.scrollNav.previous").addClass("disabled");
8909                    }
8910                    $this.find(".clip").addClass("noBackground");
8911                    //$this.find(".scrollControl").show();                    
8912                    methods.enableTouchEvents($this.find(".clip"));
8913                } else {
8914
8915                    //if (resize) {
8916                    //Less than 10 - calculate width and disable both scroll buttons
8917                    // $this.width(vLength * 97);
8918                    $this.find("a.scrollNav.previous").addClass("disabled");
8919                    $this.find("a.scrollNav.next").addClass("disabled");
8920                    // $this.find(".scrollControl").hide();
8921                    // $this.find(".clip").width(vLength * 97);
8922                    // }
8923                }
8924
8925                if (groupedArray.length == 0) {
8926                    $this.find(".emptyMessage").fadeIn(500);
8927                }
8928
8929
8930                //Set counter text if enabled
8931                if (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayCounter) {
8932                    $this.find(".viewCounter").text(vLength);
8933                }
8934
8935
8936                //Set class on parent element to indicate content has loaded
8937                $this.addClass("contentLoaded");
8938                methods.loadVisibleItems($this.find(".recentlyViewedGroupWrapper"));
8939                $this.find("a.scrollNav.previous").click(function () { methods.scroll(1, this, $this); return false; });
8940                $this.find("a.scrollNav.next").click(function () { methods.scroll(-1, this, $this); return false; });
8941
8942            },
8943                //This is the error callback
8944                function () {
8945
8946                    $this.find(".recentlyViewedGroupWrapper").fadeOut(500);
8947                    $this.find(".loader").hide();
8948                    $this.find(".errorMessageBlock").fadeIn(500);
8949
8950                });
8951
8952        },
8953        reload: function (element) {
8954
8955            var $this = $(element);
8956
8957            $this.find(".recentlyViewedGroupWrapper").fadeIn(500);
8958
8959            $this.find(".errorMessageBlock").fadeOut(300, function () {
8960                $this.find(".loader").fadeIn(300);
8961            });
8962
8963            methods.bindData($this);
8964
8965        },
8966        addItem: function (item) {
8967
8968            //Add to recently viewed
8969            RecentlyViewed.addItem(item);
8970
8971        },
8972        scroll: function (direction, element, parent) {
8973
8974            var listWrapper = parent.find(".recentlyViewedGroupWrapper");
8975
8976            if ($(element).hasClass("disabled")
8977                || listWrapper.hasClass("locked")
8978                || listWrapper.position().left >= 0 && direction == 1
8979                || listWrapper.find("li").length <= maxItemsOnPage) {
8980                return false;
8981            }
8982
8983            var liCount = listWrapper.find("li").length;
8984
8985            var currentOffset = listWrapper.css("left").replace('px', '');
8986
8987            var pageSize = 95 * 9;
8988            var listLen = liCount * 95;
8989            var distance = pageSize * direction;
8990
8991            if (Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1) {
8992                pageSize = rvItemWidthWithMargins * 8;
8993                listLen = liCount * rvItemWidthWithMargins;
8994                distance = pageSize * direction;
8995            }
8996
8997            //The following checks are there to prevent the scroller getting out of sync when touch enabled scrolling is enabled.
8998            //When a user uses touch-scroll, the paging will become irrelevant so need a check to make sure we don't scroll beyond the limit of the list
8999            var newOffset = parseInt(currentOffset) + parseInt(distance);
9000            var maxOffset = (listLen - pageSize) * direction;
9001
9002            if (!isRTL) {
9003                if ((newOffset < maxOffset) && direction == -1) {
9004                    distance = maxOffset - parseInt(currentOffset);
9005                }
9006
9007                if ((newOffset > 0) && direction == 1) {
9008                    distance = 0 - parseInt(currentOffset);
9009                }
9010            }
9011            else {
9012                if ((newOffset > maxOffset) && direction == 1) {
9013                    distance = maxOffset - parseInt(currentOffset);
9014                }
9015
9016                if ((newOffset < 0) && direction == -1) {
9017                    distance = 0 - parseInt(currentOffset);
9018                }
9019            }
9020
9021            //Safety check
9022            if (distance > pageSize) {
9023                distance = pageSize;
9024            }
9025
9026            if (distance < -pageSize) {
9027                distance = -pageSize;
9028            }
9029
9030            //ie8 and below don't like animating from one css class to another - so, set the animation time to 0
9031            var transitionSpeed = 200;
9032            if (!Modernizr.csstransitions) {
9033                transitionSpeed = 0;
9034            }
9035
9036
9037            listWrapper.addClass("locked").animate({
9038                left: "+=" + distance
9039            }, 500, function () {
9040
9041                if (direction == -1) {
9042                    parent.find("a.scrollNav.previous").removeClass("disabled", transitionSpeed);
9043                }
9044
9045                if (listWrapper.position().left >= 0) {
9046                    parent.find("a.scrollNav.previous").addClass("disabled", transitionSpeed);
9047                }
9048
9049                if (parent.find("li").length * rvItemWidthWithMargins < listWrapper.width()) { 
9050                    parent.find("a.scrollNav.next").addClass("disabled", transitionSpeed);
9051                } else {
9052                    parent.find("a.scrollNav.next").removeClass("disabled", transitionSpeed);
9053                }
9054
9055                listWrapper.removeClass("locked");
9056
9057                methods.loadVisibleItems(listWrapper);
9058
9059            });
9060
9061        },
9062        clearList: function () {
9063
9064            //Clears the full list of recently viewed items
9065            preventCollapse = true;
9066
9067            //Build target url
9068            var targetURL = methods.getListsURLOrSecureListsURL() + "/recentlyviewed/clear/" + _visitorId;
9069
9070            //Clear recently viewed data
9071            RecentlyViewed.clearList(targetURL);
9072
9073            //And update the UI
9074            var _this = this;
9075
9076            _this.find(".recentlyViewedGroupWrapper").fadeOut(500, function () {
9077                //Fade in message
9078                _this.find(".emptyMessage").fadeIn(500);
9079            });
9080
9081            //Disable clear link
9082            _this.find("a.clearAll").addClass("disabled");
9083
9084            //Disable scroll buttons
9085            $("a.scrollNav.previous").addClass("disabled", 200);
9086            $("a.scrollNav.next").addClass("disabled", 200);
9087
9088            //Make sure clip background is visible
9089            $(".clip").removeClass("noBackground");
9090
9091
9092            //Update display count
9093            if (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayCounter) {
9094                _this.find(".viewCounter").text("0");
9095            }
9096        },
9097        loadVisibleItems: function (wrapper) {
9098            //Load items as they appear in view
9099            if (wrapper.length > 0) {
9100                var allowance = Next.Settings.UI.IsInnovationDesktopResponsiveEnabled ? 1100 : 1000; //change this value to add more buffer/tune performance)
9101
9102                var itemDataPromises = [];
9103
9104                wrapper.find("ul").each(function () {
9105                    if ($(this).length > 0) {
9106                        var ulOffset = $(this).position().left + wrapper.position().left;
9107
9108                        $(this).find("li").each(function () {
9109                            if (!$(this).hasClass("databound")) { // Check if already loaded
9110                                var liOffset = $(this).position().left + ulOffset;
9111                                if (liOffset >= 0 && liOffset < allowance) {
9112                                    itemDataPromises.push(methods.getItemDataPromise(this));
9113                                }
9114                            }
9115                        });
9116                    }
9117                });
9118
9119                var allItemsLoaded = Promise.all(itemDataPromises);
9120                var itemCount = wrapper.find("li").length;
9121
9122                allItemsLoaded.then(() => {
9123                    var prices = wrapper.find("span");
9124
9125                    if (prices.length != itemCount) {
9126                        return;
9127                    }
9128
9129                    var prices = wrapper.find("span");
9130                    $(".RecentlyViewedWrapper").removeClass("price-range");
9131
9132                    for (var i = 0; i < prices.length; i++) {
9133                        var price = prices[i];
9134
9135                        if (price.innerText.includes("-")) {
9136                            $(".RecentlyViewedWrapper").addClass("price-range");
9137
9138                            if (price.innerText.includes("-") && Next.Settings.Channel.ResponsiveShoppingBagIsEnabled && url.indexOf("/shoppingbag") > -1) {
9139                                var splitedPrice = price.innerText.split("-");
9140                                var nicelyBrokenText = `<span>${splitedPrice[0]} -</span><span class="price-second-part"> ${splitedPrice[1]}</span>`;
9141                                price.innerHTML = nicelyBrokenText;
9142                            }
9143                        }
9144                    }
9145                });
9146            }
9147        },
9148        getItemData: function (li, callback) {
9149            //Loads the item component for a given list-item with provided data-attributes
9150            var $li = $(li);
9151            $li.addClass("databound");
9152            var path = $li.attr("data-itempath");
9153            var url = $li.attr("data-itemURL");
9154
9155            RecentlyViewed.getItem(path, function (data) {
9156                if (data !== undefined && data !== null && data.indexOf("<a") > -1) {
9157                    var d = $(data);
9158                    var img = d.find("img");
9159
9160                    if ($li.data("type") != "tabbedItem") {
9161                        d.attr("href", url);
9162                    }
9163                    img.css("opacity", 0);
9164                    $li.prepend(d);
9165                    img.animate({ opacity: 1 }, 300);
9166                }
9167                else {
9168                    var siblings = $li.siblings().length;
9169                    $li.remove();
9170                    if (siblings === 0) {
9171                        methods.displayClearDataUI();
9172                    }
9173                }
9174
9175                if (callback) {
9176                    callback();
9177                }
9178            });
9179        },
9180        getItemDataPromise: function (li) {
9181            return new Promise((resolve, reject) => {
9182                this.getItemData(li, () => {
9183                    resolve();
9184                });
9185            });
9186        }, 
9187        enableTouchEvents: function (element) {
9188
9189            var config = {
9190                touchStart: methods.touchStart,
9191                touchMove: methods.touchMove,
9192                touchEnd: methods.touchEnd,
9193                useMouse: true
9194            }
9195
9196            $(element).NXTouch(config);
9197
9198            var maxScroll = -(($(element).find("li").length * 95) - 855);
9199
9200            $(element).attr("data-maxscroll", maxScroll)
9201
9202        },
9203        touchStart: function (e, NXTouchObj) {
9204            isTouchDown = true;
9205
9206            var targetEl = $(e.currentTarget).find(".recentlyViewedGroupWrapper");
9207            var currentX = parseInt(targetEl.css("left").replace("px"));
9208
9209            if (!currentX) {
9210                currentX = 0;
9211            }
9212
9213            targetEl.attr("data-startx", currentX);
9214        },
9215        touchMove: function (e, NXTouchObj) {
9216
9217            if (isTouchDown) {
9218                var maxScroll = parseInt($(e.currentTarget).attr("data-maxscroll"));
9219
9220                var targetEl = $(e.currentTarget).find(".recentlyViewedGroupWrapper");
9221
9222                var targetX = parseInt(targetEl.attr("data-startx")) + NXTouchObj.DistanceX;
9223
9224
9225                if (targetX >= 0) {
9226
9227                    targetX = 0;
9228
9229                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.previous").addClass("disabled");
9230
9231                } else {
9232                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.previous").removeClass("disabled");
9233                }
9234
9235                if (targetX <= maxScroll) {
9236                    targetX = maxScroll;
9237                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.next").addClass("disabled");
9238                } else {
9239                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.next").removeClass("disabled");
9240                }
9241
9242                targetEl.css("left", targetX);
9243
9244                methods.loadVisibleItems(targetEl);
9245            }
9246        },
9247        touchEnd: function (e, NXTouchObj) {
9248            isTouchDown = false;
9249            var targetEl = $(e.currentTarget).find(".recentlyViewedGroupWrapper");
9250            var currentX = parseInt(targetEl.css("left").replace('px', ''));
9251
9252            var snapTo = (Math.round(currentX / 95)) * 95;
9253            var maxScroll = parseInt($(e.currentTarget).attr("data-maxscroll"));
9254            targetEl.animate({ left: snapTo + "px" }, 300, function () {
9255
9256                if (snapTo == 0) {
9257
9258                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.previous").addClass("disabled");
9259
9260                } else {
9261                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.previous").removeClass("disabled");
9262                }
9263
9264                if (snapTo == maxScroll) {
9265
9266                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.next").addClass("disabled");
9267                } else {
9268                    $(e.currentTarget).closest(".scrollRowWrapper").find("a.scrollNav.next").removeClass("disabled");
9269                }
9270            });
9271
9272        },
9273        displayClearDataUI: function () {
9274
9275            $(".recentlyViewedGroupWrapper").fadeOut(500);
9276
9277            //Fade in message
9278            $(".emptyMessage").fadeIn(500);
9279
9280            //Disable clear link
9281            $("a.clearAll").addClass("disabled");
9282
9283            //Disable scroll buttons
9284            $("a.scrollNav.previous").addClass("disabled", 200);
9285            $("a.scrollNav.next").addClass("disabled", 200);
9286
9287            //Make sure clip background is visible
9288            $(".clip").removeClass("noBackground");
9289
9290            //Update display count
9291            if (Next.FeatureManager.FeatureSettings.RecentlyViewed.DisplayCounter) {
9292                $(".viewCounter").text("0");
9293            }
9294        }
9295    };
9296
9297    $.fn.ItemScroller = function (method) {
9298
9299        if (methods[method]) {
9300            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
9301        } else if (typeof method === 'object' || !method) {
9302            return methods.init.apply(this, arguments);
9303        } else {
9304            $.error('Method ' + method + ' does not exist on jQuery.ItemScroller');
9305        }
9306    };
9307
9308})(jQuery);
9309
9310;
9311// ------------------------------------------------------------------------------------------ //
9312// Name: NXTouch - Touch Event Layer Plug-in
9313// Authors: John Loydall
9314// Copyright: Next PLC
9315// Description: Abstracts the touch events from different vendors/devices
9316//              into a common set of touch events with custom, device-independent touch objects
9317//
9318// ------------------------------------------------------------------------------------------ //
9319
9320/*
9321
9322//Usage////////////////////////////////////////
9323
9324Initialise the component to be touch-enabled. Pass in config object defining function calls for touch events
9325along with other initialisation paramaters
9326
9327//Parameters////////////////////////////////////
9328
9329touchStart - named function to handle touch start
9330touchMove -  named function to handle touch move
9331touchEnd -  named function to handle touch end
9332useMouse - boolean to indicate whether to map mouse events to the touch event handers (useful for testing)
9333
9334e.g.
9335var config = { 
9336touchStart: touchStart,
9337touchMove: touchMove,
9338touchEnd: touchEnd,
9339useMouse: true
9340}
9341 
9342Then initialise:
9343
9344$(element).NXTouch(config);
9345
9346And - make sure you define each function with the signature (e, NXTouchObj)
9347e.g.
9348
9349function touchMove(e, NXTouchObj) {
9350
9351}
9352
9353...where e will be the original event and NXTouchObj is the custom client touch point object
9354
9355The custom object exposes a number of properties of the current client point regardless of device
9356
9357e.g.
9358{
9359DistanceX: 28,
9360DistanceY: 2,
9361SpeedX: 1,
9362SpeedY: 0,
9363X: 68,
9364Y: 28
9365}
9366
9367e.g. 
9368
9369function touchMove(e, NXTouchObj) {
9370console.log(NXTouchObj.DistanceX);
9371}
9372
9373 
9374*/
9375
9376
9377
9378
9379
9380
9381
9382(function ($) {
9383    var startX = 0;
9384    var startY = 0;
9385    var currentX = 0;
9386    var currentY = 0;
9387    var previousX = 0;
9388    var previousY = 0;
9389    var movedX = 0;
9390    var movedY = 0;
9391    var speedX = 0;
9392    var speedY = 0;
9393    var currentClientPoint = {};
9394    var isMouseDown = false;
9395    var useMouse = false;
9396    var elementOffsetX = 0;
9397    var elementOffsetY = 0;
9398    var methods = {
9399        init: function (config) {
9400
9401            //If device isn't touch enabled and mouse input isn't set, return false
9402            if (!isTouchEnabled && !config.useMouse) {
9403                return false;
9404            }
9405
9406
9407            elementOffsetX = this.offset().left;
9408            elementOffsetY = this.offset().top;
9409
9410
9411
9412            //If using mouse, set plug-in variable
9413            if (config.useMouse) {
9414                useMouse = true;
9415            }
9416
9417            //If a touchstart event handler has been defined, bind to the corresponding device events
9418            if (config.touchStart) {
9419
9420                if (isTouchEnabled) {
9421                    this.bind('touchstart', function (e) { $(this).NXTouch('tStart', e, config.touchStart); })
9422                }
9423                if (isMSPointerDevice) {
9424                    this[0].addEventListener('MSPointerDown', function (e) { $(this).NXTouch('tStart', e, config.touchStart); })
9425                }
9426                //                if (useMouse) {
9427                //                    this.bind('mousedown', function (e) { $(this).NXTouch('tStart', e, config.touchStart); })
9428                //                }
9429            }
9430            //If a touchMove event handler has been defined, bind to the corresponding device events
9431            if (config.touchMove) {
9432
9433                if (isTouchEnabled) {
9434                    this.bind('touchmove', function (e) { $(this).NXTouch('tMove', e, config.touchMove); })
9435                }
9436                if (isMSPointerDevice) {
9437                    this[0].addEventListener('MSPointerMove', function (e) { $(this).NXTouch('tMove', e, config.touchMove); })
9438                }
9439                //                if (useMouse) {
9440                //                    this.bind('mousemove', function (e) { $(this).NXTouch('tMove', e, config.touchMove); })
9441                //                }
9442            }
9443            //If a touchEnd event handler has been defined, bind to the corresponding device events
9444            if (config.touchEnd) {
9445
9446                if (isTouchEnabled) {
9447                    this.bind('touchend', function (e) { $(this).NXTouch('tEnd', e, config.touchEnd); })
9448                }
9449                if (isMSPointerDevice) {
9450                    this[0].addEventListener('MSPointerUp', function (e) { $(this).NXTouch('tEnd', e, config.touchEnd); })
9451                }
9452                //                if (useMouse) {
9453                //                    this.bind('mouseup', function (e) { $(this).NXTouch('tEnd', e, config.touchEnd); })
9454                //                }
9455            }
9456
9457        },
9458        tStart: function (e, targetFunction) {
9459
9460            //touchStart wrapper - creates a standard client point object from the different device touch event properties
9461            var clientPoint = {};
9462
9463
9464            //Get client X & Y from different devices
9465
9466
9467            if (event.touches != null) {
9468                clientPoint.X = event.touches[0].pageX - elementOffsetX;
9469                clientPoint.Y = event.touches[0].pageY - elementOffsetY;
9470            }
9471            else if (e.pageX != null) {
9472                clientPoint.X = e.pageX - elementOffsetX;
9473                clientPoint.Y = e.pageY - elementOffsetY;
9474            }
9475
9476
9477            //            if (useMouse) {
9478            //                isMouseDown = true;
9479            //                clientPoint.X = e.clientX - elementOffsetX;
9480            //                clientPoint.Y = e.clientY - elementOffsetY;
9481            //            }
9482
9483            //Store client location
9484            startX = clientPoint.X;
9485            startY = clientPoint.Y;
9486
9487            currentX = clientPoint.X;
9488            currentY = clientPoint.Y;
9489
9490            currentClientPoint = clientPoint;
9491
9492            //Pass custom client object to function defined in plugin config 
9493            targetFunction(e, clientPoint);
9494
9495        },
9496        tMove: function (e, targetFunction) {
9497
9498            e.preventDefault();
9499
9500
9501
9502            if (useMouse && !isMouseDown) {
9503
9504                // return false;
9505            }
9506
9507            var clientPoint = {};
9508
9509
9510
9511            if (event.touches != null) {
9512                clientPoint.X = event.touches[0].pageX - elementOffsetX;
9513                clientPoint.Y = event.touches[0].pageY - elementOffsetY;
9514            }
9515            else if (e.pageX != null) {
9516
9517                switch (e.pointerType) {
9518                    case e.MSPOINTER_TYPE_TOUCH:
9519                        //console.log("touch");
9520                        break;
9521                    case e.MSPOINTER_TYPE_PEN:
9522                        return false;
9523                        break;
9524                    case e.MSPOINTER_TYPE_MOUSE:
9525                        return false;
9526                        break;
9527                }
9528
9529                clientPoint.X = e.pageX - elementOffsetX;
9530                clientPoint.Y = e.pageY - elementOffsetY;
9531                rvScrollOffset = currentX - startX; //this will be useful in Footer.js to identify item scrolling has taken place or not
9532            }
9533
9534
9535            //            if (useMouse) {
9536            //                clientPoint.X = e.clientX - elementOffsetX;
9537            //                clientPoint.Y = e.clientY - elementOffsetY;
9538            //            }
9539
9540            previousX = currentX;
9541            previousY = currentY;
9542
9543            currentX = clientPoint.X;
9544            currentY = clientPoint.Y;
9545
9546            movedX = currentX - startX;
9547            movedY = currentY - startY;
9548
9549            speedX = currentX - previousX;
9550            speedY = currentY - previousY;
9551
9552            clientPoint.DistanceX = movedX;
9553            clientPoint.DistanceY = movedY;
9554
9555            clientPoint.SpeedX = speedX;
9556            clientPoint.SpeedY = speedY;
9557
9558            currentClientPoint = clientPoint;
9559
9560            targetFunction(e, clientPoint);
9561
9562        },
9563        tEnd: function (e, targetFunction) {
9564
9565            isMouseDown = false;
9566            var clientPoint = currentClientPoint;
9567            targetFunction(e, clientPoint);
9568        }
9569    };
9570
9571    $.fn.NXTouch = function (method) {
9572
9573        //Method calling 
9574        if (methods[method]) {
9575            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
9576        } else if (typeof method === 'object' || !method) {
9577            return methods.init.apply(this, arguments);
9578        } else {
9579            $.error('Method ' + method + ' does not exist on jQuery.NXTouch');
9580        }
9581
9582    };
9583
9584})(jQuery);;
9585/*!
9586* Modal Popup
9587* Version: 2014.5.9.0
9588* Original author: Curtis Timson
9589*/
9590
9591var ModalPopup = {
9592    options: null,
9593    vars: {
9594        showMidClass: "show-mid",
9595        showClass: "show",
9596        modalPopupClass: "ModalPopup",
9597        modalPopupContainerClass: "ModalPopupContainer",
9598        modalPopupContainerOverlayClass: "overlay",
9599        modalPopupWrapperClass: "ModalPopupWrapper",
9600        $modalPopupContainer: null,
9601        $modalPopupWrapper: null,
9602        $modalPopup: null,
9603        isActive: false,
9604        modalDataSet: null
9605    },
9606    constants: {
9607        scrollLockEvents: "mousewheel.modalscroll DOMMouseScroll.modalscroll MozMousePixelScroll.modalscroll"
9608    },
9609    init: function (options) {
9610        var _this = this;
9611
9612        //Plugin Name and Default values
9613        var pluginName = 'ModalPopup',
9614		defaults = {
9615		    closeClass: 'closemodal',
9616		    scrollClass: 'ModalScroll',
9617		    overlay: true,
9618		    width: null,
9619		    height: null,
9620		    onPreClose: null,
9621		    onClose: null,
9622		    lockBackgroundScroll: false,
9623		    closeOnContainerClick: true,
9624		    fixedTopPosition: null,//these variables are used by Secci responsive design
9625		    fixedLeftPosition: null,
9626		    fullyLockBackgroundScroll: false, //this is used for Find in Store modal on Desktop PDP, this will override lockBackgroundScroll
9627            isPersonalisedGift: false
9628		};
9629
9630        _this.options = $.extend({}, defaults, options);
9631
9632        if (_this.options && _this.options.fullyLockBackgroundScroll && _this.vars.$modalPopup) {
9633            _this.vars.$modalPopup.remove();
9634        }
9635
9636        _this.vars.$modalPopup = $("." + _this.vars.modalPopupClass);
9637        if (!_this.vars.$modalPopup.length) {
9638            _this.vars.$modalPopup = $("<div/>");
9639            _this.vars.$modalPopup.addClass(_this.vars.modalPopupClass);
9640            if (_this.options.isPersonalisedGift) {
9641                _this.vars.$modalPopup.addClass("PersonalisedModal");
9642            }
9643
9644            if (_this.options && _this.options.fullyLockBackgroundScroll) {
9645                _this.vars.$modalPopup.css("position", "relative");
9646                _this.vars.$modalPopupWrapper = $("<div/>");
9647                _this.vars.$modalPopupWrapper.addClass(_this.vars.modalPopupWrapperClass);
9648                $("body").append(_this.vars.$modalPopupWrapper.append(_this.vars.$modalPopup));
9649            } else {
9650                $("body").append(_this.vars.$modalPopup);
9651            }
9652        }
9653
9654
9655        _this.addContainer();
9656
9657        if (_this.options.isPersonalisedGift){
9658            this.CalculateScreenSpaceForPersonalisedGiftModal();
9659        }
9660
9661        if(!_this.vars.$modalPopup.hasClass("ZoomedModal")){
9662            if (_this.options.width) {
9663                _this.vars.$modalPopup.width(_this.options.width);
9664            }
9665
9666            if (_this.options.height) {
9667                _this.vars.$modalPopup.height(_this.options.height);
9668            }
9669        }
9670        else    {
9671             _this.vars.$modalPopup.removeAttr("style");
9672        }
9673
9674        //close binding
9675        _this.vars.$modalPopup.on("click", "." + _this.options.closeClass, function (e) {
9676            _this.close(e);
9677        });
9678
9679        //window resize
9680        $(window).resize(function () {
9681            _this.setModalPosition();
9682        });
9683
9684        if (_this.options && _this.options.fullyLockBackgroundScroll) {
9685            this.LockBackgroundScroll();
9686        }
9687        else if (_this.options.lockBackgroundScroll) {
9688            this.EnableScrollLock();
9689        }
9690
9691        if (_this.options.modalDataSet) {
9692            _this.vars.modalDataSet = this.options.modalDataSet;
9693        }
9694
9695
9696        return _this.vars.$modalPopup;
9697    },
9698    addContainer: function () {
9699        var _this = this;
9700        _this.vars.$modalPopupContainer = $("<div/>");
9701        _this.vars.$modalPopupContainer.addClass(_this.vars.modalPopupContainerClass);
9702        if (_this.options.overlay) {
9703            _this.vars.$modalPopupContainer.addClass(_this.vars.modalPopupContainerOverlayClass);
9704        }
9705
9706        if (_this.options && _this.options.fullyLockBackgroundScroll) {
9707            _this.vars.$modalPopupWrapper.before(_this.vars.$modalPopupContainer);
9708        } else {
9709            _this.vars.$modalPopup.before(_this.vars.$modalPopupContainer);
9710        }
9711
9712        _this.vars.$modalPopupContainer = $("." + _this.vars.modalPopupContainerClass);
9713        _this.vars.$modalPopupContainer.click(function (e) {
9714            if (_this.options.closeOnContainerClick) {
9715                _this.close(e);
9716            }
9717        });
9718    },
9719    show: function () {
9720        var _this = this;
9721
9722        if ($("." + _this.vars.modalPopupContainerClass).length < 1) {
9723            _this.addContainer();
9724        }
9725
9726        _this.setModalPosition();
9727
9728        if (_this.options && _this.options.fullyLockBackgroundScroll) {
9729            _this.vars.$modalPopupWrapper.addClass(_this.vars.showClass);
9730        }
9731
9732        _this.vars.$modalPopup.addClass(_this.vars.showMidClass);
9733        setTimeout(function () {
9734            _this.vars.$modalPopup.addClass(_this.vars.showClass);
9735            document.dispatchEvent(new CustomEvent("PopUpDisplayed", this));
9736        }, 1);
9737
9738        _this.vars.isActive = true;
9739    },
9740    close: function (e) {
9741
9742        var _this = this;
9743
9744        if (_this.options && _this.options.fullyLockBackgroundScroll) {
9745            $("body").css("overflow", "");
9746        }
9747
9748        if (_this.vars.isActive) {
9749            if (e) {
9750                e.preventDefault();
9751            }
9752
9753            if (_this.options.onPreClose) {
9754                _this.options.onPreClose();
9755            }
9756
9757            //Remove container element
9758            if (_this.vars.$modalPopupContainer) {
9759
9760                if (_this.options && !_this.options.fullyLockBackgroun
9760dScroll) {
9761                    _this.vars.$modalPopupContainer.off(_this.constants.scrollLockEvents);
9762                }
9763
9764                _this.vars.$modalPopupContainer.replaceWith(_this.vars.$modalPopupContainer.contents());
9765            }
9766
9767            if (_this.options && _this.options.fullyLockBackgroundScroll) {
9768                _this.vars.$modalPopupWrapper.remove();
9769            } else {
9770                _this.vars.$modalPopup.off(_this.constants.scrollLockEvents);
9771            }
9772
9773            _this.vars.$modalPopup.removeClass(_this.vars.showClass);
9774            setTimeout(function () {
9775                _this.vars.$modalPopup.removeClass(_this.vars.showMidClass);
9776            }, 100);
9777
9778            if (_this.options && !_this.options.fullyLockBackgroundScroll) {
9779                $(document).off(_this.constants.scrollLockEvents);
9780            }
9781
9782            _this.vars.isActive = false;
9783            if (_this.options.onClose) {
9784                _this.options.onClose();
9785            }
9786        }
9787    },
9788    setModalPosition: function () {
9789        var _this = this;
9790        if(_this.options.isPersonalisedGift){
9791            this.CalculateScreenSpaceForPersonalisedGiftModal();
9792        }
9793        if(!_this.vars.$modalPopup.hasClass("ZoomedModal")){
9794            //Adjust position of modal popup
9795            var modalPopupTop = parseInt(($(window).height() / 2) - (_this.vars.$modalPopup.outerHeight() / 2), 10);
9796            var modalPopupLeft = parseInt(($(window).width() / 2) - (_this.vars.$modalPopup.outerWidth() / 2), 10);
9797
9798            if (_this.options.fixedTopPosition != null) {
9799                modalPopupTop = _this.options.fixedTopPosition;
9800            }
9801
9802            if (_this.options.fixedLeftPosition != null) {
9803                modalPopupLeft = _this.options.fixedLeftPosition;
9804            }       
9805
9806            _this.vars.$modalPopup.css("top", modalPopupTop);
9807            _this.vars.$modalPopup.css("left", modalPopupLeft);
9808        }
9809        else{
9810            _this.vars.$modalPopup.removeAttr("style");
9811        }
9812    },
9813    EnableScrollLock: function () {
9814        var _this = this;
9815
9816        $(document).on(_this.constants.scrollLockEvents, function (e) {
9817            return false;
9818        });
9819
9820        _this.vars.$modalPopupContainer.on(_this.constants.scrollLockEvents, function (e) {
9821            e.preventDefault();
9822        });
9823        _this.vars.$modalPopup.on(_this.constants.scrollLockEvents, function (e) {
9824            e.preventDefault();
9825
9826            var $target = $(e.target);
9827            var $scrollableElement = _this.vars.$modalPopup.find("." + _this.options.scrollClass);
9828            var $targetScrollable = $target.closest($scrollableElement);
9829
9830            if ($targetScrollable.length) {
9831                var scrollTo = null;
9832
9833                if (e.type == 'mousewheel') {
9834                    scrollTo = (e.originalEvent.wheelDelta * -1);
9835                }
9836                else if (e.type == 'DOMMouseScroll') {
9837                    scrollTo = 40 * e.originalEvent.detail;
9838                }
9839
9840                if (scrollTo) {
9841                    $targetScrollable.scrollTop(scrollTo + $targetScrollable.scrollTop());
9842                }
9843            }
9844
9845        });
9846    },
9847    LockBackgroundScroll: function () {
9848        $("body").css("overflow", "hidden");
9849    },
9850    GetModalDataSet: function() {
9851        return this.vars.modalDataSet;
9852    },
9853
9854    CalculateScreenSpaceForPersonalisedGiftModal: function(){
9855        var _this = this;        
9856        if(window.innerHeight <= 625){
9857            _this.vars.$modalPopup.addClass("ZoomedModal");
9858        }
9859        else{
9860            _this.vars.$modalPopup.removeClass("ZoomedModal");
9861        }
9862    }
9863};;
9864/*
9865 * June 2015
9866 * This code is written to support search suggestions in departments.
9867 * However the departments have been removed from the SLI feed, so much of the code is
9868 * redundant. This might change in the future.
9869 *
9870 * October 2019
9871 * The search auto complete has been updated to include an enriched view with product list
9872 */
9873var Search;
9874(function (Search) {
9875    var Keys;
9876    (function (Keys) {
9877        Keys[Keys["UpArrow"] = 38] = "UpArrow";
9878        Keys[Keys["DownArrow"] = 40] = "DownArrow";
9879        Keys[Keys["Tab"] = 9] = "Tab";
9880        Keys[Keys["Enter"] = 13] = "Enter";
9881        Keys[Keys["Escape"] = 27] = "Escape";
9882    })(Keys || (Keys = {}));
9883    var DomSelector;
9884    (function (DomSelector) {
9885        DomSelector["Input"] = "sli_search_1";
9886        DomSelector["Form"] = "#newsearch";
9887        DomSelector["StateIsEnriched"] = "is-enriched";
9888        DomSelector["StateIsLoading"] = "is-loading";
9889        DomSelector["StateHideIfNoResults"] = "hide-if-no-results";
9890        DomSelector["StateShowRecent"] = "show-recent";
9891        DomSelector["StateNoRecent"] = "no-recent";
9892        DomSelector["StateSelected"] = "selected";
9893        DomSelector["StateNoResults"] = "no-results";
9894        DomSelector["SearchDropdownCover"] = "search-dropdown-content-cover";
9895        DomSelector["RecentHeading"] = "recent-heading";
9896        DomSelector["ClearRecent"] = "clear-recent";
9897        DomSelector["SearchItem"] = "search-item";
9898        DomSelector["Open"] = "open";
9899        DomSelector["Divider"] = "divider";
9900        DomSelector["Title"] = "title";
9901        DomSelector["CurrentSearchTerm"] = "freeTextSearchTerm";
9902    })(DomSelector || (DomSelector = {}));
9903    var AutoComplete = /** @class */ (function () {
9904        function AutoComplete(baseAddress, recentSearchesSaved, suggestionsEnabled, autoCompleteUrl) {
9905            var _this = this;
9906            this.recentSearches = new KeyCookies(recentSearchesSaved);
9907            this.input = document.getElementById(DomSelector.Input);
9908            this.filter = document.getElementById('search-af');
9909            this.$form = $('#newsearch');
9910            this.$dropdownContainer = this.$form.find('.search-dropdown-container');
9911            this.$dropdown = this.$form.find('.search');
9912            if (baseAddress.length > 0 && baseAddress.charAt(baseAddress.length - 1) !== "/") {
9913                baseAddress += "/";
9914            }
9915            this.url = baseAddress + autoCompleteUrl;
9916            this.$form.submit(function (e) { return _this.searchSubmit(); });
9917            var $input = $(this.input);
9918            $input.on('focus, click', function (e) {
9919                _this.openDropdown();
9920            });
9921            $input.on('blur', function (e) {
9922                _this.delayCloseDropdown();
9923            });
9924            $('#MainNavigation').hover(function (e) { return _this.delayCloseDropdown(); });
9925            this.setLastSearch();
9926            this.initClearSearchTextButton();
9927            this.initSelectionEvents();
9928            if (suggestionsEnabled) {
9929                this.initSuggestions();
9930            }
9931            else {
9932                this.initNoSuggestions();
9933            }
9934        }
9935        /**
9936         * Use this to unload this class and all associated DOM items
9937         */
9938        AutoComplete.prototype.destroy = function () {
9939            // Remove all events on input field
9940            $('#' + DomSelector.Input).off('click blur focus keyup keydown');
9941            // Remove items added to the DOM
9942            this.$dropdown.empty();
9943        };
9944        /**
9945         * Initialise when suggestions are turned off
9946         */
9947        AutoComplete.prototype.initNoSuggestions = function () {
9948            var _this = this;
9949            var inputText = this.input.value;
9950            $(this.input).keyup(function (e) {
9951                // No change so return
9952                if (_this.input.value === inputText)
9953                    return;
9954                inputText = _this.input.value;
9955                // Ignore keys that can change the content but shouldn't close the dropdown
9956                if (_this.IgnoreKey(e.keyCode))
9957                    return;
9958                _this.clearDropdown();
9959                if (inputText.length == 0)
9960                    _this.loadRecentSearches();
9961                _this.refresh();
9962            });
9963        };
9964        /**
9965         * Set up button to clear the search text.
9966         */
9967        AutoComplete.prototype.initClearSearchTextButton = function () {
9968            var _this = this;
9969            var btn = this.$form.find('.clear-search-text');
9970            this.showOrHideClearSearchTextButton();
9971            btn.click(function (e) {
9972                _this.input.value = '';
9973                _this.showOrHideClearSearchTextButton();
9974                _this.clearDropdown();
9975                _this.loadRecentSearches();
9976                setTimeout(function () { return _this.input.focus(); }, 500);
9977            });
9978        };
9979        AutoComplete.prototype.showOrHideClearSearchTextButton = function () {
9980            var btn = this.$form.find('.clear-search-text');
9981            var show = this.input.value !== '';
9982            show ? btn.addClass("visible") : btn.removeClass("visible");
9983        };
9984        /**
9985         * Initialise the suggestion searches
9986         */
9987        AutoComplete.prototype.initSuggestions = function () {
9988            var _this = this;
9989            var inputText;
9990            var timeoutId = 0;
9991            $(this.input).keyup(function (e) {
9992                // If no change in input return
9993                if (_this.input.value === inputText)
9994                    return;
9995                inputText = _this.input.value;
9996                _this.showOrHideClearSearchTextButton();
9997                // Ignore keys that can change the content but don't need to invoke a search
9998                if (_this.IgnoreKey(e.keyCode))
9999                    return;
10000                // Input changed so clear any selection
10001                _this.clearSelected();
10002                // Restart timer
10003                clearTimeout(timeoutId);
10004                timeoutId = setTimeout(function () {
10005                    if (inputText.length == 0) {
10006                        _this.clearDropdown();
10007                        _this.loadRecentSearches();
10008                        _this.refresh();
10009                    }
10010                    else {
10011                        if (Next.Settings.Channel.BloomReachSearchOverrideEnabled) {
10012                            _this.brsearch(inputText)
10013                                .done(function (result) {
10014                                _this.clearDropdown();
10015                                _this.brProcessResponse(result);
10016                                _this.refresh();
10017                            })
10018                                .fail(function (xhr, status, error) {
10019                                ConsoleLog("Auto-complete feed error: " + status);
10020                                _this.clearDropdown();
10021                                _this.refresh();
10022                            });
10023                        }
10024                        //start: to remove
10025                        else if (Next.Settings.Channel.BloomReachSearchEnabled &&
10026                            typeof _this.recentSearches.monetateSearchCookie != 'undefined' &&
10027                            _this.recentSearches.monetateSearchCookie.indexOf(Next.Settings.Cookie.MonetateCookieBloomReachValue) === 0) {
10028                            _this.brsearch(inputText)
10029                                .done(function (result) {
10030                                _this.clearDropdown();
10031                                _this.brProcessResponse(result);
10032                                _this.refresh();
10033                            })
10034                                .fail(function (xhr, status, error) {
10035                                ConsoleLog("Auto-complete feed error: " + status);
10036                                _this.clearDropdown();
10037                                _this.refresh();
10038                            });
10039                        }
10040                    }
10041                }, 500);
10042            });
10043            this.initialSuggestions();
10044        };
10045        AutoComplete.prototype.initSelectionEvents = function () {
10046            var _this = this;
10047            $(this.input).keydown(function (e) {
10048                switch (e.keyCode) {
10049                    case Keys.UpArrow:
10050                    case Keys.DownArrow:
10051                        e.preventDefault();
10052                        _this.keyUpDown(e.keyCode);
10053                        break;
10054                    case Keys.Enter:
10055                        return _this.selectItem();
10056                }
10057            });
10058        };
10059        /**
10060         * Initialise the suggestions
10061         */
10062        AutoComplete.prototype.initialSuggestions = function () {
10063            var _this = this;
10064            if (this.input.value && Next.Settings.Channel.BloomReachSearchOverrideEnabled) {
10065                this.brsearch(this.input.value)
10066                    .done(function (result) {
10067                    _this.clearDropdown();
10068                    _this.brProcessResponse(result);
10069                    _this.refresh();
10070                })
10071                    .fail(function (xhr, status, error) {
10072                    if ('abort' !== status) {
10073                        // If ajax request fails then it could be due to adblocker
10074                        _this.clearDropdown();
10075                        _this.refresh();
10076                    }
10077                });
10078            }
10079        };
10080        /**
10081         * Which keys to ignore when search input has focus.
10082         */
10083        AutoComplete.prototype.IgnoreKey = function (keyCode) {
10084            if (keyCode == Keys.UpArrow)
10085                return true;
10086            if (keyCode == Keys.DownArrow)
10087                return true;
10088            return false;
10089        };
10090        /**
10091         * Invoke the Ajax search for suggestions
10092         */
10093        AutoComplete.prototype.search = function (term) {
10094            var ajaxSettings = {
10095                url: this.url,
10096                dataType: "json",
10097                cache: true,
10098                data: {
10099                    word: term
10100                }
10101            };
10102            return $.ajax(ajaxSettings);
10103        };
10104        /**
10105         * Parse the SLI response and return the suggestions array.
10106         */
10107        AutoComplete.prototype.processResponse = function (response) {
10108            var _this = this;
10109            var ss = response.results.search_suggestions;
10110            if (!ss)
10111                return null;
10112            if (ss.department_suggestions)
10113                $.each(ss.department_suggestions, function (index, item) { return _this.addDepartment(item); });
10114            if (ss.suggestions) {
10115                if (this.haveItemsInList()) {
10116                    this.addDivider();
10117                    this.addSearchesTitle();
10118                }
10119                $.each(ss.suggestions, function (index, text) { return _this.addSuggestion(text); });
10120            }
10121        };
10122        //bloomreach
10123        /**
10124         * Invoke the Ajax search for suggestions
10125         */
10126        AutoComplete.prototype.brsearch = function (term) {
10127            var bruid = this.recentSearches.brUIDCookie;
10128            var requestID = new Date().getTime();
10129            var viewId = Next.Settings.Channel.BloomReachAutoSuggestViewIdEnabled ? (Next.Settings.Channel.BloomReachCountryCode ? "&view_id=" + Next.Settings.Channel.BloomReachCountryCode : "") : ""; // View_id is a parameter that needs to be present for Intl but not for UK
10130            var url = Next.Settings.Channel.BloomReachAutosuggestDomain +
10131                "?account_id=" + Next.Settings.Channel.BloomReachAccountID +
10132                "&auth_key=" +
10133                "&domain_key=" + Next.Settings.Channel.BloomReachDomainKey +
10134                viewId +
10135                "&request_id=" + requestID +
10136                "&_br_uid_2=" + bruid +
10137                "&request_type=suggest" +
10138                "&q=" + term;
10139            var ajaxSettings = {
10140                url: url,
10141                dataType: "json"
10142            };
10143            return $.ajax(ajaxSettings);
10144        };
10145        /**
10146         */
10147        AutoComplete.prototype.brProcessResponse = function (response) {
10148            var _this = this;
10149            var ss = response.response;
10150            if (!ss)
10151                return null;
10152            if (ss.suggestions) {
10153                if (this.haveItemsInList()) {
10154                    this.addDivider();
10155                    this.addSearchesTitle();
10156                }
10157                ss.suggestions = ss.suggestions.slice(0, 10);
10158                $.each(ss.suggestions, function (index, s) { return _this.addSuggestion(s.q); });
10159            }
10160        };
10161        /**
10162         * Simulate a click on the currently selected item
10163         */
10164        AutoComplete.prototype.selectItem = function () {
10165            var $selected = this.$dropdown.find('li.selected');
10166            if (!$selected.length)
10167                return true;
10168            $selected.click();
10169            return false;
10170        };
10171        AutoComplete.prototype.keyUpDown = function (keyCode) {
10172            var $list = this.$dropdown.find('li.search-item');
10173            var listLength = $list.length;
10174            if (listLength == 0)
10175                return;
10176            if (listLength == 1) {
10177                $list.first().addClass('selected');
10178                return;
10179            }
10180            var $selected = $list.filter('.selected');
10181            var index = $list.index($selected);
10182            $selected.removeClass('selected');
10183            if (keyCode == Keys.UpArrow) {
10184                if (index-- < 0)
10185                    index = listLength - 1;
10186            }
10187            if (keyCode == Keys.DownArrow) {
10188                if (++index == listLength)
10189                    index = 0;
10190            }
10191            var $li = $list.eq(index);
10192            $li.addClass('selected');
10193            this.input.value = $li.data("term");
10194        };
10195        /**
10196         * Clear the selected list item
10197         */
10198        AutoComplete.prototype.clearSelected = function () {
10199            var $item = this.$dropdown.find('li.selected');
10200            $item.removeClass("selected");
10201        };
10202        /**
10203         * Add the heading in the list for the recently searched
10204         */
10205        AutoComplete.prototype.addRecentHeading = function () {
10206            var _this = this;
10207            var $li = $("<li>")
10208                .addClass("recent-heading")
10209                .text(nxt.jstranslations.autocomplete.recentsearches || "Your Recent Searches...")
10210                .append("<a>")
10211                .find("a")
10212                .addClass("clear-recent")
10213                .attr("href", "#")
10214                .click(function () { return _this.deleteRecent(); })
10215                .text(nxt.jstranslations.common.clear || "Clear")
10216                .end();
10217            this.$dropdown.append($li);
10218        };
10219        /**
10220         * Add the divider in the list
10221         */
10222        AutoComplete.prototype.addDivider = function () {
10223            var $li = $("<li>")
10224                .addClass("divider");
10225            this.$dropdown.append($li);
10226        };
10227        /**
10228         * Add the title of the search section in the list
10229         */
10230        AutoComplete.prototype.addSearchesTitle = function () {
10231            var $li = $("<li>")
10232                .addClass("title")
10233                .text(nxt.jstranslations.autocomplete.populasearches || "Popular Searches");
10234            this.$dropdown.append($li);
10235        };
10236        /**
10237         * Get the recently searched cookies and add them to the dropdown list
10238         */
10239        AutoComplete.prototype.loadRecentSearches = function () {
10240            var _this = this;
10241            this.addRecentHeading();
10242            var kc = this.recentSearches.load();
10243            $.each(kc, function (i, s) {
10244                if (i < Next.FeatureManager.FeatureSettings.Search.RecentSearchesSaved) {
10245                    _this.addRecent(s);
10246                }
10247            });
10248        };
10249        /**
10250         * Refresh the state of the search drop down
10251         */
10252        AutoComplete.prototype.refresh = function () {
10253            if (this.haveItemsInList())
10254                this.showDropdown();
10255            else
10256                this.hideDropdown();
10257        };
10258        AutoComplete.prototype.openDropdown = function () {
10259            this.refresh();
10260        };
10261        AutoComplete.prototype.delayCloseDropdown = function () {
10262            var _this = this;
10263            // delay is visually better but also necessary to make sure the "clear" event is not squashed
10264            setTimeout(function () { return _this.hideDropdown(100); }, 150);
10265        };
10266        AutoComplete.prototype.hideDropdown = function (duration) {
10267            duration ? this.$dropdownContainer.hide(duration, 'swing') : this.$dropdownContainer.hide();
10268            $(this.input).removeClass('open');
10269        };
10270        AutoComplete.prototype.showDropdown = function () {
10271            this.$dropdownContainer.show();
10272            $(this.input).addClass('open');
10273        };
10274        /**
10275         * Remove leading, trailing and double spaces.
10276         */
10277        AutoComplete.prototype.clean = function (term) {
10278            term = term.replace(/^[\s]*/, '').replace(/[\s]*$/, '').replace(/ +/, ' ');
10279            return term;
10280        };
10281        /**
10282         * The form is being submitted
10283         */
10284        AutoComplete.prototype.searchSubmit = function () {
10285            this.input.value = this.clean(this.input.value);
10286            if (!this.input.value)
10287                return;
10288            // If filter is set recent searches have already been added.
10289            if (this.filter.value)
10290                return;
10291            var suggestion = {
10292                term: this.input.value,
10293                af: '',
10294                name: ''
10295            };
10296            this.recentSearches.add(suggestion);
10297        };
10298        /**
10299         * Set the search input control to the last searched term if on a search page.
10300         */
10301        AutoComplete.prototype.setLastSearch = function () {
10302            var lastSearch = this.recentSearches.getLastSearch();
10303            if (!lastSearch) {
10304                this.loadRecentSearches();
10305                return;
10306            }
10307            if (this.onResultsPage()) {
10308                this.input.value = lastSearch;
10309                return;
10310            }
10311            this.recentSearches.clearLastSearch();
10312            this.loadRecentSearches();
10313        };
10314        /**
10315         * return true if this is the search results page.
10316         */
10317        AutoComplete.prototype.onResultsPage = function () {
10318            // To do when we can determine if we are a search results page.
10319            return false;
10320        };
10321        /**
10322         * Remove all items from the list
10323         */
10324        AutoComplete.prototype.clearDropdown = function () {
10325            this.$dropdown.empty();
10326        };
10327        AutoComplete.prototype.deleteRecent = function () {
10328            this.recentSearches.clear();
10329            this.clearDropdown();
10330        };
10331        AutoComplete.prototype.dropdownItemSelected = function (item) {
10332            this.input.value = item;
10333            this.$form.submit();
10334        };
10335        AutoComplete.prototype.dropdownDepartmentItemSelected = function (item) {
10336            this.input.value = item.term;
10337            this.filter.value = item.af;
10338            this.recentSearches.add(item);
10339            this.$form.submit();
10340        };
10341        /**
10342         * Add a department suggestion into the dropdown list.
10343         */
10344        AutoComplete.prototype.addDepartment = function (item) {
10345            var _this = this;
10346            var display = this.surroundTextThatMatchesInput(item.term);
10347            display += "<span class='dept-name'>" + nxt.stringFormat(nxt.jstranslations.autocomplete.autocompleteIn || "in", item.name) + "</span>";
10348            var $li = $("<li/>", { "html": display, "class": "search-item" })
10349                .click(function (e) {
10350                _this.dropdownDepartmentItemSelected(item);
10351            });
10352            $li.data("term", item.term);
10353            this.$dropdown.append($li);
10354        };
10355        /**
10356         * Add a search suggestion into the dropdown list.
10357         */
10358        AutoComplete.prototype.addSuggestion = function (text) {
10359            var _this = this;
10360            var display = this.surroundTextThatMatchesInput(text);
10361            var $li = $("<li/>", { "html": display, "class": "search-item" })
10362                .click(function (e) {
10363                _this.dropdownItemSelected(text);
10364            });
10365            $li.data("term", text);
10366            this.$dropdown.append($li);
10367        };
10368        /**
10369         * Add a recent search item into the dropdown list
10370         */
10371        AutoComplete.prototype.addRecent = function (item) {
10372            if (item.name) {
10373                this.addDepartment(item);
10374            }
10375            else if (item.term) {
10376                this.addSuggestion(item.term);
10377            }
10378        };
10379        /**
10380            * Surround the portion of the text that matches the input with a span
10381            */
10382        AutoComplete.prototype.surroundTextThatMatchesInput = function (suggestion) {
10383            var input = this.clean(this.input.value);
10384            var term = input.replace(/ /g, "|");
10385            var re = new RegExp(term, 'ig');
10386            var display = suggestion.replace(re, "<span class='typed-text'>$&</span>");
10387            return display;
10388        };
10389        AutoComplete.prototype.haveRecentSearches = function () {
10390            return this.recentSearches.any();
10391        };
10392        AutoComplete.prototype.haveItemsInList = function () {
10393            return this.$dropdown.find('li.search-item').length > 0;
10394        };
10395        AutoComplete.prototype.haveInput = function () {
10396            return this.input.value.length > 0;
10397        };
10398        return AutoComplete;
10399    }());
10400    var EnrichedAutoComplete = /** @class */ (function () {
10401        function EnrichedAutoComplete(baseAddress, recentSearchesSaved, suggestionsEnabled, autoCompleteCharCountTrigger, autoCompleteUrl, hideIfNoResults) {
10402            var _this = this;
10403            this.searchTimeoutId = 0;
10404            this.recentSearches = new KeyCookies(recentSearchesSaved);
10405            this.eventLogger = new EventLogger();
10406            this.input = document.getElementById(DomSelector.Input);
10407            this.filter = document.getElementById('search-af');
10408            this.$form = $(DomSelector.Form);
10409            this.$dropdownContainer = this.$form.find('.search-dropdown-container');
10410            this.$currentSearchHeading = this.$form.find('.search-dropdown-products__heading');
10411            this.$dropdown = this.$form.find('.search');
10412            this.$dropdownProducts = this.$form.find('.search-dropdown-products__list');
10413            this.searchCache = {};
10414            this.isOpening = false;
10415            this.autoCompleteTermLimit = 10;
10416            this.autoCompleteCharCountTrigger = autoCompleteCharCountTrigger;
10417            this.hideIfNoResults = hideIfNoResults;
10418            this.currentSearchTerm = document.getElementById(DomSelector.CurrentSearchTerm) ? document.getElementById(DomSelector.CurrentSearchTerm).value : '';
10419            if (baseAddress.length > 0 && baseAddress.charAt(baseAddress.length - 1) !== "/")
10420                baseAddress += "/";
10421            this.url = baseAddress + autoCompleteUrl;
10422            this.$form.submit(function (e) { return _this.searchSubmit(); });
10423            var $input = $(this.input);
10424            $input.on('focus', function (e) {
10425                if (!_this.isOpening) {
10426                    _this.openDropdown();
10427                }
10428            });
10429            // In case have focus but dropdown closed e.g. by hover over main navigation
10430            $input.on('click', function (e) {
10431                _this.isOpening = true;
10432                _this.openDropdown();
10433            });
10434            // Hide autosuggest if user clicks anywhere other than the input field or enriched auto complete dropdown
10435            $(document).click(function (e) {
10436                var $target = $(e.target);
10437                if (_this.input !== document.activeElement && 0 == $target.closest(DomSelector.Form).length) {
10438                    _this.hideDropdown(100);
10439                }
10440                else {
10441                    // If user has clicked on the cover
10442                    if ($target.hasClass('search-dropdown-content-cover')) {
10443                        _this.hideDropdown(100);
10444                    }
10445                }
10446            });
10447            // Hide autosuggest if user presses escape
10448            $(document).keyup(function (e) {
10449                if (Keys.Escape == e.keyCode) {
10450                    _this.hideDropdown(100);
10451                }
10452            });
10453            this.setLastSearch();
10454            this.initClearSearchTextButton();
10455            this.initSelectionEvents();
10456            if (suggestionsEnabled) {
10457                this.initSuggestions();
10458            }
10459            else {
10460                this.initNoSuggestions();
10461            }
10462            this.manageEnrichedSuggestionsEnabledState();
10463        }
10464        /**
10465         * Use this to unload this class and all associated DOM items
10466         */
10467        EnrichedAutoComplete.prototype.destroy = function () {
10468            // Remove all events on input field
10469            $('#' + DomSelector.Input).off('click blur focus keyup keydown');
10470            // Remove items added to the DOM
10471            this.$dropdown.empty();
10472            this.$dropdownContainer.find($('.' + DomSelector.SearchDropdownCover)).remove();
10473            // Remove CSS Classes
10474            this.$dropdownContainer.removeClass(DomSelector.StateIsEnriched);
10475            this.$form.removeClass(DomSelector.StateIsEnriched);
10476        };
10477        /**
10478         * Initialise when suggestions are turned off
10479         */
10480        EnrichedAutoComplete.prototype.initNoSuggestions = function () {
10481            var _this = this;
10482            var inputText = this.clean(this.input.value);
10483            $(this.input).keyup(function (e) {
10484                // No change so return
10485                if (_this.clean(_this.input.value) === _this.clean(inputText)) {
10486                    return;
10487                }
10488                inputText = _this.clean(_this.input.value);
10489                // Ignore keys that can change the content but shouldn't close the dropdown
10490                if (_this.IgnoreKey(e.keyCode)) {
10491                    return;
10492                }
10493                _this.clearDropdown();
10494                if (!_this.canSearch(inputText) && !_this.isRecentMenu()) {
10495                    _this.loadRecentSearches();
10496                }
10497                _this.checkRecentView();
10498                _this.refresh();
10499            });
10500        };
10501        /**
10502         * Set up button to clear the search text.
10503         */
10504        EnrichedAutoComplete.prototype.initClearSearchTextButton = function () {
10505            var _this = this;
10506            var btn = this.$form.find('.clear-search-text');
10507            this.showOrHideClearSearchTextButton();
10508            btn.click(function (e) {
10509                _this.input.value = '';
10510                _this.showOrHideClearSearchTextButton();
10511                _this.clearDropdown();
10512                _this.loadRecentSearches();
10513                setTimeout(function () { return _this.input.focus(); }, 500);
10514            });
10515        };
10516        EnrichedAutoComplete.prototype.showOrHideClearSearchTextButton = function () {
10517            var btn = this.$form.find('.clear-search-text');
10518            var show = this.clean(this.input.value) !== '';
10519            show ? btn.addClass("visible") : btn.removeClass("visible");
10520        };
10521        /**
10522         * Initialise the suggestion searches
10523         */
10524        EnrichedAutoComplete.prototype.initSuggestions = function () {
10525            var _this = this;
10526            $(this.input).keyup(function (e) {
10527                var inputText = _this.clean(_this.input.value);
10528                // Ignore keys that can change the content but don't need to invoke a search
10529                if (_this.IgnoreKey(e.keyCode)) {
10530                    return;
10531                }
10532                _this.checkRecentView();
10533                if (!_this.canSearch(inputText)) {
10534                    clearTimeout(_this.searchTimeoutId);
10535                    _this.clearDropdown();
10536                    _this.loadRecentSearches();
10537                    _this.refresh();
10538                    return;
10539                }
10540                else {
10541                    // If we've exceeded the minimum character count trigger number then continue
10542                    _this.searchTerm(inputText, false);
10543                }
10544            });
10545            this.checkRecentView();
10546        };
10547        EnrichedAutoComplete.prototype.checkRecentView = function () {
10548            var inputText = this.clean($(this.input).val()), canSearch = this.canSearch(inputText);
10549            if (!canSearch) {
10550                this.$dropdownContainer.addClass(DomSelector.StateShowRecent);
10551                this.$dropdownContainer.removeClass(DomSelector.StateIsLoading);
10552                // If no recent then hide the dropdown
10553                var kc = this.recentSearches.load();
10554                if (0 === kc.length) {
10555                    this.$dropdownContainer.addClass(DomSelector.StateNoRecent);
10556                }
10557                else {
10558                    this.$dropdownContainer.removeClass(DomSelector.StateNoRecent);
10559                }
10560            }
10561            else {
10562                this.$dropdownContainer.removeClass(DomSelector.StateShowRecent);
10563                this.$dropdownContainer.removeClass(DomSelector.StateNoRecent);
10564            }
10565        };
10566        EnrichedAutoComplete.prototype.canSearch = function (term) {
10567            // Decides if a search should be performed or not
10568            return term.length > this.autoCompleteCharCountTrigger;
10569        };
10570        EnrichedAutoComplete.prototype.searchTerm = function (term, productsOnly, clearSelected) {
10571            var _this = this;
10572            if (clearSelected === void 0) { clearSelected = true; }
10573            this.searchInputText = term;
10574            this.showOrHideClearSearchTextButton();
10575            // Input changed so clear any selection
10576            if (clearSelected) {
10577                this.clearSelected();
10578            }
10579            this.resetCurrentSearchTitle();
10580            if (this.isRecentMenu()) {
10581                this.clearDropdown();
10582            }
10583            this.checkRecentView();
10584            // Restart timer
10585            clearTimeout(this.searchTimeoutId);
10586            // Cancel original ajax request
10587            if (this.searchAjaxRequest && this.searchAjaxRequest.readyState != 4) {
10588                this.searchAjaxRequest.abort();
10589            }
10590            if (this.searchCache[this.searchInputText]) {
10591                this.clearDropdown(productsOnly);
10592                this.brProcessResponse(this.searchCache[this.searchInputText], productsOnly);
10593                this.refresh();
10594            }
10595            else {
10596                if (!this.canSearch(this.searchInputText)) {
10597                    this.clearDropdown();
10598                    this.loadRecentSearches();
10599                    this.refresh();
10600                }
10601                else {
10602                    this.searchTimeoutId = setTimeout(function () {
10603                        _this.checkRecentView();
10604                        if (!_this.canSearch(_this.searchInputText)) {
10605                            _this.clearDropdown();
10606                            _this.loadRecentSearches();
10607                            _this.refresh();
10608                        }
10609                        else {
10610                            // If search has already been performed for this term then use cached results
10611                            if (Next.Settings.Channel.BloomReachSearchOverrideEnabled || (Next.Settings.Channel.BloomReachSearchEnabled &&
10612                                typeof _this.recentSearches.monetateSearchCookie != 'undefined' &&
10613                                _this.recentSearches.monetateSearchCookie.indexOf(Next.Settings.Cookie.MonetateCookieBloomReachValue) === 0)) {
10614                                _this.searchAjaxRequest = _this.brsearch(_this.searchInputText)
10615                                    .done(function (result) {
10616                                    _this.clearDropdown(productsOnly);
10617                                    // Save search to cache to prevent duplicate ajax queries
10618                                    _this.searchCache[_this.searchInputText] = result;
10619                                    _this.brProcessResponse(result, productsOnly);
10620                                    _this.refresh();
10621                                })
10622                                    .fail(function (xhr, status, error) {
10623                                    if ('abort' !== status) {
10624                                        // If ajax request fails then it could be due to adblocker
10625                                        _this.clearDropdown();
10626                                        _this.refresh();
10627                                    }
10628                                });
10629                            }
10630                        }
10631                    }, 100);
10632                }
10633            }
10634        };
10635        EnrichedAutoComplete.prototype.initSelectionEvents = function () {
10636            var _this = this;
10637            $(this.input).keydown(function (e) {
10638                switch (e.keyCode) {
10639                    case Keys.UpArrow:
10640                    case Keys.DownArrow:
10641                        e.preventDefault();
10642                        _this.keyUpDown(e.keyCode);
10643                        break;
10644                    case Keys.Enter:
10645                        return _this.selectItem();
10646                }
10647            });
10648        };
10649        /**
10650         * Which keys to ignore when search input has focus.
10651         */
10652        EnrichedAutoComplete.prototype.IgnoreKey = function (keyCode) {
10653            if (keyCode == Keys.UpArrow)
10654                return true;
10655            if (keyCode == Keys.DownArrow)
10656                return true;
10657            if (keyCode == Keys.Escape)
10658                return true;
10659            return false;
10660        };
10661        /**
10662         * Invoke the Ajax search for suggestions
10663         */
10664        EnrichedAutoComplete.prototype.search = function (term) {
10665            var ajaxSettings = {
10666                url: this.url,
10667                dataType: "json",
10668                cache: true,
10669                data: {
10670                    word: term
10671                }
10672            };
10673            return $.ajax(ajaxSettings);
10674        };
10675        /**
10676         * Parse the SLI response and return the suggestions array.
10677         */
10678        EnrichedAutoComplete.prototype.processResponse = function (response, productsOnly) {
10679            var _this = this;
10680            var ss = response.results.search_suggestions;
10681            if (!ss)
10682                return null;
10683            if (ss.department_suggestions) {
10684                $.each(ss.department_suggestions, function (index, item) { return _this.addDepartment(item); });
10685            }
10686            if (ss.suggestions) {
10687                // Add text suggestions
10688                $.each(ss.suggestions, function (index, text) { return _this.addSuggestion(text); });
10689            }
10690        };
10691        //bloomreach
10692        /**
10693         * Invoke the Ajax search for suggestions
10694         */
10695        EnrichedAutoComplete.prototype.brsearch = function (term) {
10696            var bruid = this.recentSearches.brUIDCookie;
10697            var requestID = new Date().getTime();
10698            var viewId = Next.Settings.Channel.BloomReachAutoSuggestViewIdEnabled ? (Next.Settings.Channel.BloomReachCountryCode ? "&view_id=" + Next.Settings.Channel.BloomReachCountryCode : "") : ""; // View_id is a parameter that needs to be present for Intl but not for UK
10699            var url = Next.Settings.Channel.BloomReachAutosuggestDomain +
10700                "?account_id=" + Next.Settings.Channel.BloomReachAccountID +
10701                "&auth_key=" +
10702                "&domain_key=" + Next.Settings.Channel.BloomReachDomainKey +
10703                viewId +
10704                "&request_id=" + requestID +
10705                "&_br_uid_2=" + bruid +
10706                "&request_type=suggest" +
10707                "&q=" + term;
10708            var ajaxSettings = {
10709                url: url,
10710                dataType: "json"
10711            };
10712            return $.ajax(ajaxSettings);
10713        };
10714        /**
10715         * Parse the BR response and return the suggestions array.
10716         */
10717        EnrichedAutoComplete.prototype.brProcessResponse = function (response, productsOnly) {
10718            var _this = this;
10719            var ss = response.response;
10720            var resultsCount = 0;
10721            if (!ss)
10722                return null;
10723            if (ss.suggestions) {
10724                resultsCount = ss.suggestions.length;
10725                if (resultsCount > 0) {
10726                    // Add suggestions to list
10727                    if (!productsOnly) {
10728                        ss.suggestions = ss.suggestions.slice(0, this.autoCompleteTermLimit);
10729                        $.each(ss.suggestions, function (index, s) { return _this.addSuggestion(s.q); });
10730                    }
10731                    if (ss.products) {
10732                        // Add product suggestions
10733                        $.each(ss.products, function (index, product) { return _this.addProductSuggestion(product); });
10734                    }
10735                    this.addProductsSeeAllLink(ss.q);
10736                }
10737            }
10738            this.addCurrentSearchTitle(this.searchInputText, resultsCount);
10739        };
10740        /**
10741         * Simulate a click on the currently selected item
10742         */
10743        EnrichedAutoComplete.prototype.selectItem = function () {
10744            var $selected = this.$dropdown.find('li.selected');
10745            if (!$selected.length)
10746                return true;
10747            this.input.value = $selected.text();
10748            return false;
10749        };
10750        EnrichedAutoComplete.prototype.keyUpDown = function (keyCode) {
10751            var $list = this.$dropdown.find('li.' + DomSelector.SearchItem);
10752            var listLength = $list.length;
10753            if (listLength == 0)
10754                return;
10755            if (listLength == 1) {
10756                $list.first().addClass(DomSelector.StateSelected);
10757                if (!this.isRecentMenu()) {
10758                    this.searchTerm($li.first().text(), true, false);
10759                }
10760                return;
10761            }
10762            var $selected = $list.filter('.selected');
10763            var index = $list.index($selected);
10764            $selected.removeClass(DomSelector.StateSelected);
10765            if (keyCode == Keys.UpArrow) {
10766                if (index-- < 0)
10767                    index = listLength - 1;
10768            }
10769            if (keyCode == Keys.DownArrow) {
10770                if (++index == listLength)
10771                    index = 0;
10772            }
10773            var $li = $list.eq(index);
10774            $li.addClass(DomSelector.StateSelected);
10775            if (!this.isRecentMenu()) {
10776                this.searchTerm($li.text(), true, false);
10777            }
10778        };
10779        /**
10780         * Clear the selected list item
10781         */
10782        EnrichedAutoComplete.prototype.clearSelected = function () {
10783            var $item = this.$dropdown.find('li.selected');
10784            $item.removeClass(DomSelector.StateSelected);
10785        };
10786        /**
10787         * Add the heading in the list for the recently searched
10788         */
10789        EnrichedAutoComplete.prototype.addRecentHeading = function () {
10790            var _this = this;
10791            var $li = $("<li>")
10792                .addClass(DomSelector.RecentHeading)
10793                .text(nxt.jstranslations.autocomplete.recentsearches || "Your Recent Searches...")
10794                .append("<a>")
10795                .find("a")
10796                .addClass(DomSelector.ClearRecent)
10797                .attr("href", "#")
10798                .click(function () { return _this.deleteRecent(); })
10799                .text(nxt.jstranslations.common.clear || "Clear")
10800                .end();
10801            this.$dropdown.append($li);
10802        };
10803        /**
10804         * Add the divider in the list
10805         */
10806        EnrichedAutoComplete.prototype.addDivider = function () {
10807            var $li = $("<li>")
10808                .addClass(DomSelector.Divider);
10809            this.$dropdown.append($li);
10810        };
10811        /**
10812         * Add the title of the search section in the list
10813         */
10814        EnrichedAutoComplete.prototype.addSearchesTitle = function () {
10815            var $li = $("<li>")
10816                .addClass(DomSelector.Title)
10817                .text(nxt.jstranslations.autocomplete.populasearches || "Popular Searches");
10818            this.$dropdown.append($li);
10819        };
10820        /**
10821         * Add the title of the search in the products list header
10822         */
10823        EnrichedAutoComplete.prototype.addCurrentSearchTitle = function (query, resultsCount) {
10824            this.$dropdownContainer.removeClass(DomSelector.StateIsLoading);
10825            if (resultsCount > 0) {
10826                this.$currentSearchHeading.html(nxt.stringFormat(nxt.jstranslations.autocomplete.topResultsFor || "Top results for '{0}'", '<strong>' + query + '</strong>'));
10827            }
10828            else {
10829                this.$currentSearchHeading.html(nxt.stringFormat(nxt.jstranslations.autocomplete.noResultsFor || "No results found for '{0}'", '<strong>' + query + '</strong>'));
10830            }
10831        };
10832        /**
10833         * Add the title of the search in the products list header
10834         */
10835        EnrichedAutoComplete.prototype.resetCurrentSearchTitle = function () {
10836            this.$dropdownContainer.addClass(DomSelector.StateIsLoading);
10837            this.$currentSearchHeading.html(nxt.jstranslations.autocomplete.loading || "Loading..");
10838        };
10839        /**
10840         * Get the recently searched cookies and add them to the dropdown list
10841         */
10842        EnrichedAutoComplete.prototype.loadRecentSearches = function () {
10843            var _this = this;
10844            var kc = this.recentSearches.load();
10845            if (kc.length > 0) {
10846                this.addRecentHeading();
10847                $.each(kc, function (i, s) { return _this.addRecent(s); });
10848            }
10849        };
10850        /**
10851         * Refresh the state of the search drop down
10852         */
10853        EnrichedAutoComplete.prototype.refresh = function () {
10854            var _this = this;
10855            this.manageEnrichedSuggestionsEnabledState();
10856            if (this.haveItemsInList()) {
10857                this.$dropdownContainer.show();
10858                this.$dropdownContainer.addClass(DomSelector.Open);
10859                $(this.input).addClass(DomSelector.Open);
10860                this.$dropdownContainer.removeClass(DomSelector.StateNoResults);
10861            }
10862            else {
10863                this.$dropdownContainer.addClass(DomSelector.StateNoResults);
10864            }
10865            // To prevent double openings
10866            setTimeout(function () { return _this.isOpening = false; }, 10);
10867            this.checkRecentView();
10868        };
10869        EnrichedAutoComplete.prototype.manageEnrichedSuggestionsEnabledState = function () {
10870            this.$dropdownContainer.addClass(DomSelector.StateIsEnriched);
10871            this.$form.addClass(DomSelector.StateIsEnriched);
10872            if (this.hideIfNoResults) {
10873                this.$dropdownContainer.addClass(DomSelector.StateHideIfNoResults);
10874            }
10875            if (0 === this.$dropdownContainer.find('.' + DomSelector.SearchDropdownCover).length) {
10876                this.$dropdownContainer.append($('<div class="' + DomSelector.SearchDropdownCover + '"></div>'));
10877            }
10878        };
10879        EnrichedAutoComplete.prototype.openDropdown = function () {
10880            this.refresh();
10881        };
10882        EnrichedAutoComplete.prototype.hideDropdown = function (duration) {
10883            duration ? this.$dropdownContainer.hide(duration, 'swing') : this.$dropdownContainer.hide();
10884            this.$dropdownContainer.removeClass(DomSelector.Open);
10885            $(this.input).removeClass(DomSelector.Open);
10886        };
10887        /**
10888         * Remove leading, trailing and double spaces.
10889         */
10890        EnrichedAutoComplete.prototype.clean = function (term) {
10891            term = term.replace(/^[\s]*/, '').replace(/[\s]*$/, '').replace(/ +/, ' ').replace(/<[^>]*>?/gm, '');
10892            return term;
10893        };
10894        /**
10895         * The form is being submitted
10896         */
10897        EnrichedAutoComplete.prototype.searchSubmit = function () {
10898            var inputText = this.clean(this.input.value);
10899            if (!inputText || 0 === inputText.length) {
10900                return;
10901            }
10902            // If filter is set recent searches have already been added.
10903            if (this.filter.value) {
10904                return;
10905            }
10906            var suggestion = {
10907                term: inputText,
10908                af: '',
10909                name: ''
10910            };
10911            this.recentSearches.add(suggestion);
10912        };
10913        /**
10914         * Set the search input control to the last searched term if on a search page.
10915         */
10916        EnrichedAutoComplete.prototype.setLastSearch = function () {
10917            var lastSearch = this.recentSearches.getLastSearch();
10918            if (!lastSearch) {
10919                this.loadRecentSearches();
10920                return;
10921            }
10922            if (this.onResultsPage()) {
10923                this.input.value = lastSearch;
10924                return;
10925            }
10926            this.recentSearches.clearLastSearch();
10927            this.loadRecentSearches();
10928        };
10929        /**
10930         * return true if this is the search results page.
10931         */
10932        EnrichedAutoComplete.prototype.onResultsPage = function () {
10933            // To do when we can determine if we are a search results page.
10934            return false;
10935        };
10936        /**
10937         * Remove all items from the list
10938         */
10939        EnrichedAutoComplete.prototype.clearDropdown = function (productsOnly) {
10940            if (productsOnly === void 0) { productsOnly = false; }
10941            if (!productsOnly) {
10942                this.$dropdown.empty();
10943            }
10944            this.$dropdownProducts.empty();
10945        };
10946        EnrichedAutoComplete.prototype.deleteRecent = function () {
10947            this.recentSearches.clear();
10948            this.clearDropdown();
10949            this.hideDropdown();
10950            return false;
10951        };
10952        EnrichedAutoComplete.prototype.dropdownItemSelected = function (item) {
10953            // If text in input box is the same as current search then simply
10954            // hide the overlay (https://next-tfs.next-uk.next.loc/Directory/NextOnline/_workitems/edit/398050)
10955            if (item.toLowerCase() === this.currentSearchTerm.toLowerCase()) {
10956                this.hideDropdown(100);
10957                return;
10958            }
10959            this.input.value = item;
10960            this.$form.submit();
10961        };
10962        EnrichedAutoComplete.prototype.dropdownDepartmentItemSelected = function (item) {
10963            this.input.value = item.term;
10964            this.filter.value = item.af;
10965            this.recentSearches.add(item);
10966            this.$form.submit();
10967        };
10968        /**
10969         * Add a department suggestion into the dropdown list.
10970         */
10971        EnrichedAutoComplete.prototype.addDepartment = function (item) {
10972            var _this = this;
10973            var display = this.surroundTextThatMatchesInput(item.term);
10974            display += "<span class='dept-name'>" + nxt.stringFormat(nxt.jstranslations.autocomplete.autocompleteIn || "in", item.name) + "</span>";
10975            var $li = $("<li/>", { "html": display, "class": DomSelector.SearchItem })
10976                .click(function (e) {
10977                _this.dropdownDepartmentItemSelected(item);
10978            });
10979            this.$dropdown.append($li);
10980        };
10981        /**
10982         * Add a search suggestion into the dropdown list.
10983         */
10984        EnrichedAutoComplete.prototype.addSuggestion = function (text) {
10985            var _this = this;
10986            var display = this.surroundTextThatMatchesInput(text);
10987            var $li = $("<li/>", { "html": display, "class": DomSelector.SearchItem })
10988                .click(function (e) {
10989                _this.eventLogger.log(_this.input.value, text, 'List');
10990                _this.dropdownItemSelected(text);
10991            });
10992            $li.hover(function (e) {
10993                if (!_this.isRecentMenu()) {
10994                    _this.searchTerm(text, true);
10995                }
10996            });
10997            this.$dropdown.append($li);
10998        };
10999        /**
11000         * Add a search suggestion into the dropdown list.
11001         */
11002        EnrichedAutoComplete.prototype.addProductSuggestion = function (product) {
11003            var _this = this;
11004            var productPrice = product.sale_price;
11005            var formattedProductPrice = '';
11006            // Rules
11007            // 1) If number is 0.01 conver to 0 (free) - this is due to a limitation of BloomReach - it doesn't allow zero numbers
11008            // 2) If number has decimal point ensure it's always 2 fixed points
11009            // 3) If number is a round number then ensure no decimal points are used
11010            // 4) If number is greater than 999 ensure it has a comma
11011            if (0.01 == productPrice) {
11012                formattedProductPrice = '0';
11013            }
11014            else {
11015                if (Math.ceil(parseFloat(productPrice.toString())).toFixed(2) > Math.floor(parseFloat(productPrice.toString())).toFixed(2)) {
11016                    formattedProductPrice = this.numberWithCommas(parseFloat(productPrice.toString()).toFixed(2));
11017                }
11018                else {
11019                    formattedProductPrice = this.numberWithCommas(Math.floor(parseFloat(productPrice.toString())).toFixed(0));
11020                }
11021            }
11022            var $productTemplate = "\t\t<a class=\"search-dropdown-products__product\" href=\"" + product.url + "\"> \t\t    <span class=\"search-dropdown-products__product-inner\"> \t\t    <span class=\"search-dropdown-products__product-img\"> \t\t    <img alt=\"" + product.title + "\" src=\"" + product.thumb_image.replace('AltItemZoom', 'search/224x336') + "\" /> \t\t    </span> \t\t    <p class=\"search-dropdown-products__product-title\">" + product.title + "</p> \t\t    <span class=\"search-dropdown-products__product-price\">" + Next.Settings.Channel.CurrencySymbol + formattedProductPrice + "</span> \t\t    </span> \t\t</a> \t    ";
11023            var $product = $($productTemplate).click(function (e) {
11024                var currentSearch = _this.$currentSearchHeading.find('strong').text();
11025                _this.eventLogger.log(_this.input.value, currentSearch, 'Image');
11026            });
11027            this.$dropdownProducts.append($product);
11028        };
11029        EnrichedAutoComplete.prototype.numberWithCommas = function (price) {
11030            return price.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
11031        };
11032        /**
11033         * Add a link to "See all results" beneath the product lists
11034         */
11035        EnrichedAutoComplete.prototype.addProductsSeeAllLink = function (query) {
11036            var _this = this;
11037            var $link = $("<a/>", { "html": (nxt.jstranslations.autocomplete.seeAllResultsLink || "See All Results"), "class": "search-dropdown-products__see-all", "href": "#" })
11038                .click(function (e) {
11039                e.preventDefault();
11040                _this.dropdownItemSelected(query);
11041            });
11042            this.$dropdownProducts.append($link);
11043        };
11044        /**
11045         * Add a recent search item into the dropdown list
11046         */
11047        EnrichedAutoComplete.prototype.addRecent = function (item) {
11048            if (item.name)
11049                this.addDepartment(item);
11050            else
11051                this.addSuggestion(item.term);
11052        };
11053        /**
11054            * Surround the portion of the text that matches the input with a span
11055            */
11056        EnrichedAutoComplete.prototype.surroundTextThatMatchesInput = function (suggestion) {
11057            var input = this.clean(this.input.value);
11058            var term = input.replace(/ /g, "|");
11059            var re = new RegExp(term, 'ig');
11060            var display = suggestion.replace(re, "<span class='typed-text'>$&</span>");
11061            return display;
11062        };
11063        EnrichedAutoComplete.prototype.isRecentMenu = function () {
11064            return this.$dropdown.find('.' + DomSelector.RecentHeading).length > 0;
11065        };
11066        EnrichedAutoComplete.prototype.haveItemsInList = function () {
11067            return this.$dropdown.find('li.' + DomSelector.SearchItem).length > 0;
11068        };
11069        return EnrichedAutoComplete;
11070    }());
11071    var EventLogger = /** @class */ (function () {
11072        function EventLogger() {
11073        }
11074        EventLogger.prototype.log = function (eTerm, eSelected, eType) {
11075            // Safety checks
11076            if ('undefined' !== typeof dataLayer && dataLayer.length > 0) {
11077                var logDetail = {
11078                    'autoSearchTerm': eTerm,
11079                    'autoSearchSelected': eSelected,
11080                    'autoSearchType': eType // 'List' or 'Image'
11081                };
11082                dataLayer.push({
11083                    'event': 'enriched-auto-complete-search',
11084                    'detail': logDetail
11085                });
11086            }
11087            else {
11088                return;
11089            }
11090        };
11091        return EventLogger;
11092    }());
11093    var KeyCookies = /** @class */ (function () {
11094        function KeyCookies(maxSave) {
11095            this.recentSearches = [];
11096            this.maxSave = maxSave;
11097            this.initCookies();
11098        }
11099        KeyCookies.prototype.initCookies = function () {
11100            if (!this.maxSave)
11101                return;
11102            var cookie = this.getCookie('recentSearches');
11103            if (cookie)
11104                this.recentSearches = JSON.parse(cookie);
11105            var searchCookie = this.getCookie(Next.Settings.Cookie.MonetateCookieName);
11106            if (searchCookie)
11107                this.monetateSearchCookie = searchCookie;
11108            var bruidCookie = this.getCookie('_br_uid_2');
11109            if (bruidCookie)
11110                this.brUIDCookie = bruidCookie;
11111            var backToNextBagCookie = Next.Settings.Cookie.BackToNextCookieName;
11112            if (backToNextBagCookie)
11113                this.backToNextBagCookieName = backToNextBagCookie;
11114            var backToNextUrlCookieName = Next.Settings.Cookie.BackToNextURLCookieName;
11115            if (backToNextUrlCookieName)
11116                this.backToNextUrlCookieName = Next.Settings.Cookie.BackToNextURLCookieName;
11117        };
11118        KeyCookies.prototype.getCookie = function (value) {
11119            var cookie = '';
11120            var c = document.cookie.split('; ');
11121            $.each(c, function (i, s) {
11122                var kv = s.split('=');
11123                if (kv[0] == value)
11124                    cookie = kv[1];
11125            });
11126            return decodeURIComponent(cookie);
11127        };
11128        KeyCookies.prototype.load = function () {
11129            return this.recentSearches;
11130        };
11131        KeyCookies.prototype.any = function () {
11132            return this.recentSearches.length > 0;
11133        };
11134        /**
11135         * Add a new search term to the recent search list or if existing term move to top of list
11136         */
11137        KeyCookies.prototype.add = function (suggestion) {
11138            this.setLastSearch(suggestion.term);
11139            var name = suggestion.name; // department
11140            var af = suggestion.af;
11141            var term = suggestion.term.toLowerCase();
11142            var list = [suggestion];
11143            $.each(this.recentSearches, function (index, item) {
11144                if (item.term.toLowerCase() != term || item.name != name)
11145                    list.push(item);
11146            });
11147            this.recentSearches = list.slice(0, this.maxSave);
11148            var cookie = JSON.stringify(this.recentSearches);
11149            var dt = new Date();
11150            dt.setMonth(dt.getMonth() + 1);
11151            var expires = "; expires=" + dt.toUTCString();
11152            document.cookie = "recentSearches=" + encodeURIComponent(cookie) + "; path=/" + expires;
11153        };
11154        /**
11155         * Cache the last searched term.
11156         */
11157        KeyCookies.prototype.setLastSearch = function (term) {
11158            document.cookie = "lastSearch=" + encodeURIComponent(term) + "; path=/";
11159        };
11160        KeyCookies.prototype.getLastSearch = function () {
11161            return this.getCookie('lastSearch');
11162        };
11163        KeyCookies.prototype.clearLastSearch = function () {
11164            document.cookie = "lastSearch=; path=/; expires = Thu, 01 Jan 1970 00:00:00 GMT";
11165        };
11166        KeyCookies.prototype.clear = function () {
11167            document.cookie = "recentSearches=; path=/; expires = Thu, 01 Jan 1970 00:00:00 GMT";
11168            this.recentSearches.length = 0;
11169        };
11170        return KeyCookies;
11171    }());
11172    var Manager = /** @class */ (function () {
11173        function Manager() {
11174            var enabled = false, enrichedSuggestionsEnabled = false, autoCompleteCharCountTrigger = 0, autoSearchRecentCount = 12, hideIfNoResults = false, autoCompleteUrl = 'v1/gb/en-gb/autocomplete';
11175            try {
11176                var searchFeature = Next.FeatureManager.FeatureSettings.Search;
11177                var baseAddress = searchFeature.BaseAddress;
11178                var suggestionsEnabled = Next.Settings.Channel.SearchAutoComplete;
11179                var recentSearchesSaved = searchFeature.RecentSearchesSaved;
11180                var autoCompleteOverrideSwitch = Next.Settings.Channel.AutoCompleteDisabledOverride;
11181                enabled = suggestionsEnabled || recentSearchesSaved > 0;
11182                if (autoCompleteOverrideSwitch && enabled)
11183                    enabled = false;
11184                enrichedSuggestionsEnabled = Next.Settings.Channel.BloomReachEnrichedAutoSearchEnabled || enrichedSuggestionsEnabled;
11185                autoCompleteCharCountTrigger = Next.Settings.Channel.BloomReachEnrichedAutoSearchCharCountTrigger || autoCompleteCharCountTrigger;
11186                autoSearchRecentCount = Next.Settings.Channel.BloomReachEnrichedAutoSearchRecentCount || autoSearchRecentCount;
11187                autoCompleteUrl = Next.Settings.Channel.BloomReachAutoCompleteUrl || autoCompleteUrl;
11188                hideIfNoResults = Next.Settings.Channel.BloomReachEnrichedAutoSearchHideIfNoResults || hideIfNoResults;
11189                recentSearchesSaved = recentSearchesSaved;
11190            }
11191            catch (e) {
11192                ConsoleLog("'Feature Manager' search features not configured. ");
11193            }
11194            if (enabled && Manager.isSearchOnPage()) {
11195                if (enrichedSuggestionsEnabled) {
11196                    this.enrichedAutoComplete = new EnrichedAutoComplete(baseAddress, autoSearchRecentCount, suggestionsEnabled, autoCompleteCharCountTrigger, autoCompleteUrl, hideIfNoResults);
11197                }
11198                else {
11199                    this.autoComplete = new AutoComplete(baseAddress, recentSearchesSaved, suggestionsEnabled, autoCompleteUrl);
11200                }
11201            }
11202            this.setupEnhanced();
11203        }
11204        Manager.isSearchOnPage = function () {
11205            return $(DomSelector.Form).length !== 0;
11206        };
11207        Manager.prototype.setupEnhanced = function () {
11208            var _this = this;
11209            // - In order to trigger
11210            //   $(document).trigger('autocomplete.enableEnhanced');
11211            $(document).on('autocomplete.enableEnhanced', function (e) {
11212                if (!Next.Settings.Channel.BloomReachEnrichedAutoSearchEnabled) {
11213                    if (_this.autoComplete) {
11214                        _this.autoComplete.destroy();
11215                        delete _this.autoComplete;
11216                        Next.Settings.Channel.BloomReachEnrichedAutoSearchCharCountTrigger = 2;
11217                        Next.Settings.Channel.BloomReachEnrichedAutoSearchRecentCount = 12;
11218                        Next.Settings.Channel.BloomReachEnrichedAutoSearchEnabled = true;
11219                        Next.SearchManager = new Search.Manager();
11220                    }
11221                }
11222            });
11223            // - In order to trigger
11224            //   $(document).trigger('autocomplete.disableEnhanced');
11225            $(document).on('autocomplete.disableEnhanced', function (e) {
11226                if (Next.Settings.Channel.BloomReachEnrichedAutoSearchEnabled) {
11227                    if (_this.enrichedAutoComplete) {
11228                        _this.enrichedAutoComplete.destroy();
11229                        delete _this.enrichedAutoComplete;
11230                        Next.Settings.Channel.BloomReachEnrichedAutoSearchEnabled = false;
11231                        Next.SearchManager = new Search.Manager();
11232                    }
11233                }
11234            });
11235        };
11236        return Manager;
11237    }());
11238    Search.Manager = Manager;
11239})(Search || (Search = {}));
11240$(document).on("featureSettingsReady", function () {
11241    Next.SearchManager = new Search.Manager();
11242});
11243//# sourceMappingURL=autocomplete.js.map;
11244$(document).on("featureSettingsReady", function () {
11245    SetRecentlyViewedDisplay();
11246 });;
11247;(function(factory) {
11248    if (typeof define === 'function' && define.amd) {
11249        define(['jquery'], factory);
11250    }
11251    else if (typeof exports === 'object') {
11252        module.exports = factory(require("jquery"));
11253    }
11254    else {
11255        //factory(jQuery);
11256    }
11257}
11258(function($) {
11259    "use strict";
11260
11261    var pluginName = "tinyscrollbar"
11262    ,   defaults = {
11263            axis : 'y'//axis
11264        ,   wheel : true
11265        ,   wheelSpeed : 20//wheel
11266        ,   wheelLock : true//lockscroll
11267        ,   touchLock : true
11268        ,   trackSize : false//size
11269        ,   thumbSize : false//sizethumb
11270        ,   thumbSizeMin : 20
11271        }
11272    ;
11273
11274    function Plugin($container, options) {
11275        
11276
11277        /**
11278         * The options of the carousel extend with the defaults.
11279         *
11280         * @property options
11281         * @type Object
11282         */
11283        this.options = $.extend({}, defaults, options);
11284        
11285        /**
11286         * @property _defaults
11287         * @type Object
11288         * @private
11289         * @default defaults
11290         */
11291        this._defaults = defaults;
11292
11293        /**
11294         * @property _name
11295         * @type String
11296         * @private
11297         * @final
11298         * @default 'tinyscrollbar'
11299         */
11300        this._name = pluginName;
11301
11302        var self = this
11303        ,   $viewport = $container.find(".viewport")
11304        ,   $overview = $container.find(".overview")
11305        ,   $scrollbar = $container.find(".scrollbar")
11306        ,   $track = $scrollbar.find(".track")
11307        ,   $thumb = $scrollbar.find(".thumb")
11308
11309        ,   hasTouchEvents = ("ontouchstart" in document.documentElement)
11310        ,   wheelEvent = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
11311                         document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
11312                         "DOMMouseScroll" // let's assume that remaining browsers are older Firefox
11313        ,   isHorizontal = this.options.axis === 'x'
11314        ,   sizeLabel = isHorizontal ? "width" : "height"
11315        ,   posiLabel = isHorizontal ? "left" : "top"
11316
11317        ,   mousePosition = 0
11318        ;
11319
11320        /**
11321         * The position of the content relative to the viewport.
11322         *
11323         * @property contentPosition
11324         * @type Number
11325         */
11326        this.contentPosition = 0;
11327
11328        /**
11329         * The height or width of the viewport.
11330         *
11331         * @property viewportSize
11332         * @type Number
11333         */
11334        this.viewportSize = 0;
11335
11336        /**
11337         * The height or width of the content.
11338         *
11339         * @property contentSize
11340         * @type Number
11341         */
11342        this.contentSize = 0;
11343
11344        /**
11345         * The ratio of the content size relative to the viewport size.
11346         *
11347         * @property contentRatio
11348         * @type Number
11349         */
11350        this.contentRatio = 0;
11351
11352        /**
11353         * The height or width of the content.
11354         *
11355         * @property trackSize
11356         * @type Number
11357         */
11358        this.trackSize = 0;
11359
11360        /**
11361         * The size of the track relative to the size of the content.
11362         *
11363         * @property trackRatio
11364         * @type Number
11365         */
11366        this.trackRatio = 0;
11367
11368        /**
11369         * The height or width of the thumb.
11370         *
11371         * @property thumbSize
11372         * @type Number
11373         */
11374        this.thumbSize = 0;
11375
11376        /**
11377         * The position of the thumb relative to the track.
11378         *
11379         * @property thumbPosition
11380         * @type Number
11381         */
11382        this.thumbPosition = 0;
11383
11384        /**
11385         * Will be true if there is content to scroll.
11386         *
11387         * @property hasContentToSroll
11388         * @type Boolean
11389         */
11390        this.hasContentToSroll = false;
11391
11392        /**
11393         * @method _initialize
11394         * @private
11395         */
11396        function _initialize() {
11397            self.update();
11398            _setEvents();
11399
11400            return self;
11401        }
11402
11403        /**
11404         * You can use the update method to adjust the scrollbar to new content or to move the scrollbar to a certain point.
11405         *
11406         * @method update
11407         * @chainable
11408         * @param {Number|String} [scrollTo] Number in pixels or the values "relative" or "bottom". If you dont specify a parameter it will default to top
11409         */
11410        this.update = function(scrollTo) {
11411            var sizeLabelCap = sizeLabel.charAt(0).toUpperCase() + sizeLabel.slice(1).toLowerCase();
11412            this.viewportSize = $viewport[0]['offset'+ sizeLabelCap];
11413            this.contentSize = $overview[0]['scroll'+ sizeLabelCap];
11414            this.contentRatio = this.viewportSize / this.contentSize;
11415            this.trackSize = this.options.trackSize || this.viewportSize;
11416            this.thumbSize = Math.min(this.trackSize, Math.max(this.options.thumbSizeMin, (this.options.thumbSize || (this.trackSize * this.contentRatio))));
11417            this.trackRatio = (this.contentSize - this.viewportSize) / (this.trackSize - this.thumbSize);
11418            this.hasContentToSroll = this.contentRatio < 1;
11419
11420            $scrollbar.toggleClass("disable", !this.hasContentToSroll);
11421
11422            switch (scrollTo) {
11423                case "bottom":
11424                    this.contentPosition = Math.max(this.contentSize - this.viewportSize, 0);
11425                    break;
11426
11427                case "relative":
11428                    this.contentPosition = Math.min(Math.max(this.contentSize - this.viewportSize, 0), Math.max(0, this.contentPosition));
11429                    break;
11430
11431                default:
11432                    this.contentPosition = parseInt(scrollTo, 10) || 0;
11433            }
11434
11435            this.thumbPosition = this.contentPosition / this.trackRatio;
11436
11437            _setCss();
11438
11439            return self;
11440        };
11441
11442        /**
11443         * @method _setCss
11444         * @private
11445         */
11446        function _setCss() {
11447            $thumb.css(posiLabel, self.thumbPosition);
11448            $overview.css(posiLabel, -self.contentPosition);
11449            $scrollbar.css(sizeLabel, self.trackSize);
11450            $track.css(sizeLabel, self.trackSize);
11451            $thumb.css(sizeLabel, self.thumbSize);
11452        }
11453
11454        /**
11455         * @method _setEvents
11456         * @private
11457         */
11458        function _setEvents() {
11459            if(hasTouchEvents) {
11460                $viewport[0].ontouchstart = function(event) {
11461                    if(1 === event.touches.length) {
11462                        event.stopPropagation();
11463
11464                        _start(event.touches[0]);
11465                    }
11466                };
11467            }
11468            else {
11469                $thumb.bind("mousedown", function(event){
11470                    event.stopPropagation();
11471                    _start(event);
11472                });
11473                $track.bind("mousedown", function(event){
11474                    _start(event, true);
11475                });
11476            }
11477
11478            $(window).resize(function() {
11479                self.update("relative");
11480            });
11481
11482            if(self.options.wheel && window.addEventListener) {
11483                $container[0].addEventListener(wheelEvent, _wheel, false);
11484            }
11485            else if(self.options.wheel) {
11486                $container[0].onmousewheel = _wheel;
11487            }
11488        }
11489
11490        /**
11491         * @method _isAtBegin
11492         * @private
11493         */
11494        function _isAtBegin() {
11495            return self.contentPosition > 0;
11496        }
11497
11498        /**
11499         * @method _isAtEnd
11500         * @private
11501         */
11502        function _isAtEnd() {
11503            return self.contentPosition <= (self.contentSize - self.viewportSize) - 5;
11504        }
11505
11506        /**
11507         * @method _start
11508         * @private
11509         */
11510        function _start(event, gotoMouse) {
11511            if(self.hasContentToSroll) {
11512                $("body").addClass("noSelect");
11513
11514                mousePosition = gotoMouse ? $thumb.offset()[posiLabel] : (isHorizontal ? event.pageX : event.pageY);
11515
11516                if(hasTouchEvents) {
11517                    document.ontouchmove = function(event) {
11518                        if(self.options.touchLock || _isAtBegin() && _isAtEnd()) {
11519                            event.preventDefault();
11520                        }
11521                        _drag(event.touches[0]);
11522                    };
11523                    document.ontouchend = _end;
11524                }
11525                else {
11526                    $(document).bind("mousemove", _drag);
11527                    $(document).bind("mouseup", _end);
11528                    $thumb.bind("mouseup", _end);
11529                    $track.bind("mouseup", _end);
11530                }
11531
11532                _drag(event);
11533            }
11534        }
11535
11536        /**
11537         * @method _wheel
11538         * @private
11539         */
11540        function _wheel(event) {
11541            if(self.hasContentToSroll) {
11542                // Trying to make sense of all the different wheel event implementations..
11543                //
11544                var evntObj = event || window.event
11545                ,   wheelDelta = -(evntObj.deltaY || evntObj.detail || (-1 / 3 * evntObj.wheelDelta)) / 40
11546                ,   multiply = (evntObj.deltaMode === 1) ? self.options.wheelSpeed : 1
11547                ;
11548
11549                self.contentPosition -= wheelDelta * multiply * self.options.wheelSpeed;
11550                self.contentPosition = Math.min((self.contentSize - self.viewportSize), Math.max(0, self.contentPosition));
11551                self.thumbPosition = self.contentPosition / self.trackRatio;
11552
11553                /**
11554                 * The move event will trigger when the carousel slides to a new slide.
11555                 *
11556                 * @event move
11557                 */
11558                $container.trigger("move");
11559
11560                $thumb.css(posiLabel, self.thumbPosition);
11561                $overview.css(posiLabel, -self.contentPosition);
11562
11563                if(self.options.wheelLock || _isAtBegin() && _isAtEnd()) {
11564                    evntObj = $.event.fix(evntObj);
11565                    evntObj.preventDefault();
11566                }
11567            }
11568        }
11569
11570        /**
11571         * @method _drag
11572         * @private
11573         */
11574        function _drag(event) {
11575            if(self.hasContentToSroll) {
11576                var mousePositionNew = isHorizontal ? event.pageX : event.pageY
11577                ,   thumbPositionDelta = hasTouchEvents ? (mousePosition - mousePositionNew) : (mousePositionNew - mousePosition)
11578                ,   thumbPositionNew = Math.min((self.trackSize - self.thumbSize), Math.max(0, self.thumbPosition + thumbPositionDelta))
11579                ;
11580
11581                self.contentPosition = thumbPositionNew * self.trackRatio;
11582
11583                $container.trigger("move");
11584
11585                $thumb.css(posiLabel, thumbPositionNew);
11586                $overview.css(posiLabel, -self.contentPosition);
11587            }
11588        }
11589
11590        /**
11591         * @method _end
11592         * @private
11593         */
11594        function _end() {
11595            self.thumbPosition = parseInt($thumb.css(posiLabel), 10) || 0;
11596
11597            $("body").removeClass("noSelect");
11598            $(document).unbind("mousemove", _drag);
11599            $(document).unbind("mouseup", _end);
11600            $thumb.unbind("mouseup", _end);
11601            $track.unbind("mouseup", _end);
11602            document.ontouchmove = document.ontouchend = null;
11603        }
11604
11605        return _initialize();
11606    }
11607
11608    /**
11609    * @class tinyscrollbar
11610    * @constructor
11611    * @param {Object} options
11612        @param {String} [options.axis='y'] Vertical or horizontal scroller? ( x || y ).
11613        @param {Boolean} [options.wheel=true] Enable or disable the mousewheel.
11614        @param {Boolean} [options.wheelSpeed=40] How many pixels must the mouswheel scroll at a time.
11615        @param {Boolean} [options.wheelLock=true] Lock default window wheel scrolling when there is no more content to scroll.
11616        @param {Number} [options.touchLock=true] Lock default window touch scrolling when there is no more content to scroll.
11617        @param {Boolean|Number} [options.trackSize=false] Set the size of the scrollbar to auto(false) or a fixed number.
11618        @param {Boolean|Number} [options.thumbSize=false] Set the size of the thumb to auto(false) or a fixed number
11619        @param {Boolean} [options.thumbSizeMin=20] Minimum thumb size.
11620    */
11621    $.fn[pluginName] = function(options) {
11622        return this.each(function() {
11623            if(!$.data(this, "plugin_" + pluginName)) {
11624                $.data(this, "plugin_" + pluginName, new Plugin($(this), options));
11625            }
11626        });
11627    };
11628}(jQuery)));
11629;
11630;
11631(function($) {
11632    "use strict";
11633
11634    var methods = {};
11635
11636    methods.update = function () {
11637        var $scrollbar_plugin = this.data("plugin_tinyscrollbar");//get the plugin
11638        var hasContent = false;
11639        var $newContent = $(this);//get the new modified html content
11640        var viewportSize = $newContent.find('.viewport')[0].offsetHeight;
11641        var overviewSize = $newContent.find('.overview')[0].scrollHeight;
11642        var contentRatio = viewportSize / overviewSize;
11643        var trackSize = viewportSize;
11644        var thumbSize = trackSize * contentRatio;
11645        var trackRatio = (overviewSize - viewportSize) / (trackSize - thumbSize);
11646
11647        if (contentRatio < 1) {
11648            hasContent = true;
11649        }
11650        if (hasContent) {
11651            var maxPos = (trackSize - thumbSize) * trackRatio;
11652            var newPos = $scrollbar_plugin.contentPosition <= maxPos ? $scrollbar_plugin.contentPosition : maxPos;
11653            
11654            $scrollbar_plugin.update(newPos);
11655        }
11656        else {
11657            $scrollbar_plugin.update();
11658        };
11659    };
11660
11661    methods.init = function (options) {
11662        /*Bespoke code to wrap the scrollbar div, which is needed for tinyscrollbar to work!*/
11663        this.children().wrapAll('<div class="viewport"><div class="overview"></div></div>');
11664        this.prepend('<div class="scrollbar"><div class="track"><div class="thumb"><div class="end"></div></div></div></div>');
11665        this.tinyscrollbar(this, options);
11666        //get the height of the bagDetail and add this to the parent as a data attribute
11667        //var totalHeight = 0;
11668        //$('.itemWrapper').each(function (i, elem) {
11669        //    totalHeight = totalHeight
11670        //        + $(elem).height()
11671        //        + parseInt($(elem).css('padding-top').toString().replace('px', ''))
11672        //        + parseInt($(elem).css('padding-bottom').toString().replace('px', ''))
11673        //        + parseInt($(elem).css('margin-top').toString().replace('px', ''))
11674        //        + parseInt($(elem).css('margin-bottom').toString().replace('px', ''));
11675        //});//each itemWrapper's height, padding and margin must be added together to obtain the height as padding isn't rendered in time!
11676            
11677        //$(this).attr('data-bagDetailHeight', totalHeight+20);
11678    };
11679
11680    /**
11681    * @class tinyscrollbar
11682    * @constructor
11683    * @param {Object} options
11684        @param {String} [options.axis='y'] Vertical or horizontal scroller? ( x || y ).
11685        @param {Boolean} [options.wheel=true] Enable or disable the mousewheel.
11686        @param {Boolean} [options.wheelSpeed=40] How many pixels must the mouswheel scroll at a time.
11687        @param {Boolean} [options.wheelLock=true] Lock default window wheel scrolling when there is no more content to scroll.
11688        @param {Number} [options.touchLock=true] Lock default window touch scrolling when there is no more content to scroll.
11689        @param {Boolean|Number} [options.trackSize=false] Set the size of the scrollbar to auto(false) or a fixed number.
11690        @param {Boolean|Number} [options.thumbSize=false] Set the size of the thumb to auto(false) or a fixed number
11691        @param {Boolean} [options.thumbSizeMin=20] Minimum thumb size.
11692    */
11693    $.fn.NXtinyscrollbar = function (method) {
11694        if (methods[method]) {
11695            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
11696        }
11697        if (typeof method === 'object' || !method) {
11698            return methods.init.apply(this, arguments);
11699        }
11700    };
11701}(jQuery));
11702;
11703// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
11704if (!Array.prototype.find) {
11705    Object.defineProperty(Array.prototype, 'find', {
11706        value: function (predicate) {
11707            // 1. Let O be ? ToObject(this value).
11708            if (this == null) {
11709                throw new TypeError('"this" is null or not defined');
11710            }
11711            var o = Object(this);
11712            // 2. Let len be ? ToLength(? Get(O, "length")).
11713            var len = o.length >>> 0;
11714            // 3. If IsCallable(predicate) is false, throw a TypeError exception.
11715            if (typeof predicate !== 'function') {
11716                throw new TypeError('predicate must be a function');
11717            }
11718            // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
11719            var thisArg = arguments[1];
11720            // 5. Let k be 0.
11721            var k = 0;
11722            // 6. Repeat, while k < len
11723            while (k < len) {
11724                // a. Let Pk be ! ToString(k).
11725                // b. Let kValue be ? Get(O, Pk).
11726                // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
11727                // d. If testResult is true, return kValue.
11728                var kValue = o[k];
11729                if (predicate.call(thisArg, kValue, k, o)) {
11730                    return kValue;
11731                }
11732                // e. Increase k by 1.
11733                k++;
11734            }
11735            // 7. Return undefined.
11736            return undefined;
11737        },
11738        configurable: true,
11739        writable: true
11740    });
11741}
11742//# sourceMappingURL=Find.js.map;
11743if (!String.prototype.endsWith) {
11744    String.prototype.endsWith = function (search, this_len) {
11745        if (this_len === undefined || this_len > this.length) {
11746            this_len = this.length;
11747        }
11748        return this.substring(this_len - search.length, this_len) === search;
11749    };
11750}
11751//# sourceMappingURL=EndsWith.js.map;
11752(function () {
11753    if (typeof window.CustomEvent === "function")
11754        return false;
11755    function CustomEvent(event, params) {
11756        params = params || { bubbles: false, cancelable: false, detail: undefined };
11757        var evt = document.createEvent('CustomEvent');
11758        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
11759        return evt;
11760    }
11761    CustomEvent.prototype = window.Event.prototype;
11762    window.CustomEvent = CustomEvent;
11763})();
11764//# sourceMappingURL=CustomEvent.js.map;
11765var ModalProductPageHelper;
11766(function (ModalProductPageHelper) {
11767    var modalModeArgs = "modalMode=true&SinglePDPModalMode=true";
11768    var headerClass = "singlePDPModalHeader";
11769    var contentClass = "singlePDPModalContents";
11770    var footerClass = "singlePDPModalFooter";
11771    var modalWrapperClass = "modalWrapper";
11772    var pageWrapperClass = "singlePDPPageWrapper";
11773    var Config = {
11774        Contents: "",
11775        FullUrl: "",
11776        HeadingText: "PRODUCT QUICKVIEW",
11777        ChildHeading: "",
11778        Height: 563,
11779        Width: 819,
11780        onPreClose: null,
11781        onClose: function () {
11782            $('body').css('overflow', '');
11783            $("body").css("position", '');
11784        }
11785    };
11786    function ShowProductPageModal(url, fullUrl) {
11787        var config = $.extend({}, Config);
11788        var urlParts = url.split("#");
11789        var iframeUrl = urlParts[0];
11790        var separator = iframeUrl.indexOf('?') !== -1 ? "&" : "?";
11791        iframeUrl = iframeUrl + separator + modalModeArgs;
11792        if (urlParts.length > 0)
11793            iframeUrl += "#" + urlParts[1];
11794        var pageContents = $("<div />").addClass(pageWrapperClass);
11795        var loadingSpinner = $("<div/>").addClass("singlePDPModalLoading");
11796        var iFrame = $("<iframe />")
11797            .attr("src", iframeUrl)
11798            .attr("id", "relatedProductFrame")
11799            .attr("onload", "ModalProductPageHelper.FrameLoaded(this);")
11800            .attr("style", "opacity:0;");
11801        pageContents.append(loadingSpinner);
11802        pageContents.append(iFrame);
11803        config.Contents = pageContents;
11804        config.FullUrl = fullUrl;
11805        ShowModal(config);
11806    }
11807    ModalProductPageHelper.ShowProductPageModal = ShowProductPageModal;
11808    function ModalAddToBag(itemID, optionNo, chain, quantity, pdpLocation) {
11809        NextBasket.ItemAdd(itemID, optionNo, quantity, chain, false, function () { }, "", pdpLocation.pathname);
11810        ModalPopup.close(null);
11811        if ($(window).scrollTop() != 0 && $('html').hasClass('touch')) {
11812            $(window).scrollTop(0);
11813        }
11814    }
11815    ModalProductPageHelper.ModalAddToBag = ModalAddToBag;
11816    function FrameLoaded(iframeObject) {
11817        try {
11818            var innerDoc = iframeObject.contentDocument || iframeObject.contentWindow.document;
11819            var $innerDoc = $(innerDoc);
11820            var fadeOutOverlay = true;
11821            if ($innerDoc.find(".ProductPage").length == 0) {
11822                if ($innerDoc.find(".Error404").length == 0 && $innerDoc.find(".Error500").length == 0) {
11823                    fadeOutOverlay = false;
11824                    var iframeUrl = iframeObject.src;
11825                    var iframeUrlwithoutHash = iframeUrl.substr(0, iframeUrl.indexOf('#'));
11826                    window.location = iframeUrlwithoutHash;
11827                }
11828            }
11829            else {
11830                var $continueShoppingLink = $("a.continueShopping");
11831                var $articleStyle_1 = $innerDoc.find("article.Style");
11832                if ($articleStyle_1.length == 1) {
11833                    $continueShoppingLink.on("click", function (e) {
11834                        var mpItemNo = $articleStyle_1.find(".StyleMeta .ItemNumber").text();
11835                        if (mpItemNo) {
11836                            mpItemNo = mpItemNo.replace("-", "").toLowerCase().substring(0, 6);
11837                            var tplUrl = (Next.Settings.Channel.IsTotalPlatformLiteClient) ? Next.Settings.Channel.SiteUrl : "";
11838                            window.location.href = tplUrl + "/search?w=" + mpItemNo;
11839                            return false;
11840                        }
11841                    });
11842                }
11843            }
11844            $innerDoc.on('click', '.loginPopoverLink, .favourites-sign-out-link', function () {
11845                window.location.href = $(this).attr('href');
11846            });
11847            if (fadeOutOverlay) {
11848                $('.singlePDPModalLoading').fadeOut('fast');
11849                $(iframeObject).attr("style", "opacity:1;");
11850            }
11851            setTimeout(function () {
11852                iframeObject.contentWindow.focus();
11853            }, 100);
11854        }
11855        catch (e) {
11856            window.location.href = iframeObject.src;
11857        }
11858    }
11859    ModalProductPageHelper.FrameLoaded = FrameLoaded;
11860    function ShowModal(config) {
11861        var contents = config.Contents;
11862        var headingWrapper = $("<div />").addClass(headerClass);
11863        var closeButton = $("<a />").addClass("closeButton").text("Close");
11864        var footerWrapper = $("<div />").addClass(footerClass);
11865        var pUrl = config.FullUrl;
11866        var urlArr = config.FullUrl.split('#');
11867        if (urlArr.length > 1) {
11868            var pid = urlArr[1];
11869            pUrl = '';
11870            pUrl = Next.Settings.Channel.SiteUrl + "/search?w=" + pid;
11871        }
11872        var continueShopping = $("<a />").addClass("continueShopping").text("View Full Product Page").attr("href", pUrl);
11873        closeButton.click(function (e) {
11874            $('body').removeAttr('style');
11875            ModalPopup.close(e);
11876        });
11877        var heading = $("<h2 />").text(config.HeadingText);
11878        headingWrapper.append(heading);
11879        headingWrapper.append(closeButton);
11880        footerWrapper.append(continueShopping);
11881        var modalContents = $("<div />").addClass(contentClass);
11882        modalContents.append(headingWrapper);
11883        modalContents.append(contents);
11884        modalContents.append(footerWrapper);
11885        var $modal = ModalPopup.init({
11886            overlay: true,
11887            width: config.Width,
11888            height: config.Height,
11889            onPreClose: config.onPreClose,
11890            onClose: config.onClose,
11891            lockBackgroundScroll: false,
11892            fullyLockBackgroundScroll: true
11893        });
11894        if (isIOS) {
11895            $('body').css({
11896                'overflow': 'hidden',
11897                'position': 'fixed'
11898            });
11899        }
11900        else {
11901            $('body').css({
11902                'overflow': 'hidden'
11903            });
11904        }
11905        $modal.addClass(modalWrapperClass);
11906        $modal.empty();
11907        $modal.append(modalContents);
11908        ModalPopup.show();
11909    }
11910    function ModularPDPAddToBag(itemID, optionNo, chain, quantity, pdpPathname) {
11911        NextBasket.ItemAdd(itemID, optionNo, quantity, chain, false, function () { }, "", pdpPathname);
11912        ModalPopup.close(null);
11913        if ($(window).scrollTop() != 0 && $('html').hasClass('touch')) {
11914            $(window).scrollTop(0);
11915        }
11916    }
11917    ModalProductPageHelper.ModularPDPAddToBag = ModularPDPAddToBag;
11918})(ModalProductPageHelper || (ModalProductPageHelper = {}));
11919//# sourceMappingURL=ModalProductPageHelper.js.map;
11920/*
11921 * @preserve dataset polyfill for IE < 11. See https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset and http://caniuse.com/#search=dataset
11922 *
11923 * @author ShirtlessKirk copyright 2015
11924 * @license WTFPL (http://www.wtfpl.net/txt/copying)
11925 */
11926/*global define: false, module: false */
11927/*jslint nomen: true, regexp: true, unparam: true */
11928(function datasetModule(global, definition) { // non-exporting module magic dance
11929    'use strict';
11930
11931    var
11932        amd = 'amd',
11933        exports = 'exports'; // keeps the method names for CommonJS / AMD from being compiled to single character variable
11934
11935    if (typeof define === 'function' && define[amd]) {
11936        define(function definer() {
11937            return definition(global);
11938        });
11939    } else if (typeof module === 'function' && module[exports]) {
11940        module[exports] = definition(global);
11941    } else {
11942        definition(global);
11943    }
11944}(this, function datasetPolyfill(global) {
11945    'use strict';
11946
11947    var
11948        attribute,
11949        attributes,
11950        counter,
11951        dash,
11952        dataRegEx,
11953        document = global.document,
11954        hasEventListener,
11955        length,
11956        match,
11957        mutationSupport,
11958        test = document.createElement('_'),
11959        DOMAttrModified = 'DOMAttrModified';
11960
11961    function clearDataset(event) {
11962        delete event.target._datasetCache;
11963    }
11964
11965    function toCamelCase(string) {
11966        return string.replace(dash, function (m, letter) {
11967            return letter.toUpperCase();
11968        });
11969    }
11970
11971    function getDataset() {
11972        var
11973            dataset = {};
11974
11975        attributes = this.attributes;
11976        for (counter = 0, length = attributes.length; counter < length; counter += 1) {
11977            attribute = attributes[counter];
11978            match = attribute.name.match(dataRegEx);
11979            if (match) {
11980                dataset[toCamelCase(match[1])] = attribute.value;
11981            }
11982        }
11983
11984        return dataset;
11985    }
11986
11987    function mutation() {
11988        if (hasEventListener) {
11989            test.removeEventListener(DOMAttrModified, mutation, false);
11990        } else {
11991            test.detachEvent('on' + DOMAttrModified, mutation);
11992        }
11993
11994        mutationSupport = true;
11995    }
11996
11997    if (test.dataset !== undefined) {
11998        return;
11999    }
12000
12001    dash = /\-([a-z])/ig;
12002    dataRegEx = /^data\-(.+)/;
12003    hasEventListener = !!document.addEventListener;
12004    mutationSupport = false;
12005
12006    if (hasEventListener) {
12007        test.addEventListener(DOMAttrModified, mutation, false);
12008    } else {
12009        test.attachEvent('on' + DOMAttrModified, mutation);
12010    }
12011
12012    // trigger event (if supported)
12013    test.setAttribute('foo', 'bar');
12014
12015    Object.defineProperty(global.Element.prototype, 'dataset', {
12016        get: mutationSupport
12017            ? function get() {
12018                if (!this._datasetCache) {
12019                    this._datasetCache = getDataset.call(this);
12020                }
12021
12022                return this._datasetCache;
12023            } : getDataset
12024    });
12025
12026    if (mutationSupport && hasEventListener) { // < IE9 supports neither
12027        document.addEventListener(DOMAttrModified, clearDataset, false);
12028    }
12029}));;
12030/// <reference path="typings/jquery/jquery.d.ts" />
12031var BloomReachSEOWidgets = /** @class */ (function () {
12032    function BloomReachSEOWidgets() {
12033        $('document').ready(function () {
12034            var urlpath = window.location.href.toLowerCase();
12035            var plpHeader = "View Related Items";
12036            // Parse document for data
12037            if (window.widgetObject) {
12038                var defaultDataLimits = {
12039                    items: 8,
12040                    products: 10,
12041                    categories: 10
12042                };
12043                var dataLimits = {
12044                    items: (Next.Settings.Channel.BRSEOWidgetsItemsMax ? Next.Settings.Channel.BRSEOWidgetsItemsMax : defaultDataLimits.items),
12045                    products: (Next.Settings.Channel.BRSEOWidgetsProductsMax ? Next.Settings.Channel.BRSEOWidgetsProductsMax : defaultDataLimits.products),
12046                    categories: (Next.Settings.Channel.BRSEOWidgetsCategoriesMax ? Next.Settings.Channel.BRSEOWidgetsCategoriesMax : defaultDataLimits.categories)
12047                };
12048                var theData = {
12049                    // Trim products based on config
12050                    // --------------------------------------
12051                    // View Related Items
12052                    moreResults: (Array.isArray(window.widgetObject['more-results']) ? window.widgetObject['more-results'].slice(0, dataLimits.items) : window.widgetObject['more-results']),
12053                    //
12054                    // More Related Products
12055                    relatedItem: (Array.isArray(window.widgetObject['related-item']) ? window.widgetObject['related-item'].slice(0, dataLimits.products) : window.widgetObject['related-item']),
12056                    // 
12057                    // Categories
12058                    relatedCategory: (Array.isArray(window.widgetObject['related-category']) ? window.widgetObject['related-category'].slice(0, dataLimits.categories) : window.widgetObject['related-category']),
12059                };
12060                // Replace data lists with newly trimmed versions
12061                window.widgetObject['more-results'] = theData.moreResults;
12062                window.widgetObject['related-item'] = theData.relatedItem;
12063                window.widgetObject['related-category'] = theData.relatedCategory;
12064            }
12065            //display only View Related Items
12066            if (!Next.Settings.Channel.EnableBRSEOWidgetsDisplayAllRows) {
12067                if (document.getElementById("br-related-items-widget")) {
12068                    document.getElementById("br-related-items-widget").style.display = "none";
12069                }
12070            }
12071            //ensure bottom two rows of widgets are in mixed case
12072            var camelCaseRc = "";
12073            $(".br_widget_wrapper .br-ri-link").each(function (i, obj) {
12074                camelCaseRc = $(this).text().toLowerCase();
12075                $(this).text(camelCaseRc);
12076            });
12077            $(".br_widget_wrapper .br-rc-link").each(function (i, obj) {
12078                camelCaseRc = $(this).text().toLowerCase();
12079                $(this).text(camelCaseRc);
12080            });
12081            $(".br_widget_wrapper .br-ri-link").addClass('CamelCase');
12082            $(".br_widget_wrapper .br-rc-link").addClass('CamelCase');
12083            //change header & reset left margin on plp
12084            if (urlpath.indexOf("shop") > -1 || urlpath.indexOf("search") > -1) {
12085                $(".br_widget_wrapper .br-found-heading span").text(plpHeader);
12086                $(".br_widget_wrapper .br-sf-widget-merchant-popup-maincont").addClass('PLPSEOAlterations');
12087            }
12088            else {
12089                //Reset left margin on pdp
12090                $(".br_widget_wrapper .br-sf-widget-merchant-popup-maincont").removeClass('PLPSEOAlterations').removeClass('PLPSEOAlterationsNoFlash');
12091                //Append pop up to parent container  
12092                var seoPopupDivs = $('#br-more-results-widget .br-rp-qv-hide');
12093                seoPopupDivs.each(function (index, v) {
12094                    $("#br-more-results-widget").append(v);
12095                });
12096            }
12097            //alter styling for IE and edge
12098            if (document.documentMode || /Edge/.test(navigator.userAgent) || (navigator.userAgent.indexOf("MSIE") != -1) || navigator.appVersion.indexOf('Trident/') > -1) {
12099                $(".br_widget_wrapper .br-sf-widget-merchant-popup-view").addClass('InternetExplorer');
12100            }
12101            //shorten string lengths for the widgets
12102            StringLengthsFunction(".br_widget_wrapper .br-sf-widget-merchant-title a", 30);
12103            StringLengthsFunction(".br_widget_wrapper .br-sf-widget-merchant-desc", 105);
12104            StringLengthsFunction(".br_widget_wrapper .br-sf-widget-merchant-popup-title a", 105);
12105            StringLengthsFunction(".br_widget_wrapper .br-sf-widget-merchant-popup-desc", 400);
12106            StringLengthsFunction(".br_widget_wrapper .br-ri-link", 40);
12107            StringLengthsFunction(".br_widget_wrapper .br-rc-link", 40);
12108            function StringLengthsFunction(className, stringLength) {
12109                $(className).each(function (i) {
12110                    var thisText = $(this).text().trim();
12111                    if (thisText.length > stringLength) {
12112                        $(this).text(thisText.substring(0, stringLength).trim() + "…");
12113                    }
12114                });
12115            }
12116            window.isModalVisible || false;
12117            function hideBrRpQv() {
12118                var elems = document.querySelectorAll(".br-rp-qv-show");
12119                for (var i = 0; i < elems.length; i++) {
12120                    var classStr = elems[i].getAttribute('class') + ' ';
12121                    classStr = classStr.replace('br-rp-qv-show ', 'br-rp-qv-hide ');
12122                    elems[i].setAttribute('class', classStr);
12123                    window.isModalVisible = false;
12124                }
12125            }
12126            ;
12127            function showBrRpQv(id) {
12128                hideBrRpQv();
12129                var classStr = document.getElementById(id).getAttribute('class') + ' ';
12130                classStr = classStr.replace('br-rp-qv-hide ', 'br-rp-qv-show ');
12131                document.getElementById(id).setAttribute('class', classStr);
12132                setTimeout(function () {
12133                    window.isModalVisible = true;
12134                }, 100);
12135            }
12136            ;
12137            // Add event handler for clicking outside the modal
12138            $(document).click(function (e) {
12139                var $target = $(e.target), isModalClick = $target.parents('.br-sf-widget-merchant-popup-cont').length > 0 || $target.hasClass('br-sf-widget-merchant-popup-cont');
12140                if (!isModalClick && window.isModalVisible) {
12141                    hideBrRpQv();
12142                }
12143            });
12144            // Add event handler for pressing the escape key
12145            $(document).keyup(function (e) {
12146                if (27 === e.keyCode) {
12147                    hideBrRpQv();
12148                }
12149            });
12150            // Show popup
12151            $('.js-br-sf-widget-btn').on('click', function (e) {
12152                e.preventDefault();
12153                var brId = $(this).data('br-id');
12154                showBrRpQv(brId);
12155            });
12156            // Close popups
12157            $('.br-sf-widget-merchant-popup-close').on('click', function (e) {
12158                e.preventDefault();
12159                hideBrRpQv();
12160            });
12161            //dataLayer for seo search pills
12162            $('#ResultBanner a').on('click', function (e) {
12163                if (dataLayer != null) {
12164                    dataLayer.push({
12165                        event: 'seoPills',
12166                        link_category: 'seoPills',
12167                        link_id: 'click',
12168                        link_name: this.innerText,
12169                        link_value: ''
12170                    });
12171                }
12172            });
12173        });
12174    }
12175    return BloomReachSEOWidgets;
12176}());
12177new BloomReachSEOWidgets();
12178//# sourceMappingURL=BloomReachSEOWidgets.js.map;
12179var NumOfItemsInRow = 0;
12180var Orientation = 'Portrait';
12181var $article;
12182var $scrollRowWrapper;
12183var imageSize = 174.5;
12184var maxPossibleWidth = 880;
12185var stdScreenWidth = 1280;
12186var itemWidth = 175;
12187var rhsContheight = 0;
12188
12189var FindSimilar = {
12190    
12191    getSimilarItems: function (item) {
12192
12193        $article = $(item).parents("article.Item").first();
12194        var $page = $article.parents("div.Page").first();
12195        var position = $article.attr('data-itemposition');
12196        var $findSimilarDiv = $(item).parents("div.find-similar").first();
12197        var productNo = $findSimilarDiv.attr('data-mltId');
12198        var responsiveLargeClass = Next.Settings.UI.HorizontalFiltersEnabled ? "responsiveLarge hf" : "responsiveLarge";
12199        this.hideElements();
12200        rhsContheight = $("#rhs").css("min-height");
12201
12202        $('.showMore').not($(item)).removeClass('Hide');
12203        
12204        Orientation = $page.hasClass('Landscape') ? 'Landscape' : 'Portrait';
12205        getNumberOfColumns();
12206        
12207        var targetUrl = "/mlt?w=" + productNo;
12208
12209        var hasColors = $article.find(".ColourExpander").length > 0;
12210
12211        if (!hasColors) {
12212            $findSimilarDiv.find('.arrow_box').addClass('colorway');
12213        }
12214        
12215        var totalWidth = 0;
12216
12217        setTimeout(function() {
12218            $.ajax({
12219                url: targetUrl,
12220                type: "GET",
12221                cache: true,
12222                dataType: "json",
12223                success: function (data) {
12224                   var mltContainer = "<div class='mltContainer'>" + "<div class='mainWrapper'>" + "<div class='mltClose'>" +
12225                        "<svg width='20px' height='15px' viewBox='0 0 22 20' version='1.1'><g><g transform='translate(-964.000000, -789.000000)' stroke='#525252' stroke-width='2.3'>" +
12226                        "<g  transform='translate(965.000000, 789.000000)'><path d='M0,0 L20,20'></path>" +
12227                        "<path d='M20,0 L0,20'></path></g></g></g></svg></div> <div class='scrollRowWrapper'>" +
12228                        "<div class='scrollControl left'><a href='#' class='scrollNav previous disabled'>&lt;</a></div>" +
12229                        "<div class='clip'>" + "<div class='mltItemContainer'><ul class='mlt_animate'></ul></div></div>" +
12230                        "<div class='scrollControl right'><a href='#' class='scrollNav next'>&gt;</a></div></div></div>";
12231
12232                    var itemPosition = parseInt(position);
12233                    var numberOfSiblingsInRow = getNumberOfSiblingsInCurrentRow();
12234                    var $endOfRow = (numberOfSiblingsInRow > 0) ? $article.nextAll('#i' + (itemPosition + numberOfSiblingsInRow) +
12235                        ", #campaignArticleWide, #campaignArticleNarrow").filter(function () {
12236                            if ($(this).css("display") == "none") {
12237                                return false;
12238                            }
12239                            return true;
12240                        }).first() : $article;
12241
12242                    $(mltContainer).insertAfter($endOfRow);
12243
12244                    switch (Orientation) {
12245                        case 'Landscape':
12246                            $('.mltContainer').addClass('Landscape');
12247                            switch (NumOfItemsInRow) {
12248                                case 2:
12249                                    $('.mltContainer').addClass('responsiveSmall');
12250                                    break;
12251                                case 3:
12252                                    $('.mltContainer').addClass(responsiveLargeClass);
12253                                    break;
12254                                case 4:
12255                                    $('.mltContainer').addClass('responsiveXL');
12256                                    break;
12257                            }
12258                            break;
12259                        case 'Portrait':
12260                            $('.mltContainer').addClass('Portrait');
12261                            switch (NumOfItemsInRow) {
12262                                case 3:
12263                                    $('.mltContainer').addClass('responsiveSmall');
12264                                    break;
12265                                case 4:
12266                                    $('.mltContainer').addClass(responsiveLargeClass);
12267                                    break;
12268                                case 5:
12269                                    $('.mltContainer').addClass('responsiveXL');
12270                                    break;
12271                            }
12272                            break;
12273                    }
12274
12275                    var $ul = $(".mlt_animate");
12276
12277                    $.each(data.MltSearchResults, function (i, mltItem) {
12278                        $("<li/>").attr('class', 'mlt_item').attr("data-image", mltItem.SearchImage).attr("data-itemURL", mltItem.Url).attr("data-price", mltItem.Price).appendTo($ul);
12279                    });
12280
12281                    $ul.find("li.mlt_item").last().addClass("noPaddingRight");
12282
12283                    $findSimilarDiv.find('.arrow_box').css('display', 'block');
12284                    $findSimilarDiv.find('.showLess').removeClass('Hide');
12285                    $findSimilarDiv.find('.showMore').addClass('Hide');
12286
12287                    totalWidth += data.MltSearchResults.length * imageSize;
12288                    
12289                    $('.mltItemContainer').width(totalWidth);
12290
12291                    if (Next.Settings.UI.HorizontalFiltersEnabled && $(".mltContainer .clip").length > 0) {
12292                        maxPossibleWidth = $(".mltContainer .clip").outerWidth();
12293                        totalWidth = Math.floor(totalWidth);
12294                    }
12295                    if (totalWidth <= maxPossibleWidth) {
12296                        $("a.next").addClass("disabled");
12297                    }
12298
12299                    if ($('.mlt_animate').length > 0) {
12300
12301                        $('.mlt_animate').find("li").each(function (i) {
12302                            if (i < (NumOfItemsInRow + 1) * 2) {
12303                                var $li = $(this);
12304                                $li.addClass("databound");
12305                                var url = $li.attr("data-itemURL");
12306                                var imageUrl = $li.attr("data-image");
12307                                var price = $li.attr("data-price");
12308                                var $itemDiv = $("<div/>").appendTo($li);
12309                                var $pdp = $("<a/>").attr('href', url).appendTo($itemDiv);
12310                                $("<img />").attr('src', imageUrl).attr('class', 'mlt_image').appendTo($pdp);
12311                                $("<div class='mlt_price'></div>").html(price).appendTo($pdp);
12312                            }
12313                        });
12314                    }
12315
12316                    $scrollRowWrapper = $(".scrollRowWrapper").first();
12317                    $scrollRowWrapper.css({"border-bottom": "1px solid #c7c5c5"});
12318
12319                    Results.MltBusy = false;
12320
12321                    //function to fix the gap that appears between MLT box and arrow when there is a longer article element in the same row
12322                    FindSimilar.arrowGapFix();
12323
12324                    //check if MLT panel is out of view port if so scroll into view
12325                    var isInViewport = $('.mltItemContainer').isVisibleInViewPort();
12326                    if (!isInViewport) {
12327                        var elementHeight = $findSimilarDiv.height();
12328                        var viewportHeight = $(window).height();
12329                        $([document.documentElement, document.body]).animate({
12330                            scrollTop: $findSimilarDiv.offset().top - ((viewportHeight - elementHeight) / 2)
12331                        }, 1000);
12332                    }
12333                    if (Next.Settings.UI.HorizontalFiltersEnabled && $("#ContentArea").outerHeight() < $(window).height()) {
12334                        $("#rhs").css("min-height", $(window).height());
12335                        if ($("body").hasClass("touchMode")) {
12336                            $("body").css("overflow-y", "hidden");
12337                        }
12338                    }
12339                    $("a.scrollNav.previous").click(function () {
12340                        FindSimilar.scroll(1, this, $('.scrollRowWrapper'));
12341                        if (!$(this).hasClass("disabled")) {
12342                            TrackGAEvent("Desktop MLT", "Clicked on the 'previous' scroll control arrow", "Clicked on the 'previous' scroll control arrow for Item Number " + productNo, "ID: " + productNo + " - Previous");
12343                        }
12344                        return false;
12345                    });
12346                    $("a.scrollNav.next").click(function () {
12347                        FindSimilar.scroll(-1, this, $('.scrollRowWrapper'));
12348                        if (!$(this).hasClass("disabled")) {
12349                            TrackGAEvent("Desktop MLT", "Clicked on the 'next' scroll control arrow", "Clicked on the 'next' scroll control arrow for Item Number " + productNo, "ID: " + productNo + " - Next");
12350                        }
12351                        return false;
12352                    });
12353                    $(".mltClose").click(function () { FindSimilar.closeMltContainer(this); return false; });
12354                },
12355                error: function() {
12356                    Results.MltBusy = false;
12357                }
12358
12359            });
12360        }, 0);
12361        TrackGAEvent("Desktop MLT", "Click on 'More Like This' link", "Clicked on 'More Like This' link for Item Number " + productNo, "ID: " + productNo + " - Open MLT");
12362       
12363    },
12364    closeMltContainer: function() {
12365        FindSimilar.hideElements();
12366        $('.showMore').removeClass('Hide');
12367        if (Next.Settings.UI.HorizontalFiltersEnabled && $("#ContentArea").outerHeight() < $(window).height()) {
12368            $("#rhs").css("min-height", $(window).height());
12369            if ($("body").hasClass("touchMode")) {
12370                $("body").css("overflow-y", "hidden");
12371            }
12372        }
12373        if (Next.Settings.UI.HorizontalFiltersEnabled) {
12374            $("#rhs").css("min-height", rhsContheight);
12375            if ($("body").hasClass("touchMode")) {
12376                $("body").css("overflow-y", "scroll");
12377            }
12378        }
12379     },
12380    hideElements: function() {
12381        $('.mltContainer').remove();
12382        $('.showLess').addClass("Hide");
12383        $('.arrow_box').css('display', 'none');
12384        $(".mltClose").addClass("Hide");
12385    },
12386    scroll: function(direction, element, parent) {
12387
12388        var mltContainer = parent.find(".mltItemContainer");
12389
12390        if ($(element).hasClass("disabled") ||
12391            mltContainer.hasClass("locked") ||
12392            mltContainer.position().left === 0 && direction === 1 ||
12393            mltContainer.find("li").length < NumOfItemsInRow) {
12394            return false;
12395        }
12396
12397        var liCount = mltContainer.find("li").length;
12398
12399        var currentOffset = mltContainer.css("margin-left").replace('px', '');
12400
12401        var mltItems = (Orientation == 'Landscape') ? (parseInt(NumOfItemsInRow) + 2) : (parseInt(NumOfItemsInRow) + 1);
12402
12403        var pageSize = itemWidth * mltItems;
12404        var listLen = liCount * itemWidth;
12405        var distance = pageSize * direction;
12406
12407        var newOffset = parseInt(currentOffset) + parseInt(distance);
12408        var maxOffset = (listLen - pageSize) * direction;
12409        
12410        if ((newOffset < maxOffset) && direction === -1) {
12411                distance = maxOffset - parseInt(currentOffset);
12412                }
12413
12414        if ((newOffset > 0) && direction === 1) {
12415            distance = 0 - parseInt(currentOffset);
12416        }
12417        
12418        //Safety check
12419        if (distance > pageSize) {
12420            distance = pageSize;
12421        }
12422
12423        if (distance < -pageSize) {
12424            distance = -pageSize;
12425        }
12426
12427        //ie8 and below don't like animating from one css class to another - so, set the animation time to 0
12428        var transitionSpeed = 200;
12429
12430        mltContainer.addClass("locked").stop().animate({ marginLeft: "+=" + distance },500,function() {
12431
12432            if (direction === -1) {
12433                $('.scrollRowWrapper').find("a.scrollNav.previous").removeClass("disabled", transitionSpeed);
12434            }
12435            
12436            var left = parseInt($(mltContainer).css('margin-left'));
12437
12438            if (left === 0) {
12439                $('.scrollRowWrapper').find("a.scrollNav.previous").addClass("disabled", transitionSpeed);
12440            }
12441
12442            if ((left + mltContainer.width()) < pageSize) {
12443                $('.scrollRowWrapper').find("a.scrollNav.next").addClass("disabled", transitionSpeed);
12444            } else {
12445                $('.scrollRowWrapper').find("a.scrollNav.next").removeClass("disabled", transitionSpeed);
12446            }
12447
12448            mltContainer.removeClass("locked");
12449                    
12450             $('.mlt_animate').find("li").each(function () {
12451                     var i = 0;
12452                     if (!$(this).hasClass("databound")) { // Check if image is already loaded
12453                            if (i < (NumOfItemsInRow + 1) * 2) {
12454                                var $li = $(this);
12455                                $li.addClass("databound");
12456                                var url = $li.attr("data-itemURL");
12457                                var imageUrl = $li.attr("data-image");
12458                                var price = $li.attr("data-price");
12459
12460                                var $itemDiv = $("<div/>").appendTo($li);
12461                                var $pdp = $("<a/>").attr('href', url).appendTo($itemDiv);
12462                                $("<img />").attr('src', imageUrl).attr('class', 'mlt_image').appendTo($pdp);
12463                                $("<div class='mlt_price'></div>").html(price).appendTo($pdp);
12464                                i++;
12465                            }
12466                     }
12467            });
12468        });
12469        return false;
12470    },
12471    arrowGapFix: function () {
12472        var $arrow = $article.find(".arrow_box").first();
12473       
12474        var scrollRowWrapperTop = $scrollRowWrapper.offset().top;
12475        
12476        $arrow.offset({ top: (scrollRowWrapperTop + 1) });
12477    }
12478};
12479$(function () {
12480    if (Next.Settings.Channel.EnableFindSimilar) {
12481        window.onresize = function() {
12482            var rows = (Orientation !== 'Landscape' ? 3 : 2);
12483            if (Next.Settings.UI.HorizontalFiltersEnabled) {
12484                rows = 4;//Number of items in row.
12485            }
12486            if ((NumOfItemsInRow > rows && window.innerWidth < stdScreenWidth) ||
12487                (NumOfItemsInRow <= rows && window.innerWidth > stdScreenWidth)) {
12488                FindSimilar.hideElements();
12489                $('.showMore').removeClass('Hide');
12490            }
12491        }
12492        $.fn.isVisibleInViewPort = function () {
12493            var $t = $(this),
12494                $w = $(window),
12495                viewTop = $w.scrollTop(),
12496                viewBottom = viewTop + $w.height(),
12497                top = $t.offset().top,
12498                bottom = top + $t.height();
12499              
12500            return ((bottom <= viewBottom) && (top >= viewTop));
12501        };
12502    }
12503
12504});
12505
12506function getNumberOfSiblingsInCurrentRow() {
12507    var i = 0;
12508    var $articleSiblings = $article.nextAll("article");
12509    $articleSiblings.each(function () {
12510        if ($(this).css("display") == "none") {
12511            return true;
12512        }
12513        if ($(this).offset().top > $article.offset().top) {
12514            return false;
12515        }
12516        else {
12517            i++;
12518        }
12519    });
12520    return i;
12521}
12522
12523function getNumberOfColumns() {
12524    if (window.innerWidth >= stdScreenWidth) {
12525        if (Orientation === 'Landscape') {
12526            NumOfItemsInRow = Next.Settings.UI.HorizontalFiltersEnabled ? 4 : 3;
12527        }
12528        else {
12529            NumOfItemsInRow = Next.Settings.UI.HorizontalFiltersEnabled ? 5 : 4;
12530        }
12531    }
12532    else {
12533        if (Orientation === 'Landscape') {
12534            NumOfItemsInRow = Next.Settings.UI.HorizontalFiltersEnabled ? 3 : 2;
12535        }
12536        else {
12537            NumOfItemsInRow = Next.Settings.UI.HorizontalFiltersEnabled ? 4 : 3;
12538        }
12539    }
12540};
12541var nextBagCookieName = Next.Settings.Cookie.BackToNextCookieName;
12542var fromNextURLCookieName = Next.Settings.Cookie.BackToNextURLCookieName;
12543var shortCompanyName = Next.Settings.Channel.ShortCompanyName;
12544var currentUrl = window.location.href.toLowerCase();
12545var isEntry = currentUrl.indexOf('?fromnext') > 0;
12546var bagTextShowName = "showb2nBagText";
12547var nextBagCookieVal = readCookie(nextBagCookieName);
12548var nextBagUrlVal = readCookie(fromNextURLCookieName);
12549var userDeviceType = (dataLayer.length >= 2 && dataLayer[1].device_type) ? (dataLayer[1].device_type).toLowerCase() : "";
12550var url = "//www.next.co.uk";
12551if ((isEntry || nextBagCookieVal == "True") && (Next.Settings.Channel.ChannelTheme != "")) {
12552    if (Next.Settings.Channel.EnableBackToNextBanner) {
12553        if (Next.Settings.Channel.BackToNextURL)
12554            url = Next.Settings.Channel.BackToNextURL;
12555        switch (userDeviceType) {
12556            case "desktop":
12557                insertBannerToHTMLDesktop();
12558                break;
12559            case "mobile":
12560                insertBannerToHTMLMobile();
12561                break;
12562        }
12563        if (nextBagCookieVal != "True")
12564            createCookie(nextBagCookieName, "True", null, location.host);
12565        if (nextBagUrlVal == null) {
12566            if (Next.Settings.Channel.StateConvergence != null && Next.Settings.Channel.StateConvergence.Domains != null && Next.Settings.Channel.StateConvergence.Domains.some(function (x) { return x > 0; }))
12567                url = Next.Settings.Channel.StateConvergence.Domains.find(function (x) { return !x.includes("mobile.") || !x.includes("m."); });
12568            createCookie(fromNextURLCookieName, url, null, location.host);
12569        }
12570        ;
12571    }
12572}
12573if (isEntry) {
12574    var bagCheck = setInterval(function () {
12575        if (NextBasket.Loaded) {
12576            if (nextBagCookieVal == "True") {
12577                if (NextBasket.Data["ItemCount"] > 0 && Next.Settings.Channel.StateConvergence.IsEnabled) {
12578                    sessionStorage.setItem(bagTextShowName, "true");
12579                    displayBackToNextBagText();
12580                }
12581                clearInterval(bagCheck);
12582            }
12583        }
12584    }, 200);
12585}
12586else if (sessionStorage.getItem(bagTextShowName) == "true") {
12587    displayBackToNextBagText();
12588}
12589function displayBackToNextBagText() {
12590    $("#backToNext-shoppingBagText").css("display", "inline-block");
12591}
12592var backToNextBanner = $("#backToNextBanner");
12593//Only run code if the banner has been added to the DOM
12594if (backToNextBanner.length) {
12595    var btnbHeight = backToNextBanner.height();
12596    //DESKTOP - Initial setup of the margin adjustments for elements across different pages
12597    $(".PageHeader").ready(function () {
12598        //Used across the site
12599        var height = $(".PageHeader").height();
12600        if (nextBagCookieVal == "True") {
12601            height += btnbHeight;
12602        }
12603        $(".HeaderSpacer").height(height + "px");
12604        //Tablet 2.0 Header
12605        var headerHeight = parseInt($("#header_upper-nav_nav").css("height")) + parseInt($("#header_lower-nav_nav").css("height"));
12606        $("#nav-headers-spacer").height(headerHeight);
12607        //Used on PLP Page
12608        $(".filterControls").css("margin-top", (parseInt($(".filterControls").css("margin-top")) + btnbHeight) + "px");
12609        $(".ResultCount").css("margin-top", (parseInt($(".ResultCount").css("margin-top")) + btnbHeight) + "px");
12610        $(".ResultCount").attr("data-btnb", "true");
12611        if (!Next.Settings.UI.HorizontalFiltersEnabled) {
12612            $("#ResultHeader").css("margin-top", (parseInt($("#ResultHeader").css("margin-top")) + btnbHeight) + "px");
12613        }
12614        //Tablet 2.0
12615        // horizontal brands page
12616        $(".bp-wrapper").addClass("backToNextActive");
12617    });
12618    //MOBILE
12619    var filterHeader = parseInt($("#filter-header").css("top"));
12620    var filterHeaderwithBtnb = filterHeader + btnbHeight;
12621    var plp_filterWrapperHeader = parseInt($("#filter-wrapper").css("top"));
12622    var plp_filterWrapperHeaderwithBtnb = plp_filterWrapperHeader + btnbHeight;
12623    var plp_sortMoreWrapperHeader = parseInt($("#sort-wrapper").css("margin-top"));
12624    var plp_sortMoreWrapperHeaderwithBtnb = plp_sortMoreWrapperHeader + btnbHeight;
12625    var plp_moreViewsWrapperHeader = parseInt($("#more-wrapper").css("margin-top"));
12626    var plp_moreViewsWrapperHeaderwithBtnb = plp_moreViewsWrapperHeader + btnbHeight;
12627    var tablet_upperHeader = $("#header_upper-nav_nav");
12628    var tablet_lowerNav = $("#header_lower-nav_nav");
12629    var tablet_baseNav = $(".navbar");
12630    var tablet_headerSpacer = $("#nav-headers-spacer");
12631    var origNavHeadersSpacer = $("#nav-headers-spacer").height();
12632    var newNavHeadersSpacer = origNavHeadersSpacer + btnbHeight;
12633    $("#filter-header").css('top', filterHeaderwithBtnb + "px");
12634    $("#filter-wrapper").css('top', plp_filterWrapperHeaderwithBtnb + "px");
12635    $("#sort-wrapper").css('margin-top', plp_sortMoreWrapperHeaderwithBtnb + "px");
12636    $("#more-wrapper").css('margin-top', plp_moreViewsWrapperHeaderwithBtnb + "px");
12637    tablet_lowerNav.addClass("backToNextActive");
12638    tablet_upperHeader.addClass("backToNextActive");
12639    tablet_baseNav.addClass("backToNextActive");
12640    tablet_headerSpacer.addClass("backToNextActive");
12641    //Store Locator
12642    $("#searchTextField, #viewToggleButton").attr('style', "top: " + ($("#nav-headers").height() + 6) + "px !important");
12643    //CLOSE BANNER
12644    $("#backToNextClose").click(function (e) {
12645        e.preventDefault();
12646        var btnbHeight = backToNextBanner.height();
12647        if (dataLayer[1].device_type == "mobile") {
12648            TrackGTMEvent("back_to_next", "tap", "Banner_backtonextclosed");
12649        }
12650        else if (dataLayer[1].device_type == "desktop") {
12651            TrackGAEvent("back_to_next", "click", "Banner_backtonextclosed");
12652        }
12653        backToNextBanner.remove();
12654        $(".HeaderSpacer").height($(".PageHeader").height() + "px");
12655        document.cookie = fromNextURLCookieName + "=; path=/; domain=" + location.host + "; expires = Thu, 01 Jan 1970 00:00:00 GMT";
12656        document.cookie = nextBagCookieName + "=; path=/; domain=" + location.host + "; expires = Thu, 01 Jan 1970 00:00:00 GMT";
12657        sessionStorage.removeItem(bagTextShowName);
12658        //DESKTOP
12659        //Used on PLP Page
12660        $(".filterControls").css("margin-top", (parseInt($(".filterControls").css("margin-top")) - btnbHeight) + "px");
12661        $(".ResultCount").css("margin-top", (parseInt($(".ResultCount").css("margin-top")) - btnbHeight) + "px");
12662        $(".ResultCount").attr("data-btnb", "false");
12663        if (!Next.Settings.UI.HorizontalFiltersEnabled) {
12664            $("#ResultHeader").css("margin-top", (parseInt($("#ResultHeader").css("margin-top")) - btnbHeight) + "px");
12665        }
12666        // horizontal brands page
12667        $(".bp-wrapper").removeClass("backToNextActive");
12668        //MOBILE
12669        //Tablet 2.0
12670        tablet_lowerNav.removeClass("backToNextActive");
12671        tablet_upperHeader.removeClass("backToNextActive");
12672        tablet_baseNav.removeClass("backToNextActive");
12673        tablet_headerSpacer.removeClass("backToNextActive");
12674        //Site wide for header
12675        $("#nav-headers-spacer").css('height', $("#nav-headers").height() + 'px');
12676        //PLP
12677        $("#filter-header").css('top', filterHeader + "px");
12678        $("#filter-wrapper").css('top', plp_filterWrapperHeader + "px");
12679        $("#sort-wrapper").css('margin-top', plp_sortMoreWrapperHeader + "px");
12680        $("#more-wrapper").css('margin-top', plp_moreViewsWrapperHeader + "px");
12681        //Store Locator
12682        $("#searchTextField, #viewToggleButton").attr('style', "top: " + ($("#nav-headers").height() + 6) + "px !important");
12683    });
12684    //SELECT 'BACK TO NEXT'
12685    $("#backToNextLink").on("click", function (e) {
12686        document.cookie = fromNextURLCookieName + "=; path=/; domain=" + location.host + "; expires = Thu, 01 Jan 1970 00:00:00 GMT";
12687        document.cookie = nextBagCookieName + "=; path=/; domain=" + location.host + "; expires = Thu, 01 Jan 1970 00:00:00 GMT";
12688        sessionStorage.removeItem(bagTextShowName);
12689        if (dataLayer[1].device_type == "mobile") {
12690            TrackGTMEvent("back_to_next", "tap", "Banner_backtonextclicked");
12691        }
12692        else if (dataLayer[1].device_type == "desktop") {
12693            TrackGAEvent("back_to_next", "click", "Banner_backtonextclicked");
12694        }
12695    });
12696}
12697function insertBannerToHTMLDesktop() {
12698    var insertString = '<div id="backToNextBanner"><span id="backToNext">';
12699    insertString += '<a id="backToNextLink" href="' + url + '" data-link-id="back_to_next" data-link-name="Banner_backtonextclicked">';
12700    insertString += '<img id="backToNextArrow" src="/Images/Childsplay/back_arrow_black.svg"><p>Back to</p><img id="backToNextIcon" src="/Images/LittleLabel/Next-Logo.svg"></a></span><div id="backToNext-shoppingBagText"><div class="backToNextHeartIcon"><img src="/Images/Childsplay/brands-heart.svg"></div><span class="backToNext-Text">Luxury Kids Brands from BOSS to Versace</span></div>';
12701    insertString += '<span id="backToNextClose" data-link-id="back_to_next" data-link-name="Banner_backtonextclosed"><img class="backToNextCloseIcon" src="/Images/Childsplay/close_icon_black.svg"></span></div>';
12702    $(".PageHeader").prepend(insertString);
12703}
12704function insertBannerToHTMLMobile() {
12705    var colxsname = Next.Settings.Channel.EnableUpgradedBootstrap ? "col" : "col-xs";
12706    var insertString = '<div class="' + colxsname + '-12" id="backToNextBanner">';
12707    insertString += '<div class="backToNext"><div id="backToNext-left"><a id="backToNextLink" href="' + url + '" data-link-id="back_to_next" data-link-name="Banner_backtonextclicked"><span id="backToNextLogo-arrowImg"></span><span id="backToNextLogo-backtoText">Back to</span><span id="backToNextLogo-nextLogo"></span></a></div>';
12708    insertString += '<div id="backToNext-shoppingBagText"><div class="backToNextHeartIcon"><img src="/Images/Childsplay/brands-heart.svg"></div><span class="backToNext-Text">Luxury Kids Brands from BOSS to Versace</span></div><span id="backToNextClose" data-link-id="back_to_next" data-link-name="Banner_backtonextclosed"><img class="backToNextCloseIcon" src="/Images/Childsplay/close_icon_black.svg"/></span></div></div>';
12709    $("#navigationheader").prepend(insertString);
12710    $("#header_upper-nav_nav").prepend(insertString);
12711}
12712//# sourceMappingURL=BackToNext.js.map;
12713/* 
12714 * Search A/B Testing within Cache
12715 *
12716 * Created:January 2020
12717 *
12718 * A cookie is generated based on the value of the Bloomreach ID (BRUID),
12719 * this allows for the switching between different cached pages on the Akamai servers.
12720 *
12721 * For further information, please consult the following document,
12722 * "Search AB Testing Cache Implementation v_2_0.docx"
12723 */
12724
12725const PartsLength = 4;
12726const UidParts = 2;
12727const UidLength = 2;
12728const FullRange = 100;
12729
12730try {    
12731    var useCloudHeader = Next.Settings.Channel.EnableModernisedHeader;
12732    var isEnabled = (Next.Settings.Channel.BloomReachCachingEnabled && !useCloudHeader);
12733    var bruidCookie = readCookie(Next.Settings.Channel.BloomReachCachingIdentifier);
12734    var cookieJar = Next.Settings.Channel.BloomReachCachingCookieList.split(',');
12735    var cookieName = Next.Settings.Channel.BloomReachCachingCookieName;
12736    var numberOfDays = Next.Settings.Channel.BloomReachCachingCookieLifetime;
12737
12738    if (isEnabled && bruidCookie !== null && bruidCookie !== undefined && cookieJar !== null && cookieJar !== undefined && cookieJar.length > 1 && cookieName !== null && cookieName !== undefined && cookieName.length > 1) {
12739        
12740        var parts = decodeURIComponent(bruidCookie).split(':');
12741
12742        // Extract the Bloomreach user identifier (uid).
12743        if (parts !== null && parts !== undefined && parts.length == PartsLength) {
12744
12745            var uid = parts[0].split('=');
12746            if (uid !== null && uid !== undefined && uid.length == UidParts && uid[1].length > UidLength) {
12747                // Check the last 2 digits of the UID and select the appropriate cookie.
12748                var check = parseInt(uid[1].substr(uid[1].length - UidLength));
12749                var segment = Math.floor(FullRange / cookieJar.length);
12750                var index = Math.floor(check / segment);
12751
12752                if (index <= 0 || index >= cookieJar.length) index = 0;
12753
12754                createCookie(cookieName, cookieJar[index], numberOfDays, '');               
12755            }
12756
12757        }
12758    }
12759    else if (!useCloudHeader) {
12760        eraseCookie(cookieName);
12761    }
12762} catch (e) {
12763    console.log(e);
12764};
12765var GAFirebase;
12766(function (GAFirebase) {
12767    var GAFirebaseAnalytics = /** @class */ (function () {
12768        function GAFirebaseAnalytics() {
12769        }
12770        GAFirebaseAnalytics.prototype.ga = function (command, hitType, eventCategory, eventAction, eventLabel, eventValue, fieldsObject) {
12771            var win = window;
12772            if (win.AnalyticsWebInterface) {
12773                // Call Android interface
12774                if (typeof hitType === "string") {
12775                    win.AnalyticsWebInterface.logEvent(command, hitType, eventCategory, eventAction, eventLabel, eventValue, JSON.stringify(fieldsObject));
12776                }
12777                else {
12778                    win.AnalyticsWebInterface.logEvent(command, null, null, null, null, null, JSON.stringify(fieldsObject));
12779                }
12780            }
12781            else if (win.webkit
12782                && win.webkit.messageHandlers
12783                && win.webkit.messageHandlers.firebase) {
12784                // Call iOS interface
12785                if (typeof hitType === "string") {
12786                    var message = {
12787                        command: command,
12788                        hitType: hitType,
12789                        eventCategory: eventCategory,
12790                        eventAction: eventAction,
12791                        eventLabel: eventLabel,
12792                        eventValue: eventValue,
12793                        fieldsObject: fieldsObject
12794                    };
12795                    win.webkit.messageHandlers.firebase.postMessage(JSON.stringify(message));
12796                }
12797                else {
12798                    var altMessage = {
12799                        command: command,
12800                        fieldsObject: hitType
12801                    };
12802                    win.webkit.messageHandlers.firebase.postMessage(JSON.stringify(altMessage));
12803                }
12804            }
12805            else {
12806                ga(command, hitType, eventCategory, eventAction, eventLabel, eventValue, fieldsObject);
12807                console.log(ga.q);
12808            }
12809        };
12810        GAFirebaseAnalytics.prototype.push = function (gtmParams) {
12811            var win = window;
12812            if (win.AnalyticsWebInterface) {
12813                // Call Android interface
12814                win.AnalyticsWebInterface.push(JSON.stringify(gtmParams));
12815            }
12816            else if (win.webkit
12817                && win.webkit.messageHandlers
12818                && win.webkit.messageHandlers.firebase) {
12819                win.webkit.messageHandlers.firebase.postMessage(JSON.stringify(gtmParams));
12820            }
12821            else {
12822                if (win.dataLayer !== undefined) {
12823                    win.dataLayer.push(gtmParams);
12824                }
12825            }
12826        };
12827        GAFirebaseAnalytics.prototype.updateFirebasePushNotificationIdentifier = function (firebasePushNotificationIdentifier) {
12828            var win = window;
12829            if (win.AnalyticsWebInterface) {
12830                // Call Android interface
12831                win.AnalyticsWebInterface.updateFirebasePushNotificationIdentifier(firebasePushNotificationIdentifier);
12832            }
12833            else if (win.webkit
12834                && win.webkit.messageHandlers
12835                && win.webkit.messageHandlers.firebase) {
12836                var message = {
12837                    pushNotificationIdentifier: firebasePushNotificationIdentifier
12838                };
12839                win.webkit.messageHandlers.firebase.postMessage(JSON.stringify(message));
12840            }
12841            else {
12842            }
12843        };
12844        GAFirebaseAnalytics.prototype.updateLoginStatus = function (loginstatus) {
12845            var win = window;
12846            if (win.AnalyticsWebInterface) {
12847                // Call Android interface
12848                win.AnalyticsWebInterface.updateLoginStatus(loginstatus);
12849            }
12850            else if (win.webkit
12851                && win.webkit.messageHandlers
12852                && win.webkit.messageHandlers.firebase) {
12853                var message = {
12854                    LoginStatus: loginstatus
12855                };
12856                win.webkit.messageHandlers.firebase.postMessage(JSON.stringify(message));
12857            }
12858            else {
12859            }
12860        };
12861        GAFirebaseAnalytics.prototype.exponeaTrack = function (exponea, eventname, parameters) {
12862            var win = window;
12863            if (win.AnalyticsWebInterface) {
12864                // Call Android interface
12865                win.AnalyticsWebInterface.track(eventname, parameters);
12866            }
12867            else if (win.webkit
12868                && win.webkit.messageHandlers
12869                && win.webkit.messageHandlers.exponea) {
12870                var message = {
12871                    eventName: eventname,
12872                    eventParameters: parameters
12873                };
12874                win.webkit.messageHandlers.exponea.postMessage(JSON.stringify(message));
12875            }
12876            else {
12877                if (exponea !== undefined) {
12878                    exponea.track(eventname, parameters);
12879                }
12880            }
12881        };
12882        GAFirebaseAnalytics.prototype.exponeaIdentify = function (exponea, identifier) {
12883            var win = window;
12884            if (win.AnalyticsWebInterface) {
12885                // Call Android interface
12886                win.AnalyticsWebInterface.identify(identifier);
12887            }
12888            else if (win.webkit
12889                && win.webkit.messageHandlers
12890                && win.webkit.messageHandlers.exponea) {
12891                var message = {
12892                    eventName: 'identify',
12893                    eventParameters: identifier
12894                };
12895                win.webkit.messageHandlers.exponea.postMessage(JSON.stringify(message));
12896            }
12897            else if (exponea !== undefined) {
12898                exponea.identify('registered', identifier);
12899            }
12900        };
12901        GAFirebaseAnalytics.prototype.transferWebEventToApp = function (eventName, messageContent) {
12902            var win = window;
12903            if (win.AnalyticsWebInterface && win.AnalyticsWebInterface.transferWebEventToApp) {
12904                // Call Android interface
12905                win.AnalyticsWebInterface.transferWebEventToApp(eventName, JSON.stringify(messageContent));
12906            }
12907            else if (win.webkit
12908                && win.webkit.messageHandlers
12909                && win.webkit.messageHandlers.webEventBridge) {
12910                var message = {
12911                    eventName: eventName,
12912                    messageContent: JSON.stringify(messageContent)
12913                };
12914                win.webkit.messageHandlers.webEventBridge.postMessage(message);
12915            }
12916        };
12917        return GAFirebaseAnalytics;
12918    }());
12919    GAFirebase.GAFirebaseAnalytics = GAFirebaseAnalytics;
12920})(GAFirebase || (GAFirebase = {}));
12921var firebase = new GAFirebase.GAFirebaseAnalytics();
12922function firebaseEvent(event, category, id, name, value) {
12923    if (value === void 0) { value = 0; }
12924    if (firebase != undefined) {
12925        firebase.push({
12926            "event": event,
12927            "link_category": category,
12928            "link_id": id,
12929            "link_name": name,
12930            "link_value": value
12931        });
12932    }
12933}
12934//# sourceMappingURL=GAFirebase.js.map;

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.