1// requires jquery v1.8.2+ 2var Recommendations = { 3 4 settings: { 5 apiRoot: "" 6 }, 7 8 init: function (options) { 9 $.extend(this.settings, options); 10 11 if (this.settings.apiRoot) 12 this.settings.apiRoot = this.settings.apiRoot.replace(/\/+$/, ""); 13 }, 14 15 getRecommendations: function (options) { 16 var p = $.extend({ 17 siteCode: null, 18 zone: null, 19 productKey: null, 20 callback: null 21 }, options); 22 23 if (!p.siteCode || !p.zone || !p.callback) { 24 if (p.callback) 25 p.callback(null); 26 return; 27 } 28 var uniqueID = Recommendations.uniqueCustomerID(); 29 var url = this.settings.apiRoot + "/api/Recommendations/" + p.siteCode + "/" + p.zone + (p.productKey ? "/" + p.productKey : "") + (uniqueID ? "?uniqueCustomerID=" + uniqueID : ""); 30 31 this.util.ajax(url, null, p.callback); 32 }, 33 34 reportProductView : function(options){ 35 var p = $.extend({ 36 siteCode: null, 37 productKeys: [], 38 callback: null, 39 recID: null 40 }, options); 41 42 if (!p.siteCode || !p.productKeys || !Array.isArray(p.productKeys) || p.productKeys.length == 0) { 43 if (typeof p.callback === "function") 44 p.callback({ success: false }); 45 return; 46 } 47 48 var url = this.settings.apiRoot + "/api/ProductViewEvent"; 49 this.util.ajax(url, { siteCode: p.siteCode, productKeysCsv: p.productKeys.join(','), uniqueCustomerID: this.uniqueCustomerID(), recID: p.recID }, p.callback); 50 }, 51 52 reportAddToCart: function (options) { 53 var p = $.extend({ 54 siteCode: null, 55 productKeys: [], 56 callback: null, 57 recID: null 58 }, options); 59 60 if (!p.siteCode || !p.productKeys || !Array.isArray(p.productKeys) || p.productKeys.length == 0) { 61 if (typeof p.callback === "function") 62 p.callback({ success: false }); 63 return; 64 } 65 66 var url = this.settings.apiRoot + "/api/AddToCartEvent"; 67 this.util.ajax(url, { siteCode: p.siteCode, productKeysCsv: p.productKeys.join(','), uniqueCustomerID: this.uniqueCustomerID(), recID: p.recID }, p.callback); 68 }, 69 70 reportPurchase: function (options) { 71 var p = $.extend({ 72 siteCode: null, 73 orderItems: [], 74 orderID: null, 75 callback: null 76 }, options); 77 78 if (!p.siteCode || !p.orderID || !Array.isArray(p.orderItems) || p.orderItems.length == 0) { 79 if (typeof p.callback === "function") 80 p.callback({ success: false }); 81 return; 82 } 83 84 var url = this.settings.apiRoot + "/api/PurchaseEvent"; 85 86 this.util.ajax(url, { siteCode: p.siteCode, items: p.orderItems, uniqueCustomerID: this.uniqueCustomerID(), orderID: p.orderID }, p.callback); 87 }, 88 89 reportUserLogin: function (options) { 90 var p = $.extend({ 91 siteCode: null, 92 userID: null, 93 callback: null 94 }, options); 95 96 if (!p.siteCode || !p.userID) { 97 if (typeof p.callback === "function") 98 p.callback({ success: false }); 99 return; 100 } 101 102 var url = this.settings.apiRoot + "/api/UserLoginEvent"; 103 104 this.util.ajax(url, { siteCode: p.siteCode, uniqueCustomerID: this.uniqueCustomerID(), userID: p.userID }, p.callback); 105 }, 106 107 uniqueCustomerID: function (uniqueID) { 108 if (uniqueID === undefined) 109 return Storage.get("__RecUniqueID"); 110 var expires = new Date(); 111 expires.setFullYear(expires.getFullYear() + 1); 112 Storage.set("__RecUniqueID", uniqueID, expires); 113 }, 114 115 util: { 116 ajax: function (url, data, callback, errorCallback) { 117 $.ajax({
118 data: data, 119 url: url, 120 timeout: 8000, 121 dataType: "jsonp", 122 crossDomain: true, 123 tryCount: 0, 124 retryLimit: 2, 125 success: this.standardCallback(callback), 126 error: this.jsonpErrorCallback(errorCallback) 127 }); 128 }, 129 130 standardCallback: function(callback){ 131 return function (data, textStatus) { 132 if (data && data.uniqueCustomerID) 133 Recommendations.uniqueCustomerID(data.uniqueCustomerID); 134 135 if (typeof callback === "function") 136 callback(data); 137 }; 138 }, 139 140 jsonpErrorCallback: function (callback) { 141 return callback || function (data, textStatus, errorThrown) { 142 if (typeof(console) != "undefined") { 143 console.log(textStatus, errorThrown); 144 if(errorThrown == 'timeout') { 145 this.tryCount++; 146 if (this.tryCount <= this.retryLimit) { 147 console.log("Retry #"+this.tryCount); 148 this.context = undefined; 149 $.ajax(this); 150 return; 151 } else { 152 console.log('Retry limit exceeded.'); 153 } 154 } 155 } 156 }; 157 } 158 } 159}; 160 161//Object that stores in localStorage, falling back to cookies when localStorage is unavailable. 162var Storage = { 163 hasLocalStorage: function () { 164 //Stolen from Modernizr 165 try { 166 localStorage.setItem('__test_ls__', '__test_ls__'); 167 localStorage.removeItem('__test_ls__'); 168 return true; 169 } catch (e) { 170 return false; 171 } 172 }, 173 174 get: function (key) { 175 if (this.hasLocalStorage()) { 176 return this.LocalStorage.getItem(key); 177 } 178 return this.Cookies.getItem(key); 179 }, 180 181 set: function (key, value, expires) { 182 if (this.hasLocalStorage(key)) { 183 this.LocalStorage.setItem(key, value, expires); 184 return; 185 } 186 this.Cookies.setItem(key, value, expires); 187 }, 188 189 LocalStorage:{ 190 getItem: function (key) { 191 var value = localStorage.getItem(key); 192 if (value === null || value === undefined) return null; 193 194 var expires = localStorage.getItem(key + "_exp"); 195 if (expires !== null && expires !== undefined) { 196 var date = new Date(expires); 197 if (date <= new Date()) { 198 localStorage.removeItem(key); 199 return null 200 } 201 } 202 203 return value; 204 }, 205 206 setItem: function(key, value, expires){ 207 localStorage.setItem(key, value); 208 if (expires !== null && expires !== undefined) { 209 localStorage.setItem(key + "_exp", expires.toString()); 210 } 211 } 212 }, 213 214 //https://developer.mozilla.org/en-US/docs/Web/API/document.cookie 215 Cookies: { 216 getItem: function (sKey) { 217 return decodeURI(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURI(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; 218 }, 219 220 setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { 221 if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } 222 var sExpires = ""; 223 if (vEnd) { 224 switch (vEnd.constructor) { 225 case Number: 226 sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; 227 break; 228 case String: 229 sExpires = "; expires=" + vEnd; 230 break; 231 case Date: 232 sExpires = "; expires=" + vEnd.toUTCString(); 233 break; 234 } 235 } 236 document.cookie = encodeURI(sKey) + "=" + encodeURI(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); 237 return true; 238 }, 239 240 removeItem: function (sKey, sPath, sDomain) { 241 if (!sKey || !this.hasItem(sKey)) { return false; } 242 document.cookie = encodeURI(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : ""); 243 return true; 244 }, 245 246 hasItem: function (sKey) { 247 return (new RegExp("(?:^|;\\s*)" + encodeURI(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); 248 }, 249 250 keys: /* optional method: you can safely remove it! */ function () { 251 var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); 252 for (var nIdx = 0; nIdx < aKeys.length; nIdx++) { aKeys[nIdx] = decodeURI(aKeys[nIdx]); } 253 return aKeys; 254 } 255 } 256 257};
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.