1/* Minification failed. Returning unminified contents. 2(2418,36-37): run-time error JS1003: Expected ':': , 3(2418,48-49): run-time error JS1003: Expected ':': , 4(2418,61-62): run-time error JS1003: Expected ':': } 5(2620,40-41): run-time error JS1195: Expected expression: ) 6(2620,43-44): run-time error JS1195: Expected expression: > 7(2622,22-23): run-time error JS1195: Expected expression: , 8(2622,28-29): run-time error JS1003: Expected ':': ) 9(2623,17-18): run-time error JS1002: Syntax error: } 10(2625,72-73): run-time error JS1004: Expected ';': { 11(2632,18-19): run-time error JS1195: Expected expression: ) 12(2634,72-73): run-time error JS1004: Expected ';': { 13(2638,18-19): run-time error JS1195: Expected expression: ) 14(2647,62-63): run-time error JS1004: Expected ';': { 15(2689,17-18): run-time error JS1028: Expected identifier or string: . 16(2689,19-20): run-time error JS1010: Expected identifier: . 17(2690,25-26): run-time error JS1004: Expected ';': : 18(2690,64-65): run-time error JS1197: Too many errors. The file might not be a JavaScript file: , 19(2664,5-44): run-time error JS1301: End of file encountered before function is properly closed: function eventTrack(action, properties) 20(2691,14-15): run-time error JS1195: Expected expression: ) 21(2691,15-16): run-time error JS1197: Too many errors. The file might not be a JavaScript file: ; 22 */ 23/* Minification failed. Returning unminified contents. 24(2396,36-37): run-time error JS1003: Expected ':': , 25(2396,48-49): run-time error JS1003: Expected ':': , 26(2396,61-62): run-time error JS1003: Expected ':': } 27(2598,40-41): run-time error JS1195: Expected expression: ) 28(2598,43-44): run-time error JS1195: Expected expression: > 29(2600,22-23): run-time error JS1195: Expected expression: , 30(2600,28-29): run-time error JS1003: Expected ':': ) 31(2601,17-18): run-time error JS1002: Syntax error: } 32(2603,72-73): run-time error JS1004: Expected ';': { 33(2610,18-19): run-time error JS1195: Expected expression: ) 34(2612,72-73): run-time error JS1004: Expected ';': { 35(2616,18-19): run-time error JS1195: Expected expression: ) 36(2625,62-63): run-time error JS1004: Expected ';': { 37(2667,17-18): run-time error JS1028: Expected identifier or string: . 38(2667,19-20): run-time error JS1010: Expected identifier: . 39(2668,25-26): run-time error JS1004: Expected ';': : 40(2668,64-65): run-time error JS1197: Too many errors. The file might not be a JavaScript file: , 41(2642,5-44): run-time error JS1301: End of file encountered before function is properly closed: function eventTrack(action, properties) 42(2669,14-15): run-time error JS1195: Expected expression: ) 43(2669,15-16): run-time error JS1197: Too many errors. The file might not be a JavaScript file: ; 44 */ 45(function () { 46 'use strict'; 47 angular.module( 48 'Lexus', [ 49 'Lexus.Directives', 50 'Lexus.Components', 51 'Lexus.Factories', 52 'Lexus.Services', 53 'Lexus.Filters', 54 'ngTouch', 55 'ngCookies', 56 'ngSanitize', 57 'ngAnimate', 58 'ngTagsInput', 59 'ng-directives-utils.transcludeReplace', 60 'vcRecaptcha', 61 '720kb.datepicker', 62 'ngRoute', 63 'ngDialog', 64 'angularCancelOnNavigateModule', 65 'angulartics', 66 'Lexus.angulartics', 67 'angulartics.debug', 68 'duParallax' 69 70 ]); 71 72 // Namespaces 73 angular.module('Lexus.Directives', []); 74 angular.module('Lexus.Factories', []); 75 angular.module('Lexus.Services', []); 76 angular.module('Lexus.Filters', []); 77 angular.module('Lexus.Components', []); 78})(); 79; 80"use strict"; 81 82angular.module('Lexus.Filters', []) 83.filter('formatArgs', [function () { // pass url and array of arguments. 84 return function (url, args) { 85 86 var urlReplacers = url.match(/\{[0-9]+\}/g); 87 var replaced = 0; 88 // Loop through arguments and replace url value. 89 angular.forEach(args, function (value, key) { 90 url = url.replace("{" + key + "}", value); 91 replaced++; 92 }); 93 //strips off the unused replacers from URL 94 if (urlReplacers.length > replaced) { 95 for (var _t = replaced; _t < urlReplacers.length; _t++) { 96 url = url.replace("/{" + _t + "}", ''); 97 } 98 } 99 100 return url; 101 }; 102}]) 103.filter('format', [function () { 104 return function (value, template) { 105 return template.replace('{0}', value); 106 } 107}]) 108.filter('replaceCaseInsensitive', [function () { 109 return function (value, substringValue) { 110 if (typeof (value) != "string") return value; 111 112 var r = new RegExp(substringValue, "i"); 113 return value.replace(r, ""); 114 } 115}]) 116.filter('sanatize', [function () { // Remove certain characters from variable. 117 return function (value) { 118 if (value !== null) { 119 return value.replace(/[^a-z0-9.\-@\s\/\'\&\u2019\u004
1191-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]+/gi, ''); 120 } 121 }; 122}]) 123.filter('lowerCaseFirstLetter', function () { 124 return function (input) { 125 return (!!input) ? input.charAt(0).toLowerCase() + input.substr(1) : ''; 126 } 127}) 128.filter('currencyNoZero', ['$filter', function ($filter) { 129 return function (input) { 130 return (parseInt(input) === 0) ? '' : $filter('currency')(input); 131 } 132}]) 133.filter('currencyNoZeroNoCents', ['$filter', function ($filter) { 134 return function (input) { 135 return (parseInt(input) === 0) ? '' : $filter('currency')(input, undefined, 0); 136 } 137}]) 138.filter('currencyRounded', ['$filter', function ($filter) { 139 return function (input) { 140 return $filter('currency')(Math.round(input)); 141 } 142}]) 143.filter('dateToBE', ['$filter', function ($filter) { // Format FE date for BE. 144 return function (value, format) { 145 if (angular.isDefined(value) && !angular.equals(value, '')) { 146 var date = moment(value, format); 147 148 return { 149 day: date.format('D'), 150 month: date.format('M'), 151 year: date.format('YYYY'), 152 fullDate: date.format('YYYY-M-D') 153 }; 154 } else { 155 return { 156 day: '', 157 month: '', 158 year: '', 159 fullDate: '' 160 }; 161 } 162 }; 163}]) 164.filter('dateToUniversal', ['$filter', function ($filter) { // Format BE date for FE. 165 return function (value) { 166 if (angular.isDefined(value) && !angular.equals(value, '')) { 167 var date = moment(value, 'YYYY-MM-DD'); 168 169 return date.unix(); 170 } else { 171 return ''; 172 } 173 }; 174}]) 175.filter('filterLower', function () { 176 return function (array, value) { 177 return array.filter(function (element, index, array) { 178 if (element.rating <= value.rating) { 179 return element; 180 } 181 }); 182 }; 183}) 184.filter('filterHigher', function () { 185 return function (array, value) { 186 return array.filter(function (element, index, array) { 187 if (element.rating >= value.rating) { 188 return element; 189 } 190 }); 191 }; 192}) 193.filter('removeSpaces', function () { 194 return function (text) { 195 return String(text).replace(/\s+/g, ''); 196 } 197}) 198.provider('filterWatcher', function() { 199 200 this.$get = ['$window', '$rootScope', function($window, $rootScope) { 201 202 /** 203 * Cache storing 204 * @type {Object} 205 */ 206 var $$cache = {}; 207 208 /** 209 * Scope listeners container 210 * scope.$destroy => remove all cache keys 211 * bind to current scope. 212 * @type {Object} 213 */ 214 var $$listeners = {}; 215 216 /** 217 * $timeout without triggering the digest cycle 218 * @type {function} 219 */ 220 var $$timeout = $window.setTimeout; 221 222 /**
223 * @description 224 * get `HashKey` string based on the given arguments. 225 * @param fName 226 * @param args 227 * @returns {string} 228 */ 229 function getHashKey(fName, args) { 230 function replacerFactory() { 231 var cache = []; 232 return function(key, val) { 233 if (angular.isObject(val) && !(val==null)) { 234 if (~cache.indexOf(val)) return '[Circular]'; 235 cache.push(val) 236 } 237 if($window == val) return '$WINDOW'; 238 if($window.document == val) return '$DOCUMENT'; 239 if (val && val.$evalAsync && val.$watch) return '$SCOPE'; 240 return val; 241 } 242 } 243 return [fName, JSON.stringify(args, replacerFactory())] 244 .join('#') 245 .replace(/"/g,''); 246 } 247 248 /** 249 * @description 250 * fir on $scope.$destroy, 251 * remove cache based scope from `$$cache`, 252 * and remove itself from `$$listeners` 253 * @param event 254 */ 255 function removeCache(event) { 256 var id = event.targetScope.$id; 257 forEach($$listeners[id], function(key) { 258 delete $$cache[key]; 259 }); 260 delete $$listeners[id]; 261 } 262 263 /** 264 * @description 265 * for angular version that greater than v.1.3.0 266 * it clear cache when the digest cycle is end. 267 */ 268 function cleanStateless() { 269 $$timeout(function() { 270 if(!$rootScope.$$phase) 271 $$cache = {}; 272 }, 2000); 273 } 274 275 /** 276 * @description 277 * Store hashKeys in $$listeners container 278 * on scope.$destroy, remove them all(bind an event). 279 * @param scope 280 * @param hashKey 281 * @returns {*} 282 */ 283 function addListener(scope, hashKey) { 284 var id = scope.$id; 285 if (angular.isUndefined($$listeners[id])) { 286 scope.$on('$destroy', removeCache); 287 $$listeners[id] = []; 288 } 289 return $$listeners[id].push(hashKey); 290 } 291 292 /** 293 * @description 294 * return the `cacheKey` or undefined. 295 * @param filterName 296 * @param args 297 * @returns {*} 298 */ 299 function $$isMemoized(filterName, args) { 300 var hashKey = getHashKey(filterName, args); 301 return $$cache[hashKey]; 302 } 303 304 /** 305 * @description 306 * store `result` in `$$cache` container, based on the hashKey. 307 * add $destroy listener and return result 308 * @param filterName 309 * @param args 310 * @param scope 311 * @param result 312 * @returns {*} 313 */ 314 function $$memoize(filterName, args, scope, result) { 315 var hashKey = getHashKey(filterName, args); 316 //store result in `$$cache` container 317 $$cache[hashKey] = result; 318 // for angular versions that less than 1.3 319 // add to `$destroy` listener, a cleaner callback 320 if(scope && scope.$evalAsync && scope.$watch) { 321 addListener(scope, hashKey); 322 } else { 323 cleanStateless(); 324 } 325 return result; 326 } 327 328 return { 329 isMemoized: $$isMemoized, 330 memoize: $$memoize 331 } 332 }]; 333 }) 334.filter('groupBy', [ '$parse', 'filterWatcher', function ( $parse, filterWatcher ) { 335 return function (collection, property) { 336 337 if (!angular.isObject(collection) || angular.isUndefined(property)) { 338 return collection; 339 } 340 341 return filterWatcher.isMemoized('groupBy', arguments) || 342 filterWatcher.memoize('groupBy', arguments, this, 343 _groupBy(collection, $parse(property))); 344 345 /** 346 * groupBy function 347 * @param collection 348 * @param getter 349 * @returns {{}} 350 */ 351 function _groupBy(collection, getter) { 352 var result = {}; 353 var prop; 354 355 angular.forEach( collection, function( elm ) { 356 prop = getter(elm); 357 358 if(!result[prop]) { 359 result[prop] = []; 360 } 361 result[prop].push(elm); 362 }); 363 return result; 364 } 365 } 366}]); 367; 368"use strict"; 369angular.module('Lexus.Factories') 370.factory('API', ['$http', '$q', function ($http, $q) { // Query API and return JSON. 371 return { 372 get: function (url,callback) { 373 var deferred = $q.defer(); 374 375 $http({ method: 'GET', url: url }). 376 then(function success(response) { 377 if (callback) { 378 callback(); 379 } 380 if (response.data.ErrorMessage) { 381 deferred.reject(response.data, 200); 382 } else { 383 deferred.resolve(response.data); 384 } 385 }, function error(response) { 386 var myresult = { reason: response.data, status: response.status, ErrorMessage: response.statusText }; 387 deferred.reject(myresult); 388 }); 389 390 return deferred.promise; 391 }, 392 post: function (url, data) { 393 var deferred = $q.defer(); 394 395 $http({ method: 'POST', url: url, data: data }). 396 then(function success(response) { 397 if (response.data.ErrorMessage) { 398 deferred.reject(response.data, 200); 399 } else { 400 deferred.resolve(response.data); 401 } 402 }, function (response) { 403 var myresult = { reason: response.data, status: response.status, ErrorMessage: response.statusText }; 404 deferred.reject(myresult); 405 }); 406 407 return deferred.promise; 408 }, 409 del: function (url, callback) { 410 var deferred = $q.defer(); 411 412 $http({ method: 'DELETE', url: url }). 413 then(function success(response) { 414 if (callback) { 415 callback(); 416 } 417 if (response.data.ErrorMessage) { 418 deferred.reject(response.data, 200); 419 } else { 420 deferred.resolve(response.data); 421 } 422 }, function error(response) { 423 var myresult = { reason: response.data, status: response.status, ErrorMessage: response.statusText }; 424 deferred.reject(myresult); 425 }); 426 427 return deferred.promise; 428 } 429 }; 430}]);; 431"use strict"; 432angular.module('angularCancelOnNavigateModule', []) 433 .config(['$httpProvider', function ($httpProvider) { 434 $httpProvider.interceptors.push('HttpRequestTimeoutInterceptor'); 435 }]) 436 .run(['$rootScope', 'HttpPendingRequestsService', function ($rootScope, HttpPendingRequestsService) { 437 //$rootScope.$on('$locationChangeSuccess', function (event, newUrl, oldUrl) { 438 // if (newUrl != oldUrl) { 439 // HttpPendingRequestsService.cancelAll(); 440 // } 441 //}) 442 }]); 443 444angular.module('angularCancelOnNavigateModule') 445 .service('HttpPendingRequestsService',['$q', function ($q) { 446 var cancelPromises = []; 447 448 function newTimeout() { 449 var cancelPromise = $q.defer(); 450 cancelPromises.push(cancelPromise); 451 //console.log('%c HttpPendingRequestsService newTimeout() -> cancelPromises: ', 'color: red;', cancelPromises); 452 return cancelPromise.promise; 453 } 454 455 function cancelAll() { 456 console.log('%c HttpPendingRequestsService cancelAll() -> cancelPromises: ', 'color: red;', cancelPromises); 457 angular.forEach(cancelPromises, function (cancelPromise) { 458 cancelPromise.promise.isGloballyCancelled = true; 459 cancelPromise.resolve(); 460 }); 461 cancelPromises.length = 0; 462 } 463 464 return { 465 newTimeout: newTimeout, 466 cancelAll: cancelAll 467 }; 468 }]); 469 470angular.module('angularCancelOnNavigateModule') 471 .factory('HttpRequestTimeoutInterceptor',['$q', 'HttpPendingRequestsService', function ($q, HttpPendingRequestsService) { 472 return { 473 request: function (config) { 474 config = config || {}; 475 if (config.timeout === undefined && !config.noCancelOnRouteChange) { 476 config.timeout = HttpPendingRequestsService.newTimeout(); 477 } 478 return config; 479 }, 480 481 responseError: function (response) { 482 if (response.config.timeout.isGloballyCancelled) { 483 return $q.defer().promise; 484 } 485 return $q.reject(response); 486 } 487 }; 488 }]);; 489"use strict"; 490 491angular.module('Lexus.Factories') 492 .factory('Geolocation', ['$q', '$rootScope', function ($q, $rootScope) { 493 return function () { 494 495 var deferred = $q.defer(); 496 var geoLocServiceExists = 'geolocation' in navigator; 497 var timeout; 498 499 var defOptions = { 500 timeout: 8000 501 }; 502 503 if (geoLocServiceExists) { 504 //success 505 var geoOnSuccess = function (position) { 506 if (position) { 507 window.clearTimeout(timeout); 508 deferred.resolve({ 509 "lat": position.coords.latitude, 510 "lng": position.coords.longitude, 511 "success": true, 512 "message": "pass" 513 }); 514 } 515 }; 516 //error 517 var geoOnError = function (error) { 518 window.clearTimeout(timeout); 519 deferred.reject({ 520 "success": false, 521 "error": error, 522 "message": error 523 }, 200); 524 }; 525 526 // start timer. See firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=675533 527 // this will force a failure notice after the above configured timeout, as firefox will 528 // never give us the error 529 timeout = window.setTimeout(geoOnError, defOptions.timeout); 530 531 //getPosition call 532 navigator.geolocation.getCurrentPosition(geoOnSuccess, geoOnError, defOptions); 533 534 // when opening the modal, stop attempting to get the location 535 $rootScope.$on('modal-open', function () { 536 window.clearTimeout(timeout); 537 }); 538 } 539 else { 540 deferred.reject({ 541 "success": false, 542 "message": "geoLocation is not supported" 543 }); 544 } 545 546 return deferred.promise; 547 } 548 }]);; 549"use strict"; 550 551angular.module('Lexus.Factories') 552 .factory('Geodecode', ['$q', '$filter', 'API', 'Geolocation', function ($q, $filter, API, Geolocation) { 553 return function () { 554 555 556 var geodeferred = $q.defer(); 557 558 var response = { 559 isSuccessfull: false, 560 data: {}, 561 message: '' 562 }; 563 564 var addressParse = {}; 565 566 var onSuccess = function (geoData) { 567 if (geoData && geoData.success) { 568 var addressDecode = $filter('formatArgs')(Lexus.API.Address.GeoDecode, [Lexus.ID.Site, geoData.lat, geoData.lng]); 569 570 API.get(addressDecode).then(function (req) { 571 572 $.each(req.Data.results, function (i, item) { 573 if (item.types[0] === "postal_code") { 574 addressParse.postcode = item.address_components[0].short_name; 575 } 576 if (item.types[0] === "locality") { 577 addressParse.suburb = item.address_components[0].short_name; 578 } 579 if (item.types[0] === "administrative_area_level_1") { 580 addressParse.state = item.address_components[0].short_name; 581 } 582 }); 583 584 response.isSuccessfull = true; 585 response.data = addressParse; 586 587 geodeferred.resolve(response); 588 589 }, function (data) { 590 response.message = "failed to get the parsed address"; 591 geodeferred.reject(response); 592 }); 593 } 594 else { 595 response.message = "failed to get the co-ordinates from geolocation service"; 596 geodeferred.reject(response); 597 } 598 }; 599 600 var onError = function (data) { 601 response.message = (data) ? data.message : "geo service unavailable"; 602 geodeferred.reject(response); 603 }; 604 605 //Invoke Geolocation service 606 var _g = Geolocation(); 607 _g.then(onSuccess, onError); 608 609 return geodeferred.promise; 610 } 611 }]);; 612"use strict"; 613 614angular.module('Lexus.Services') 615.service('AddressSuggestService', ['$timeout', '$http', 'API', '$filter', function ($timeout, $http, API, $filter) { 616 var self = this; 617 var params = {}; 618 619 params.defaults = { 620 siteID: Lexus.ID.Site, 621 term: null 622 }; 623 624 params.params = { 625 siteID: params.defaults.siteID, 626 term: params.defaults.term 627 }; 628 629 self.GetResults = function (callback) { 630 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.Suburb, [ 631 params.params.siteID, 632 params.params.term 633 ]); 634 635 return API.get(params.params.searchQueryUrl, callback); 636 } 637 638 // Update a search parameter. 639 self.setParam = function (name, value) { 640 params.params[name] = value; 641 }; 642 643 // Get a parameter value 644 self.getParam = function (name) { 645 return params.params[name]; 646 }; 647 648 649 return self; 650}]);; 651"use strict"; 652 653angular.module('Lexus.Services') 654.factory('BuildPriceService', ['$q', '$timeout', 'BuildPriceAPIService', function ($q, $timeout, BuildPriceAPIService) { 655 var self = this; 656 657 self.events = { 658 pageNavigation: 'bp-page-navigation', 659 pageNavigationBroadcast: 'bp-page-navigation-broadcast', 660 openPostcodeDialog: 'open-change-postcode', 661 closePostcodeDialog: 'close-change-postcode', 662 postcodeChanged: 'postcode-changed', 663 openPostcodeSlideout: 'open-postcode-slideout', 664 confirmPostcodeFromSlideout: 'confirm-postcode-slideout', 665 666 overviewDataReceived: 'bp-overview-data-received', 667 vehicleDataReceived: 'bp-vehicle-data', 668 enhancementPacksReceived: 'bp-enhancement-pack-data', 669 trimsReceived: 'bp-trim-data', 670 paintsReceived: 'bp-colour-data', 671 672 modelSelected: 'bp-did-select-model', 673 modelSelectedUpdateMenu: 'bp-did-select-model-update-menu', 674 engineVariantSelected: 'bp-did-select-engine-variant',
675 gradeSelected: 'bp-did-select-grade', 676 enhancementPackSelected: 'bp-did-select-enhancement-pack', 677 paintSelected: 'bp-did-select-paint', 678 trimSelected: 'bp-did-select-trim', 679 680 threeSixtyLoad: 'bp-did-360-start', 681 threeSixtyLoaded: 'bp-did-360-done', 682 683 userSelection: 'bp-user-selection', 684 685 priceLoad: 'bp-did-price-start', 686 priceDone: 'bp-did-price-done', 687 priceReceived: 'bp-did-price-succeed', 688 priceError: 'bp-did-price-error', 689 690 onOfferText: 'bp-on-offer-text', 691 692 vehicleDataRelay: 'bp-vehicle-relay', 693 paintDataRelay: 'bp-paint-relay', 694 invalidSelectionError: 'bp-invalid-selection', 695 696 holdPricingCalls: 'bp-hold-pricing-calls', 697 holdPricingCallsRelay: 'bp-hold-pricing-calls-relay', 698 699 gtmEvent: 'bp-gtm-event', 700 onCompareVehicles: 'cv-on-compare-vehicles', 701 compareVehicleActiveSelection: 'cv-vehicle-active-selection', 702 703 triggerSaveBuildPriceDialog: 'trigger-save-build-price', 704 triggerCloseSaveBuildPriceDialog: 'trigger-close-save-build-price', 705 closeSaveBuildPriceDialog: 'close-save-build-price', 706 openSaveBuildPriceDialog: 'open-save-build-price', 707 }; 708 709 self.findModelInVehicleData = function (modelName) { 710 var modelObj; 711 for (var btIdx in BuildPriceAPIService.data) { 712 modelObj = BuildPriceAPIService.data[btIdx].models.find(function (model) { 713 return model.uriName === modelName; 714 }); 715 if (modelObj) { 716 return modelObj; 717 } 718 } 719 }; 720 721 //Remove soon, moved to bp-api 722 self.findEngineVariantInVehicleData = function (variantName) { 723 for (var btIdx in BuildPriceAPIService.data) { 724 for (var mdlIdx in BuildPriceAPIService.data[btIdx].models) { 725 var engineVariantObj = BuildPriceAPIService.data[btIdx].models[mdlIdx].modelEngineVariants.find(function (variant) { 726 return variant.uriName === variantName; 727 }); 728 if (engineVariantObj) { 729 return engineVariantObj; 730 } 731 } 732 } 733 734 return { 735 grades: [] 736 }; 737 }; 738 739 self.findGradeInVehicleData = function (gradeId) { 740 var gradeObj; 741 for (var btIdx in BuildPriceAPIService.data) { 742 for (var mdlIdx in BuildPriceAPIService.data[btIdx].models) { 743 for (var varIdx in BuildPriceAPIService.data[btIdx].models[mdlIdx].modelEngineVariants) { 744 gradeObj = BuildPriceAPIService.data[btIdx].models[mdlIdx].modelEngineVariants[varIdx].grades.find(function (grade) { 745 return grade.id === gradeId; 746 }); 747 if (gradeObj) { 748 return gradeObj; 749 } 750 } 751 } 752 } 753 }; 754 755 self.waitCondition = { 756 CHANGED: 0, 757 NOTNULL: 1, 758 ISNULL: 2, 759 NOTEMPTY: 3, 760 ISTRUE: 4, 761 ISSTRICTLYTRUE: 5, 762 ISFALSE: 6, 763 ISSTRICTLYFALSE: 7 764 }; 765 766 self.stepIds = { 767 MODEL: "MODEL", 768 GRADE: "GRADE", 769 ENHANCEMENT_PACK: "ENHANCEMENT_PACK", 770 PAINT_TRIM: "PAINT_TRIM", 771 SUMMARY: "SUMMARY" 772 }; 773 774 self.routingSettings = { 775 baseUrl: '', 776 argIdx: ['carmodel', 'engineVariant', 'grade', 'enhancementPack', 'colour', 'trim'] 777 }; 778 779 self.waitFor = function (target, waitCondition) { 780 var defer = $q.defer(); 781 782 var currentValue = eval("this." + target); 783 if ((waitCondition === self.waitCondition.NOTNULL && currentValue != null 784 || waitCondition === self.waitCondition.ISNULL && currentValue == null)) { 785 defer.resolve(currentValue); 786 } 787 788 var unbind = this.$watch(target, function (newValue, oldValue) { 789 switch (waitCondition) { 790 case self.waitCondition.CHANGED: 791 unbind(); 792 defer.resolve(newValue); 793 break; 794 case self.waitCondition.NOTNULL: 795 if (newValue != null) { 796 unbind(); 797 defer.resolve(newValue); 798 } 799 break; 800 case self.waitCondition.ISNULL: 801 if (newValue == null) { 802 unbind(); 803 defer.resolve(newValue); 804 } 805 break; 806 case self.waitCondition.NOTEMPTY: 807 if (newValue != null && newValue.length != null && newValue.length > 0) { 808 unbind(); 809 defer.resolve(newValue); 810 } 811 break; 812 case self.waitCondition.ISTRUE: 813 if (newValue == true) { 814 unbind(); 815 defer.resolve(newValue); 816 } 817 break; 818 case self.waitCondition.ISSTRICTLYTRUE: 819 if (newValue === true) { 820 unbind(); 821 defer.resolve(newValue); 822 } 823 break; 824 case self.waitCondition.ISFALSE: 825 if (newValue == false) { 826 unbind(); 827 defer.resolve(newValue); 828 } 829 break; 830 case self.waitCondition.ISSTRICTLYFALSE: 7 831 if (newValue === false) { 832 unbind(); 833 defer.resolve(newValue); 834 } 835 break; 836 default: 837 unbind(); 838 defer.reject(); 839 } 840 }); 841 842 return defer.promise 843 } 844 845 self.watchDebounce = function(func, wait, immediate) { 846 var timeout; 847 848 var deferred = $q.defer(); 849 850 return function () { 851 var context = this, args = arguments; 852 var later = function () { 853 timeout = null; 854 if (!immediate) {
855 deferred.resolve(func.apply(context, args)); 856 deferred = $q.defer(); 857 } 858 }; 859 var callNow = immediate && !timeout; 860 if (timeout) { 861 $timeout.cancel(timeout); 862 } 863 timeout = $timeout(later, wait); 864 if (callNow) { 865 deferred.resolve(func.apply(context, args)); 866 deferred = $q.defer(); 867 } 868 return deferred.promise; 869 }; 870 } 871 872 self.getGradeNameFromId = function (gradeId) { 873 var grade = self.findGradeInVehicleData(gradeId); 874 return grade ? grade.name : "Unknown"; 875 } 876 877 self.getColourFromUri = function (colours, colour) { 878 return colours.find(function (currentColour) { 879 return currentColour.uriName == colour; 880 }); 881 882 } 883 884 self.emitInvalidSelection = function (invalidSelectionData) { 885 886 console.error("Specification validation failed in " + (invalidSelectionData.controllerName ? invalidSelectionData.controllerName : "scope id " + invalidSelectionData.$scope.$id) + ": '" + invalidSelectionData.invalidValue + "' - value defaulted to '" + invalidSelectionData.defaultValue + "'"); 887 invalidSelectionData.$scope.$emit(self.events.invalidSelectionError, invalidSelectionData); 888 } 889 890 self.fragmentReplacementMap = [ 891 //orig-regex, orig-replacement, reverse-regex, reverse-replacement 892 [/-/g, "_", /_/g, "-"], 893 [/\s/g, "-", /-/g, " "], 894 [/\//g, "~", /~/g, "/"] 895 ]; 896 897 self.pathReplacementMap = [ 898 [/\/+/g, "/"] 899 ]; 900 901 //Makes replacements in the fragmentReplacementMap 902 self.encodeUriFragment = function (pathFragment) { 903 if (pathFragment == null) return; 904 for (var i = 0; i < self.fragmentReplacementMap.length; i++) { 905 pathFragment = pathFragment.replace(self.fragmentReplacementMap[i][0], self.fragmentReplacementMap[i][1]); 906 } 907 return pathFragment 908 } 909 910 self.decodeUriFragment = function (pathFragment) { 911 if (pathFragment == null) return; 912 for (var i = self.fragmentReplacementMap.length - 1; i >= 0; i--) { 913 pathFragment = pathFragment.replace(self.fragmentReplacementMap[i][2], self.fragmentReplacementMap[i][3]); 914 } 915 return pathFragment; 916 } 917 918 //Makes replacements in the pathReplacementMap 919 self.encodeUriPath = function (path) { 920 if (path == null) return; 921 for (var i = 0; i < self.pathReplacementMap.length; i++) { 922 path = path.replace(self.pathReplacementMap[i][0], self.pathReplacementMap[i][1]); 923 } 924 return path; 925 } 926 927 //Vehicle structure in the format 928 /* 929 vehicle: { 930 carmodel: 'CT', 931 engineVariant: 'CT 200', 932 grade: '', 933 postcode: '3000', 934 enhancementPack: 'Standard', 935 colour: '', 936 trim: '' 937 } 938 */ 939 self.getBuildPriceLink = function (vehicle, step) { 940 941 var url = (vehicle.carmodel) ? self.encodeUriFragment(vehicle.carmodel) : ""; 942 url = url + "/"; 943 944 if (vehicle.engineVariant) { 945 946 url = url + self.encodeUriFragment(vehicle.engineVariant) + "/"; 947 if (vehicle.grade) { 948 url = url + self.encodeUriFragment(vehicle.grade) + "/"; 949 950 if (vehicle.enhancementPack) { 951 url = url + vehicle.enhancementPack + "/"; 952 953 if (vehicle.colour) { 954 url = url + self.encodeUriFragment(vehicle.colour) + "/"; 955 } 956 957 if (vehicle.trim) { 958 url = url + self.encodeUriFragment(vehicle.trim) + "/"; 959 960 if (step) { 961 url = url + "/" + step + "#lx-bp-nav"; 962 } 963 } 964 } 965 } 966 } 967 968 var path = self.encodeUriPath(url); 969 970 return path; 971 } 972 973 return self; 974}]);; 975"use strict"; 976 977angular.module('Lexus.Services') 978.factory('BuildPriceAPIService', ['$q', '$timeout', 'VehicleService', function ($q, $timeout, VehicleService) { 979 var self = this; 980 //self.data = []; 981 982 self.isEmpty = function (obj) { 983 for (var prop in obj) { 984 if (obj.hasOwnProperty(prop)) 985 return false; 986 } 987 988 return JSON.stringify(obj) === JSON.stringify({}); 989 } 990 991 self.waitCondition = { 992 CHANGED: 0, 993 NOTNULL: 1, 994 ISNULL: 2, 995 NOTEMPTY: 3 996 }; 997 998 self.waitFor = function (target, waitCondition) { 999 var defer = $q.defer(); 1000 1001 var currentValue = eval("this." + target); 1002 if ((waitCondition === self.waitCondition.NOTNULL && currentValue != null 1003 || waitCondition === self.waitCondition.ISNULL && currentValue == null)) { 1004 defer.resolve(currentValue); 1005 } 1006 1007 if (!Object.prototype.watch) { 1008 Object.defineProperty(Object.prototype, "watch", { 1009 enumerable: false 1010 , configurable: true 1011 , writable: false 1012 , value: function (prop, handler) { 1013 var 1014 oldval = this[prop] 1015 , newval = oldval 1016 , getter = function () { 1017 return newval; 1018 } 1019 , setter = function (val) { 1020 oldval = newval; 1021 return newval = handler.call(this, prop, oldval, val); 1022 } 1023 ; 1024 1025 if (delete this[prop]) { // can't watch constants 1026 Object.defineProperty(this, prop, { 1027 get: getter 1028 , set: setter 1029 , enumerable: true 1030 , configurable: true 1031 }); 1032 } 1033 } 1034 }); 1035 } 1036 1037 // object.unwatch 1038 if (!Object.prototype.unwatch) { 1039 Object.defineProperty(Object.prototype, "unwatch", { 1040 enumerable: false 1041 , configurable: true 1042 , writable: false 1043 , value: function (prop) { 1044 var val = this[prop]; 1045 delete this[prop]; // remove accessors 1046 this[prop] = val; 1047 } 1048 }); 1049 } 1050 1051 function isEmpty(obj) { 1052 for (var prop in obj) { 1053 if (obj.hasOwnProperty(prop)) 1054 return false; 1055 } 1056 1057 return JSON.stringify(obj) === JSON.stringify({}); 1058 } 1059 1060 var obj = this; 1061 obj.watch(target, function (id, oldValue, newValue) { 1062 switch (waitCondition) { 1063 case self.waitCondition.CHANGED: 1064 obj.unwatch(target); 1065 defer.resolve(newValue); 1066 break; 1067 case self.waitCondition.NOTNULL: 1068 if (newValue != null) { 1069 obj.unwatch(target); 1070 defer.resolve(newValue); 1071 } 1072 break; 1073 case self.waitCondition.ISNULL: 1074 if (newValue == null) { 1075 obj.unwatch(target); 1076 defer.resolve(newValue); 1077 } 1078 break; 1079 case self.waitCondition.NOTEMPTY: 1080 //if (newValue != null && newValue.length != null && newValue.length > 0) { 1081 if (!isEmpty(newValue)) { 1082 obj.unwatch(target); 1083 defer.resolve(newValue); 1084 } 1085 break; 1086 default: 1087 obj.unwatch(target); 1088 defer.reject(); 1089 } 1090 }); 1091 return defer.promise 1092 } 1093 1094 self.getModels = function (callback) { 1095 return VehicleService.getVehiclesOverview().then(function success(response) { 1096 self.data = response.data; 1097 if (callback && typeof (callback) === "function") { 1098 callback(); 1099 } 1100 return response; 1101 }, function failure(response) { 1102 var msg = "Error loading vehicle overview"; 1103 console.error ? console.error(msg) : console.log("Error: " + msg); 1104 }); 1105 1106 } 1107 1108 self.findEngineVariantInVehicleData = function (engineVariantName) { 1109 //if (!self.data) { 1110 // console.log("self.findEngineVariantInVehicleData -> self.data: ", self.data); 1111 // console.log("self.findEngineVariantInVehicleData -> engineVariantName: ", engineVariantName); 1112 //} 1113 1114 for (var btIdx in self.data) { 1115 if (self.data.hasOwnProperty(btIdx)) { 1116 var bodyTypeObj = self.data[btIdx]; 1117 for (var mdlIdx in bodyTypeObj.models) { 1118 if (bodyTypeObj.models.hasOwnProperty(mdlIdx)) { 1119 var modelObj = bodyTypeObj.models[mdlIdx]; 1120 var engineVariantObj = modelObj.modelEngineVariants.find(function (variant) { 1121 return variant.uriName === engineVariantName; 1122 }); 1123 if (engineVariantObj) { 1124 return engineVariantObj; 1125 } 1126 } 1127 } 1128 } 1129 } 1130 1131 }; 1132 1133 self.findModelInVehicleData = function (carmodel) { 1134 for (var btIdx in self.data) { 1135 if (self.data.hasOwnProperty(btIdx)) { 1136 var bodyTypeObj = self.data[btIdx]; 1137 var modelObj = bodyTypeObj.models.find(function (model) { 1138 return model.uriName === carmodel; 1139 }); 1140 if (modelObj) { 1141 return modelObj; 1142 } 1143 } 1144 } 1145 1146 }; 1147 1148 self.getGradeByName = function (engineVariantName, gradeName) { 1149 if (engineVariantName == null || gradeName == null) return false; 1150 var grades = (self.findEngineVariantInVehicleData(engineVariantName) || {}).grades; 1151 return (grades || []).find(function (item) { 1152 return item.uriName == gradeName; 1153 }); 1154 1155 } 1156 1157 self.getGradeByID = function (engineVariantName, gradeId) { 1158 return (self.findEngineVariantInVehicleData(engineVariantName).grades || []).find(function (item) { 1159 return item.id == gradeId; 1160 }); 1161 } 1162 1163 self.getVariantByID = function (engineVariantName, gradeId, variantId) { 1164 var grade = self.getGradeByID(engineVariantName, gradeId); 1165 return (grade.variants || []).find(function (item) { 1166 return item.mdmid == variantId; 1167 }); 1168 } 1169 1170 self.getVariantByName = function (engineVariantName, gradeId, variantName) { 1171 var grade = self.getGradeByID(engineVariantName, gradeId); 1172 return (grade.variants || []).find(function (item) { 1173 return item.uriName == variantName; 1174 }); 1175 } 1176 1177 self.getTrimByID = function (engineVariantName, gradeId, variantId, trimId) { 1178 var variant = self.getVariantByID(engineVariantName, gradeId, variantId); 1179 return (variant.trims.availableTrims || []).find(function (item) { 1180 return item.id == trimId;
1181 }); 1182 } 1183 1184 self.getTrimByName = function (engineVariantName, gradeId, variantId, trimName) { 1185 var variant = self.getVariantByID(engineVariantName, gradeId, variantId); 1186 1187 return (variant.trims.availableTrims || []).find(function (trim) { 1188 return trim.uriName == trimName; 1189 }); 1190 } 1191 1192 self.getPaintByID = function (engineVariantName, gradeId, variantId, trimId, materialCode) { 1193 var trim = self.getTrimByID(engineVariantName, gradeId, variantId, trimId); 1194 return (trim.paints.availableColours || []).find(function (item) { 1195 return item.materialCode == materialCode; 1196 }); 1197 } 1198 1199 self.getPaintByName = function (engineVariantName, gradeId, variantId, trimId, paintName) { 1200 var trim = self.getTrimByID(engineVariantName, gradeId, variantId, trimId); 1201 return (trim.paints.availableColours || []).find(function (paint) { 1202 return paint.shortName == paintName || paint.uriName == paintName; 1203 }); 1204 } 1205 1206 self.getVariants = function (engineVariantName, gradeId, callback) { 1207 var myGrade = self.getGradeByID(engineVariantName, gradeId); 1208 1209 if (myGrade.variants) { 1210 1211 if (callback && typeof (callback) === "function") { 1212 callback(myGrade.variants); 1213 } 1214 return myGrade.variants; 1215 } 1216 else { 1217 return VehicleService.getVariants(gradeId).then(function success(response) { 1218 if (!myGrade.variants) { 1219 myGrade.variants = response.data; 1220 } 1221 if (callback && typeof (callback) === "function") { 1222 callback(response.data); 1223 } 1224 }, function failure(response) { 1225 //emit error event? 1226 var msg = "Error loading enhancement packs"; 1227 console.error ? console.error(msg) : console.log("Error: " + msg); 1228 }); 1229 } 1230 //bpEnPack.variants = response.data; 1231 } 1232 1233 self.getTrims = function (engineVariantName, gradeId, variantId, callback) { 1234 self.getVariants(engineVariantName, gradeId, function(variants) { 1235 var myVariant = self.getVariantByID(engineVariantName, gradeId, variantId); 1236 var myGrade = self.getGradeByID(engineVariantName, gradeId); 1237 1238 if (myVariant.trims) { 1239 1240 var availableTrims = myVariant.trims.availableTrims; 1241 var unavailableTrims = self.GetUnAvailableCollection(myGrade.availableTrims, availableTrims); 1242 1243 myVariant.trims = { 1244 allTrims: myGrade.availableTrims, 1245 availableTrims: availableTrims, 1246 unavailableTrims: unavailableTrims 1247 } 1248 1249 if (callback && typeof (callback) === "function") { 1250 callback(myVariant.trims.availableTrims, myVariant.trims.unavailableTrims, myVariant.trims.allTrims); 1251 } 1252 } 1253 else { 1254 VehicleService.getTrims(gradeId, variantId).then(function success(response) { 1255 if (response.data.length == 0) { 1256 console.warn('getTrims received 0 results for ' + engineVariant + ' with grade ID ' + gradeId); 1257 } 1258 1259 var availableTrims = response.data; 1260 var unavailableTrims = self.GetUnAvailableCollection(myGrade.availableTrims, availableTrims); 1261 1262 if (!myVariant.trims) { 1263 myVariant.trims = { 1264 allTrims: myGrade.availableTrims, 1265 availableTrims: availableTrims, 1266 unavailableTrims: unavailableTrims 1267 }; 1268 } 1269 1270 if (callback && typeof (callback) === "function") { 1271 callback(myVariant.trims.availableTrims, myVariant.trims.unavailableTrims, myVariant.trims.allTrims); 1272 } 1273 1274 }, function error(response) { 1275 console.error('getTrims returned an error'); 1276 }); 1277 1278 } 1279 }); 1280 } 1281 1282 self.getPaints = function (engineVariantName, gradeId, variantId, trimId, callback) { 1283 self.getTrims(engineVariantName, gradeId, variantId, function (trims) { 1284 var myTrim = self.getTrimByID(engineVariantName, gradeId, variantId, trimId); 1285 var myGrade = self.getGradeByID(engineVariantName, gradeId); 1286 if (myTrim.paints) { 1287 if (callback && typeof (callback) === "function") { 1288 callback(myTrim.paints.availableColours, myTrim.paints.unavailableColours); 1289 } 1290 } 1291 else { 1292 VehicleService.getPaints(gradeId, variantId, trimId).then(function success(response) { 1293 if (response.data.length == 0) { 1294 console.warn('getColours received 0 results for ' + trimId); 1295 } 1296 1297 var availableColours = response.data; 1298 var unavailableColours = self.GetUnAvailableCollection(myGrade.availablePaints, availableColours); 1299 1300 if (!myTrim.paints) { 1301 myTrim.paints = { 1302 availableColours: availableColours, 1303 unavailableColours: unavailableColours 1304 1305 }; 1306 } 1307 1308 if (callback && typeof (callback) === "function") { 1309 callback(myTrim.paints.availableColours, myTrim.paints.unavailableColours); 1310 } 1311 }, function error(response) { 1312 console.error('getColours returned an error'); 1313 }); 1314 } 1315 1316 1317 }); 1318 } 1319 1320 //Remove intersections with Available Colours from from AvailablePaints 1321 self.GetUnAvailableCollection = function (allCollection, availableCollection) { 1322 var unavailableCollection = []; 1323 for (var a = 0, lenA = allCollection.length; a < lenA; a++) { 1324 var foundMatch = false; 1325 for (var b = 0, lenB = availableCollection.length; b < lenB; b++) { 1326 if (allCollection[a].code == availableCollection[b].code) { 1327 foundMatch = true; 1328 } 1329 } 1330 if (!foundMatch) { 1331 unavailableCollection.push(allCollection[a]); 1332 } 1333 } 1334 return unavailableCollection; 1335 } 1336 1337 self.FilterAvailableCollection = function (allCollection, availableCollection) { 1338 var filteredCollection = []; 1339 for (var a = 0, lenA = allCollection.length; a < lenA; a++) { 1340 var foundMatch = false; 1341 for (var b = 0, lenB = availableCollection.length; b < lenB; b++) { 1342 if (allCollection[a].code == availableCollection[b].code) { 1343 foundMatch = true; 1344 } 1345 } 1346 if (foundMatch) { 1347 filteredCollection.push(allCollection[a]); 1348 } 1349 } 1350 return filteredCollection; 1351 } 1352 1353 self.getUnavailableTrimsBasedOnPaint = function (engineVariantName, gradeId, variantId, trimId, paintName) { 1354 var myGrade = self.getGradeByID(engineVariantName, gradeId); 1355 var paint = self.getPaintByName(engineVariantName, gradeId, variantId, trimId, paintName); 1356 1357 var availableTrims = paint.availableTrims; 1358 var unavailableTrims = self.GetUnAvailableCollection(myGrade.availableTrims, availableTrims); 1359 return {availableTrims: availableTrims, unavailableTrims: unavailableTrims }; 1360 } 1361 1362 self.getExteriorImages = function (engineVariantName, gradeId, variantId, trimId, materialCode, callback) { 1363 self.getPaints(engineVariantName, gradeId, variantId, trimId, function (paints) { 1364 var myPaint = self.getPaintByID(engineVariantName, gradeId, variantId, trimId, materialCode); 1365 if (myPaint.images && myPaint.images.exterior) { 1366 if (callback && typeof (callback) === "function") { 1367 callback(myPaint.images.exterior); 1368 } 1369 } 1370 else { 1371 VehicleService.getVehicleImages(gradeId, variantId, trimId, materialCode).then(function (response) { 1372 if (!myPaint.images) 1373 { 1374 myPaint.images = {}; 1375 } 1376 if (!myPaint.images.exterior) { 1377 myPaint.images.exterior = response.data; 1378 } 1379 if (callback && typeof (callback) === "function") { 1380 callback(myPaint.images.exterior); 1381 } 1382 }); 1383 1384 } 1385 }); 1386 }; 1387 1388 return self; 1389}]);; 1390"use strict"; 1391 1392angular.module('Lexus.Services') 1393 .factory('PreLaunchAPIService', ['$q', '$timeout', 'PreLaunchVehicleService', function ($q, $timeout, PreLaunchVehicleService) { 1394 var self = this; 1395 //self.data = []; 1396 1397 self.getModels = function (callback) { 1398 return PreLaunchVehicleService.getVehiclesOverview().then(function success(response) { 1399 self.data = response.data; 1400 if (callback && typeof (callback) === "function") { 1401 callback(); 1402 } 1403 return response; 1404 }, function failure(response) { 1405 var msg = "Error loading vehicle overview for pre launch vehicles"; 1406 console.error ? console.error(msg) : console.log("Error: " + msg); 1407 }); 1408 1409 }; 1410 1411 self.findEngineVariantInVehicleData = function (engineVariantName) { 1412 1413 for (var btIdx in self.data) { 1414 if (self.data.hasOwnProperty(btIdx)) { 1415 var bodyTypeObj = self.data[btIdx]; 1416 for (var mdlIdx in bodyTypeObj.models) { 1417 if (bodyTypeObj.models.hasOwnProperty(mdlIdx)) { 1418 var modelObj = bodyTypeObj.models[mdlIdx]; 1419 var engineVariantObj = modelObj.modelEngineVariants.find(function (variant) { 1420 return variant.uriName === engineVariantName; 1421 }); 1422 if (engineVariantObj) { 1423 return engineVariantObj; 1424 } 1425 } 1426 } 1427 } 1428 } 1429 1430 }; 1431 1432 self.getGradesList = function (engineVariantName) { 1433 if (engineVariantName == null) return false; 1434 var grades = (self.findEngineVariantInVehicleData(engineVariantName) || {}).grades; 1435 return (grades || []).map(function (grade) { 1436 return grade.name; 1437 }); 1438 }; 1439 1440 self.getGradesByEngineVariant = function (engineVariantName) { 1441 if (engineVariantName == null) return false; 1442 var grades = (self.findEngineVariantInVehicleData(engineVariantName) || {}).grades; 1443 return grades || []; 1444 }; 1445 1446 self.getInteriorsByGradeName = function (engineVariantName, gradeName) { 1447 if (engineVariantName == null) return false; 1448 var grades = (self.findEngineVariantInVehicleData(engineVariantName) || {}).grades; 1449 var grade = (grades || []).find(function (item) { 1450 return item.name == gradeName; 1451 }); 1452 return (grade && grade.baseVariant) ? grade.baseVariant.trims : []; 1453 }; 1454 1455 self.getExteriorsByGradeName = function (engineVariantName, gradeName) { 1456 if (engineVariantName == null) return false; 1457 var grades = (self.findEngineVariantInVehicleData(engineVariantName) || {}).grades; 1458 var grade = (grades || []).find(function (item) { 1459 return item.name == gradeName; 1460 }); 1461 return (grade && grade.baseVariant) ? grade.baseVariant.paints : []; 1462 }; 1463 1464 return self; 1465}]);; 1466"use strict"; 1467 1468angular.module('Lexus.Services') 1469 .service('DealersService', ['$timeout', '$filter', '$http', '$rootScope', 'API', function ($timeout, $filter, $http, $rootScope, API) 1470 { 1471 var service = this; 1472 var params = {}; 1473 var decodeEmailPart = function (str) { 1474 return typeof atob === "function" 1475 ? decodeURIComponent(atob(str)) 1476 : typeof Buffer !== "undefined" && typeof Buffer.from === "function" 1477 ? decodeURIComponent(Buffer.from(str, 'base64').toString()) 1478 : str; 1479 }; 1480 var decodeDealerEmail = function (dealer) { 1481 if (!dealer || !dealer.locations || !dealer.locations.length) { return; } 1482 dealer.locations.forEach(service.DecodeLocationEmail); 1483 }; 1484 var decodeDealerResponseEmail = function (data) { 1485 if (!data || !data.Data) { return; } 1486 if (data.Data instanceof Array) { 1487 data.Data.forEach(decodeDealerEmail); 1488 } else { 1489 decodeDealerEmail(data.Data); 1490 } 1491 }; 1492 1493 params.defaults = { 1494 siteID: Lexus.ID.Site, 1495 postCode: 'null', 1496 suburb: 'null', 1497 state: 'null', 1498 type: 'All', 1499 dealerID: '', 1500 branchCode: '', 1501 dealerState: '' 1502 }; 1503 1504 params.params = { 1505 siteID: params.defaults.siteID, 1506 postCode: params.defaults.postCode, 1507 suburb: params.defaults.suburb, 1508 state: params.defaults.state, 1509 type: params.defaults.type, 1510 dealerID: params.defaults.dealerID, 1511 branchCode: params.defaults.branchCode,
1512 dealerState: params.defaults.dealerState 1513 }; 1514 1515 service.DeconstructCompositeID = function (dealerCompositeKey) { 1516 if (dealerCompositeKey.indexOf('-')) { 1517 var parts = dealerCompositeKey.split('-'); 1518 return { 1519 dealerID: parts[0], 1520 branchCode: parts[1], 1521 sapCode: parts[2] 1522 }; 1523 } 1524 else { 1525 return; 1526 } 1527 }; 1528 1529 service.DecodeLocationEmail = function (location) { 1530 if (location && location.elMailFirstPartEncoded && location.elMailLastPartEncoded) { 1531 location.email = decodeEmailPart(location.elMailFirstPartEncoded) + "@" + decodeEmailPart(location.elMailLastPartEncoded); 1532 } 1533 if (location && location.serviceElMailFirstPartEncoded && location.serviceElMailLastPartEncoded) { 1534 location.serviceEmail = decodeEmailPart(location.serviceElMailFirstPartEncoded) + "@" + decodeEmailPart(location.serviceElMailLastPartEncoded); 1535 } 1536 }; 1537 1538 service.GetDealerBranches = function () { 1539 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.DealerBranches, [ 1540 params.params.siteID, 1541 params.params.dealerID, 1542 params.params.type 1543 ]); 1544 1545 API.get(params.params.searchQueryUrl) 1546 .then(function (data) { 1547 decodeDealerResponseEmail(data); 1548 $rootScope.$broadcast('dealer-search-results-received', data); 1549 $timeout($rootScope.$broadcast('refresh-gtm', 'Dealer Results'), 0); 1550 }, function (reason) { 1551 $rootScope.$broadcast('dealer-search-results-error', reason); 1552 }); 1553 } 1554 1555 service.GetDealerBranch = function () { 1556 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.DealerBranchByCode, [ 1557 params.params.siteID, 1558 params.params.dealerID, 1559 params.params.branchCode 1560 ]); 1561 1562 API.get(params.params.searchQueryUrl) 1563 .then(function (data) { 1564 decodeDealerResponseEmail(data); 1565 $rootScope.$broadcast('dealer-search-results-received', data); 1566 $timeout($rootScope.$broadcast('refresh-gtm', 'Dealer Results'), 0); 1567 }, function (reason) { 1568 $rootScope.$broadcast('dealer-search-results-error', reason); 1569 }); 1570 }; 1571 1572 service.GetResult = function () { 1573 1574 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.DealerById, [ 1575 params.params.siteID, 1576 params.params.dealerID, //This dealerID a composite key ex. 050055-22541-12345 1577 params.params.dealerState 1578 ]); 1579 1580 API.get(params.params.searchQueryUrl) 1581 .then(function (data) { 1582 decodeDealerResponseEmail(data); 1583 $rootScope.$broadcast('dealer-search-result-received', data); 1584 $timeout($rootScope.$broadcast('refresh-gtm', 'Dealer Results'), 0); 1585 }, function (reason) { 1586 $rootScope.$broadcast('dealer-search-result-error', reason); 1587 }); 1588 }; 1589 1590 service.GetResults = function () { 1591 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.DealersByLocation, [ 1592 params.params.siteID, 1593 params.params.postCode, 1594 params.params.suburb, 1595 params.params.state, 1596 params.params.type 1597 ]); 1598 1599 return API.get(params.params.searchQueryUrl) 1600 .then(function (data) { 1601 decodeDealerResponseEmail(data); 1602 $rootScope.$broadcast('dealer-search-results-received', data); 1603 $timeout($rootScope.$broadcast('refresh-gtm', 'Dealer Results'), 0); 1604 return data; 1605 }, function (error) { 1606 $rootScope.$broadcast('dealer-search-results-error', error); 1607 throw error; 1608 }); 1609 }; 1610 1611 // Update a search parameter. 1612 service.setParam = function (name, value) { 1613 params.params[name] = value; 1614 }; 1615 1616 // Get a parameter value 1617 service.getParam = function (name) { 1618 return params.params[name]; 1619 }; 1620 1621 return service; 1622 }]); 1623 1624 1625 1626; 1627"use strict"; 1628 1629angular.module('Lexus.Services') 1630.service('FormsService', ['$timeout', '$http', '$rootScope', function ($timeout, $http, $rootScope) 1631{ 1632 var self = this; 1633 1634 self.ShowResult = function (element) { 1635 if(!element.classList.contains('lx-form-no-scroll')){ 1636 TweenLite.to(window, 2, { scrollTo: { y: element.parentElement.offsetTop, x: 0 }, ease: Power4.easeOut }); 1637 } 1638 $rootScope.$broadcast('broadcast.lazyLoadRevalidate'); 1639 } 1640 1641 return self; 1642}]);; 1643"use strict"; 1644 1645angular.module('Lexus.Services') 1646.service('MouseDetectionService', ['$rootScope', function ($rootScope) 1647{ 1648 var self = this; 1649 1650 var MouseDetectionAgent = function() { 1651 this.resetMouseFoundAndBuffer(); 1652 this.startWatching(); 1653 return this; 1654 }; 1655 1656 MouseDetectionAgent.prototype.timestampMsArrayLooksLikeMouseData = function(timestampMsArray, maxBufferSize, mouseFrequencyThresholdHz) { 1657 var bufferFull = timestampMsArray.length === maxBufferSize; 1658 var bufferDurationThresholdMs = maxBufferSize / mouseFrequencyThresholdHz * 1000; 1659 if (bufferFull) { 1660 var firstTimestampMsInBuffer = timestampMsArray[0]; 1661 var lastTimestampMsInBuffer = timestampMsArray[timestampMsArray.length - 1]; 1662 if (bufferDurationThresholdMs >= lastTimestampMsInBuffer - firstTimestampMsInBuffer) { 1663 return true; 1664 } 1665 } 1666 return false; 1667 }; 1668 1669 MouseDetectionAgent.prototype.resetMouseFoundAndBuffer = function() { 1670 this.mouseMoveTimestampMsBuffer = []; 1671 this.mouseFound = false; 1672 $rootScope.$broadcast('did-lose-mouse'); 1673 }; 1674 1675 MouseDetectionAgent.prototype.tellMouseFound = function() { 1676 this.mouseFound = true; 1677 $rootScope.$broadcast('did-detect-mouse'); 1678 }; 1679 1680 MouseDetectionAgent.prototype.stopWatching = function() { 1681 $('body').off('mousemove.MouseDetectionAgent'); 1682 }; 1683 1684 MouseDetectionAgent.prototype.startWatching = function() { 1685 var self = this 1686 , maxBufferSize = 10; 1687 $('body').on('mousemove.MouseDetectionAgent', function() { 1688 if (self.mouseMoveTimestampMsBuffer.length >= maxBufferSize) { 1689 self.mouseMoveTimestampMsBuffer.shift(); 1690 } 1691 1692 self.mouseMoveTimestampMsBuffer.push((new Date).valueOf()); 1693 1694 if (self.timestampMsArrayLooksLikeMouseData(self.mouseMoveTimestampMsBuffer, maxBufferSize, 10)) { 1695 self.tellMouseFound(); 1696 self.stopWatching(); 1697 } 1698 }) 1699 }; 1700 1701 return new MouseDetectionAgent(); 1702}]); 1703; 1704"use strict"; 1705 1706angular.module('Lexus.Services') 1707 .service('PricingService', ['$filter', 'API', function ($filter, API) { 1708 var params = { 1709 defaults: { 1710 siteID: Lexus.ID.Site, 1711 gradeId: null, 1712 postCode: null, 1713 pricingZone: null, 1714 enablePricingByZone: false 1715 } 1716 }; 1717 1718 params.params = { 1719 siteID: params.defaults.siteID, 1720 gradeId: params.defaults.gradeId, 1721 postCode: params.defaults.postCode, 1722 pricingZone: params.defaults.pricingZone, 1723 enablePricingByZone: params.defaults.enablePricingByZone 1724 }; 1725 1726 var service = { 1727 driveAwayByGrade: driveAwayByGrade, 1728 driveAwayByEnhancementPack: driveAwayByEnhancementPack, 1729 detailPriceByPaint: detailPriceByPaint, 1730 setParam: setParam, 1731 getParam: getParam 1732 }; 1733 1734 return service; 1735 1736 function driveAwayByGrade(gradeID, postCode, pricingZone) { 1737 var endpoint = Lexus.API.Lookup.DriveAwayByGrade; 1738 var location = postCode; 1739 1740 if (params.params.enablePricingByZone === true && pricingZone) { 1741 endpoint = Lexus.API.Lookup.DriveAwayByGradeByZone; 1742 location = pricingZone; 1743 } 1744 1745 var apiUrl = $filter('formatArgs')(endpoint, [ 1746 params.params.siteID, 1747 gradeID, 1748 location 1749 ]); 1750 return API.get(apiUrl); 1751 } 1752 1753 function driveAwayByEnhancementPack(gradeID, enhancementPack, postCode, pricingZone) { 1754 var endpoint = Lexus.API.Lookup.DriveAwayByEnhancementPack; 1755 var location = postCode; 1756 1757 if (params.params.enablePricingByZone === true && pricingZone) { 1758 endpoint = Lexus.API.Lookup.DriveAwayByEnhancementPackByZone; 1759 location = pricingZone; 1760 } 1761 1762 var apiUrl = $filter('formatArgs')(endpoint, [ 1763 params.params.siteID, 1764 gradeID, 1765 enhancementPack, 1766 location 1767 ]); 1768 return API.get(apiUrl); 1769 }; 1770 1771 function detailPriceByPaint(gradeId, variantId, trimId, materialCode, postCode, pricingZone) { 1772 var endpoint = Lexus.API.Lookup.DetailPriceByPaint; 1773 var location = postCode; 1774 1775 if (params.params.enablePricingByZone === true && pricingZone) { 1776 endpoint = Lexus.API.Lookup.DetailPriceByPaintByZone; 1777 location = pricingZone; 1778 } 1779 var apiUrl = $filter('formatArgs')(endpoint, [ 1780 params.params.siteID, 1781 gradeId, 1782 variantId, 1783 trimId, 1784 materialCode, 1785 location 1786 ]); 1787 1788 return API.get(apiUrl); 1789 }; 1790 1791 // Update a search parameter. 1792 function setParam(name, value) { 1793 params.params[name] = value; 1794 }; 1795 1796 // Get a parameter value 1797 function getParam(name) { 1798 return params.params[name]; 1799 }; 1800 }]); 1801; 1802"use strict"; 1803 1804angular.module('Lexus.Services') 1805.service('RepairersService', ['$timeout', '$filter', '$http', '$rootScope', 'API', function Map($timeout, $filter, $http, $rootScope, API) { 1806 var self = this; 1807 var params = {}; 1808 1809 params.defaults = { 1810 siteID: Lexus.ID.Site, 1811 state: 'null' 1812 }; 1813 1814 params.params = { 1815 siteID: params.defaults.siteID, 1816 state: params.defaults.state 1817 }; 1818 1819 self.GetResults = function () { 1820 params.params.searchQueryUrl = $filter('formatArgs')(Lexus.API.Lookup.RepairerByState, [ 1821 params.params.siteID, 1822 params.params.state 1823 ]); 1824 1825 API.get(params.params.searchQueryUrl) 1826 .then(function (data) { 1827 $rootScope.$broadcast('repairers-search-results-received', data); 1828 }, function (reason) { 1829 $rootScope.$broadcast('repairers-search-results-error', reason); 1830 }); 1831 } 1832 1833 // Update a search parameter. 1834 self.setParam = function (name, value) { 1835 params.params[name] = value; 1836 }; 1837 1838 // Get a parameter value 1839 self.getParam = function (name) { 1840 return params.params[name]; 1841 }; 1842 1843 1844 return self; 1845}]);; 1846"use strict"; 1847 1848angular.module('Lexus.Services') 1849.service('UserPreferencesService', ['$filter', '$rootScope', '$cookies', 'API', '$location', '$log', 1850 function ($filter, $rootScope, $cookies, API, $location, $log) { 1851 var self = this; 1852 self.$location = $location; 1853 var params = {}; 1854 var version = Lexus.ID.CacheVersion; 1855 var cookieOptions = { domain: '.lexus.com.au', path: '/' }; 1856 1857 params.defaults = { 1858 visitor: { 1859 postCode: null, 1860 suburb: null, 1861 state: null, 1862 pricingZone: null, 1863 }, 1864 dealer: { 1865 dealerID: null, //This dealerID a composite key ex. 050055-22541-12345 1866 dealerCodeSimple: null, 1867 branchCode: null, 1868 dealerName: null, 1869 dealerType: null, 1870 dealerUrl: null, 1871 dealerState: null 1872 }, 1873 vehicle: { 1874 model: null, 1875 grade: null, 1876 engineVariant: null, 1877 enhancementPack: null, 1878 trim: null, 1879 colour: null, 1880 materialCode: null 1881 }, 1882 compareVehicles: { 1883 model: null, 1884 bodyType:null, 1885 modelsBrowsed: null, 1886 variantsSelected:null 1887 }, 1888 analytics: { 1889 identifier: null 1890 }, 1891 languagePref: { 1892 translate: null 1893 }, 1894 personalization: { 1895 lifestyle: null, 1896 } 1897 }; 1898 1899 params.params = { 1900 visitor: { 1901 postCode: params.defaults.visitor.postCode, 1902 suburb: params.defaults.visitor.suburb, 1903 state: params.defaults.visitor.state, 1904 pricingZone: params.defaults.visitor.pricingZone, 1905 }, 1906 dealer: { 1907 dealerID: params.defaults.dealer.dealerID, 1908 dealerCodeSimple: params.defaults.dealer.dealerCodeSimple, 1909 branchCode: params.defaults.dealer.branchCode,
1910 dealerName: params.defaults.dealer.dealerName, 1911 dealerType: params.defaults.dealer.dealerType, 1912 dealerUrl: params.defaults.dealer.dealerUrl, 1913 dealerState: params.defaults.dealer.dealerState 1914 }, 1915 vehicle: { 1916 model: params.defaults.vehicle.model, 1917 grade: params.defaults.vehicle.grade, 1918 engineVariant: params.defaults.vehicle.engineVariant, 1919 enhancementPack: params.defaults.vehicle.enhancementPack, 1920 trim: params.defaults.vehicle.trim, 1921 colour: params.defaults.vehicle.colour, 1922 materialCode: params.defaults.vehicle.materialCode 1923 }, 1924 compareVehicles: { 1925 model: params.defaults.compareVehicles.model, 1926 bodyType: params.defaults.compareVehicles.bodyType, 1927 modelsBrowsed: params.defaults.compareVehicles.modelsBrowsed, 1928 variantsSelected: params.defaults.compareVehicles.variantsSelected 1929 }, 1930 analytics: { 1931 identifier: params.defaults.analytics.identifier 1932 }, 1933 languagePref: { 1934 translate: params.defaults.languagePref.translate 1935 }, 1936 personalization: { 1937 lifestyle: params.defaults.personalization.lifestyle, 1938 } 1939 }; 1940 1941 // ************************************** 1942 // Init. 1943 // ************************************** 1944 1945 self.init = function () { 1946 var visitor = $cookies.getObject('lexus-visitor' + version); 1947 var dealer = $cookies.getObject('lexus-dealer' + version); 1948 var vehicle = $cookies.getObject('lexus-vehicle' + version); 1949 var compareVehicles = $cookies.getObject('lexus-compare-vehicles' + version); 1950 var analytics = $cookies.getObject('lexus-analytics' + version); 1951 var languagePref = $cookies.getObject('lexus-analytics' + version); 1952 var personalization = $cookies.getObject('lexus-personalization' + version); 1953 1954 if (visitor) params.params.visitor = visitor; 1955 if (dealer) params.params.dealer = dealer; 1956 if (vehicle) params.params.vehicle = vehicle; 1957 if (compareVehicles) params.params.compareVehicles = compareVehicles; 1958 if (analytics) params.params.analytics = analytics; 1959 if (languagePref) params.params.languagePref = languagePref; 1960 if (personalization) params.params.personalization = personalization; 1961 1962 }; 1963 1964 $rootScope.$on('preferred-dealer-change', function (event, dealer) { 1965 if (!dealer.dealerID || dealer.dealerID == 0) { 1966 $cookies.remove('lexus-dealer' + version, cookieOptions); 1967 } else { 1968 $cookies.putObject('lexus-dealer' + version, dealer, cookieOptions); 1969 } 1970 }); 1971 1972 self.setVisitorCookie = function (event, visitor) { 1973 //all or nothing / don't write the cookie unless we have postcode, state and suburb (or all are empty) - forms dealing with the user's address need all three 1974 if ((visitor.postCode && visitor.suburb && visitor.state) || (!visitor.postCode && !visitor.suburb && !visitor.state)) { 1975 $cookies.putObject('lexus-visitor' + version, visitor, cookieOptions); 1976 } else { 1977 console.error("Incomplete visitor cookie") 1978 } 1979 }; 1980 1981 self.setAnalyticsCookie = function (analytics) { 1982 if (analytics) { 1983 $cookies.putObject('lexus-analytics' + version, analytics); 1984 } else {
1985 console.error("No analytics info.") 1986 } 1987 }; 1988 1989 self.getAnalyticsCookie = function (urlParameters) { 1990 var result = $cookies.getObject('lexus-analytics' + version) || params.params.analytics; 1991 if (urlParameters) { 1992 result.identifier = urlParameters.identifier || result.identifier; 1993 } 1994 return result; 1995 } 1996 1997 self.setLanguagePref = function (languagePref, pageGuid) { 1998 if (languagePref) { 1999 $cookies.putObject('lexus-language-pref-' + pageGuid + version, languagePref); 2000 } else { 2001 console.error("No language preference info.") 2002 } 2003 }; 2004 2005 self.getLanguagePref = function (pageGuid) { 2006 var result = $cookies.getObject('lexus-language-pref-' + pageGuid + version) || params.params.languagePref; 2007 return result; 2008 } 2009 2010 self.setPageVisited = function (event, pageId) { 2011 if (!pageId || pageId == "") { 2012 console.warn("Visit not recorded for page " + window.location.pathname + ", guid is null or empty"); 2013 return; 2014 } 2015 var cookieName = 'lexus-page-visit' + version; 2016 var visitedPages = $cookies.getObject(cookieName) || []; 2017 if (visitedPages.find(function (id) { return id === pageId; }) == null) { 2018 visitedPages.push(pageId); 2019 $cookies.putObject(cookieName, visitedPages); 2020 } 2021 }; 2022 $rootScope.$on('record-page-visit', self.setPageVisited); 2023 2024 //functionality for these two event handlers has converged except for the casing of postcode, todo: refactor out one of these 2025 $rootScope.$on('visitor-details-cookie-change', self.setVisitorCookie); 2026 $rootScope.$on('visitor-details-change-autocomplete', function (event, visitor) { 2027 if (visitor.postcode) { 2028 visitor.postCode = visitor.postcode; 2029 delete visitor.postcode; 2030 } 2031 self.setVisitorCookie(event, visitor); 2032 }); 2033 2034 $rootScope.$on('visitor-details-session-change', function (event, visitor) { 2035 return API.post($filter('formatArgs')(Lexus.API.User.SetPreferences, [Lexus.ID.Site]), visitor); 2036 2037 }); 2038 2039 $rootScope.$on('language-pref-change', function (event, languagePref) { 2040 self.setLanguagePref(event, languagePref); 2041 }); 2042 2043 $rootScope.$on('vehicle-preference-change', function (event, vehicle) { 2044 //$log.log('vehicle-preference-change'); 2045 //$log.log(vehicle); 2046 $cookies.putObject('lexus-vehicle' + version, vehicle, cookieOptions); 2047 }); 2048 2049 $rootScope.$on('compare-vehicle-change', function (event, compareVehicleState) { 2050 $cookies.putObject('lexus-compare-vehicles' + version, compareVehicleState); 2051 }); 2052 2053 $rootScope.$on('personalization-change', function (event, personalization) { 2054 $cookies.putObject('lexus-personalization' + version, personalization); 2055 }); 2056 2057 self.getAutocompleteTagFromVisitor = function (visitor) { 2058 return { 2059 text: visitor.suburb + " " + visitor.postCode, 2060 data: { 2061 postcode: visitor.postCode, 2062 suburb: visitor.suburb, 2063 state: visitor.state, 2064 pricingZone: visitor.pricingZone 2065 } 2066 }; 2067 } 2068 2069 self.splitAutoCompleteResult = function (suggestion) { 2070 var msg = "splitAutoCompleteResult deprecated: use <postcode-result>.data directly instead of splitting <postcode-result>.text"; 2071 console.warn ? console.warn(msg) : console.log(msg); 2072 var visitor = { 2073 postCode: suggestion.slice(suggestion.lastIndexOf(' ') + 1, suggestion.length).trim(), 2074 suburb: suggestion.slice(0, suggestion.lastIndexOf(' ')).trim() 2075 }; 2076 return visitor; 2077 } 2078 2079 // Get a parameter value 2080 self.getParam = function (name) { 2081 return params.params[name]; 2082 }; 2083 2084 self.getLexusDealer = function (urlParameters) { 2085 var result = $cookies.getObject('lexus-dealer' + version) || params.params.dealer; 2086 if (urlParameters) { 2087 result.dealerID = urlParameters.dealerID || result.dealerID; 2088 result.dealerCodeSimple = urlParameters.dealerCodeSimple || result.dealerCodeSimple; 2089 result.dealerName = urlParameters.dealerName || result.dealerName; 2090 result.dealerState = urlParameters.dealerState || result.dealerState; 2091 } 2092 return result; 2093 2094 } 2095 2096 self.getLexusVisitor = function (urlParameters) { 2097 var result = $cookies.getObject('lexus-visitor' + version) || params.params.visitor; 2098 if (urlParameters) { 2099 //overrides for visitor? 2100 } 2101 return result; 2102 } 2103 2104 self.getLexusVehicle = function (urlParameters) { 2105 var result = $cookies.getObject('lexus-vehicle' + version) || params.params.vehicle; 2106 if (urlParameters) { 2107 result.model = urlParameters.model || result.model; 2108 result.grade = urlParameters.grade || result.grade; 2109 result.engineVariant = urlParameters.engineVariant || result.engineVariant; 2110 result.enhancementPack = urlParameters.enhancementPack || result.enhancementPack; 2111 result.trim = urlParameters.trim || result.trim; 2112 result.colour = urlParameters.colour || result.colour; 2113 result.materialCode = urlParameters.materialCode || result.materialCode; 2114 } 2115 return result; 2116 } 2117 2118 self.isPageVisited = function (pageId) { 2119 if (!pageId || pageId == "") { 2120 return false; 2121 } 2122 2123 var cookieName = 'lexus-page-visit' + version; 2124 var pages = $cookies.getObject(cookieName); 2125 if (pages && pages.length > 0) { 2126 return pages.indexOf(function (item) { return item == pageId; }) != null; 2127 } 2128 } 2129 2130 self.getLexusVisitorSession = function () { 2131 return API.get($filter('formatArgs')(Lexus.API.User.GetPreferences, [Lexus.ID.Site])); 2132 } 2133 2134 //#region UTM parameters - cookies disabled - incompatible with Eloqua handling of UTM campaign 2135 //self.setUtmParameters = function (utmParameters) { 2136 // $cookies.putObject('lexus-utm', utmParameters); 2137 //}; 2138 2139 self.getUtmParameters = function () { 2140 //var utmParameters = $cookies.getObject('lexus-utm');
2141 var utmParams = ["utm_campaign", "utm_medium", "utm_source", "utm_content"]; 2142 var result = {}; 2143 var queryParams = this.$location.search(); 2144 for (var idx = 0, pLen = utmParams.length; idx < pLen; idx++) { 2145 var param = utmParams[idx]; 2146 if(typeof param == 'string'){ 2147 result[param.replace(/utm_/, '')] = queryParams[param]; 2148 } 2149 } 2150 2151 return result; 2152 }; 2153 //#endregion 2154 2155 self.getEloquaCustomerGUID = function () { 2156 2157 if (typeof (GetElqCustomerGUID) == "function") { 2158 return GetElqCustomerGUID(); 2159 } 2160 else { 2161 return ""; 2162 } 2163 } 2164 2165 self.getCompareVehiclesState = function (urlParameters) { 2166 var result = $cookies.getObject('lexus-compare-vehicles' + version) || params.params.compareVehicles; 2167 if (urlParameters) { 2168 result.model = urlParameters.model || result.model; 2169 result.bodyType = urlParameters.bodyType || result.bodyType; 2170 result.modelsBrowsed = urlParameters.modelsBrowsed || result.modelsBrowsed; 2171 result.variantsSelected = urlParameters.variantsSelected || result.variantsSelected; 2172 } 2173 return result; 2174 } 2175 2176 self.getPersonalizationState = function (urlParameters) { 2177 var result = $cookies.getObject('lexus-personalization' + version) || params.params.personalization; 2178 if (urlParameters) { 2179 result.lifestyle = urlParameters.lifestyle || result.lifestyle; 2180 } 2181 return result; 2182 } 2183 2184 self.init(); 2185 2186 return self; 2187}]); 2188 2189; 2190"use strict"; 2191 2192angular.module('Lexus.Services') 2193.service('VehicleService', ['$timeout', '$filter', '$http', 'API', '$rootScope', function ($timeout, $filter, $http, API, $rootScope) { 2194 var self = this; 2195 var params = {}; 2196 2197 params.defaults = { 2198 siteID: Lexus.ID.Site, 2199 bodyTypeId: null, 2200 modelId: null, 2201 engineVariants: [] 2202 }; 2203 2204 params.params = { 2205 siteID: params.defaults.siteID, 2206 bodyTypeId: params.defaults.bodyTypeId, 2207 modelId: params.defaults.modelId, 2208 engineVariants: params.defaults.engineVariants 2209 }; 2210 2211 self.getBodyTypes = function () { 2212 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleBodyTypes, [ 2213 params.params.siteID 2214 ]); 2215 return API.get(apiUrl); 2216 }; 2217 2218 self.getVehiclesOverview = function () { 2219 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehiclesOverview, [ 2220 params.params.siteID 2221 ]); 2222 return API.get(apiUrl); 2223 }; 2224 2225 self.getModels = function (bodyTypeId) { 2226 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleModels, [ 2227 params.params.siteID, 2228 bodyTypeId 2229 ]); 2230 return API.get(apiUrl); 2231 }; 2232 2233 self.getEngineVariants = function (modelId) { 2234 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleEngineVariants, [ 2235 params.params.siteID, 2236 modelId 2237 ]); 2238 return API.get(apiUrl); 2239 }; 2240 2241 self.getEngineVariantsWithGrades = function (modelId) { 2242 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleEngineVariantsWithGrades, [ 2243 params.params.siteID, 2244 modelId 2245 ]); 2246 return API.get(apiUrl); 2247 }; 2248 2249 self.getTrims = function (gradeID, variantId) { 2250 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleTrims, [ 2251 params.params.siteID, 2252 gradeID, 2253 variantId 2254 ]); 2255 return API.get(apiUrl); 2256 }; 2257 2258 self.getPaints = function (gradeID, variantId, trimId) { 2259 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehiclePaints, [ 2260 params.params.siteID, 2261 gradeID, 2262 variantId, 2263 trimId 2264 ]); 2265 return API.get(apiUrl); 2266 }; 2267 2268 self.getVariants = function (gradeId) { 2269 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleVariants, [ 2270 params.params.siteID, 2271 gradeId 2272 ]); 2273 return API.get(apiUrl); 2274 }; 2275 2276 self.getEnhancementPacks = function (gradeId) { 2277 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleEnhancementPacks, [ 2278 params.params.siteID, 2279 gradeId 2280 ]); 2281 return API.get(apiUrl); 2282 }; 2283 2284 self.getVehicleImages = function (gradeId, variantId, trimId, materialCode) { 2285 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleImages, [ 2286 params.params.siteID, 2287 gradeId, 2288 variantId, 2289 trimId, 2290 materialCode 2291 ]); 2292 return API.get(apiUrl); 2293 }; 2294 2295 self.getVehiclePanoXMLUrl = function (gradeId, variantId, trimId, materialCode) { 2296 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.PanoXML, [ 2297 params.params.siteID, 2298 gradeId, 2299 variantId, 2300 trimId, 2301 materialCode 2302 ]); 2303 return apiUrl; 2304 }; 2305 2306 2307 2308 //self.getPaintNTrimDetails = function (variantID) { 2309 // var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.PaintNTrimByGrade, [ 2310 // params.params.siteID, 2311 // variantID 2312 // ]); 2313 // return API.get(apiUrl); 2314 //} 2315 2316 // Update a search parameter. 2317 self.setParam = function (name, value) { 2318 params.params[name] = value; 2319 }; 2320 2321 // Get a parameter value 2322 self.getParam = function (name) { 2323 return params.params[name]; 2324 }; 2325 2326 return self; 2327}]); 2328; 2329"use strict"; 2330 2331angular.module('Lexus.Services') 2332.service('PreLaunchVehicleService', ['$timeout', '$filter', '$http', 'API', '$rootScope', function ($timeout, $filter, $http, API, $rootScope) { 2333 var self = this; 2334 var params = {}; 2335 2336 params.defaults = { 2337 siteID: Lexus.ID.Site 2338 }; 2339 2340 params.params = { 2341 siteID: params.defaults.siteID 2342 }; 2343 2344 self.getVehiclesOverview = function () { 2345 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehiclesOverviewPreLaunch, [ 2346 params.params.siteID 2347 ]); 2348 return API.get(apiUrl); 2349 } 2350 2351 self.getTrims = function (gradeID, variantId) { 2352 var apiUrl = $filter('formatArgs')(Lexus.API.Lookup.VehicleTrims, [ 2353 params.params.siteID, 2354 gradeID, 2355 variantId 2356 ]); 2357 return API.get(apiUrl); 2358 } 2359 2360 return self; 2361}]); 2362; 2363"use strict"; 2364 2365angular.module("Lexus.Services") 2366 .factory("EloquaService", ["UserPreferencesService", function EloquaService(UserPreferencesService) 2367 { 2368 var service = { 2369 attachEloquaFields: AttachEloquaFields 2370 }; 2371 return service; 2372 2373 //Takes an object and attaches the corresponding eloqua fields to it 2374 function AttachEloquaFields(toObject) { 2375 var elqCustomerGUID = UserPreferencesService.getEloquaCustomerGUID(); 2376 2377 if (toObject) { 2378 toObject.ElqCustomerGUID = elqCustomerGUID; 2379 } 2380 return toObject; 2381 } 2382 }]); 2383 2384 2385; 2386'use strict'; 2387 2388angular.module('Lexus.Services').service('ViewportService', [ 2389 '$window', 2390 function($window) { 2391 var self = this; 2392 2393 self.isMobile = function() { 2394 return $window.innerWidth < Lexus.Breakpoint.Small 2395 }; 2396 2397 self.isDesktop = function() { 2398 return !self.isMobile(); 2399 } 2400 2401 return self; 2402 } 2403]); 2404; 2405'use strict'; 2406 2407(function() { 2408 angular.module("Lexus.Services").service("FontIconService", function () { 2409 var self = this; 2410 2411 self.generateDataURLfromIcon = function (size, unicode, color) { 2412 var canvas = document.createElement("canvas"); 2413 var ctx = canvas.getContext("2d"); 2414 2415 canvas.height = size; 2416 canvas.width = size; 2417 ctx.fillStyle = color; 2418 ctx.font = size + "px icomoon"; 2419 ctx.textAlign = "center"; 2420 ctx.textBaseline = "middle"; 2421 ctx.fillText(unicode, size / 2, size / 2); 2422 2423 return canvas.toDataURL("image/png"); 2424 }; 2425 2426 // hack to fix the above function resulting in wrong icon by icomoon. 2427 self.generateCursorIcon = function () { 2428 // FontIconService.generateDataURLfromIcon(32, '\ue92b', '#f0eee6'); 2429 var lightBoxCursor = 2430 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACf0lEQVRYR+2XvWsUYRCHn9lTxCLs7Z5Fbg/BSlBQsLOw8KPyP9AETTAokoiCSoqIiIgpghEUFVEiiRL1P7DSWFjYCREUbBTk9lJ4u3umENG7kffihSPxdtdE3CZbvbAz83veeb9mJAr8j8AWOn+fsKyBfL77RYzNsl9RNLefRmMiKbZEgf8V6IoJ/hnL6l8hwCSwOSb2/FKAusC07Xp9fzPbtLa1wJ9S6AVyv30WAQT4AOwC6qJM2wWvP23gNHa1qj+psij+BtgKaCsDqMhpQXtRDgA/EB7mHe94muBJNlHo30c5CqxHeK7ItKjeNH6LACIM/Ww0ZnLIFCL7gO+KTjhu6VSSQNz/MCjfEmQA2IDqTB3tW2dZ+1S5vQzAdrxH89XK9oboXYU9BgK4nne9CyuBiAL/KnDWiAu8slROdhWK72qhf6QNoBw1SZBB2/Uem7GBqIua8c6VQrSLA7M5lR4jbuLXAr9H0TutDIyYQd71RttnuQDBE1AD8U2VcafgXUyTibDqXxHhHLARZDanHG6Jt/yjwG/qmt3f8VsCMS8i47ZTvBznUwsrl1TViHd1Em/3jwVopqs6t1ulcQ/YAVoDRvNuaexPEFFQHgZGQGzgrah1wi50v44DTgQwzmFY2SvaXLNtQCDokO2WnrYHrgXlQ4qYne0C71Vk0HGKL5OWLBXAwsapHFTVGwibVPW8Uyg9aA8eVsvHROQayhcROWO7xWdJ4ol7IE2A1dqkzsBqhTr5rwGsZSB1BtqOoauqwx2O4RhK8M+PYaYXUaZX8X95jFrPYmbPcRRkX5CYvgBTE2ZUkjUbkyZApkVp1mV55o1JqzfMrDXLtDnNtD3/BcgX4+AyBu25AAAAAElFTkSuQmCC"; 2431 2432 // FontIconService.generateDataURLfromIcon(32, '\ue90f', '#e4e1d7'); 2433 var prevCursor = 2434 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB+klEQVRYR8WXv2sTYRjHP08KbTMUulTQ5HJxKF4ijoKDm4N1UQQHhy5VKhSkHToUB6md1KGDpWCp1IIIOnYoKPgPCI5ic6WDvV7OQrsUOsQfbR654WKWpJfc1ff+gPt87vu+9/wQTukJPPeVoqOq8tEqOrdbYSRt/r7rDvzO6kuFu0BG4ZNll67/F4EQ/iur74CRCN5fkztDjnN46gLV6lae46NV4BpQB9b6ajLWDh5KpXIEu9638hE9S4JeDeEC73trMnESPBWBEH6MrIJcBv4I8iZnO+Nx71aiBKrfN66QkWXgEvBThRWrUHoYF54oAX9784ZI/QUwDNQQnc8Xyo87gXctEOy4txRdQCkAhwLzObs01ym8KwHfc0cFfQ6cAzlQmLVsZ6EbeMcCwbZ7T0WfAmeAPVF5lCs6r7uFdyTge+6kwBzoIPBDkRnLdt4mgccWCLzKrMI0MAB4qpkJq3jhQ1J4LIHAc58pOglkgS3VzFRa8BMF/J3Koij3gX7gK3V9kD9f/pzGl0fvaFmIfK/yRGAG6AP90oOOnbUvbqQJb5uA
2434cYHQzugRRFEbvYT/JAz+hpGE0ULUSMJkKW5KwlwzaiRhsh03kjA5kEQSRkeySMLoUNosYWwsbxyHycUkkjC6mjVLNC+nwHreLt1s1cYTLSbtZoO46/lfr4cXMA1Qm1oAAAAASUVORK5CYII="; 2435 2436 // FontIconService.generateDataURLfromIcon(32, '\ue910', '#e4e1d7'); 2437 var nextCursor = 2438 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB70lEQVRYR8XXP2jUcBTA8e+7KNcOIggOklxzDsVcBTfBUTu1UztWB20HF5E6FBR1EBEEBQeLlEKhrULp2k51at3dCr1GOrTpXXEQhNKhil6eJJ7YwfRyl+AvY/IL78Pv33tPSHjqO34/wjxoUVQe2mVvNmlslveSAlACviLy2OnxprME+9e/iYBo8N6uP6SqbwAH2Bf0ue32vcwTcSwgClTb+TQoEr4GeoEDgVe2W3maF6IlIEZsb16Vgk6BVIBvikyWXO9BHohUgChQfbt6BUumUS4BPwR5Z7ve7ayI1IAo0Odgo6+BzIFcBhrAguNWRrMg2gLEM1Hfcmj8fAtcA0JgqXgoY2c976ATSNuAKMgX3z/1vVsXgYFm0PfFQ7neCaIjwBHEHDAMFIA1rBO3HKe33s5MdAz4iwij0zECWKAfLXTsnHuxmhaRCfAnyF7gzyh6EziJsG5peCMtIhdAfFcE/gtBx4Eu0E0N5U7pfOVDq5nIDRCfkN3qM1QmgG5gS7Vwr1S+sHIcIldAnD+C6n1FHgGnI5OI3LV7vOUkRO6A5nKMC/oEOANSQxl1yt5q29mw1folfa8FvjmA0SUwugmNHkNjF9HvpGToKm5mRDPJyGg6NlqQGC3JjBalRstyo42J0dbsSHdspjn9X+35L8RtDDDXC10pAAAAAElFTkSuQmCC"; 2439 2440 return { lightBoxCursor, prevCursor, nextCursor }; 2441 }; 2442 2443 return self; 2444 }); 2445})(); 2446; 2447"use strict"; 2448angular.module('Lexus.Directives') 2449.directive('lxAccordion', ['$window', '$timeout', '$filter', '$http', function ($window, $timeout, $filter, $http) { 2450 accordionController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$rootScope']; 2451 return { 2452 scope: true, 2453 restrict: 'A', 2454 controller: accordionController, 2455 controllerAs: 'ac', 2456 bindToController: true, 2457 link: function (scope, element, attrs, filter, http) { 2458 } 2459 }; 2460 2461 function accordionController($scope, $http, $filter, $timeout, $window, $interval, $rootScope) { 2462 var ac = this; 2463 $scope.init = function (collapseOthersOnExpansion, broadcastSelection) { 2464 ac.panels = []; 2465 ac.collapseOthersOnExpansion = collapseOthersOnExpansion; 2466 ac.broadcastSelection = broadcastSelection; 2467 }; 2468 2469 $scope.toggleVisible = function (i) { 2470 var becomeVisible = !ac.panels[i].visible; 2471 ac.panels[i].visible = becomeVisible; 2472 2473 // On first open, init content gallery 2474 if (becomeVisible && !ac.panels[i].hasBeenVisible) { 2475 $scope.$broadcast('broadcast.contentGalleryReload', { targetId: ac.panels[i].id }); 2476 ac.panels[i].hasBeenVisible = true; 2477 } 2478 2479 if (becomeVisible == true && ac.collapseOthersOnExpansion) { 2480 for (var j = 0; j < ac.panels.length; j++) { 2481 if (j != i) { 2482 ac.panels[j].visible = false; 2483 } 2484 } 2485 } 2486 2487 if (ac.broadcastSelection) { 2488 $rootScope.$broadcast('variant-selected', { selectedVariantIndex: i }); 2489 } 2490 }; 2491 2492 $scope.initPanel = function (i, initiallyExpanded) { 2493 ac.panels[i] = {}; 2494 ac.panels[i].id = i; 2495 ac.panels[i].visible = initiallyExpanded; 2496 ac.panels[i].hasBeenVisible = false; 2497 }; 2498 2499 // Check if the URL has a hash link that should set an accordion item open by default. 2500 $scope.expandItemByDefault = function (divId) { 2501 return ($window.location.hash === divId) ? true : false; 2502 }; 2503 2504 } 2505}]); 2506 2507 2508; 2509"use strict"; 2510angular.module('Lexus.Directives') 2511 .directive('lxAnchorMenuBar', ['$window', function ($window) { 2512 lxAnchorMenuBarController.$inject = ['$scope', '$filter', '$timeout']; 2513 return { 2514 scope: true, 2515 restrict: 'A', 2516 controller: lxAnchorMenuBarController, 2517 controllerAs: 'amc', 2518 bindToController: { 2519 modelName: '@' 2520 }, 2521 link: function (scope, element, attrs) { 2522 scope.currentlyScrolledId = ''; 2523 2524 if (attrs.anchorMenuItems) { 2525 scope.anchorMenuItems = angular.fromJson(attrs.anchorMenuItems); 2526 2527 var transitionDelay = 0; 2528 for (var i = scope.anchorMenuItems.length - 1; i >= 0; i--) { 2529 var anchorMenuItem = scope.anchorMenuItems[i]; 2530 anchorMenuItem.transitionDelay = transitionDelay; 2531 scope.anchorMenuItems[i] = anchorMenuItem; 2532 transitionDelay += 0.15; 2533 } 2534 } 2535 2536 angular.element($window).bind("scroll", function () { 2537 calcCurrentlyScrolledIdComponent($window); 2538 }); 2539 2540 function calcCurrentlyScrolledIdComponent(window) { 2541 var currentlyScrolledIdComponent; 2542 for (var i = 0; i < scope.anchorMenuItems.length; i++) { 2543 var anchorMenuItem = scope.anchorMenuItems[i]; 2544 var item = $("#" + anchorMenuItem.anchorId)[0]; 2545 if (!item) continue; 2546 anchorMenuItem.offsetTop = item.offsetTop; 2547 2548 if (window.pageYOffset + 73 >= anchorMenuItem.offsetTop 2549 && (currentlyScrolledIdComponent == null || anchorMenuItem.offsetTop > currentlyScrolledIdComponent.offsetTop)) { 2550 currentlyScrolledIdComponent = anchorMenuItem; 2551 } 2552 } 2553 scope.currentlyScrolledId = currentlyScrolledIdComponent != null ? currentlyScrolledIdComponent.anchorId : scope.anchorMenuItems[0].anchorId; 2554 } 2555 } 2556 }; 2557 2558 function lxAnchorMenuBarController($scope, $filter, $timeout) { 2559 this.mobileMenuOpen = false; 2560 this.menuOpenTimeouts = []; 2561 this.menuCloseTimeouts = []; 2562 2563 this.getCurrentlyScrolledId = function () { 2564 return $scope.currentlyScrolledId; 2565 }; 2566 2567 this.getCurrentlyActiveItem = function () { 2568 var item = $filter("filter")($scope.anchorMenuItems, { anchorId: $scope.currentlyScrolledId }); 2569 return item != null && item.length > 0 ? item[0].title : ''; 2570 }; 2571 2572 this.toggleMobileAnchorMenu = function () { 2573 this.mobileMenuOpen = !this.mobileMenuOpen; 2574 2575 if (this.mobileMenuOpen == true) { 2576 if ($scope.anchorMenuItems) { 2577 for (var i = 0; i < this.menuOpenTimeouts.length; i++) { 2578 $timeout.cancel(this.menuOpenTimeouts[i]); 2579 } 2580 2581 this.menuOpenTimeouts = []; 2582 2583 for (var i = 0; i < $scope.anchorMenuItems.length; i++) { 2584 var timeout = $timeout(fireMenuOpened, 600, true, $scope.anchorMenuItems[i]); 2585 this.menuOpenTimeouts.push(timeout); 2586 } 2587 } 2588 } 2589 else { 2590 if ($scope.anchorMenuItems) { 2591 2592 for (var i = 0; i < this.menuCloseTimeouts.length; i++) { 2593 $timeout.cancel(this.menuCloseTimeouts[i]); 2594 } 2595 2596 this.menuCloseTimeouts = []; 2597 2598 for (var i = 0; i < $scope.anchorMenuItems.length; i++) { 2599 var timeout = $timeout(fireMenuClosed, 0, true, $scope.anchorMenuItems[i]); 2600 this.menuCloseTimeouts.push(timeout); 2601 } 2602 } 2603 } 2604 2605 $('body').removeClass("modal-open"); 2606 2607 if (this.mobileMenuOpen) { 2608 $('body').addClass("modal-open"); 2609 } 2610 }; 2611 2612 this.closeMobileAnchorMenu = function () { 2613 this.mobileMenuOpen = false; 2614 $('body').removeClass("modal-open"); 2615 }; 2616 2617 function fireMenuOpened(anchorMenuItem) { 2618 $scope.$broadcast('anchor-menu-opened', anchorMenuItem); 2619 } 2620 2621 function fireMenuClosed(anchorMenuItem) { 2622 $scope.$broadcast('anchor-menu-closed', anchorMenuItem); 2623 } 2624 } 2625 }]); 2626 2627 2628angular.module('Lexus.Directives') 2629 .directive('lxAnchorMenuItem', ['$rootScope', '$anchorScroll', '$location', function ($rootScope, $anchorScroll, $location) { 2630 return { 2631 scope: true, 2632 restrict: 'A', 2633 require: "^lxAnchorMenuBar", 2634 link: function (scope, element, attrs, controller) { 2635 scope.anchorId = attrs.anchorId; 2636 2637 scope.isActive = function () { 2638 return controller.getCurrentlyScrolledId() == attrs.anchorId; 2639 }; 2640 2641 scope.lazyRerender = function () { 2642 window.setTimeout(() => { 2643 $rootScope.$digest(); 2644 }, 1100); 2645 } 2646 2647 scope.$on('anchor-menu-opened', function (event, data) { 2648 if (scope.anchorId == data.anchorId) { 2649 element.css({ 2650 transition: "opacity 0.25s ease-out " + data.transitionDelay + "s, transform 0.25s ease-out " + data.transitionDelay + "s" 2651 }); 2652 element.addClass("menu-open"); 2653 } 2654 }); 2655 2656 scope.$on('anchor-menu-closed', function (event, data) { 2657 if (scope.anchorId == data.anchorId) { 2658 element.removeClass("menu-open"); 2659 } 2660 }); 2661 2662 } 2663 } 2664 }]); 2665; 2666'use strict'; 2667 2668angular.module('Lexus.angulartics', ['angulartics']) 2669.config(['$analyticsProvider', function ($analyticsProvider) { 2670 2671 $analyticsProvider.settings.ga = { 2672 userId: null 2673 }; 2674 2675 $analyticsProvider.registerPageTrack(function (path) { 2676 var dataLayer = window.dataLayer = window.dataLayer || []; 2677 dataLayer.push({ 2678 'event': 'content-view', 2679 'content-name': path, 2680 'userId': $analyticsProvider.settings.ga.userId 2681 }); 2682 });
2683 2684 $analyticsProvider.registerEventTrack(eventTrack); 2685 2686 function eventTrack(action, properties) { 2687 var dataLayer = window.dataLayer = window.dataLayer || []; 2688 properties = properties || {}; 2689 2690 // Only fire when the GA4 event comes from clicking email or phone. 2691 if ((properties.serviceType === "Sales" || properties.serviceType === "Service") && (properties.label === "Phone" || properties.label === "Email")) { 2692 dataLayer.push({ 2693 "event": "find_a_dealer", 2694 "target": properties.category, 2695 "action": properties.action, 2696 "target-properties": properties.label, 2697 "value": properties.value, 2698 "interaction-type": properties.noninteraction, 2699 "model": properties.model, 2700 "driveAwayPrice": properties.driveAwayPrice, 2701 "variant": properties.variant, 2702 "userId": $analyticsProvider.settings.ga.userId, 2703 "salesOrService": properties.serviceType, 2704 "dealerSelected": properties.dealer, 2705 "contactMethod": properties.label, 2706 }); 2707 } 2708 2709 if (properties.event === "build_and_price") { 2710 dataLayer.push({ 2711 ...properties, 2712 "userId": $analyticsProvider.settings.ga.userId, 2713 }); 2714 return; 2715 } 2716 2717 dataLayer.push({ 2718 'event': properties.event || 'interaction', 2719 'target': properties.category, 2720 'action': properties.action, 2721 'target-properties': properties.label, 2722 'value': properties.value, 2723 'interaction-type': properties.noninteraction, 2724 'model': properties.model, 2725 'driveAwayPrice': properties.driveAwayPrice, 2726 'variant': properties.variant, 2727 'userId': $analyticsProvider.settings.ga.userId 2728 }); 2729 2730 } 2731 2732 $analyticsProvider.registerExceptionTrack(function (error, cause) { 2733 2734 eventTrack(error.toString(), { 2735 'category': 'Exceptions', 2736 'label': error.stack 2737 }); 2738 2739 }); 2740 2741 $analyticsProvider.registerSetUsername(function (userId) { 2742 $analyticsProvider.settings.ga.userId = userId; 2743 }); 2744 2745}]); 2746 2747angular.module('Lexus.Directives') 2748.directive('lxGtm', ['$window', '$timeout', '$filter', '$http', '$analytics', function ($window, $timeout, $filter, $http, $analytics) { 2749 gtmController.$inject = ['$rootScope', '$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$analytics', 'UserPreferencesService']; 2750 return { 2751 scope: true, 2752 restrict: 'A', 2753 controller: gtmController, 2754 controllerAs: 'gtm', 2755 bindToController: true, 2756 link: function (scope, element, attrs, filter, http) { 2757 var helpers = {}; 2758 helpers.now = Date.now || function () { 2759 return new Date().getTime(); 2760 }; 2761 helpers.debounce = function (func, wait, immediate) { 2762 var timeout, args, context, timestamp, result; 2763 2764 var later = function () { 2765 var last = helpers.now() - timestamp; 2766 2767 if (last < wait && last >= 0) { 2768 timeout = setTimeout(later, wait - last); 2769 } else { 2770 timeout = null; 2771 if (!immediate) { 2772 result = func.apply(context, args); 2773 if (!timeout) context = args = null; 2774 } 2775 } 2776 }; 2777 2778 return function () { 2779 context = this; 2780 args = arguments; 2781 timestamp = helpers.now(); 2782 var callNow = immediate && !timeout; 2783 if (!timeout) timeout = setTimeout(later, wait); 2784 if (callNow) { 2785 result = func.apply(context, args); 2786 context = args = null; 2787 } 2788 2789 return result; 2790 }; 2791 }; 2792 helpers.throttle = function (func, wait) { 2793 var context, args, timeout, throttling, more, result; 2794 var whenDone = helpers.debounce(function () { more = throttling = false; }, wait); 2795 return function () { 2796 context = this; args = arguments; 2797 var later = function () { 2798 timeout = null;
2799 if (more) func.apply(context, args); 2800 whenDone(); 2801 }; 2802 if (!timeout) timeout = setTimeout(later, wait); 2803 if (throttling) { 2804 more = true; 2805 } else { 2806 result = func.apply(context, args); 2807 } 2808 whenDone(); 2809 throttling = true; 2810 return result; 2811 }; 2812 }; 2813 2814 var currentScrollDepth = 0; 2815 2816 var scrollDepth = function (e) { 2817 //whatever 2818 var topEdge = $window.pageYOffset, 2819 clientHeight = $window.innerHeight, 2820 fullHeight = document.body.clientHeight, 2821 calculatedScrollDepth = ((topEdge / (fullHeight - clientHeight)) * 100).toFixed(); 2822 2823 var scrollEvent = function (calculated, current) { 2824 if (calculated != current) { 2825 currentScrollDepth = calculated; 2826 //$analytics.eventTrack('Scroll Event', { category: window.location.pathname, action: 'Page Scroll', label: currentScrollDepth + '%', noninteraction: true }); 2827 $analytics.eventTrack('Scroll Event', { event: 'Scroll', category: window.location.pathname, action: 'Page Scroll', label: currentScrollDepth + '%', noninteraction: true }); 2828 } 2829 }; 2830 2831 if ((calculatedScrollDepth - currentScrollDepth) > 10 || (calculatedScrollDepth - currentScrollDepth) < -10) { 2832 scrollEvent(((calculatedScrollDepth / 10).toFixed() * 10), currentScrollDepth); 2833 } 2834 else if (calculatedScrollDepth == 0) { 2835 scrollEvent(0, currentScrollDepth); 2836 } 2837 else if (calculatedScrollDepth == 100) { 2838 scrollEvent(100, currentScrollDepth); 2839 } 2840 }; 2841 2842 angular.element($window).bind("scroll", helpers.throttle(scrollDepth, 100)); 2843 } 2844 }; 2845 2846 function gtmController($rootScope, $scope, $http, $filter, $timeout, $window, $interval, $analytics, UserPreferencesService) { 2847 var gtm = this; 2848 gtm.trackers = []; 2849 gtm.forms = {}; 2850 gtm.chatTracked = false; 2851 2852 if (window.Element && !Element.prototype.closest) { 2853 Element.prototype.closest = 2854 function (s) { 2855 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 2856 i, 2857 el = this; 2858 do { 2859 i = matches.length; 2860 while (--i >= 0 && matches.item(i) !== el) { }; 2861 } while ((i < 0) && (el = el.parentElement)); 2862 return el; 2863 }; 2864 } 2865 2866 if (!Element.prototype.matches) { 2867 Element.prototype.matches = 2868 Element.prototype.matchesSelector || 2869 Element.prototype.mozMatchesSelector || 2870 Element.prototype.msMatchesSelector || 2871 Element.prototype.oMatchesSelector || 2872 Element.prototype.webkitMatchesSelector || 2873 function (s) { 2874 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 2875 i = matches.length; 2876 while (--i >= 0 && matches.item(i) !== this) { } 2877 return i > -1; 2878 }; 2879 } 2880 2881 function extractContent(s) { 2882 var span = document.createElement('span'); 2883 span.innerHTML = s; 2884 return span.textContent || span.innerText; 2885 }; 2886 2887 function checkValue(val, el, type) { 2888 var newVal = val; 2889 switch (val) { 2890 case ':path': 2891 newVal = window.location.pathname; 2892 break; 2893 case ':link': 2894 newVal = el.getAttribute('href'); 2895 break; 2896 case ':parentlink': 2897 newVal = el.parentElement.getAttribute('href'); 2898 break; 2899 } 2900 2901 if (el.matches('[type]') && el.type.toLowerCase() == 'submit' && type == 'label') { 2902 if (angular.element(el).closest('form').hasClass('ng-invalid')) 2903 newVal += ' - Errors'; 2904 } 2905 2906 return newVal.replace(/\n/g, ' '); 2907 } 2908 2909 function getGtmDetails(el) { 2910 var labelEl = el.closest('[data-gtm-label]'); 2911 var categoryEl = el.closest('[data-gtm-category]'); 2912 var subCategoryEl = el.closest('[data-gtm-sub-category]');
2913 var priceEl = el.closest('[data-gtm-drive-away-price]'); 2914 var dealerEl = el.closest("[data-gtm-dealer]"); 2915 //temp change: this is for find a dealer only unless refactor to React component 2916 var findADealerEl = el.closest("[data-gtm-find-a-dealer]"); 2917 2918 var label = labelEl ? checkValue(labelEl.dataset.gtmLabel, el, 'label') : false; 2919 var subCategory = subCategoryEl ? checkValue((subCategoryEl) ? subCategoryEl.dataset.gtmSubCategory : '', el, 'subCategory') : false; 2920 var category = categoryEl ? checkValue((categoryEl) ? categoryEl.dataset.gtmCategory : '', el, 'category') : false; 2921 var price = priceEl ? checkValue((priceEl) ? priceEl.dataset.gtmDriveAwayPrice : '', el, 'driveAwayPrice') : false; 2922 var dealer = dealerEl ? checkValue(labelEl.dataset.gtmDealer, el, "dealer") : false; 2923 var serviceType = findADealerEl 2924 ? checkValue(findADealerEl.dataset.gtmFindADealer, el, "findADealer") 2925 : false; 2926 2927 if (label && subCategory && category) { 2928 var tracker = { 2929 el: el, 2930 category: category, 2931 subCategory: subCategory, 2932 label: label, 2933 driveAwayPrice: price, 2934 dealer, 2935 serviceType, 2936 }; 2937 return tracker; 2938 } 2939 } 2940 2941 var pushAnalytics = function (label, data) { 2942 var data = data; 2943 var preferences = UserPreferencesService.getLexusVehicle(); 2944 data.model = preferences.model; 2945 data.variant = preferences.engineVariant; 2946 2947 $analytics.eventTrack(label.replace(/\s/gi, '-'), data); 2948 }; 2949 2950 var analyticsClick = function (event) { 2951 var el = event.target; 2952 $timeout(function () { 2953 var gtmDetails = getGtmDetails(el); 2954 //$analytics.eventTrack(gtmDetails.subCategory, { category: gtmDetails.category, action: gtmDetails.subCategory, label: gtmDetails.label }); 2955 if (gtmDetails) { 2956 pushAnalytics(gtmDetails.subCategory, { 2957 category: gtmDetails.category, 2958 action: gtmDetails.subCategory, 2959 label: gtmDetails.label, 2960 driveAwayPrice: gtmDetails.driveAwayPrice, 2961 dealer: gtmDetails.dealer, 2962 serviceType: gtmDetails.serviceType, 2963 }); 2964 } 2965 }); 2966 }; 2967 2968 var analyticsBlur = function (event) { 2969 var el = event.target, 2970 details = el.dataset.gtmFormDetails.split('||'); 2971 gtm.forms[details[0]][details[1]].touched = true; 2972 }; 2973 2974 var chatClick = function (event) { 2975 pushAnalytics('Live Chat', { category: window.location.pathname, action: 'Live Chat', label: 'Chat Clicked' }); 2976 }; 2977 2978 var addTrackers = function () { 2979 gtm.labels = document.querySelectorAll('[data-gtm-label]'); 2980 2981 for (var e = 0, len = gtm.labels.length; e < len; e++) { 2982 var el = gtm.labels[e]; 2983 angular.element(el).off('click', analyticsClick); 2984 angular.element(el).on('click', analyticsClick); 2985 }; 2986 }; 2987 2988 var addForms = function () { 2989 //Exclude SC from which will have its own GTM supported specifically 2990 var forms = document.querySelectorAll('form:not(.lx-scforms)'); 2991 for (var f = 0, len = forms.length; f < len; f++) { 2992 var frm = forms[f]; 2993 var formName = frm.closest("[data-gtm-sub-category]")?.dataset.gtmSubCategory.replace(/\W/g, ""); 2994 gtm.forms[formName] = []; 2995 var inputs = frm.querySelectorAll('input,select,textarea,button'); 2996 2997 for (var i = 0, inputLen = inputs.length; i < inputLen; i++) { 2998 var el = inputs[i]; 2999 var labelText = el.closest('label'); 3000 if (el.type != 'hidden' && el.type != 'submit' && !el.matches('[style*="display: none"')) { 3001 var inputLabel = null;
3002 if (inputLabel == null) inputLabel = (el.closest('label')) ? el.closest('label').innerText : null; 3003 if (inputLabel == null) inputLabel = (el.closest('.lx-form-text-label')) ? el.closest('.lx-form-text-label').innerText : null; 3004 if (inputLabel == null) 3005 inputLabel = el.hasAttribute("id") 3006 ? document.querySelector("[for=" + el.id + "]")?.innerText 3007 : el.innerText; 3008 3009 inputLabel = 3010 inputLabel && 3011 inputLabel 3012 .replace(/^\n/, "") 3013 .replace(/^\s*/, "") 3014 .replace(/(.*)\n(.*)/g, "$1") 3015 .replace(/\W/g, "-") 3016 .replace(/-{2,}/g, "-"); 3017 3018 var item = { el: el, label: inputLabel, index: gtm.forms[formName].length, touched: false }; 3019 el.setAttribute('data-gtm-form-details', formName + '||' + item.index); 3020 3021 angular.element(el).on('blur change input', analyticsBlur); 3022 gtm.forms[formName].push(item); 3023 } 3024 } 3025 } 3026 3027 //console.log(gtm.forms); 3028 3029 }; 3030 3031 var addChat = function () { 3032 var chatButton = document.querySelector('img[id^=LCM]'); 3033 3034 if (chatButton && !gtm.chatTracked) { 3035 angular.element(chatButton).on('click', chatClick); 3036 gtm.chatTracked = true; 3037 } 3038 }; 3039 3040 var checkForChat = function (delay, count, limit) { 3041 //console.log('checkForChat(' + delay + ',' + count + ',' + limit + ')'); 3042 if (typeof LCM != 'undefined' && LCM) { 3043 console.log(LCM); 3044 addChat(); 3045 } else if(count < limit){ 3046 setTimeout(function () { checkForChat(delay, count + 1, limit); }, delay); 3047 } 3048 3049 }; 3050 3051 $rootScope.$on('open-modal-window', function (event, data) { 3052 var errorWords = ['oops', 'error', 'warning', 'unavailable', 'problem']; 3053 var matchString = new RegExp(errorWords.join('|'), 'gi', ''); 3054 3055 var modalType = (data.content.match(matchString)) ? 'Error Message' : 'Dialog'; 3056 3057 var eventObject = { 3058 category: window.location.pathname, 3059 action: 'Modal ' + modalType, 3060 label: extractContent(data.content) 3061 }; 3062 //console.log(eventObject); 3063 //$analytics.eventTrack('Modal Window', eventObject); 3064 pushAnalytics('Modal Window', eventObject); 3065 3066 }); 3067 3068 $scope.$on('gtm-form-success', function (event, data, labelSuffix) { 3069 var category = window.location.pathname; 3070 var action = data; // Form name 3071 var label = 'Form Submission Success' + (labelSuffix != null ? " - " + labelSuffix : ""); 3072 pushAnalytics(category, { category: category, action: action, label: label }); 3073 }); 3074 3075 $scope.$on('gtm-form-failure', function (event, data) { 3076 var category = window.location.pathname; 3077 var action = data; // Form name 3078 3079 pushAnalytics(category, { category: category, action: action, label: 'Form Submission Failure' }); 3080 }); 3081 3082 function pushVehicleAnalytics(area, vehicle, eventData) { 3083 3084 if (vehicle.carmodel != null && vehicle.carmodel != "") 3085 pushAnalytics(area, { category: area, action: 'Model', label: eventData.source + ': ' + vehicle.carmodel }); 3086 if (vehicle.engineVariant != null && vehicle.engineVariant != "") 3087 pushAnalytics(area, { category: area, action: 'Variant', label: eventData.source + ': ' + vehicle.engineVariant }); 3088 if (vehicle.grade != null && vehicle.grade != "") 3089 pushAnalytics(area, { category: area, action: 'Grade', label: eventData.source + ': ' + vehicle.grade }); 3090 if (vehicle.enhancementPack != null && vehicle.enhancementPack != "") 3091 pushAnalytics(area, { category: area, action: 'Enhancement Pack', label: eventData.source + ': ' + vehicle.enhancementPack }); 3092 if (vehicle.colour != null && vehicle.colour != "") 3093 pushAnalytics(area, { category: area, action: 'Colour', label: eventData.source + ': ' + vehicle.colour }); 3094 if (vehicle.trim != null && vehicle.trim != "") 3095 pushAnalytics(area, { category: area, action: 'Trim', label: eventData.source + ': ' + vehicle.trim }); 3096 } 3097 3098 $scope.$on('gtm-buildPrice', function (event, eventData) { 3099 var area = 'Build And Price'; 3100 var vehicle = eventData.data; 3101 3102 if (eventData.source.toLowerCase().match(/initial|summary|default/)) { 3103 pushVehicleAnalytics(area, vehicle, eventData); 3104 } 3105 3106 if (eventData.source == "360") { 3107 pushAnalytics(area, { category: area, action: '360', label: 'Vehicle Rotated' }); 3108 } 3109 3110 if (eventData.source.toLowerCase().replace(/\s/gi, '')
3110== "postcoderoadblock") { 3111 if (eventData.data.dialogDisplayed) { 3112 if (eventData.data.firstVisit) { 3113 pushAnalytics(area, { category: 'Postcode Roadblock', action: area, label: 'Roadblock displayed' }); 3114 } else { 3115 pushAnalytics(area, { category: 'Postcode Roadblock', action: area, label: 'Postcode displayed' }); 3116 } 3117 } else { 3118 pushAnalytics(area, { category: 'Postcode Roadblock', action: area, label: 'Roadblock and Postcode not displayed' }); 3119 } 3120 } 3121 3122 // New GA4 event. Only send event on last step 3123 if (eventData.source.toLowerCase() === "summary") { 3124 const dealerName = eventData.data.dealerName; 3125 const data = { 3126 "event": "build_and_price", 3127 "model": vehicle.carmodel || "unknown", 3128 "variant": vehicle.engineVariant || "unknown", 3129 "grade": vehicle.grade || "unknown", 3130 "enhancement_pack": vehicle.enhancementPack || "unknown", 3131 "exterior_colour": vehicle.colour || "unknown", 3132 "interior_colour": vehicle.trim || "unknown", 3133 "website": dealerName || "Corporate" 3134 } 3135 $analytics.eventTrack("build_and_price", data); 3136 } 3137 }); 3138 3139 $scope.$on('gtm-preLaunch', function (event, eventData) { 3140 var area = 'Pre Launch'; 3141 3142 if (eventData.source.toLowerCase().match(/initial|interior|exterior|default/)) { 3143 var vehicle = eventData.data; 3144 pushVehicleAnalytics(area, vehicle, eventData); 3145 } 3146 3147 }); 3148 3149 $scope.$on('refresh-gtm', function (event, data) { 3150 console.log('lxGtm: refresh-gtm event received from: ', data); 3151 $timeout(function () { addTrackers(); }, 150, false); 3152 }); 3153 3154 $window.addEventListener('beforeunload', function (event) { 3155 var forms = Object.keys(gtm.forms); 3156 if (forms.length > 0) { 3157 forms.forEach(function (formName) { 3158 var form = gtm.forms[formName]; 3159 var touched = []; 3160 var filled = ''; 3161 form.forEach(function (item) { 3162 if (item.touched) { 3163 touched.push(item); 3164 filled += (filled.length > 0) ? ' >> ' + item.label : item.label; 3165 } 3166 }); 3167 var eventObject = { 3168 category: window.location.pathname, 3169 action: formName, 3170 label: touched.length + '/' + form.length + ' fields: ' + filled 3171 }; 3172 //console.log(eventObject); 3173 //$analytics.eventTrack(formName, eventObject); 3174 pushAnalytics(formName, eventObject); 3175 3176 }); 3177 } 3178 }); 3179 3180 function init() { 3181 $timeout(function () { addTrackers(); addForms(); }, 0, false); 3182 $timeout(function () { addTrackers(); addForms(); checkForChat(100,0,10); }, 500, false); 3183 } 3184 3185 init(); 3186 3187 } 3188}]); 3189 3190; 3191"use strict"; 3192/* Directives */ 3193angular.module('Lexus.Directives') 3194.directive('lxHero', [function () { 3195 return { 3196 restrict: 'A', 3197 link: function (scope, element, attrs) { 3198 var controls = attrs.controls || false, 3199 _window = angular.element(window), 3200 _header = angular.element('header'), 3201 _bNav = angular.element('.lx-b-nav'), 3202 _cta = angular.element('.lx-cta-bar'), 3203 headerHeight = _header.innerHeight(), 3204 breakpointSrc = 'src-lg', 3205 oldBreakpointSrc, 3206 breakpointHeightAdjust = Lexus.Breakpoint.Small; 3207
3208 function init() { 3209 fullScreenResize(); 3210 } 3211 3212 function fullScreenResize() { 3213 var windowHeight = _window.innerHeight(), 3214 ctaHeight = (element.hasClass('has-cta-bar')) ? 0 : (_cta.length > 0) ? _cta.innerHeight() : 96, 3215 bNavHeight = (_bNav.length > 0) ? _bNav.innerHeight() : 0, 3216 imageHeight = windowHeight - headerHeight - ctaHeight - bNavHeight; 3217 3218 if (_window.width() < breakpointHeightAdjust) { 3219 imageHeight = 261; 3220 } 3221 3222 element.height(imageHeight); 3223 } 3224 3225 _window.resize(function () { 3226 fullScreenResize(); 3227 }); 3228 3229 _window.ready(function () { 3230 init(); 3231 }); 3232 } 3233 }; 3234}]); 3235; 3236"use strict"; 3237/* Directives */ 3238angular.module('Lexus.Directives') 3239.directive('lxBackgroundImage', [function () { 3240 return { 3241 restrict: 'A', 3242 link: function (scope, element, attrs) { 3243 var controls = attrs.controls || false, 3244 _window = angular.element(window), 3245 _currentSize = 0, 3246 _newSize = 0; 3247 3248 function init() {
3249 updateBackgroundSize(); 3250 } 3251 3252 function updateBackgroundSize() { 3253 3254 if (_window.width() <= Lexus.Breakpoint.ExtraExtraSmall) { _newSize = Lexus.Breakpoint.ExtraExtraSmall; } 3255 else if (_window.width() <= Lexus.Breakpoint.ExtraSmall) { _newSize = Lexus.Breakpoint.ExtraSmall; } 3256 else if (_window.width() <= Lexus.Breakpoint.Small) { _newSize = Lexus.Breakpoint.Small; } 3257 else { _newSize = 1920; }// Lexus.Breakpoint.Medium; } 3258 3259 if (_currentSize != _newSize) { 3260 3261 var resolvedBackground = attrs.background + '?q=95&w=' + _newSize; 3262 3263 if (attrs.backgroundFillVertical) { 3264 resolvedBackground = attrs.background + '?q=95&h=' + element[0].clientHeight; 3265 } 3266 3267 element.css({ 'background-image': 'url(' + resolvedBackground + ')'}); 3268 3269 _currentSize = _newSize; 3270 3271 } 3272 } 3273 3274 _window.resize(function () {
3275 updateBackgroundSize(); 3276 }); 3277 3278 _window.ready(function () { 3279 init(); 3280 }); 3281 } 3282 }; 3283}]); 3284; 3285"use strict"; 3286/* Directives */ 3287angular.module('Lexus.Directives') 3288 .directive('lxImageResize', [function () { 3289 return { 3290 restrict: 'A', 3291 link: function (scope, element, attrs) { 3292 var controls = attrs.controls || false, 3293 _window = angular.element(window), 3294 _currentSize = 0, 3295 _newSize = 0; 3296 3297 function init() { 3298 updateImageSize(); 3299 } 3300 3301 function updateImageSize() { 3302 3303 if (_window.width() <= Lexus.Breakpoint.ExtraExtraSmall) { _newSize = Lexus.Breakpoint.ExtraExtraSmall; } 3304 else if (_window.width() <= Lexus.Breakpoint.ExtraSmall) { _newSize = Lexus.Breakpoint.ExtraSmall; } 3305 else if (_window.width() <= Lexus.Breakpoint.Small) { _newSize = Lexus.Breakpoint.Small; } 3306 else { _newSize = 1200; } 3307 3308 if (_currentSize != _newSize) { 3309 var resolvedImage = attrs.image + '?q=95&w=' + _newSize; 3310 attrs.$set("src", resolvedImage); 3311 _currentSize = _newSize; 3312 } 3313 } 3314 3315 _window.resize(function () { 3316 updateImageSize(); 3317 }); 3318 3319 _window.ready(function () { 3320 init(); 3321 }); 3322 } 3323 }; 3324}]); 3325; 3326"use strict"; 3327/* Directives */ 3328angular.module('Lexus.Directives') 3329.directive('lxCarousel', [function () { // Lazy load images. 3330 return { 3331 restrict: 'A', 3332 link: function (scope, element, attrs) { 3333 var controls = attrs.controls || false, 3334 _window = angular.element(window), 3335 _header = angular.element('header'), 3336 _allImages = element.find('.lx-carousel__image'), 3337 //_videos = element.find('.carousel-video'), 3338 //_ytVideos = [], 3339 feautredCarousel = element.parent('.lx-carousel'), 3340 headerHeight = _header.innerHeight(), 3341 breakpointSrc = 'src-lg', 3342 reassignSources = true, 3343 oldBreakpointSrc, 3344 breakpointHeightAdjust = Lexus.Breakpoint.Small, 3345 //hasLoadedYoutubeAPI = false, 3346 bxSlider; 3347 3348 function init() { 3349 fullScreenResize(); 3350 imageSrc(); 3351 initSlider(); 3352 } 3353 3354 // If it is a feature carousel then resize images. 3355 function fullScreenResize() { 3356 var windowHeight = _window.innerHeight(), 3357 imageHeight = windowHeight - headerHeight - 88; 3358 3359 if (feautredCarousel.length > 0) { 3360 if (_window.width() < breakpointHeightAdjust) { 3361 imageHeight = 261; 3362 } 3363 3364 element.height(imageHeight); 3365 _allImages.height(element.height()); 3366 } 3367 } 3368 3369 function findElement(arr, propName, propValue) { 3370 for (var i = 0; i < arr.length; i++) 3371 if (arr[i][propName] == propValue) 3372 return arr[i]; 3373 3374 // will return undefined if not found; you could return a default instead 3375 } 3376 3377 // Resize all video heights, as iframes won't automatically set height 3378 //function videoResize() { 3379 // if (_videos.length) { 3380 // var videoHeight = element[0].parentElement.clientHeight * 0.97; // set to 0.97 to prevent height adjust issue 3381 // for (var i = 0; i < _videos.length; i++) { 3382 // _videos[i].height = videoHeight; 3383 // } 3384 // } 3385 //} 3386 3387 // Pauses all the videos 3388 //function pauseVideos() { 3389 // if (_ytVideos.length) { 3390 // angular.forEach(_ytVideos, function (value, key) { 3391 // if (value.value && value.value.stopVideo) { 3392 // value.value.stopVideo(); 3393 // } 3394 // }); 3395 // } 3396 //} 3397 3398 function imageSrc() { 3399 if ((reassignSources || breakpointSrc == 'src') && _window.width() > breakpointHeightAdjust) { 3400 breakpointSrc = 'src-lg'; 3401 reassignSrc(); 3402 } else if ((reassignSources || breakpointSrc == 'src-lg') && _window.width() <= breakpointHeightAdjust) { 3403 breakpointSrc = 'src'; 3404 reassignSrc(); 3405 } 3406 reassignSources = false; 3407 } 3408 3409 function reassignSrc() { 3410 $(_allImages).each(function () { 3411 var $img = $(this).hasClass('lx-carousel__image') ? $(this) : $(this).find('.lx-carousel__image'); 3412 $img.attr('src', null).attr('src', $img.attr('data-' + breakpointSrc
3412)); 3413 3414 }); 3415 } 3416 3417 //function initYoutubeAPI() { 3418 3419 // var tag = document.createElement('script'); 3420 // tag.src = "https://www.youtube.com/iframe_api"; 3421 // var firstScriptTag = document.getElementsByTagName('script')[0]; 3422 // firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 3423 // hasLoadedYoutubeAPI = true; 3424 //} 3425 3426 // Load bxslider. 3427 function initSlider() { 3428 var _allImages = element.find('.lx-carousel__image'), 3429 imagesLength = _allImages.length; 3430 3431 //// retrieve all youtube video iframes 3432 //var _frames = element.find('.carousel-video'), 3433 // framesLength = _frames.length; 3434 3435 ////Init the YT JS API 3436 //if (!hasLoadedYoutubeAPI) { 3437 // initYoutubeAPI(); 3438 //} 3439 3440 function loadBackgroundImage(slide) { 3441 if (angular.isDefined(slide) && 3442 (angular.isUndefined(slide.css('background-image')) || slide.css('background-image') == 'none' || !angular.equals(breakpointSrc, oldBreakpointSrc))) { 3443 slide.css('background-image', 'url("' + slide.data(breakpointSrc) + '")'); 3444 slide.find('img').attr('src', slide.data(breakpointSrc)).hide(); 3445 } 3446 }; 3447 3448 bxSlider = element.bxSlider({ 3449 mode: 'fade', 3450 minSlides: 1, 3451 maxSlides: 1, 3452 slideMargin: 0, 3453 captions: true, 3454 auto: true, 3455 pause: 5000, 3456 pager: true, 3457 autoHover: true, 3458 nextText: '', 3459 prevText: '', 3460 controls: controls, 3461 onSliderLoad: function (currentIndex) { 3462 3463 if (imagesLength) { 3464 var _firstElement = angular.element(_allImages[currentIndex]), 3465 _secondElement = angular.element(_allImages[currentIndex + 1]); 3466 3467 // Show first element. 3468 loadBackgroundImage(_firstElement); 3469 loadBackgroundImage(_secondElement); 3470 } 3471 //videoResize(); 3472 }, 3473 onSlideBefore: function () { 3474 }, 3475 onSlideAfter: function ($slideElement, oldIndex, newIndex) { 3476 //When a video comes into view start playing it, when its left pause it again 3477 //pauseVideos(); 3478 //if ($slideElement.hasClass('slide-video')) { 3479 // var video = $slideElement.find('iframe'); 3480 // if (!findElement(_ytVideos, 'name', video[0].id)) { 3481 // var player = new YT.Player(video[0].id, { 3482 // events: { 3483 // 'onReady': function (event) { 3484 // event.target.setVolume(0); 3485 // event.target.playVideo(); 3486 // }, 3487 // 'onStateChange': function (event) { 3488 3489 // switch (event.data) { 3490 // case YT.PlayerState.PLAYING: 3491 // bxSlider.stopAuto(); 3492 // //pause the gallery rotation 3493 // break; 3494 // case YT.PlayerState.PAUSED: 3495 // bxSlider.startAuto(); 3496 // //resume gallery rotation 3497 // break; 3498 // case YT.PlayerState.ENDED: 3499 // bxSlider.startAuto(); 3500 // //resume gallery rotation 3501 // break; 3502 // default: 3503 // //default co
3503de block 3504 // } 3505 // }, 3506 // 'onError': function (data) { 3507 // console.log('Error ' + data); 3508 // } 3509 // } 3510 // }); 3511 // _ytVideos.push({ 3512 // name: video[0].id, 3513 // value: player 3514 // }); 3515 // } 3516 // var ytObj = findElement(_ytVideos, 'name', video[0].id); 3517 // //This is used for the second pass on the same video, the above ready callback wont run 3518 // //Get player state will not be valid on first pass cause the video isnt inited yet 3519 // if (ytObj.value.getPlayerState) { 3520 // console.log(ytObj.value.getPlayerState()); 3521 3522 // switch (ytObj.value.getPlayerState()) { 3523 // case -1: //unstarted 3524 // ytObj.value.setVolume(0); 3525 // ytObj.value.playVideo(); 3526 // break; 3527 // case 0: //ended 3528 // break; 3529 // case 1: //playing 3530 // break; 3531 // case 2: //paused 3532 // break; 3533 // case 3: //buffering 3534 // break; 3535 // case 5: //video cued 3536 // break; 3537 // default: 3538 // } 3539 // } 3540 //} 3541 if (imagesLength) { 3542 var _thisImage = angular.element(_allImages[newIndex]); 3543 var _nextImage = angular.element(_allImages[newIndex + 1]); 3544 loadBackgroundImage(_thisImage); 3545 loadBackgroundImage(_nextImage); 3546 oldBreakpointSrc = breakpointSrc; 3547 } 3548 } 3549 }); 3550 } 3551 3552 3553 _window.resize(function () { 3554 3555 //put this on a short timeout to prevent continuous re-initing while resizing 3556 init(); 3557 fullScreenResize(); 3558 imageSrc(); 3559 //videoResize(); 3560 }); 3561 3562 _window.ready(function () { 3563 init(); 3564 }); 3565 } 3566 }; 3567}]); 3568; 3569'use strict'; 3570 3571(function() { 3572 var EVENT_OPEN_LIGHTBOX = 'EVENT_OPEN_LIGHTBOX'; 3573 var EVENT_OWL_CHANGED = 'EVENT_OWL_CHANGED'; 3574 3575 angular.module('Lexus.Directives').directive('lxImageGalleryCarousel', [ 3576 'FontIconService', 3577 '$timeout', 3578 '$window', 3579 function(FontIconService, $timeout, $window) { 3580 controller.$inject = ['$scope', '$attrs']; 3581 3582 return { 3583 scope: true, 3584 restrict: 'A', 3585 link: link, 3586 controller: controller, 3587 controllerAs: 'ImageGalleryCtrl', 3588 bindToController: true, 3589 transclude: true 3590 }; 3591 3592 function link(scope, element, attrs, ctrl, transclude) { 3593 transclude(scope, function(clone) { 3594 element.append(clone); 3595 }); 3596 3597 function loadAllImages(callback) { 3598 var numImagesLoaded = 0; 3599 var images = element 3600 .find('.js-owl-carousel') 3601 .first() 3602 .find('.item img') 3603 .toArray(); 3604 3605 for (var i = 0; i < images.length; i++) { 3606 var img = new Image(); 3607 img.src = images[i].src; 3608 img.addEventListener('load', function() { 3609 numImagesLoaded += 1;
3610 if (numImagesLoaded === images.length) { 3611 callback(); 3612 } 3613 }); 3614 } 3615 } 3616 3617 // Fix for owl carousel incorrectly computing the stage width 3618 // when used in conjunction with `autoWidth: true`. 3619 // https://github.com/OwlCarousel2/OwlCarousel2/issues/1139 3620 function fixOwlStageWidth() { 3621 var stage = element.find('.owl-stage').first(); 3622 stage.width(stage.width() * 2); 3623 3624 window.addEventListener('load', function() { 3625 ctrl.$owlCarousel.trigger('refresh.owl.carousel'); 3626 }); 3627 } 3628 3629 var owlCarouselOptions = { 3630 items: 2, 3631 margin: 40, 3632 nav: false, 3633 dots: false, 3634 smartSpeed: 750, 3635 autoWidth: true, 3636 onInitialized: fixOwlStageWidth, 3637 onRefreshed: fixOwlStageWidth 3638 }; 3639 var $items = element 3640 .find('.js-owl-carousel') 3641 .first() 3642 .find('.item'); 3643 3644 if (typeof attrs.lxImageGalleryCarouselOptions !== 'undefined') { 3645 owlCarouselOptions = angular.extend( 3646 owlCarouselOptions, 3647 JSON.parse(attrs.lxImageGalleryCarouselOptions) 3648 ); 3649 } 3650 3651 ctrl.numberOfItems = $items.length; 3652 ctrl.hasLightbox = typeof attrs.lxImageGalleryCarouselHasLightbox !== 'undefined'; 3653 ctrl.isInsideLightbox = typeof attrs.lxImageGalleryCarouselIsInsideLightbox !== 'undefined'; 3654 3655 // If the carousel is inside a lightbox we want to expand each items 3656 // height to fill the maximum vertical space allocated to it via CSS. 3657 function resizeItems() { 3658 var height = element 3659 .find('.lx-image-gallery-carousel__owl-body') 3660 .first() 3661 .height(); 3662 3663 $items.each(function() { 3664 $(this).css({ 3665 height: height + 'px', 3666 width: 'auto' 3667 }); 3668 }); 3669 3670 if (typeof ctrl.$owlCarousel !== 'undefined') { 3671 ctrl.$owlCarousel.trigger('refresh.owl.carousel'); 3672 } 3673 } 3674 3675 if (ctrl.isInsideLightbox) { 3676 $($window).on('resize', resizeItems); 3677 resizeItems(); 3678 } 3679 3680 // If we do not wait for the images to load, on occasion owl carousel 3681 // will not load correctly (only on occasion though). 3682 loadAllImages(function() { 3683 scope.$apply(function() { 3684 ctrl.$owlCarousel = element 3685 .find('.js-owl-carousel') 3686 .first() 3687 .owlCarousel(owlCarouselOptions); 3688 ctrl.owlCarouselInitialised = true; 3689 }); 3690 }); 3691 3692 // Apply a custom cursor to items if it this carousel contains a lightbox. 3693 if (ctrl.hasLightbox) { 3694 var { lightBoxCursor } = FontIconService.generateCursorIcon(); 3695 3696 $items.find('img').each(function() { 3697 $(this).css("cursor", "url(" + lightBoxCursor + ") 16 16, auto"); 3698 }); 3699 } 3700 3701 // Apply a custom cursor to the next/previous buttons if inside lightbox. 3702 if (ctrl.isInsideLightbox) { 3703 var { prevCursor, nextCursor } = FontIconService.generateCursorIcon(); 3704 3705 element 3706 .find(".js-lx-image-gallery-carousel-overlay-nav-button-prev") 3707 .first() 3708 .css("cursor", "url(" + prevCursor + ") 16 16, auto"); 3709 element 3710 .find(".js-lx-image-gallery-carousel-overlay-nav-button-next") 3711 .first() 3712 .css("cursor", "url(" + nextCursor + ") 16 16, auto"); 3713 } 3714 } 3715 3716 function controller($scope, $attrs) { 3717 var $owlCarousel = null; 3718 var ImageGalleryCtrl = this; 3719 ImageGalleryCtrl.sliderValue = 1; 3720 3721 ImageGalleryCtrl.handleNextClick = function() { 3722 if (!$owlCarousel) return; 3723 $owlCarousel.trigger('next.owl.carousel'); 3724 }; 3725 3726 ImageGalleryCtrl.handlePrevClick = function() { 3727 if (!$owlCarousel) return; 3728 $owlCarousel.trigger('prev.owl.carousel'); 3729 }; 3730
3731 ImageGalleryCtrl.handleItemClick = function(event) { 3732 if (!ImageGalleryCtrl.hasLightbox) return; 3733 3734 if (!$(event.target).hasClass("lx-image-gallery-carousel__owl-carousel-image")) { 3735 event.stopPropagation(); 3736 return; 3737 } 3738 3739 $scope.$broadcast(EVENT_OPEN_LIGHTBOX, ImageGalleryCtrl.sliderValue); 3740 }; 3741 3742 ImageGalleryCtrl.handleSliderChange = function() { 3743 if (!$owlCarousel) return; 3744 $owlCarousel.trigger('to.owl.carousel', ImageGalleryCtrl.sliderValue - 1); 3745 }; 3746 3747 $scope.$watch( 3748 'ImageGalleryCtrl', 3749 function(newValue, oldValue) { 3750 if (newValue.owlCarouselInitialised && !oldValue.owlCarouselInitialised) init(); 3751 }, 3752 true 3753 ); 3754 3755 function init() { 3756 $owlCarousel = ImageGalleryCtrl.$owlCarousel.owlCarousel(); 3757 3758 $owlCarousel.on('changed.owl.carousel', function(event) { 3759 ImageGalleryCtrl.sliderValue = event.item.index + 1; 3760 3761 if (!$scope.$$phase) { 3762 $scope.$apply(); 3763 } 3764 3765 if (ImageGalleryCtrl.hasLightbox) { 3766 $scope.$broadcast(EVENT_OWL_CHANGED, ImageGalleryCtrl.sliderValue); 3767 } 3768 }); 3769 3770 $attrs.$observe('lxImageGalleryCarouselSliderValue', function(sliderValue) { 3771 $owlCarousel.trigger('to.owl.carousel', sliderValue); 3772 }); 3773 } 3774 } 3775 } 3776 ]); 3777 3778 angular.module('Lexus.Directives').directive('lxImageGalleryCarouselLightbox', function() { 3779 ImageGalleryCarouselLightboxController.$inject = ['$scope', '$element']; 3780 3781 return { 3782 scope: true, 3783 restrict: 'A', 3784 controller: ImageGalleryCarouselLightboxController, 3785 controllerAs: 'LightboxCtrl', 3786 bindToController: true 3787 }; 3788 3789 function ImageGalleryCarouselLightboxController($scope, $element) { 3790 var LightboxCtrl = this; 3791 var element = $element[0]; 3792 var $document = $(document); 3793 var KEYUP_EVENT = 'keyup.lxImageGalleryCarousel'; 3794 3795 LightboxCtrl.isOpen = false; 3796 LightboxCtrl.sliderValue = 1; 3797 3798 LightboxCtrl.open = function() { 3799 bodyScrollLock.disableBodyScroll(element); 3800 LightboxCtrl.isOpen = true; 3801 $document.on(KEYUP_EVENT, function(e) { 3802 if (e.key === 'Escape') { 3803 LightboxCtrl.isOpen = false; 3804 bodyScrollLock.enableBodyScroll(element); 3805 $scope.$apply(); 3806 } 3807 }); 3808 }; 3809 3810 LightboxCtrl.close = function() { 3811 LightboxCtrl.isOpen = false; 3812 bodyScrollLock.enableBodyScroll(element); 3813 $document.off(KEYUP_EVENT); 3814 }; 3815 3816 $scope.$on(EVENT_OPEN_LIGHTBOX, function() { 3817 LightboxCtrl.open(); 3818 }); 3819 3820 $scope.$on(EVENT_OWL_CHANGED, function(event, sliderValue) { 3821 LightboxCtrl.sliderValue = sliderValue - 1; 3822 }); 3823 } 3824 }); 3825})(); 3826; 3827"use strict"; 3828/* Directives */ 3829angular.module('Lexus.Directives') 3830 .directive('lxCampaignPromoTile', function () { 3831 CampaignPromoTileController.$inject = ['$scope', '$window', '$rootScope']; 3832 return { 3833 scope: true, 3834 restrict: 'A', 3835 controller: CampaignPromoTileController, 3836 controllerAs: 'cptc', 3837 bindToController: true, 3838 link: function (scope, element, attrs) { 3839 } 3840 }; 3841 3842 function CampaignPromoTileController($scope, $window, $rootScope) { 3843 var cptc = this; 3844 cptc.shiftPromoTilesUp = false; 3845 3846 $scope.init = function () { 3847 $scope.showPromoTile = true; 3848 } 3849 3850 3851 $scope.toggleShow = function () { 3852 $scope.showPromoTile = !$scope.showPromoTile; 3853 } 3854 3855 $scope.$on("shift-promo-tiles-up", function (evt, data) { 3856 cptc.shiftPromoTilesUp = data; 3857 }); 3858 } 3859 3860 });
3861; 3862"use strict"; 3863/* Directives */ 3864angular.module('Lexus.Directives') 3865 .directive('lxCampaignRangeExplore', function () { 3866 CampaignRangeExploreController.$inject = ['$scope', '$window', '$rootScope', '$timeout']; 3867 return { 3868 scope: true, 3869 restrict: 'A', 3870 controller: CampaignRangeExploreController, 3871 controllerAs: 'crec', 3872 bindToController: true, 3873 link: function (scope, element, attrs) { 3874 scope.directiveElement = element; 3875 scope.initControl(); 3876 } 3877 }; 3878 3879 function CampaignRangeExploreController($scope, $window, $rootScope, $timeout) { 3880 var crec = this; 3881 3882 $scope.init = function (showSplashScreen) { 3883 $scope.showSplashScreen = showSplashScreen; 3884 } 3885 3886 $scope.initControl = function () { 3887 $scope.showCampaignDetails = !$scope.showSplashScreen; 3888 $scope.blurOverlayImage = true; 3889 $scope.animationStarted = false; 3890 if ($scope.showSplashScreen) { 3891 $('body').addClass("is-locked"); 3892 } 3893 } 3894 3895 $scope.attachActivateOnScroll = function () { 3896 //Wait before attaching, the window might still be anchor scrolling 3897 $timeout(function () { 3898 $scope.scrollEvent(); 3899 }, 300); 3900 } 3901 3902 $scope.scrollEvent = function () { 3903 window.onscroll = function () { 3904 if (!$scope.animationStarted) { 3905 $scope.animationStarted = true; 3906 $scope.closeOverlay(); 3907 } 3908 } 3909 } 3910 3911 $scope.scrollIntoView = function (callback) { 3912 TweenLite.to(window, 0, { scrollTo: 0, onComplete: callback }); 3913 } 3914 3915 $scope.animationComplete = function () { 3916 $(".lx-campaign-range-explore__overlay-svg").hide(); 3917 $(".lx-campaign-range-explore__centered").hide(); 3918 $(".lx-campaign-range-explore__background").hide(); 3919 } 3920 3921 $scope.fadeoutText = function () { 3922 $(".lx-campaign-range-explore__overlay").hide(); 3923 3924 var tl = new TimelineLite(); 3925 tl.delay(3); 3926 tl.to($(".lx-campaign-range-explore__centered"), 0.7, { css: { opacity: "0" }, onComplete: $scope.animateSVGShowOffer }); 3927 tl.play(); 3928 } 3929 3930 $scope.hideBackground = function () { 3931 var t = new TimelineLite(); 3932 t.to($(".lx-campaign-range-explore__background"), 1, { css: { opacity: "0" } }); 3933 t.play(); 3934 } 3935 3936 $scope.animateSVGShowOffer = function () { 3937 $scope.scrollIntoView(); 3938 $scope.hideBackground(); 3939 3940 $('body').removeClass("is-locked"); 3941 3942 var tl = new TimelineLite({ onComplete: $scope.animationComplete }); 3943 tl.to("#Poly-1", 3, { y: '200%' }, "showOffer") 3944 .to("#Poly-2", 3, { y: '-200%' }, "showOffer") 3945 .to("#Poly-3", 3, { x: '200%' }, "showOffer") 3946 .to("#Poly-4", 3, { x: '-200%' }, "showOffer") 3947 tl.play(); 3948 3949 $timeout(function () { $rootScope.$broadcast('calculate-widths') }, 100); 3950 3951 } 3952 3953 $scope.closeOverlay = function () { 3954 var tl = new TimelineLite(); 3955 tl.to($(".lx-campaign-range-explore__overlay-logo, .lx-campaign-range-explore__overlay-heading"), 1.2, { css: { top: "-5%", opacity: "0" } }); 3956 tl.play(); 3957 3958 var tl2 = new TimelineLite(); 3959 tl2.to($(".lx-campaign-range-explore__overlay-animation-outer"), 2, { css: { opacity: "0" } }); 3960 tl2.play(); 3961 3962 $scope.blurOverlayImage = false; 3963 3964 var tl3 = new TimelineLite(); 3965 tl3.to($(".lx-campaign-range-explore__overlay-svg"), 0.8, { css: { opacity: "0.9" } }); 3966 tl3.to($(".lx-campaign-range-explore__centered"), 0, { css: { transform: "translateY(15%)" } }); 3967 tl3.to($(".lx-campaign-range-explore__centered"), 1, { css: { transform: "translateY(0)", opacity: "0.9" }, onComplete: $scope.fadeoutText }); 3968 tl3.play(); 3969 $scope.showCampaignDetails = true; 3970 } 3971 } 3972 }) 3973 .directive('lxCampaignRangeExploreMainImage', [function () { 3974 return { 3975 restrict: 'A', 3976 link: function (scope, element, attrs) { 3977 var controls = attrs.controls || false, 3978 _window = angular.element(window) 3979
3980 function init() { 3981 fullScreenResize(); 3982 } 3983 3984 function fullScreenResize() { 3985 var imageHeight = _window.innerHeight(); 3986 element.height(imageHeight); 3987 } 3988 3989 _window.resize(function () { 3990 fullScreenResize(); 3991 }); 3992 3993 _window.ready(function () { 3994 init(); 3995 }); 3996 } 3997 }; 3998 }]) 3999 .directive('lxCampaignRangeExploreHero', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 4000 exploreCampaignRangeController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location']; 4001 return { 4002 scope: true, 4003 restrict: 'A', 4004 controller: exploreCampaignRangeController, 4005 controllerAs: 'er', 4006 bindToController: true, 4007 link: function (scope, element, attrs, filter, http) { 4008 } 4009 }; 4010 4011 4012 function exploreCampaignRangeController($scope, $http, $filter, $timeout, $window, $interval, $location) { 4013 var er = this, 4014 _window = angular.element(window), 4015 _currentSize = 0, 4016 _newSize = 0, 4017 _sizeFilter = '', 4018 _panelBkg = angular.element('.lx-campaign-range-explore__image-panel').attr('data-background'); 4019 4020 $scope.resolvedImage = null; 4021 4022 function init() {
4023 $scope.updateBackgroundImage(); 4024 $scope.model = null; 4025 $scope.modelFullName = null; 4026 } 4027 4028 4029 $scope.previousVehicle = function () { 4030 $rootScope.$broadcast('change-previous-vehicle'); 4031 } 4032 4033 $scope.nextVehicle = function () { 4034 $rootScope.$broadcast('change-next-vehicle'); 4035 } 4036 4037 $scope.scrollTo = function (anchor) { 4038 TweenLite.to(window, 0.5, { scrollTo: anchor, ease: Power2.easeOut }); 4039 } 4040 4041 $rootScope.$on('change-active-vehicle', function (event, args) { 4042 $scope.er.activeVehicle = args; 4043 $scope.model = args.name; 4044 $scope.modelFullName = args.fullName; 4045 $scope.updateBackgroundImage(args.imageSrc); 4046 $scope.updateDisclaimer(args.disclaimer, args.disclaimerIsDarkStyle); 4047 }); 4048 4049 $scope.updateDisclaimer = function (text, isDarkStyle) { 4050 $(".lx-campaign-range-explore__info-content").text(text); 4051 $(".lx-campaign-range-explore__info-content").closest(".lx-campaign-range-explore__info-overlay").toggleClass("lx-campaign-range-explore--dark-tooltip", isDarkStyle); 4052 } 4053 4054 $scope.updateModelTitle = function (model) { 4055 if (!model) { 4056 return; 4057 } 4058 4059 $scope.model = model.name; 4060 $scope.modelFullName = model.fullName; 4061 } 4062
4063 $scope.updateBackgroundImage = function (imageSrc) { 4064 4065 if (_window.width() <= Lexus.Breakpoint.ExtraExtraSmall) { _newSize = Lexus.Breakpoint.ExtraExtraSmall; } 4066 else if (_window.width() <= Lexus.Breakpoint.ExtraSmall) { _newSize = Lexus.Breakpoint.ExtraSmall; } 4067 else if (_window.width() <= Lexus.Breakpoint.Small) { _newSize = Lexus.Breakpoint.Small; } 4068 else { _newSize = Lexus.Breakpoint.Medium; } 4069 4070 if (_currentSize != _newSize) { 4071 _sizeFilter = '?q=95&w=' + _newSize; 4072 _currentSize = _newSize; 4073 } 4074 4075 if ($scope.resolvedImage != (imageSrc + _sizeFilter)) { 4076 $scope.resolvedImage = imageSrc + _sizeFilter; 4077 4078 } 4079 4080 } 4081 4082 _window.resize(function () { 4083 $scope.updateBackgroundImage($scope.er.activeVehicle.imageSrc); 4084 }); 4085 4086 4087 $scope.init = function () { 4088 $scope.er = { 4089 activeVehicle: { 4090 } 4091 }; 4092 } 4093 4094 } 4095 }]) 4096 .directive('lxCampaignRangeExploreSlider', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', 'UserPreferencesService', 'VehicleService', function ($window, $timeout, $filter, $http, $location, $rootScope, UserPreferencesService, VehicleService) { 4097 exploreRangeSliderController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'UserPreferencesService', 'VehicleService']; 4098 return { 4099 scope: true, 4100 restrict: 'A', 4101 controller: exploreRangeSliderController, 4102 controllerAs: 'ers', 4103 bindToController: true, 4104 link: function (scope, element, attrs, filter, http) { 4105 4106 var touchStartHandler = function (e) { 4107 scope.slider.startClientX = e.changedTouches[0].screenX; 4108 } 4109 var touchMovetHandler = function (e) { 4110 // reference first touch point for this event 4111 var relativeScrolled_x = e.changedTouches[0].screenX - scope.slider.startClientX; 4112 var idexesToFly = Math.ceil(Math.abs(relativeScrolled_x) / scope.itemWidth); 4113 //scrolled right 4114 if (relativeScrolled_x < 0) { 4115 //scroll to next element 4116 scope.slider.jumpToIndex = scope.carouselPos + idexesToFly <= scope.sliderItemCollection.length - 1 4117 ? scope.carouselPos + idexesToFly : scope.carouselPos; 4118 } 4119 //scrolled left 4120 else { 4121 //scroll to prev element 4122 scope.slider.jumpToIndex = scope.carouselPos - idexesToFly >= 0 ? scope.carouselPos - idexesToFly : 0; 4123 } 4124 } 4125 var touchEndHandler = function (e) { 4126 if (scope.slider.jumpToIndex == null || (scope.slider.jumpToIndex == scope.carouselPos)) { 4127 return; 4128 } 4129 scope.changeActiveVehicleIndex(scope.slider.jumpToIndex, true, true); 4130 } 4131 4132 function clearTouchEvents() { 4133 if (scope.carouselSlider[0].removeEventListener) { 4134 scope.carouselSlider[0].removeEventListener('touchstart', touchStartHandler); 4135 scope.carouselSlider[0].removeEventListener('touchmove', touchMovetHandler); 4136 scope.carouselSlider[0].removeEventListener('touchend', touchEndHandler); 4137 } 4138 } 4139 4140 function addTouchEvents() { 4141 clearTouchEvents(); 4142 if (scope.carouselSlider[0].addEventListener) { 4143 scope.carouselSlider[0].addEventListener('touchstart', touchStartHandler, false); 4144 scope.carouselSlider[0].addEventListener('touchmove', touchMovetHandler, false); 4145 scope.carouselSlider[0].addEventListener('touchend', touchEndHandler, false); 4146 } 4147 } 4148 4149 $rootScope.$on('calculate-widths', function (event, args) { 4150 scope.carouselSlider = element; 4151 scope.activeMarker = element.find('.lx-campaign-range-explore__marker-js'); 4152 scope.$innerContainer = scope.carouselSlider.children().first('.lx-campaign-range-explore__subpanels'); 4153 scope.itemWidth = scope.$innerContainer.find('.lx-campaign-range-explore__subpanel').first().width(); 4154 4155 scope.outerContainerWidth = scope.carouselSlider.width(); 4156 scope.maxScrollX = scope.$innerContainer.width() - scope.outerContainerWidth; 4157 scope.slider = { 4158 startClientX: undefined, 4159 jumpToIndex: null, 4160 smoothScrollonClick: false, 4161 } 4162 4163 //use native swipe scrolling for touch devices, If its a laptop with touch and wide screen assume they are using K&M 4164 if (!Modernizr.touchevents || angular.element($window).width() >= Lexus.Breakpoint.Medium) { 4165 scope.carouselSlider.mousemove(function (event) { scope.smoothScrollTo(event); }); 4166 scope.carouselSlider.mouseleave(function (event) { scope.smoothSnapToNearest(event); }); 4167 clearTouchEvents(); 4168 scope.slider.smoothScrollonClick = false; 4169 } 4170 else if (Modernizr.touchevents && angular.element($window).width() < Lexus.Breakpoint.Medium) { 4171 addTouchEvents(); 4172 scope.slider.smoothScrollonClick = true; 4173 } 4174 4175 angular.forEach(scope.$innerContainer.children('.lx-campaign-range-explore__subpanel'), function (value, key) { 4176 value.className = value.className; 4177 }); 4178 //scope.smoothSnapToNearest(event); 4179 }); 4180 4181 angular.element($window).bind('resize', function () { 4182 $rootScope.$broadcast('calculate-widths'); 4183 }); 4184 4185 scope.$on('$destroy', function () { 4186 clearTouchEvents(); 4187 }); 4188 } 4189 } 4190 4191 4192 function exploreRangeSliderController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope) { 4193 var ers = this; 4194 $scope.urlParameters = $location.search(); 4195 4196 $scope.init = function (overscrollPadding, markerRadius) { 4197 $scope.overscrollPadding = overscrollPadding; 4198 $scope.markerRadius = markerRadius; 4199 $scope.carouselTweenTime = 1; 4200 $scope.markerTweenTime = 1; 4201 $scope.easingFunction = Power2.easeOut; 4202 $scope.sliderItemCollection = []; 4203 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.urlParameters); 4204 if (dataVehicle && dataVehicle.model) { 4205 $scope.changeActiveVehicleIndex($scope.findIndexByModel(dataVehicle.model), true); 4206 } 4207 4208 4209 $rootScope.$on('change-previous-vehicle', function () { 4210 var newIndex = $scope.carouselPos - 1 >= 0 ? $scope.carouselPos - 1 : $scope.sliderItemCollection.length - 1; 4211 $scope.changeActiveVehicleIndex(newIndex, true); 4212 $scope.smoothScrollToIndex(newIndex); 4213 }); 4214 $rootScope.$on('change-next-vehicle', function () { 4215 var newIndex = $scope.carouselPos + 1 <= $scope.sliderItemCollection.length - 1 ? $scope.carouselPos + 1 : 0; 4216 $scope.changeActiveVehicleIndex(newIndex, true); 4217 $scope.smoothScrollToIndex(newIndex); 4218 }); 4219 } 4220 4221 4222 4223 $scope.findIndexByModel = function (modelName) { 4224 var modelIndex = -1; 4225 if ($scope.sliderItemCollection && $scope.sliderItemCollection.length > 0 && modelName) { 4226 modelIndex = $scope.sliderItemCollection.findIndex(function (m) { return m.name.toLowerCase() === modelName.toLowerCase() }); 4227 } 4228 return (modelIndex == -1 ? 0 : modelIndex); 4229 } 4230 4231 $scope.smoothScrollToIndex = function (index) { 4232 var left = $scope.itemWidth * index; 4233 left = Math.round(left + $scope.overscrollPadding + ($scope.itemWidth / 2) - ($scope.outerContainerWidth / 2)); 4234 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: (left) }, ease: $scope.easingFunction }); 4235 $rootScope.$broadcast('pause-smooth-scroll-to', ''); 4236 } 4237
4238 $rootScope.$on('pause-smooth-scroll-to', function (event, args) { 4239 $rootScope.pauseSmoothScrollTo = true; 4240 setTimeout(function () { 4241 $rootScope.pauseSmoothScrollTo = false; 4242 }, 1500); 4243 }); 4244 4245 $scope.smoothScrollTo = function (event) { 4246 if ($rootScope.pauseSmoothScrollTo === true) { 4247 return; 4248 } 4249 var offsetX = $scope.carouselSlider.position().left; 4250 var posInPc = (event.clientX - offsetX) / $scope.outerContainerWidth; 4251 $scope.carouselPos = $scope.maxScrollX * posInPc; 4252 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: ($scope.carouselPos) }, ease: $scope.easingFunction }); 4253 } 4254 4255 $scope.smoothSnapToNearest = function (event) { 4256 var offset = $scope.overscrollPadding; 4257 var snapWidth = $scope.itemWidth; 4258 4259 var misalignment = ($scope.carouselPos % snapWidth) - offset; 4260 var previousSnapPoint = $scope.carouselPos - misalignment; 4261 var nextSnapPoint = $scope.carouselPos - misalignment + snapWidth; 4262 4263 if (misalignment === 0) { 4264 return; 4265 } else if (misalignment < (snapWidth / 2)) { 4266 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: previousSnapPoint }, ease: $scope.easingFunction }); 4267 } else { 4268 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: nextSnapPoint }, ease: $scope.easingFunction }); 4269 } 4270 } 4271 4272 $scope.setMarkerPosition = function (failCount) { 4273 var i = failCount || 0; 4274 if (!$scope.activeMarker && i < 10) { 4275 setTimeout(function () { 4276 $scope.setMarkerPosition(i + 1); 4277 }, 100); 4278 return; 4279 } 4280 var newPosition = Math.round($scope.overscrollPadding + ($scope.carouselPos * $scope.itemWidth) + ($scope.itemWidth * 0.5) - $scope.markerRadius); 4281 $scope.activeMarker.css('left', newPosition + 'px'); 4282 //why? $scope.smoothScrollToIndex($scope.carouselPos); 4283 } 4284 4285 $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { 4286 $scope.sliderItemCollection[0].style = { "margin-left": $scope.overscrollPadding + "px" }; 4287 $scope.sliderItemCollection[$scope.sliderItemCollection.length - 1].style = { "margin-right": $scope.overscrollPadding + "px" }; 4288 $timeout(function () { $rootScope.$broadcast('calculate-widths') }, 100); 4289 $scope.setMarkerPosition(); 4290 4291 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.urlParameters); 4292 if (dataVehicle && dataVehicle.model) { 4293 $scope.changeActiveVehicleIndex($scope.findIndexByModel(dataVehicle.model), true); 4294 } 4295 4296 }); 4297 4298 this.addSliderItem = function (data) { 4299 $scope.sliderItemCollection[data.index] = data; 4300 $scope.sliderItemCollection[data.index].disabled = false; 4301 $scope.sliderItemCollection[data.index].style = {}; 4302 if (data.init) { 4303 $scope.carouselPos = parseInt(data.index); 4304 $scope.sliderItemCollection[data.index].active = true; 4305 $timeout(function () { $rootScope.$broadcast('change-active-vehicle', data) }, 100); 4306 } 4307 else { 4308 $scope.sliderItemCollection[data.index].active = false; 4309 } 4310 } 4311 4312 $rootScope.$on('campaign-vehicle-preference-change', function (event, args) { 4313 if (args) { 4314 var vehicleIndex = $scope.findIndexByModel(args.model); 4315 if (vehicleIndex >= 0) { 4316 $scope.changeActiveVehicleIndex(vehicleIndex, false); 4317 } 4318 } 4319 4320 }); 4321 4322 $scope.changeActiveVehicleIndex = function (index, broadcastChange, smoothScroll) { 4323 if ($scope.sliderItemCollection.length > 0) { 4324 4325 $scope.carouselPos = index; 4326 angular.forEach($scope.sliderItemCollection, function (value, key) { 4327 value.active = (key == index); 4328 }); 4329 $scope.setMarkerPosition();
4330 var newVehicle = $scope.sliderItemCollection[index]; 4331 4332 $scope.updateBackgroundImage(newVehicle.imageSrc); 4333 $scope.updateModelTitle(newVehicle); 4334 4335 if (broadcastChange) { 4336 $scope.updateCookieAlertOthers(newVehicle); 4337 } 4338 4339 if (smoothScroll || ($scope.slider && $scope.slider.smoothScrollonClick)) { 4340 $scope.smoothScrollToIndex(index); 4341 } 4342 4343 } 4344 } 4345 4346 $scope.updateCookieAlertOthers = function (newVehicle) { 4347 4348 $timeout(function () { $rootScope.$broadcast('change-active-vehicle', newVehicle) }, 100); 4349 4350 $rootScope.$broadcast('campaign-vehicle-preference-change', { 4351 model: newVehicle.name, 4352 grade: undefined, 4353 engineVariant: undefined, 4354 enhancementPack: undefined 4355 }); 4356 4357 } 4358 4359 4360 4361 $rootScope.$on('filter-body-type', function (event, args) { 4362 var newActiveIndex = 0; 4363 var needtoApplyNewIndex = false; 4364 angular.forEach($scope.sliderItemCollection, function (value, key) { 4365 var isDisabled = !(args == 'all' || args == value.bodyType); 4366 value.disabled = isDisabled; 4367 if (isDisabled && value.active) { 4368 value.active = false; 4369 needtoApplyNewIndex = true; 4370 } 4371 }); 4372 if (needtoApplyNewIndex) { 4373 var keepGoing = true; 4374 angular.forEach($scope.sliderItemCollection, function (value, key) { 4375 if (keepGoing) { 4376 if (!value.disabled) { 4377 value.active = true; 4378 $scope.smoothScrollToIndex(key); 4379 keepGoing = false; 4380 $timeout(function () { 4381 $rootScope.$broadcast('change-active-vehicle', value); 4382 $scope.changeActiveVehicleIndex(value.index); 4383 }, 100); 4384 } 4385 } 4386 }); 4387 } 4388 }); 4389 4390 4391 } 4392 }]) 4393 .directive('lxCampaignRangeExploreSliderItem', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 4394 return { 4395 scope: true, 4396 restrict: 'AE', 4397 require: '^lxCampaignRangeExploreSlider', 4398 link: function (scope, element, attrs, exploreRangeSliderController) { 4399 exploreRangeSliderController.addSliderItem(attrs); 4400 } 4401 } 4402 4403 4404 }]); 4405 4406; 4407(function (undefined) { 4408 4409 "use strict"; 4410 /* Directives */ 4411 angular.module('Lexus.Directives') 4412 .directive('lxCampaignModelRangeEngineVariant', CampaignModelRangeEngineVariantDirective); 4413 4414 CampaignModelRangeEngineVariantDirective.$inject = ['$location', '$rootScope', 'UserPreferencesService']; 4415 4416 function CampaignModelRangeEngineVariantDirective($location, $rootScope, UserPreferencesService) { 4417 4418 var engineVariants = null; 4419 var modelRange = null; 4420 var buildAndPriceUrl = null; 4421 var gradeName = null; 4422 campaignModelRangeEngineVariantController.$inject = ['$scope', '$window', 'VehicleService', 'BuildPriceService', 'UserPreferencesService']; 4423 return { 4424 scope: true, 4425 restrict: 'A', 4426 controller: campaignModelRangeEngineVariantController, 4427 link: link 4428 }; 4429 4430 function link(scope, element, attrs) { 4431 engineVariants = angular.fromJson(attrs.engineVariants); 4432 buildAndPriceUrl = attrs.buildAndPriceUrl; 4433 gradeName = attrs.gradeName; 4434 4435 for (var index = 0; index < engineVariants.length; index++) { 4436 engineVariants[index].selected = false; 4437 } 4438 4439 var dataVehicle = UserPreferencesService.getLexusVehicle($location.search()); 4440 4441 if (dataVehicle) { 4442 var variant = null; 4443 var foundVariant = null; 4444 var variantIndex = null; 4445 4446 for (var index = 0; index < engineVariants.length; index++) { 4447 if (engineVariants[index].model === dataVehicle.model) { 4448 variant = engineVariants[index]; 4449 foundVariant = variant.engineVariant; 4450 break; 4451 } 4452 } 4453 4454 if (foundVariant) { 4455 variantIndex = scope.selectVariant(variant.engineVariant, variant.gradeId, variant.variantId, variant.enhancementPack); 4456 } else { 4457 variantIndex = scope.selectVariant(engineVariants[0].engineVariant, engineVariants[0].gradeId, engineVariants[0].variantId, engineVariants[0].enhancementPack); 4458 } 4459 } 4460 else { 4461 variantIndex = scope.selectVariant(engineVariants[0].engineVariant, engineVariants[0].gradeId, engineVariants[0].variantId, engineVariants[0].enhancementPack); 4462 } 4463 4464 if (variantIndex != null) { 4465 scope.setModelName(engineVariants[variantIndex].model, engineVariants[variantIndex].engineVariant); 4466 } 4467 } 4468 4469 function campaignModelRangeEngineVariantController($scope, $window, VehicleService, BuildPriceService, UserPreferencesService) { 4470 4471 $scope.variantName = ""; 4472 $scope.gradeId = ""; 4473 $scope.variantId = ""; 4474 $scope.enhancementPack = ""; 4475 4476 $scope.selectVariant = function (variantName, gradeId, variantId, enhancementPack) { 4477 var selectedIndex = null; 4478 for (var index = 0; index < engineVariants.length; index++) { 4479 if (engineVariants[index].engineVariant === variantName) { 4480 engineVariants[index].selected = true; 4481 4482 selectedIndex = index; 4483 $rootScope.$broadcast('vehicle-preference-change', { 4484 model: engineVariants[index].model, 4485 engineVariant: engineVariants[index].engineVariant, 4486 grade: engineVariants[index].grade, 4487 }); 4488 } else { 4489 engineVariants[index].selected = false; 4490 } 4491 } 4492 $scope.variantName = variantName; 4493 $scope.gradeId = gradeId; 4494 $scope.variantId = variantId; 4495 $scope.enhancementPack = enhancementPack; 4496 4497 $rootScope.$broadcast('broadcast.lazyLoadRevalidate'); 4498 return selectedIndex; 4499 } 4500 4501 $scope.isSelected = function (variantName) { 4502 for (var index = 0; index < engineVariants.length; index++) { 4503 if (engineVariants[index].engineVariant === variantName) { 4504 return engineVariants[index].selected; 4505 } 4506 } 4507 } 4508 4509 $scope.isModelSelected = function (modelName) { 4510 return $scope.modelName === modelName; 4511 } 4512 4513 $scope.setModelName = function (modelName, variantName) { 4514 $scope.modelName = modelName; 4515 $scope.variantName = variantName; 4516 4517 if (variantName && !$scope.isSelected(variantName)) { 4518 $scope.selectVariant(variantName, $scope.gradeId, $scope.variantId, $scope.enhancementPack); 4519 } 4520 } 4521 4522 $scope.displayTab = function (modelName) { 4523 return modelName == $scope.modelName; 4524 } 4525 4526 $scope.buildLink = function () { 4527 var trim = null; 4528 var paint = null; 4529 4530 var dataVisitor = UserPreferencesService.getLexusVisitor($location.search()); 4531 var postCode = dataVisitor ? dataVisitor.postCode : "3000"; 4532
4533 VehicleService.getTrims($scope.gradeId, $scope.variantId).then(function success(response) { 4534 if (response.data.length == 0) { 4535 console.info('getTrims received 0 results for ' + $scope.variantName + ' with grade ID ' + $scope.gradeId); 4536 } 4537 4538 var availableTrims = response.data; 4539 if (availableTrims && availableTrims.length > 0) 4540 { 4541 trim = availableTrims[0]; 4542 4543 VehicleService.getPaints($scope.gradeId, $scope.variantId, trim.id).then(function success(response) { 4544 if (response.data.length == 0) { 4545 console.info('getPaints received 0 results for ' + $scope.variantName + ' with grade ID ' + $scope.gradeId + ' and trim Id ' + trim.id); 4546 } 4547 4548 var paints = response.data; 4549 4550 if (paints && paints.length > 0) { 4551 4552 paint = paints[0]; 4553 4554 var vehicle = { 4555 carmodel: $scope.modelName, 4556 engineVariant: $scope.variantName, 4557 grade: gradeName, 4558 postcode: postCode, 4559 enhancementPack: $scope.enhancementPack, 4560 colour: paint.uriName, 4561 trim: trim.uriName 4562 }; 4563 4564 var url = buildAndPriceUrl ? buildAndPriceUrl + '/' + BuildPriceService.getBuildPriceLink(vehicle, 2) : ''; 4565 if (url) { 4566 $window.location.href = url; 4567 } 4568 } 4569 4570 }, function error(response) { 4571 console.error('getTrims returned an error'); 4572 }); 4573 4574 } 4575 4576 }, function error(response) { 4577 console.error('getTrims returned an error'); 4578 }); 4579 } 4580 } 4581 } 4582}()); 4583 4584; 4585"use strict"; 4586/* Directives */ 4587angular.module('Lexus.Directives') 4588.directive('lxContentGallery', [function () { // Lazy load images. 4589 return { 4590 scope: { 4591 'parentAccordionPanelId': '@' 4592 }, 4593 restrict: 'A', 4594 link: function (scope, element, attrs) { 4595 var controls = attrs.controls || false, 4596 _window = angular.element(window), 4597 _allImages = element.find('.lx-content-gallery__slide'), 4598 breakpointSrc = 'src-lg', 4599 reassignSources = true, 4600 oldBreakpointSrc, 4601 breakpointHeightAdjust = Lexus.Breakpoint.Small, 4602 bxSlider; 4603 4604 function init() { 4605 imageSrc(); 4606 initSlider(); 4607 4608 scope.$on('broadcast.contentGalleryReload', function (event, args) { 4609 if (args.targetId.toString() !== scope.parentAccordionPanelId) { 4610 return; 4611 } 4612 bxSlider.reloadSlider(); 4613 }); 4614 } 4615 4616 function imageSrc() { 4617 if ((reassignSources || breakpointSrc == 'src') && _window.width() > breakpointHeightAdjust) { 4618 breakpointSrc = 'src-lg'; 4619 reassignSrc(); 4620 } else if ((reassignSources || breakpointSrc == 'src-lg') && _window.width() <= breakpointHeightAdjust) { 4621 breakpointSrc = 'src'; 4622 reassignSrc(); 4623 } 4624 reassignSources = false; 4625 } 4626 4627 function reassignSrc() { 4628 $(_allImages).each(function () { 4629 var $img = $(this).find('img'); 4630 $img.attr('src', null).attr('src', $img.attr('data-' + breakpointSrc
4630)); 4631 var a = 1; 4632 }); 4633 } 4634 4635 // Load bxslider. 4636 function initSlider() { 4637 4638 bxSlider = element.bxSlider({ 4639 mode: 'fade', 4640 slideMargin: 0, 4641 captions: true, 4642 auto: false, 4643 pause: 5000, 4644 pager: false, 4645 autoHover: true, 4646 nextText: '', 4647 prevText: '', 4648 //controls: controls, 4649 adaptiveHeight: true, 4650 onSliderLoad: function (currentIndex) { 4651 }, 4652 onSlideBefore: function () { 4653 }, 4654 onSlideAfter: function ($slideElement, oldIndex, newIndex) { 4655 4656 } 4657 }); 4658 } 4659 4660 4661 _window.resize(function () { 4662 4663 }); 4664 4665 _window.ready(function () { 4666 init(); 4667 }); 4668 } 4669 }; 4670}]); 4671; 4672"use strict"; 4673/* Directives */ 4674angular.module('Lexus.Directives') 4675 .directive('lxContentVideo', ['$rootScope', '$window', function ($rootScope, $window) { 4676 contentVideoController.$inject = ['$scope', '$rootScope']; 4677 return { 4678 scope: true, 4679 restrict: 'A', 4680 controller: contentVideoController, 4681 controllerAs: 'cv', 4682 bindToController: true, 4683 link: function (scope, element, attrs) { 4684 4685 if ((attrs.autoplay || '').toLowerCase() === 'true') { 4686 embedVideo(scope, element, attrs, element[0]); 4687 } 4688 else { 4689 element.on('click', function (event) { 4690 embedVideo(scope, element, attrs, event.currentTarget); 4691 }); 4692 } 4693 4694 angular.element($window).bind('resize', function () { 4695 scope.$broadcast('content-video-window-resize'); 4696 }); 4697 4698 function embedVideo(scope, element, attrs, targetElement) { 4699 if (!attrs['data-playing']) { 4700 var aspect = attrs.width / attrs.height; 4701 var muted = ((attrs.muted || '').toLowerCase() === 'true') ? 'true' : 'false'; 4702 targetElement.innerHTML = '<iframe src="//www.youtube.com/embed/' + attrs.id + '?modestbranding=1&autoplay=1&mute=' + muted + '&autohide=2&border=0&wmode=opaque&enablejsapi=1&controls=1&rel=0" frameborder="0" class="lx-video__inner-iframe" width="' + attrs.width + '" widthOriginal="' + attrs.width + '" height="' + attrs.height + '" aspect="' + aspect + '" allowfullscreen="allowfullscreen"></iframe>'; 4703 attrs.$set('data-playing', true); 4704 resize(element); 4705 //Can only wire up the resize listener when the iframe is injected 4706 scope.$on('content-video-window-resize', function (event, args) { 4707 resize(element); 4708 }); 4709 } 4710 } 4711 4712 function resize(myElement) { 4713 var iframe = myElement.find('iframe'); 4714 if (iframe[0].attributes.widthOriginal.value >= myElement[0].clientWidth) 4715 { 4716 iframe[0].width = myElement[0].clientWidth; 4717 iframe[0].height = myElement[0].clientWidth / iframe[0].attributes.aspect.value; 4718 } 4719 } 4720 } 4721 }; 4722 4723 function contentVideoController($scope, $rootScope) { 4724 var cv = this; 4725 $scope.init = function () { 4726 4727 } 4728 } 4729 4730}]); 4731; 4732"use strict"; 4733/* Directives */ 4734angular.module("Lexus.Directives").directive("lxDealerLookup", [ 4735 "$rootScope", 4736 "DealersService", 4737 "AddressSuggestService", 4738 "UserPreferencesService", 4739 function () { 4740 DealerLookupController.$inject = [
4741 "$scope", 4742 "$rootScope", 4743 "$http", 4744 "DealersService", 4745 "AddressSuggestService", 4746 "UserPreferencesService", 4747 ]; 4748 return { 4749 scope: true, 4750 restrict: "A", 4751 controller: DealerLookupController, 4752 controllerAs: "dlc", 4753 bindToController: true, 4754 link: function (scope, element, attrs) { 4755 scope.$on("clear-dealer-search-input", function () { 4756 element.find("tags-input input")[0].value = ""; 4757 }); 4758 }, 4759 }; 4760 4761 function DealerLookupController( 4762 $scope, 4763 $rootScope, 4764 $http, 4765 DealersService, 4766 AddressSuggestService, 4767 UserPreferencesService, 4768 ) { 4769 var dlc = this; 4770 var userPreferencesService = UserPreferencesService; 4771 4772 $scope.init = function (salesClosedDealers, serviceClosedDealers) { 4773 $scope.tags = []; 4774 $scope.tagsLoading = false; 4775 $scope.salesClosedDealers = salesClosedDealers; 4776 $scope.serviceClosedDealers = serviceClosedDealers; 4777 4778 $scope.ds = { 4779 tags: [], 4780 type: "Sales", 4781 results: null, 4782 loading: false, 4783 }; 4784 4785 var visitorPreference = userPreferencesService.getLexusVisitor(); 4786 var dealerPreference = userPreferencesService.getLexusDealer(); 4787 4788 if (visitorPreference && visitorPreference.postCode && visitorPreference.suburb) { 4789 $scope.ds.tags.push({ 4790 text: visitorPreference.suburb + " " + visitorPreference.postCode, 4791 data: { 4792 postCode: visitorPreference.postCode, 4793 suburb: visitorPreference.suburb, 4794 }, 4795 }); 4796 4797 $scope.searchNow(); 4798 } 4799 4800 $scope.preferredDealer = 4801 dealerPreference && 4802 dealerPreference.dealerID && 4803 dealerPreference.branchCode && 4804 dealerPreference.dealerName && 4805 dealerPreference.dealerUrl 4806 ? { 4807 id: dealerPreference.dealerID, 4808 4809 branchCode: dealerPreference.branchCode, 4810 name: dealerPreference.dealerName, 4811 url: dealerPreference.dealerUrl, 4812 } 4813 : {}; 4814 }; 4815 4816 $scope.ChangeDealerType = function (type) { 4817 $scope.ds.type = type; 4818 if ($scope.ds.tags.length) { 4819 $scope.searchNow(); 4820 $scope.updatePreferredDealer(); 4821 } 4822 }; 4823 4824 $scope.updatePreferredDealer = function () { 4825 $rootScope.$broadcast("preferred-dealer-change", { 4826 dealerID: $scope.preferredDealer.id, 4827 dealerCodeSimple: $scope.preferredDealer.dealerCodeSimple, 4828 branchCode: $scope.preferredDealer.branchCode, 4829 dealerName: $scope.preferredDealer.name, 4830 dealerType: $scope.ds.type, 4831 dealerUrl: $scope.preferredDealer.url, 4832 dealerState: $scope.preferredDealer.state, 4833 }); 4834 }; 4835 4836 $scope.dealerSearch = function ($tag) { 4837 $scope.ds.tags = []; 4838 $scope.ds.tags[0] = $tag; 4839 $scope.searchNow(); 4840 }; 4841 4842 $scope.checkServiceType = function (result) { 4843 var serviceString = $scope.ds.type; 4844 if (typeof result == "string") { 4845 serviceString = result; 4846 } else if (typeof result == "object" && result != null) { 4847 serviceString = result.serviceType; 4848 } 4849 4850 return serviceString.toLowerCase().match(/^service$/) ? true : false; 4851 }; 4852 4853 $scope.modifyResults = function (data) { 4854 if (data != null) { 4855 var newData = data.filter(function (d) { 4856 return ( 4857 ($scope.ds.type === "Sales" && !$scope.salesClosedDealers.includes(d.dealerCode)) || 4858 ($scope.ds.type !== "Sales" && !$scope.serviceClosedDealers.includes(d.dealerCode)) 4859 ); 4860 }); 4861 for (var r = 0, rLen = newData.length; r < rLen; r++) { 4862 if (newData[r].serviceOnly != null) { 4863 newData[r].serviceOnly = $scope.checkServiceType(data); 4864 } 4865 4866 if ($scope.ds.type === "Sales" && $scope.serviceClosedDealers.includes(newData[r].dealerCode)) { 4867 newData[r].serviceType = "Sales"; 4868 } 4869 4870 if ($scope.ds.type === "Service" && $scope.s
4870alesClosedDealers.includes(newData[r].dealerCode)) { 4871 newData[r].serviceType = "Service"; 4872 } 4873 } 4874 4875 return newData; 4876 } 4877 }; 4878 4879 $scope.searchNow = function () { 4880 $scope.ds.loading = true; 4881 $rootScope.$broadcast("visitor-details-change-autocomplete", $scope.ds.tags[0].data); 4882 4883 DealersService.setParam("postCode", $scope.ds.tags[0].data.postCode); 4884 DealersService.setParam("suburb", $scope.ds.tags[0].data.suburb); 4885 DealersService.setParam("type", $scope.ds.type); 4886 4887 DealersService.GetResults().then( 4888 function (data) { 4889 $scope.ds.results = $scope.modifyResults(data.Data); 4890 $scope.ds.loading = false; 4891 $scope.ds.showChangeDealer = false; 4892 4893 if (typeof window !== "undefined") { 4894 window.document.body.dispatchEvent(new CustomEvent("find-a-dealer-search")); 4895 } 4896 }, 4897 function (error) { 4898 console.log(error); 4899 }, 4900 ); 4901 }; 4902 4903 $scope.clearSearch = function () { 4904 $scope.$broadcast("clear-dealer-search-input"); 4905 $scope.ds.tags = []; 4906 }; 4907 4908 $scope.setPreferredDealer = function (dealer, address, preferredDealer) { 4909 var allreadyChecked = dealer.dealerCode === preferredDealer.id; 4910 if (allreadyChecked) { 4911 $scope.preferredDealer.id = null; 4912 $scope.preferredDealer.branchCode = null; 4913 $scope.preferredDealer.dealerCodeSimple = null; 4914 $scope.preferredDealer.name = null; 4915 $scope.preferredDealer.url = null; 4916 $scope.preferredDealer.state = null; 4917 } else { 4918 $scope.preferredDealer.id = dealer.dealerCode; 4919 $scope.preferredDealer.branchCode = address.branchCode; 4920 $scope.preferredDealer.dealerCodeSimple = dealer.dealerCodeSimple; 4921 $scope.preferredDealer.name = dealer.dealerName; 4922 $scope.preferredDealer.url = dealer.dealerUrl || address.webSite; 4923 $scope.preferredDealer.state = address.state; 4924 } 4925 $scope.updatePreferredDealer(); 4926 }; 4927 4928 $scope.loadTags = function (query) { 4929 $scope.tagsLoading = true; 4930 AddressSuggestService.setParam("term", query); 4931 return AddressSuggestService.GetResults($scope.tagsLoaded); 4932 }; 4933 4934 $scope.tagsLoaded = function () { 4935 $scope.tagsLoading = false; 4936 }; 4937 4938 $scope.autocompleteLoading = function () { 4939 return $scope.tagsLoading; 4940 }; 4941 } 4942 }, 4943]); 4944; 4945'use strict'; 4946 4947angular.module('Lexus.Directives') 4948.directive('lxFadeIn', ['$window', '$timeout', '$filter', '$http', '$analytics', function ($window, $timeout, $filter, $http, $analytics) { 4949 return { 4950 scope: true, 4951 restrict: 'A', 4952 bindToController: true, 4953 link: function (scope, element, attrs, filter, http) { 4954 4955 var helpers = {}; 4956 helpers.now = Date.now || function () { return new Date().getTime(); }; 4957 helpers.debounce = function (func, wait, immediate) { 4958 var timeout, args, context, timestamp, result; 4959 4960 var later = function () { 4961 var last = helpers.now() - timestamp; 4962 4963 if (last < wait && last >= 0) { 4964 timeout = setTimeout(later, wait - last); 4965 } else { 4966 timeout = null; 4967 if (!immediate) {
4968 result = func.apply(context, args); 4969 if (!timeout) context = args = null; 4970 } 4971 } 4972 }; 4973 4974 return function () { 4975 context = this; 4976 args = arguments; 4977 timestamp = helpers.now(); 4978 var callNow = immediate && !timeout; 4979 if (!timeout) timeout = setTimeout(later, wait); 4980 if (callNow) { 4981 result = func.apply(context, args); 4982 context = args = null; 4983 } 4984 4985 return result; 4986 }; 4987 }; 4988 helpers.throttle = function (func, wait) { 4989 var context, args, timeout, throttling, more, result; 4990 var whenDone = helpers.debounce(function () { more = throttling = false; }, wait); 4991 return function () { 4992 context = this; args = arguments; 4993 var later = function () { 4994 timeout = null; 4995 if (more) func.apply(context, args); 4996 whenDone(); 4997 }; 4998 if (!timeout) timeout = setTimeout(later, wait); 4999 if (throttling) { 5000 more = true; 5001 } else { 5002 result = func.apply(context, args); 5003 } 5004 whenDone(); 5005 throttling = true; 5006 return result; 5007 }; 5008 }; 5009 5010 if (window.Element && !Element.prototype.closest) { 5011 Element.prototype.closest = 5012 function (s) { 5013 var matches = (this.document || this.ownerDocument).querySelectorAll(s), 5014 i, 5015 el = this; 5016 do { 5017 i = matches.length; 5018 while (--i >= 0 && matches.item(i) !== el) { }; 5019 } while ((i < 0) && (el = el.parentElement)); 5020 return el; 5021 }; 5022 } 5023 5024 var appearClass = 'lx-appear'; 5025 var disappeaerClass = 'lx-disappeared'; 5026 var includeEls = 'h1,h2,h3,h4,h5,h6,p,li,a[class*=cta],button[class*=cta],[class*=button],[class*=btn]'; 5027 var excludeEls = '.lx-footer,.lx-footer-sticky,.lx-b-nav,.lx-c-nav,.lx-save-build-price__slideouttray,.lx-postcode-slideout'; 5028 5029 var transitionEls = element.find(includeEls); 5030 transitionEls.each(function (index, el) { 5031 if (!el.closest(excludeEls)) { 5032 angular.element(el).addClass(appearClass); 5033 angular.element(el).addClass(disappeaerClass); 5034 } 5035 }); 5036 5037 var appear = function () { 5038 var forceAppear = arguments ? arguments[0] : false; 5039 var topEdge = $window.pageYOffset, 5040 clientHeight = $window.innerHeight, 5041 fullHeight = topEdge + clientHeight; 5042 if (topEdge > 100 || forceAppear) { 5043 transitionEls.each(function (index, el) { 5044 if (angular.element(el).offset().top < fullHeight) { 5045 angular.element(el).removeClass(disappeaerClass); 5046 setTimeout(function () { angular.element(el).removeClass(appearClass) }, 500); 5047 } 5048 }); 5049 } 5050 } 5051 5052 angular.element($window).bind("scroll", helpers.throttle(appear, 50)); 5053 5054 5055 angular.element(document).ready(function () { 5056 setTimeout(function () { appear(true) } , 500); 5057 }); 5058 5059 } 5060 } 5061 5062 5063}]); 5064 5065; 5066 5067"use strict"; 5068/* Directives */ 5069angular.module('Lexus.Directives') 5070 .directive('lxFeatureTiles', [function () { 5071 featureTilesController.$inject = ['$scope', '$compile', '$window', '$rootScope']; 5072 return { 5073 scope: true, 5074 restrict: 'A', 5075 controller: featureTilesController, 5076 controllerAs: 'ft', 5077 bindToController: true, 5078 link: function (scope, element, attrs) { 5079 scope.ft.panels = []; 5080 var panelCollection = element.find(scope.ft.section), 5081 imageCollection = element.find(scope.ft.section + ' img'), 5082 history = [], 5083 resizeTimer, 5084 imageLoaded = 0; 5085 5086 function loadSection(list, scopeList) { 5087 if (scopeList.length === 0) { 5088 angular.forEach(list, function (value, key) { 5089 scopeList[key] = { 5090 isLong: (value.offsetHeight > scope.ft.sectionHeight), 5091 isOpen: false, 5092 content: value.innerHTML 5093 } 5094 }); 5095 } else { 5096 angular.forEach(list, function (value, key) { 5097 if (!scopeList[key].isLong) { 5098 scopeList[key].isLong = 5099 (value.offsetHeight > scope.ft.sectionHeight); 5100 } 5101 }); 5102 } 5103 } 5104
5105 loadSection(panelCollection, scope.ft.panels); 5106 5107 for (var i = 0; i < imageCollection.length; i++) { 5108 (function (i) { 5109 imageCollection[i].addEventListener('load', function () { 5110 imageLoaded++ 5111 if (imageLoaded === imageCollection.length) { // after all image loaded reload section class 5112 loadSection(panelCollection, scope.ft.panels); 5113 scope.$digest(); 5114 } 5115 }) 5116 })(i); 5117 } 5118 5119 window.addEventListener('resize', function () { 5120 clearTimeout(resizeTimer); // reduce flash 5121 resizeTimer = setTimeout(function () { 5122 loadSection(panelCollection, scope.ft.panels); 5123 scope.$digest(); 5124 }, 50); 5125 }); 5126 } 5127 }; 5128 5129 function featureTilesController($scope, $compile, $window, $rootScope) { 5130 var ft = this; 5131 5132 $scope.init = function () { 5133 ft.modalWrapper = [ 5134 '<div class="lx-feature-tiles__section is-in-modal">', 5135 '</div>' 5136 ]; 5137 ft.section = '.lx-feature-tiles__section'; 5138 ft.sectionHeight = '600'; 5139 ft.breakpoint = Lexus.Breakpoint.ExtraSmall; 5140 } 5141 5142 $scope.featureBtn = function (i) { 5143 if (window.innerWidth >= ft.breakpoint) { 5144 $scope.loadModal(ft.panels[i].content); 5145 } else { 5146 $scope.ft.panels[i].isOpen = !$scope.ft.panels[i].isOpen; 5147 } 5148 } 5149 5150 $scope.loadModal = function (content) { 5151 $rootScope.$broadcast('open-modal-window', { 5152 content: content, 5153 wrapper: ft.modalWrapper 5154 }); 5155 }; 5156 } 5157 }]); 5158; 5159"use strict"; 5160angular.module('Lexus.Directives') 5161 .directive("lxFixedFirstColumn", [function () { 5162 function init($scope, $element) { 5163 var interval = setInterval(function () { 5164 var tr = $element.find("tr"); 5165 angular.forEach(tr, function (i) { 5166 var columns = angular.element(i).children(); 5167 5168 if (columns.length < 1) { 5169 // Row with no columns? Ignore it. 5170 return; 5171 } 5172 if (columns.length === 2) { 5173 // Row with no columns? Ignore it. 5174 $element.find(".lx-responsive-table-viewport").css('overflow-x', 'hidden'); 5175 } 5176 var column0 = angular.element(columns[0]).children()[0] || columns[0]; 5177 var column1 = columns[1]; 5178 5179 // reset height styles (if any) so we can measure the "natural" height of these <td>s 5180 columns[0].style.height = ""; 5181 if (column1) { 5182 columns[1].style.height = ""; 5183 } 5184 5185 // Calculate heights of each <td>. 5186 var height0 = (column0).offsetHeight; 5187 var height1 = column1 ? column1.offsetHeight : 0; 5188 5189 // Calculate final height. 5190 var height = Math.max(height0, height1); 5191 5192 // Set heights of <td> and <tr>. 5193 columns[0].style.height = height + "px"; 5194 i.style.height = height + "px"; 5195 5196 if (column1) { 5197 column1.style.height = height + "px"; 5198 } 5199 5200 // If <td> heights have stabilized. 5201 if (height0 !== 0 && height0 === height1) { 5202 clearInterval(interval); 5203 } 5204 }); 5205 }, 0); 5206 } 5207 5208 return { 5209 restrict: "A", 5210 template: "<div class='lx-responsive-table-viewport'><div ng-transclude></div></div>", 5211 transclude: true, 5212 link: function ($scope, $element) { 5213 init($scope, $element); 5214 5215 var resizeHandler = function () { 5216 init($scope, $element); 5217 }; 5218 5219 $(window).on('resize', resizeHandler); 5220 5221 $scope.$on('$destroy', function () { 5222 $(window).off('resize', resizeHandler); 5223 }); 5224 } 5225 }; 5226 5227 }]);; 5228 5229"use strict"; 5230/* Directives */ 5231angular.module('Lexus.Directives') 5232.directive('lxFormFieldCarModelEngineVariantWithGrade', [function () { 5233 5234 formFieldController.$inject = ['$scope', '$rootScope', 'UserPreferencesService', 'VehicleService', '$filter', '$element', "$log"]; 5235 return { 5236 scope: true, 5237 restrict: 'A', 5238 controller: formFieldController, 5239 controllerAs: 'form', 5240 bindToController: true, 5241 link: function (scope, element, attrs) { 5242 scope.vehicleIndex = attrs.vehicleIndex || "0"; 5243 } 5244 }; 5245 5246 function formFieldController($scope, $rootScope, UserPreferencesService, VehicleService, $filter, $element, $log) { 5247 var form = this; 5248 5249 $scope.init = function () { 5250 $scope.ffc = $scope.ffc || {}; 5251 $scope.ffc.formfields = { 5252 data: { 5253 enginevariants: [], 5254 enhancementPacks: [] 5255 }, 5256 comingSoonModels: {} 5257 }; 5258 } 5259 5260 function getGradeVariantLabel(engineVariant, grade) { 5261 return engineVariant.name + ' ' + $filter('replaceCaseInsensitive')(grade.name, engineVariant.name); 5262 } 5263 5264 //sorry, this is also hardcoded in forms-finance-calculator.js 5265 function getGradeVariantKey(engineVariant, grade) { 5266 return engineVariant.name + ';' + grade.name; 5267 } 5268 5269 function getVariantAndGradeFromKey(key) { 5270 if (key) 5271 { 5272 var values = key.split(';'); 5273 if (values.length === 2) { 5274 return { 5275 engineVariant: values[0], 5276 grade: values[1] 5277 }; 5278 } 5279 } 5280 } 5281 5282 function bindEnhancementPacks() { 5283 if ($scope.ffc.formfields.data.enginevariantsandgrades) { 5284 var engineVariantAndGrade = $scope.ffc.formfields.data.enginevariantsandgrades.find(function (item) { 5285 return $scope.ffc.form.data.engineVariantAndGrade == item.key; 5286 }); 5287 5288 if (engineVariantAndGrade) { 5289 var selectedGradeId = engineVariantAndGrade.gradeId; 5290 $scope.ffc.form.data.loadingEnhancementPacks = true; 5291 VehicleService.getVariants(selectedGradeId) 5292 .then(function (response) { 5293 $scope.ffc.form.data.loadingEnhancementPacks = false; 5294 if (response.status === "Success") { 5295 $scope.ffc.formfields.data.enhancementPacks = response.data; 5296 5297 if ($scope.ffc.form.data.engineVariantAndGrade == null) { 5298 $scope.ffc.formfields.data.enhancementPacks = null; 5299 } 5300 5301 if ($scope.ffc.form.data.enhancementPack && $scope.ffc.form.data.enhancementPack !== "") { 5302 var enhancementPackFound = $scope.ffc.formfields.data.enhancementPacks.find(function (item) { 5303 return $scope.ffc.form.data.enhancementPack == item.uriName; 5304 }); 5305 5306 if (!enhancementPackFound) { 5307 $log.warn("resetting enhancement pack1"); 5308 $scope.ffc.form.data.enhancementPack = $scope.ffc.formfields.data.enhancementPacks[0].uriName; 5309 } 5310 } 5311 else { 5312 $log.warn("resetting enhancement pack2"); 5313 $scope.ffc.form.data.enhancementPack = $scope.ffc.formfields.data.enhancementPacks[0].uriName; 5314 } 5315 } 5316 }); 5317 } 5318 } 5319 } 5320 5321 //At time of model change 5322 $scope.bindEngineVariants1 = function () { 5323 VehicleService.getVehiclesOverview().then(function success(response) { 5324 var myModel; 5325 response.data.find(function (bodyType) { 5326 bodyType.models.find(function (model) { 5327 if ($scope.ffc.form.data.carmodel == model.name) 5328 { 5329 myModel = model; 5330 return; 5331 } 5332 }); 5333 return; 5334 }); 5335 5336 VehicleService.getEngineVariantsWithGrades(myModel.id) 5337 .then(function success(response) { 5338 if (response.status === "Success") { 5339 $scope.ffc.formfields.data.enginevariantsandgrades = []; 5340 var isPresent = false; 5341 response.data.forEach(function (engineVariant) {
5342 engineVariant.grades.forEach(function (grade) { 5343 $scope.ffc.formfields.data.enginevariantsandgrades.push({ 5344 engineVariant: engineVariant.name, 5345 grade: grade.name, 5346 gradeId: grade.id, 5347 mdmGradeId: grade.gradeID, 5348 label: getGradeVariantLabel(engineVariant, grade), 5349 key: getGradeVariantKey(engineVariant, grade) 5350 }); 5351 if (getGradeVariantKey(engineVariant, grade) == $scope.ffc.form.data.engineVariantAndGrade) { 5352 isPresent = true; 5353 } 5354 }); 5355 }); 5356 5357 if (!isPresent) { 5358 $scope.ffc.form.data.engineVariantAndGrade = null; 5359 $scope.ffc.formfields.data.enhancementPacks = null; 5360 } 5361 5362 //Can only bind Enhancement packs after they have been returned on bootup 5363 bindEnhancementPacks(); 5364 } 5365 }) 5366 .then(function failure(response) { }); 5367 5368 }).then(function failure(response) { }); 5369 5370 }; 5371 5372 $rootScope.$on('field-car-model-engine-variant-update-selected', function (event, data) { 5373 //Forms Have a UniqueVehicle Index , if not it defaults to one vehicle with index 0 5374 if (!data || (data && data.vehicleIndex && (data.vehicleIndex == $scope.vehicleIndex))) { 5375 $scope.updateModelSelection(true); 5376 } 5377 }); 5378 5379 $rootScope.$on('field-car-model-engine-variant-update-without-reset', function () { 5380 $scope.updateModelSelection(false); 5381 }); 5382 5383 $rootScope.$on('field-car-model-enhancement-pack-update-selected', function () { 5384 $scope.updateEngineVariantSelection(); 5385 }); 5386 5387 function resetChildControls() { 5388 $scope.ffc.formfields.data.enhancementPacks = null; 5389 $scope.ffc.formfields.data.enginevariantsandgrades = null; 5390 $scope.ffc.form.data.engineVariantAndGrade = null; 5391 $scope.ffc.form.data.engineVariant = null; 5392 $scope.ffc.form.data.grade = null; 5393 } 5394 5395 $scope.updateModelSelection = function (clearChildControls) { 5396 5397 if ($scope.ffc.formfields.comingSoonModels[$scope.ffc.form.data.carmodel]) { 5398 resetChildControls(); 5399 return; 5400 } 5401 5402 if (clearChildControls) { 5403 resetChildControls(); 5404 } 5405 $scope.bindEngineVariants1(); 5406 5407 $rootScope.$broadcast('vehicle-preference-change', { 5408 model: $scope.ffc.form.data.carmodel, 5409 grade: (UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : ""), 5410 engineVariant: (UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().engineVariant : ""), 5411 enhancementPack: (UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().enhancementPack : ""), 5412 vehicleIndex: $scope.vehicleIndex 5413 }); 5414 }; 5415 5416 //At time of engine variant change 5417 $scope.updateEngineVariantSelection = function (clearChildControls) { 5418 if (clearChildControls) { 5419 $scope.ffc.formfields.data.enhancementPacks = null; 5420 $scope.ffc.form.data.enhancementPack = null; 5421 } 5422 5423 bindEnhancementPacks(); 5424 5425 var values = getVariantAndGradeFromKey($scope.ffc.form.data.engineVariantAndGrade); 5426 var engineVariant = (values ? values.engineVariant : null); 5427 var grade = (values ? values.grade : null); 5428 $scope.ffc.form.data.engineVariant = engineVariant; 5429 $scope.ffc.form.data.grade = grade; 5430 5431 console.log('updateEngineVariantSelection'); 5432 console.log('clearChildControls=' + clearChildControls); 5433 $rootScope.$broadcast('vehicle-preference-change', { 5434 model: $scope.ffc.form.data.carmodel, 5435 engineVariant: engineVariant ? engineVariant : (UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().engineVariant : ""), 5436 grade: grade ? grade : (UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : ""), 5437 enhancementPack: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().enhancementPack : "", 5438 vehicleIndex: $scope.vehicleIndex 5439 }); 5440 5441 }; 5442 5443 $scope.updateEnhancementPackSelection = function () { 5444 var values = getVariantAndGradeFromKey($scope.ffc.form.data.engineVariantAndGrade); 5445 var engineVariant = values ? values.engineVariant : ''; 5446 var grade = values ? values.grade : ''; 5447 console.log('updateEnhancementPackSelection'); 5448 $rootScope.$broadcast('vehicle-preference-change', { 5449 model: $scope.ffc.form.data.carmodel, 5450 grade: grade ? grade : UserPreferencesService.getLexusVehicle().grade, 5451 engineVariant: engineVariant ? engineVariant : UserPreferencesService.getLexusVehicle().engineVariant, 5452 enhancementPack: $scope.ffc.form.data.enhancementPack 5453 }); 5454 }; 5455 5456 $scope.modelDisplayName = function (name, fullName, isComingSoon, offerTitle) { 5457 $scope.ffc.formfields.comingSoonModels[name] = isComingSoon && isComingSoon.toLowerCase() == 'true'; 5458 return (isComingSoon && isComingSoon.toLowerCase() == 'true') ? 'All-New ' + name + ' - ' + fullName + ' (' + offerTitle + ')' : name + '-' + fullName; 5459 }; 5460 } 5461}]) 5462 5463.directive('lxFormFieldCarModelEngineVariant', [function () { 5464 5465 formFieldController.$inject = ['$scope', '$rootScope', 'UserPreferencesService', 'VehicleService', '$filter', '$element']; 5466 return { 5467 scope: true, 5468 restrict: 'A', 5469 controller: formFieldController, 5470 controllerAs: 'form', 5471 bindToController: true, 5472 link: function (scope, element, attrs) { 5473 5474 } 5475 }; 5476 5477 function formFieldController($scope, $rootScope, UserPreferencesService, VehicleService, $filter, $element) { 5478 var form = this; 5479 $scope.init = function () { 5480 5481 $scope.ffc.formfields = { 5482 data: { 5483 enginevariants: [] 5484 }, 5485 comingSoonModels: {} 5486 }; 5487 } 5488 5489 //At time of model change 5490 $scope.bindEngineVariants2 = function () { 5491 //Clear fields at lower level and do not bind variants for comingSoon models 5492 if ($scope.ffc.formfields.comingSoonModels[$scope.ffc.form.data.carmodel]) { 5493 $scope.ffc.form.data.carmodel = null; 5494 $scope.ffc.form.data.enginevariant = null; 5495 return; 5496 } 5497 5498 VehicleService.getVehiclesOverview().then(function success(response) { 5499 var myModel; 5500 response.data.find(function (bodyType) { 5501 bodyType.models.find(function (model) { 5502 if ($scope.ffc.form.data.carmodel == model.name) { 5503 myModel = model; 5504 return; 5505 } 5506 }); 5507 return; 5508 }); 5509 5510 VehicleService.getEngineVariants(myModel.id) 5511 .then(function success(data) { 5512 if (data.status === "Success") { 5513 $scope.ffc.formfields.data.enginevariants = data.data; 5514 } 5515 }) 5516 .then(function failure(response) { }); 5517 5518 }).then(function failure(response) { }); 5519 5520 }; 5521 5522 $rootScope.$on('field-car-model-engine-variant-update-selected', function () { 5523 $scope.bindEngineVariants2(); 5524 }); 5525 5526 $scope.updateModelSelection = function () { 5527 if ($scope.ffc.formfields.comingSoonModels[$scope.ffc.form.data.carmodel]) { 5528 $scope.ffc.form.data.enginevariant = null; 5529 return; 5530 } 5531 $scope.bindEngineVariants2(); 5532 $rootScope.$broadcast('vehicle-preference-change', { 5533 model: $scope.ffc.form.data.carmodel 5534 //engineVariant: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().engineVariant : "" 5535 //grade: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : "" 5536 }); 5537 }; 5538 5539 //At time of engine variant change 5540 $scope.updateEngineVariantSelection = function () { 5541 5542 console.log("updateEngineVariantSelection"); 5543 5544 $rootScope.$broadcast('vehicle-preference-change', { 5545 model: $scope.ffc.form.data.carmodel, 5546 engineVariant: $scope.ffc.form.data.enginevariant, 5547 //grade: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : "", 5548 }); 5549 }; 5550 5551 $scope.modelDisplayName = function (name, fullName, isComingSoon, offerTitle) { 5552 $scope.ffc.formfields.comingSoonModels[name] = isComingSoon && isComingSoon.toLowerCase() == 'true'; 5553 return (isComingSoon && isComingSoon.toLowerCase() == 'true') ? 'All-New ' + name + ' - ' + fullName + ' (' + offerTitle + ')' : name + '-' + fullName; 5554 }; 5555 5556 } 5557}]) 5558.directive('lxFormFieldCarModel', [function () { 5559 formFieldController.$inject = ['$scope', '$rootScope', 'UserPreferencesService', 'VehicleService', '$filter', '$element']; 5560 return { 5561 scope: true, 5562 restrict: 'A', 5563 controller: formFieldController, 5564 controllerAs: 'form', 5565 bindToController: true, 5566 link: function (scope, element, attrs) { 5567 5568 } 5569 }; 5570 5571 function formFieldController($scope, $rootScope, UserPreferencesService, VehicleService, $filter, $element) { 5572 var form = this; 5573 $scope.init = function () { 5574 5575 $scope.ffc.formfields = { 5576 data: { 5577 enginevariants: [] 5578 }, 5579 comingSoonModels: {} 5580 }; 5581 5582 } 5583 5584 $rootScope.$on('field-car-model-update-selected', function () { 5585 $scope.updateModelSelection(); 5586 }); 5587 5588 $scope.updateModelSelection = function () { 5589 if ($scope.ffc.formfields.comingSoonModels[$scope.ffc.form.data.carmodel]) { 5590 $scope.ffc.form.data.carmodel = null; 5591 return; 5592 } 5593 $rootScope.$broadcast('vehicle-preference-change', { 5594 model: $scope.ffc.form.data.carmodel, 5595 //grade: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : "", 5596 //engineVariant: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().engineVariant : "" 5597 }); 5598 }; 5599 5600 $scope.modelDisplayName = function (name, fullName, isComingSoon, offerTitle) { 5601 $scope.ffc.formfields.comingSoonModels[name] = isComingSoon && isComingSoon.toLowerCase() == 'true'; 5602 return (isComingSoon && isComingSoon.toLowerCase() == 'true') ? 'All-New ' + name + ' - ' + fullName + ' (' + offerTitle + ')' : name + '-' + fullName; 5603 }; 5604 } 5605}]) 5606.directive('lxFormFieldDateWrap', ['$rootScope', function ($rootScope) { 5607 formFieldDateWrapController.$inject = ['$scope', '$rootScope', '$filter', '$element']; 5608 return { 5609 scope: true, 5610 restrict: 'E', 5611 controller: formFieldDateWrapController, 5612 controllerAs: 'form', 5613 bindToController: true, 5614 link: function (scope, element, attrs) { 5615 var formName = attrs.name; 5616 var dp = element.find("#datePicker"); 5617 dp.bind('change', function (elem) { 5618 if (!moment(elem.target.value, 'DD-MM-YYYY').isValid()) { 5619 $rootScope.$broadcast('date-picker-invalid'); 5620 } 5621 else { 5622 $rootScope.$broadcast('date-picker-valid'); 5623 } 5624 5625 }); 5626 } 5627 }; 5628 5629 function formFieldDateWrapController($scope, $rootScope, $filter, $element) { 5630 var form = this; 5631 $scope.init = function () { 5632 5633 } 5634 } 5635}]) 5636.directive('lxFormFieldRangeInput', ['$rootScope', function ($rootScope) { 5637 formFieldRangeInputController.$inject = ['$scope', '$rootScope', '$filter', '$element']; 5638 return { 5639 scope: true, 5640 restrict: 'A', 5641 controller: formFieldRangeInputController, 5642 controllerAs: 'form', 5643 bindToController: true, 5644 link: function (scope, element, attrs) {
5645 var control, controlMin, controlMax, controlVal, formattedValue, labelWidth, controlThumbWidth, position, positionOffset, output, range, format; 5646 control = element.find("input[type='range']"); 5647 control.on('input change', function () { 5648 calculatePosition(); 5649 }); 5650 5651 if (attrs['format']) { 5652 format = attrs['format']; 5653 } 5654 5655 if (attrs['watch']) { 5656 var watchArgs = [] 5657 5658 if (attrs.watch.split) { 5659 attrs['watch'].split(',').forEach(function (str) { 5660 watchArgs.push(str.trim()); 5661 }); 5662 } 5663 5664 watchArgs.forEach(function (item) { 5665 scope.$watch(item, function (oldValue, newValue) { 5666 if (oldValue != newValue) { 5667 calculatePosition(); 5668 } 5669 }); 5670 }); 5671 } 5672 5673 $rootScope.$on('balloon-payment-options-received', function () { 5674 //This is for second slider change can be optimised further 5675 calculatePosition(); 5676 }); 5677 5678 function calculatePosition() { 5679 controlMin = parseInt(control.attr('min')) || 0; 5680 controlMax = parseInt(control.attr('max')) || 1; 5681 controlVal = control.val(); 5682 if (format) { 5683 formattedValue = scope.formatOutput(format, controlVal); 5684 } else { 5685 formattedValue = controlVal; 5686 } 5687 5688 range = controlMax - controlMin; 5689 controlThumbWidth = 25; 5690 labelWidth = 38; 5691 5692 position = ((controlVal - controlMin) / range) * 100; 5693 5694 // Calculate negative offset: 5695 // half label width 5696 // - half thumb width zero + half thumb width 5697 // |--------------------------------------------------------------| 5698 positionOffset = Math.round(((controlThumbWidth) * position / 100) - (controlThumbWidth / 2)) + labelWidth / 2; 5699 output = control.next('.lx-form-slider__output'); 5700 5701 output.css('left', 'calc(' + position + '% - ' + positionOffset + 'px)').html(formattedValue); 5702 } 5703 5704 calculatePosition(); 5705 } 5706 5707 }; 5708 5709 function formFieldRangeInputController($scope, $rootScope, $filter, $element) { 5710 var form = this; 5711 $scope.init = function () { 5712 5713 } 5714 5715 $scope.formatOutput = function(format, val){ 5716 return $filter('formatArgs')(format, [val]); 5717 } 5718 } 5719}]) 5720.directive('lxTooltip', [function () { 5721 disclaimerBubbleController.$inject = ['$scope', '$rootScope', '$filter', '$element']; 5722 return { 5723 scope : { 5724 'cssClass': '@' 5725 }, 5726 restrict: 'AE', 5727 controller: disclaimerBubbleController, 5728 controllerAs: 'dbc', 5729 bindToController: true, 5730 transclude: true, 5731 //template: '<div class="lx-tooltip__info-overlay"><div class="lx-tooltip__info-icon" data-ng-init="init();" data-ng-mouseover="show()" data-ng-mouseleave="hide()"></div><div class="lx-tooltip__info-content" data-ng-transclude data-ng-show="showDisclaimer"></div></div>', 5732 template: '<div class="lx-tooltip__info-overlay is-{{alignment}} {{cssClass}}"' + 5733 'ng-class="{\'is-open\': isMouse && isMouseInside || !isMouse && isToggled}" ' + 5734 'mouse-detected="isMouse = true" ' + 5735 'ng-click="toggleIt($event)" ' + 5736 'ng-mouseenter="isMouseInside = true" ' + 5737 'ng-mouseleave="isMouseInside = false">' + 5738 '<div class="lx-tooltip__info-icon" ng-hide="showOffer"></div>' + 5739 '<div class="lx-tooltip__info-on-offer" ng-show="showOffer"><span>{{onOfferTitle}}</span></div>' + 5740 '<div class="lx-tooltip__info-content" data-ng-transclude ></div>' + 5741 '</div>', 5742 link: function (scope, element, attrs) { 5743 scope.alignment = attrs.lxTooltip; 5744 scope.showOffer = (attrs.tooltipOffer != null) ? attrs.tooltipOffer : false; 5745 scope.onOfferTitle = (attrs.tooltipTitle != null) ? attrs.tooltipTitle : "ON OFFER*"; 5746 } 5747 }; 5748 5749 function disclaimerBubbleController($scope, $rootScope, $filter, $element) { 5750 var dbc = this; 5751 $scope.init = function () { 5752 $scope.showDisclaimer = false; 5753 } 5754 5755 $scope.show = function () { 5756 $scope.showDisclaimer = true; 5757 } 5758 5759 $scope.hide = function () { 5760 $scope.showDisclaimer = false; 5761 } 5762 5763 $scope.toggleIt = function (event) { 5764 $scope.isToggled = !$scope.isToggled; 5765 event.stopPropagation(); 5766 } 5767 5768 } 5769}]); 5770; 5771 5772"use strict"; 5773/* Directives */ 5774angular.module('Lexus.Directives') 5775 .directive('lxForm', [function () { 5776 var formBroadcast = ''; 5777 var formName = ''; 5778 formController.$inject = ['$scope', '$rootScope', 'UserPreferencesService', '$filter', '$element', '$timeout', 'AddressSuggestService']; 5779 return { 5780 scope: true, 5781 restrict: 'A', 5782 controller: formController, 5783 controllerAs: 'form', 5784 bindToController: true, 5785 link: function (scope, element, attrs) { 5786 formBroadcast = attrs.lxForm; 5787 formName = attrs.name; 5788 scope.$broadcast("initialize"); 5789 } 5790 }; 5791 5792 function formController($scope, $rootScope, UserPreferencesService, $filter, $element, $timeout, AddressSuggestService) { 5793 var form = this, 5794 i, 5795 monthList = [4, 6, 9, 11], 5796 yesterday = moment().subtract(1, 'days'), 5797 inThreeMonths = moment().add(3, 'months'); 5798 5799 function addMonths(d, m) { 5800 var years = Math.floor(m / 12); 5801 var months = m - (years * 12); 5802 if (years) d.setFullYear(d.getFullYear() + years); 5803 if (months) d.setMonth(d.getMonth() + months); 5804 return d; 5805 } 5806 5807 function leadingZero(value) { 5808 if (value < 10) { 5809 return '0' + value; 5810 } 5811 5812 return value; 5813 } 5814 5815 function formatDateString(date) { 5816 var d = new Date(date),
5817 month = '' + (d.getMonth() + 1), 5818 day = '' + d.getDate(), 5819 year = d.getFullYear(); 5820 5821 if (month.length < 2) month = '0' + month; 5822 if (day.length < 2) day = '0' + day; 5823 return [year, month, day].join('-'); 5824 } 5825 5826 $scope.dateError = function (formName) { 5827 formName = formName || "lxForm"; 5828 5829 var value = $scope[formName].datePicker.$viewValue ? 5830 $scope[formName].datePicker.$viewValue : ''; 5831 5832 if (!value) 5833 return $scope.form.dateError[2]; 5834 5835 var dateParts = (value.indexOf('/') > 1) ? 5836 value.split('/') : false, 5837 date = (dateParts != false) ? (dateParts[2] + '-' 5838 + dateParts[1] + '-' + dateParts[0]) : value, 5839 date = Date.parse(date); 5840 5841 if (isNaN(date)) { 5842 return $scope.form.dateError[0]; 5843 } 5844 else { 5845 return $scope.form.dateError[2]; 5846 } 5847 } 5848 5849 //DO NOT NEST THIS OBJECT, Plugin doesnt like form.dateChange 5850 $scope.dateChange = function (modelName, newValue) { 5851 5852 } 5853 5854 $scope.$on("initialize", function () { 5855 $scope.user = {}; 5856 $scope.form.dateError = [ 5857 'Invalid date', 5858 'Please choose a date that is in the valid range', 5859 'Please pick date from the calendar' 5860 ]; 5861 5862 $scope.form.specificErrorMessages = { 5863 'VINMsg': 'VIN must be 17 alphanumberic characters', 5864 'VINLookupFailedMsg': 'VIN cannot be found, please check that what you have entered is correct', 5865 'RegistrationInvalidMsg': 'Maximum seven characters. Numbers and letters only.' 5866 }; 5867 5868 5869 $scope.form.errorMessages = [ 5870 'This field is required', 5871 'The format is not valid', 5872 'The input is too short', 5873 'The captcha is required', 5874 'The value is not suitable' 5875 ]; 5876 5877 $scope.form.namePattern = /^[a-zA-Z- ']*$/; 5878 $scope.form.nameMinLength = 2; 5879 $scope.form.messageMinLength = 16; 5880 $scope.form.postcodeMinLength = 4; 5881 $scope.form.dealerPostcodeMinLength = 4; 5882 $scope.form.yearMinLength = 4; 5883 $scope.form.phoneMinLength = 10; 5884 $scope.form.vinMinLength = 17; 5885 $scope.form.emailPattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@(\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,})$/; 5886 $scope.form.numberPattern = /^\d+$/; 5887 $scope.form.phonePattern = /^(0[23478]|\+[1-9])\d{8,15}$/i; 5888 $scope.form.hiddenUnselected = false; 5889 $scope.form.hasHTML5DatePicker = Modernizr.inputtypes.date; 5890 $scope.form.dateFormat = 'date'; 5891 $scope.form.minYear = "1990"; 5892 //Do not put this in a nested object, You have been warned by Ettienne!
5893 $scope.dateMin = moment().add(1, 'd').hour(12).startOf('h');//today; 5894 $scope.dateMax = moment().add(3, 'months').hour(12).startOf('h');//inThreeMonths; 5895 $scope.dateDefault = new Date(moment().add(3, 'd').hour(12).startOf('h'));//inThreeDays 5896 5897 $scope.form.dateMin2 = formatDateString(yesterday); 5898 $scope.form.dateMax2 = formatDateString(inThreeMonths); 5899 $scope.form.datePattern = /^(0[1-9]|1[0-9]|2[0-9]|3[01])\/(0[1-9]|1[012])\/(201[6-9])/; 5900 $scope[formName].date = $scope.dateDefault; 5901 $scope.form.tagsLoading = false; 5902 $scope.form.alphanumeric = /^[a-zA-Z0-9]*$/; 5903 }); 5904 5905 $scope.errorText = function (length, min, data, value, specificErrorKey) { 5906 if (value) { 5907 // console.log(value); 5908 } 5909 if(specificErrorKey) { 5910 return form.specificErrorMessages[specificErrorKey]; 5911 } 5912 else 5913 { 5914 if (!length) { 5915 return form.errorMessages[0]; 5916 } else if (min && length < min) { 5917 return form.errorMessages[2]; 5918 } else if (data) { 5919 return form.errorMessages[4]; 5920 } else { 5921 return form.errorMessages[1]; 5922 } 5923 } 5924 5925 } 5926 5927 $scope.showUnselected = function () { 5928 form.hiddenUnselected = false; 5929 } 5930 5931 $scope.hideUnselected = function () { 5932 if (!form.hiddenUnselected) { 5933 form.hiddenUnselected = true; 5934 } 5935 } 5936 5937 $scope.VINchange = function() { 5938 $rootScope.$broadcast('vin-change'); 5939 }; 5940 5941 $scope.submit = function (formName) { 5942 formName = formName || "lxForm"; 5943 //console.log(formBroadcast); 5944 if ($scope[formName].$invalid) { 5945 angular.forEach($scope[formName].$error, function (field) { 5946 angular.forEach(field, function (errorField) { 5947 if (errorField && errorField.$setTouched) { 5948 errorField.$setTouched(); 5949 errorField.$setDirty(); 5950 } 5951 }) 5952 }); 5953 if ($element.find(".ng-invalid")[0].id === 'postcodes') { 5954 $element.find(".ng-invalid input")[0].focus(); 5955 } else { 5956 $element.find(".ng-invalid")[0].focus(); 5957 } 5958 5959 } else { 5960 $rootScope.$broadcast('open-modal-window', { 5961 content: '<div class="lx-loader">Loading...</div>', 5962 closeOnEvent: 'close-modal-window', 5963 variant: Lexus.ModalVariant.Spinner 5964 }); 5965 $rootScope.$broadcast(formBroadcast, { 5966 content: $scope.user 5967 }); 5968 } 5969 } 5970 5971 $rootScope.$on('form-result', function (events, arg) { 5972 $rootScope.$broadcast('close-modal-window'); 5973 }); 5974 5975 $rootScope.$on('date-picker-invalid', function (event, value) { 5976 $scope[formName].datePicker.$setValidity("validDate", false); 5977 $scope.$apply(); 5978 }); 5979 5980 $rootScope.$on('vin-lookup-success', function (event, value) { 5981 $scope[formName].vin.$setValidity("notfound", true); 5982 }); 5983 5984 $rootScope.$on('vin-lookup-failed', function (event, value) { 5985 $scope[formName].vin.$setValidity("notfound", false); 5986 }); 5987 5988 $scope.loadTags = function (query) { 5989 $scope.form.tagsLoading = true; 5990 AddressSuggestService.setParam('term', query); 5991 return AddressSuggestService.GetResults($scope.tagsLoaded); 5992 }; 5993 5994 $scope.tagsLoaded = function () { 5995 $scope.form.tagsLoading = false; 5996 } 5997 5998 $scope.autocompleteLoading = function () { 5999 return $scope.form.tagsLoading; 6000 }; 6001 6002 $rootScope.$on('date-picker-valid', function (event, value) { 6003 $scope[formName].datePicker.$setValidity("validDate", true); 6004 $scope.$apply(); 6005 }); 6006 6007 6008 } 6009 }]); 6010; 6011"use strict"; 6012/* Directives */ 6013angular.module('Lexus.Directives') 6014.directive('lxFormsFinanceCalculator', ['$http', '$filter', '$timeout', '$window', '$interval', '$location', 6015 '$rootScope', 'DealersService', 'AddressSuggestService', 'UserPreferencesService', 6016 'VehicleService', 'vcRecaptchaService', 'FormsService', 'PricingService', '$sce', 6017 'BuildPriceService', 'BuildPriceAPIService', 'EloquaService', '$log', FormsFinanceCalculatorDirective]); 6018 6019 6020function FormsFinanceCalculatorDirective($http, $filter, $timeout, $window, $interval, $location, 6021 $rootScope, DealersService, AddressSuggestService, UserPreferencesService, 6022 VehicleService, vcRecaptchaService, FormsService, PricingService, $sce, 6023 BuildPriceService, BuildPriceAPIService, eloquaService, $log) { 6024 var formName = ''; 6025 var forceDealerId = ''; 6026 var dealerState = ''; 6027 FormsFormsFinanceCalculatorController.$inject = ['$scope']; 6028 6029 return { 6030 scope: true, 6031 restrict: 'A', 6032 controller: FormsFormsFinanceCalculatorController, 6033 controllerAs: 'ffc', 6034 bindToController: true, 6035 link: function (scope, element, attrs, filter, http) { 6036 scope.successContent = element.find('.lx-form-success'); 6037 scope.failureContent = element.find('.lx-form-failure'); 6038 formName = attrs.lxFormsName; 6039 } 6040 }; 6041 6042 function FormsFormsFinanceCalculatorController($scope) { 6043 var ftd = this; 6044 6045 $log.info("Build and Price Data:"); 6046 $log.info($scope.buildAndPriceData); 6047 6048 $scope.ffc.urlParameters = $location.search(); 6049 $scope.BuildPriceService = BuildPriceService; 6050 $scope.testValue = 10; 6051 6052 function getModelFromAvailableModels(carModel) { 6053 6054 var availableModels = $scope.ffc.form.settings.availableModels; 6055 6056 if (!availableModels || (availableModels && availableModels.length == 0)) 6057 return null; 6058 6059 if (availableModels.length === 1) { 6060 return availableModels[0]; 6061 } 6062 6063 if (availableModels.length > 1) { 6064 var modelIndex = availableModels.findIndex(function (m) { return carModel != null ? m.toLowerCase() === carModel.toLowerCase() : false }); 6065 return modelIndex > -1 ? availableModels[modelIndex] : null; 6066 } 6067 6068 return null; 6069 } 6070 6071 $rootScope.$on('change-active-vehicle', function () { 6072 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); 6073 $scope.ffc.form.data.carmodel = getModelFromAvailableModels(dataVehicle.model); 6074 $scope.clearSomeCarData(); 6075 6076 if ($scope.ffc.form.data.carmodel == null) 6077 return; 6078 6079 $rootScope.$broadcast('field-car-model-engine-variant-update-selected'); 6080 }); 6081 6082 $scope.init = function (settings) { 6083 6084 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); 6085 var dataDealer = UserPreferencesService.getLexusDealer($scope.ffc.urlParameters); 6086 var settings = settings || {}; 6087 settings.balloonPayment = settings.balloonPayment || {}; 6088 settings.loanTerm = settings.loanTerm || {}; 6089 settings.summary = settings.summary || {}; 6090 settings.messages = settings.messages || {}; 6091 6092 $scope.dealerState = settings.dealerState; 6093 $scope.forceDealerId = settings.forceDealerId; 6094 $scope.isDealerSite = settings.isDealerSite; 6095 $scope.isMultiBranchDealer = settings.isMultiBranchDealer; 6096 $scope.dealerCompositeID = settings.dealerCompositeID;
6097 6098 $scope.pricingSuccess = true; 6099 6100 $scope.currentPath = $location.path(); 6101 6102 //defaults 6103 $scope.ffc.form = { 6104 submitting: false, 6105 completed: false, 6106 errors: false, 6107 settings: { 6108 availableModels: settings.availableModels ? settings.availableModels : null, 6109 availableGrades: settings.availableGrades ? settings.availableGrades : null, 6110 balloonPayment: { 6111 fixedValue: settings.balloonPayment.fixedValue ? settings.balloonPayment.fixedValue : null, 6112 min: settings.balloonPayment.min ? settings.balloonPayment.min : 0, 6113 max: settings.balloonPayment.max ? settings.balloonPayment.max : 50, 6114 step: settings.balloonPayment.step ? settings.balloonPayment.step : 5, 6115 disabled: settings.balloonPayment.disabled != null ? settings.balloonPayment.disabled : true 6116 }, 6117 loanTerm: { 6118 personalMax: settings.loanTerm.personalMax ? settings.loanTerm.personalMax : 5, 6119 businessMax: settings.loanTerm.businessMax ? settings.loanTerm.businessMax : 5, 6120 max: settings.loanTerm.max ? settings.loanTerm.max : 5, 6121 min: 1 6122 //disabled: settings.loanTerm.disabled ? settings.loanTerm.disabled : true 6123 }, 6124 /*interestRate: { 6125 min: settings.interestRate.min ? settings.interestRate.min : 0, 6126 max: settings.interestRate.max ? settings.interestRate.max : 100, 6127 step: settings.interestRate.step ? settings.interestRate.step : 0.25 6128 },*/ 6129 summary: { 6130 paymentInterval: settings.summary.paymentInterval ? settings.summary.paymentInterval : 'month' 6131 }, 6132 messages: { 6133 apiError: settings.messages.apiError ? settings.messages.apiError : 'Oops, something went wrong while we were doing the sums. Please check the form values and try again. If the problem persists, please contact your dealer directly.' 6134 }, 6135 disclaimerPage: settings.disclaimerPage, 6136 enablePricingByZone: settings.enablePricingByZone == 'true' 6137 }, 6138 data: { 6139 postcodes: null, 6140 deposit: null, 6141 interestrate: null, 6142 interestRateCopy: "", 6143 carmodel: dataVehicle.model, 6144 grade: dataVehicle.grade, 6145 engineVariant: dataVehicle.engineVariant, 6146 engineVariantAndGrade: dataVehicle.engineVariant + ";" + dataVehicle.grade, 6147 enhancementPack: dataVehicle.enhancementPack, 6148 trim: dataVehicle.trim, 6149 colour: dataVehicle.colour, 6150 loanterm: null, 6151 balloonPayment: 0, 6152 loantype: 'Personal', //Default Selected Value 6153 dealerId: dataDealer.dealerID, 6154 dealerName: dataDealer.dealerName, 6155 source: $scope.ffc.urlParameters.source || null 6156 }, 6157 emailsettings: { 6158 email: { 6159 subject: 'Lexus Financial Services: Finance estimate', 6160 body: '', 6161 introText: '', 6162 disclaimer: '', 6163 fullBodyContents: '', 6164 //cc: emailsettings.email.cc ? emailsettings.email.cc : '', 6165 //bcc: emailsettings.email.bcc ? emailsettings.email.bcc : '' 6166 } 6167 }, 6168 results: { 6169 paint: null, 6170 trim: null, 6171 driveAwayPrice: 0, 6172 installmentPerMonth: 0, 6173 installmentPerWeek: 0, 6174 finalBalloonPayment: 0 6175 }, 6176 pricingSuccess: true, 6177 dealerquoteform: { 6178 Show: false 6179 } 6180 }; 6181 6182 $log.info("$scope.ffc.form.data:"); 6183 $log.info($scope.ffc.form.data); 6184 6185 if ($scope.ffc.form.settings.balloonPayment.fixedValue != null) {
6186 $scope.ffc.form.data.balloonPayment = $scope.ffc.form.settings.balloonPayment.fixedValue; 6187 } 6188 6189 // LEXWEB-450 / AC 16 - clear cookie if carmodel unavailable for this campaign 6190 var availableModels = $scope.ffc.form.settings.availableModels; 6191 if (availableModels) { 6192 6193 $scope.ffc.form.data.carmodel = getModelFromAvailableModels($scope.ffc.form.data.carmodel); 6194 6195 $scope.clearSomeCarData(); 6196 6197 $rootScope.$broadcast('vehicle-preference-change', { 6198 model: $scope.ffc.form.data.carmodel, //Ac6 reset all cookies on model change 6199 grade: undefined, 6200 engineVariant: undefined, 6201 enhancementPack: undefined 6202 }); 6203 6204 $rootScope.$broadcast('field-car-model-engine-variant-update-selected'); 6205 } 6206 6207 UserPreferencesService.getLexusVisitorSession().then(function success(data) { 6208 var dataUser = UserPreferencesService.getLexusVisitor($scope.ffc.urlParameters); 6209 6210 6211 //initialise subform fields 6212 $scope.ffc.form.data.email = data.Data.email; 6213 $scope.ffc.form.data.firstname = data.Data.name; 6214 $scope.ffc.form.data.lastname = data.Data.surname; 6215 $scope.ffc.form.data.phone = data.Data.phone; 6216 $scope.ffc.form.data.message = null; 6217 $scope.ffc.form.data.prefer = data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 6218 $scope.ffc.form.data.phonetype = data.Data.phoneType ? data.Data.phoneType : 'home'; 6219 $scope.ffc.form.data.additionalcomments = null; 6220 $scope.ffc.form.data.subscribe = false; 6221 $scope.ffc.form.data.captcha = ''; 6222 $scope.ffc.form.data.messagedynamic = ""; 6223 6224 if (dataUser.suburb && dataUser.postCode && dataUser.state) { 6225 if (!$scope.ffc.form.data.postcodes) { 6226 $scope.ffc.form.data.postcodes = []; 6227 } 6228 $scope.ffc.form.data.postcodes.push(UserPreferencesService.getAutocompleteTagFromVisitor(dataUser)); 6229 } 6230 }, function failure(data) { 6231 $scope.ffc.form.data.email = null; 6232 $scope.ffc.form.data.firstname = null; 6233 $scope.ffc.form.data.lastname = null; 6234 $scope.ffc.form.data.phone = null; 6235 $scope.ffc.form.data.message = null; 6236 $scope.ffc.form.data.prefer = 'email'; 6237 $scope.ffc.form.data.phonetype = 'home'; 6238 $scope.ffc.form.data.additionalcomments = null; 6239 $scope.ffc.form.data.subscribe = false; 6240 $scope.ffc.form.data.captcha = ''; 6241 $scope.ffc.form.data.messagedynamic = ""; 6242 6243 6244 }).finally(function () { 6245 6246 if ($scope.ffc.form.data.carmodel) { 6247 $rootScope.$broadcast('field-car-model-engine-variant-update-without-reset'); 6248 6249 if ($scope.ffc.form.data.engineVariantAndGrade) { 6250 $rootScope.$broadcast('field-car-model-enhancement-pack-update-selected'); 6251 } 6252 6253 } 6254 6255 //Main Site 6256 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !$scope.isDealerSite) { 6257 $scope.searchNow(); 6258 } 6259 6260 //Dealer Site Multi Branch 6261 if ($scope.isDealerSite && $scope.isMultiBranchDealer) { 6262 $scope.ffc.form.data.dealerId = null; 6263 $scope.ffc.form.data.dealerName = null; 6264 $scope.loadBranches($scope.forceDealerId); 6265 } 6266 6267 //Dealer Site NOT Multi Branch 6268 if ($scope.isDealerSite && !$scope.isMultiBranchDealer) { 6269 $scope.ffc.form.data.dealerId = $scope.dealerCompositeID;
6270 $scope.ffc.form.data.dealerName = null; 6271 } 6272 }); 6273 } 6274 6275 $scope.clearSomeCarData = function () { 6276 $scope.ffc.form.data.engineVariant = undefined; 6277 $scope.ffc.form.data.grade = undefined; 6278 $scope.ffc.form.data.engineVariantAndGrade = undefined; 6279 $scope.ffc.form.data.enhancementPack = undefined; 6280 } 6281 6282 $scope.createGenericMessage = function (vehicleIndex) { 6283 6284 var carModel = $('#carmodel_'+ vehicleIndex + ' option:selected').text(); // should we split by name of full name is ok? carModel.split('-')[0] $scope.ffc.form.data.carmodel is populating id for time being jquery is used to get model value ,once refactored shd be in ng-variable 6285 var bodyContents = "I am interested in finding out more about vehicle finance on the "; // <br>"; 6286 bodyContents += carModel + " " + $('#engineVariant_'+vehicleIndex+ ' option:selected').text() + ", "; 6287 bodyContents += ($('#enhancementPack_' + vehicleIndex + ' option:selected').val() == "") ? "" : $('#enhancementPack_' + vehicleIndex + ' option:selected').text() + ", "; 6288 bodyContents += ($scope.ffc.form.results.paint ? $scope.ffc.form.results.paint.uriName : "") + "<br><br>"; 6289 6290 bodyContents += "<strong>Usage:</strong> " + $scope.ffc.form.data.loantype.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1) }) + "<br>"; 6291 bodyContents += "<strong>" + ($scope.ffc.form.data.loantype.toLowerCase() === "personal" ? "Comparison Rate" : "Interest Rate") + ":</strong> " + $scope.ffc.form.data.interestrate + " %" + "<br>"; 6292 bodyContents += "<strong>Deposit:</strong> $" + $scope.ffc.form.data.deposit + "<br>"; 6293 bodyContents += "<strong>Loan Term:</strong> " + $scope.ffc.form.data.loanterm + " years" + "<br>"; 6294 bodyContents += "<strong>Balloon Payment<span class='lx-finance-summary__section-payment-info'>3</span> :</strong> " + ($scope.pricingSuccess ? "$" + $scope.ffc.form.results.finalBalloonPayment : "Price currently not available") + "<br>"; 6295 bodyContents += "<strong>Drive Away<span class='lx-finance-summary__section-payment-info'>1</span> :</strong> " + ($scope.pricingSuccess ? "$" + $scope.ffc.form.results.driveAwayPrice : "Price currently not available") + "<br>"; 6296 6297 bodyContents += "<strong>Estimated Repayment<span class='lx-finance-summary__section-payment-info'>2</span> :</strong> "; 6298 6299 if ($scope.ffc.form.settings.summary.paymentInterval == 'month') { 6300 bodyContents += ($scope.pricingSuccess) ? "$" + $scope.ffc.form.results.installmentPerMonth + " per month <br>" : "Price currently not available <br>"; 6301 } else { 6302 bodyContents += ($scope.pricingSuccess) ? "$" + $scope.ffc.form.results.installmentPerWeek + " per week <br>" : "Price currently not available <br>"; 6303 } 6304 6305 $scope.ffc.form.data.messagedynamic = bodyContents; 6306 6307 var t = $sce.trustAsHtml(bodyContents); 6308 6309 return t; 6310 } 6311 6312 $scope.setFocus = function ($event) { 6313 $('html, body').animate({ 6314 scrollTop: ($('#postcodes').offset().top - 80) 6315 }); 6316 $event.preventDefault(); 6317 $("#postcodes :input").focus(); 6318 }; 6319 6320 $scope.setFocusWithScroll = function ($event) { 6321 $event.preventDefault(); 6322 $('html, body').animate({ 6323 scrollTop: ($('#postcodes').offset().top - 80) 6324 }, 200); 6325 } 6326 6327 $scope.getMailLink = function (vehicleIndex) { 6328 vehicleIndex = vehicleIndex || 0; 6329 6330 var carModel = $('#carmodel_'+ vehicleIndex + ' option:selected').text(); // should we split by name of full name is ok? carModel.split('-')[0] $scope.ffc.form.data.carmodel is populating id for time being jquery is used to get model value ,once refactored shd be in ng-variable 6331 var engineVariantandGrade = $('#engineVariant_' + vehicleIndex + ' option:selected').text(); 6332 var enhancementPack = $('#enhancementPack_' + vehicleIndex + ' option:selected').text(); 6333 var lineBreak = "\n"; //"%0D%0A"; 6334 var bodyContents = $scope.ffc.form.emailsettings.email.introText + lineBreak + lineBreak; 6335 bodyContents += "Vehicle Model : " + carModel + lineBreak; 6336 bodyContents += "Variant and Grade : " + engineVariantandGrade + lineBreak; 6337 bodyContents += "Enhancement Pack : " + enhancementPack + lineBreak; 6338 bodyContents += "Disclaimer Paint : " + "The price is based on " + ($scope.ffc.form.results.paint ? $scope.ffc.form.results.paint.uriName.toUpperCase() : "a default") + " exterior and "; 6339 bodyContents += ($scope.ffc.form.results.trim ? $scope.ffc.form.results.trim.uriName.toUpperCase() : "a default") + " trim" + lineBreak; 6340 bodyContents += "Interest Rate : " + $scope.ffc.form.data.interestrate + "%" + lineBreak; 6341 bodyContents += "Deposit : $" + $scope.ffc.form.data.deposit + lineBreak; 6342 bodyContents += "Loan Term : " + $scope.ffc.form.data.loanterm + " years" + lineBreak; 6343 bodyContents += "Usage : " + $scope.ffc.form.data.loantype + lineBreak; 6344 bodyContents += "Drive-away : "; 6345 bodyContents += ($scope.pricingSuccess) ? "$" + $scope.ffc.form.results.driveAwayPrice : "Price currently not available"; 6346 bodyContents += lineBreak; 6347 6348 if ($scope.ffc.form.settings.summary.paymentInterval == 'month') { 6349 bodyContents += "Estimated Monthly Repayment^ : "; 6350 bodyContents += ($scope.pricingSuccess) ? "$" + $scope.ffc.form.results.installmentPerMonth : "Price currently not available"; 6351 } else { 6352 bodyContents += "Estimated Weekly Repayment^ : "; 6353 bodyContents += ($scope.pricingSuccess) ? "$" + $scope.ffc.form.results.installmentPerWeek : "Price currently not available"; 6354 } 6355 6356 bodyContents += lineBreak; 6357 6358 bodyContents += "Final Balloon Payment++ : $" + $scope.ffc.form.results.finalBalloonPayment + lineBreak + lineBreak; 6359 //Final Balloon Payment++ : $4,959.10 or 10% of Drive-away 6360 bodyContents += $scope.ffc.form.emailsettings.email.disclaimer + lineBreak; 6361 $scope.ffc.form.emailsettings.email.fullBodyContents = bodyContents; 6362 6363 var t = "mailto:?subject=" + encodeURIComponent($scope.ffc.form.emailsettings.email.subject) + "&body=" + encodeURIComponent($scope.ffc.form.emailsettings.email.fullBodyContents); 6364 return t; 6365 6366 } 6367 6368 $scope.getBuildPriceLink = function () { 6369 6370 var url = $scope.ffc.form.data.carmodel ? $scope.BuildPriceService.encodeUriFragment($scope.ffc.form.data.carmodel) : ""; 6371 url = url + "/"; 6372 6373 if ($scope.ffc.form.data.engineVariant) { 6374 6375 url = url + $scope.BuildPriceService.encodeUriFragment($scope.ffc.form.data.engineVariant) + "/"; 6376 url = url + $scope.BuildPriceService.encodeUriFragment($scope.ffc.form.data.grade) + "/"; 6377 6378 if ($scope.ffc.form.data.enhancementPack) { 6379 url = url + $scope.BuildPriceService.encodeUriFragment($scope.ffc.form.data.enhancementPack) + "/"; 6380 } 6381 6382 if ($scope.ffc.form.results.paint) { 6383 url = url + $scope.BuildPriceService.encodeUriFragment( 6384 $scope.ffc.form.results.paint.uriName) + "/"; 6385 } 6386 6387 if ($scope.ffc.form.results.trim) { 6388 url = url + $scope.BuildPriceService.encodeUriFragment($scope.ffc.form.results.trim.uriName); 6389 } 6390 6391 url = url + "/4#lx-bp-nav"; 6392 } 6393 6394 var path = $scope.BuildPriceService.encodeUriPath(url); 6395 6396 return path; 6397 } 6398 6399 $scope.updateIntroText = function (introText) { 6400 $scope.ffc.form.emailsettings.email.introText = $sce.trustAsHtml(introText); 6401 } 6402 6403 $scope.updateDisclaimerText = function (disclaimerText) { 6404 $scope.ffc.form.emailsettings.email.disclaimer = $sce.trustAsHtml(disclaimerText); 6405 } 6406 6407 $scope.deselectDealer = function () { 6408 $scope.ffc.form.data.dealerId = $scope.ffc.form.data.dealerName = null; 6409 } 6410 6411 $scope.selectDealer = function (dealerInputId) { 6412 var scrollPos = $(document).scrollTop(); 6413 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 6414 if (scrollPos > maxPos) { 6415 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 6416 } 6417 } 6418 6419 $scope.searchNow = function () { 6420 $scope.ffc.form.dealersLoading = true; 6421 $rootScope.$broadcast('visitor-details-change-autocomplete', $scope.ffc.form.data.postcodes[0].data); 6422 DealersService.setParam('postCode', $scope.ffc.form.data.postcodes[0].data.postCode); 6423 DealersService.setParam('suburb', $scope.ffc.form.data.postcodes[0].data.suburb); 6424 DealersService.setParam('type', 'Sales'); 6425 $scope.ffc.form.data.postcode = $scope.ffc.form.data.postcodes[0].data.postCode; 6426 DealersService.GetResults(); 6427 } 6428 6429 $scope.clearPostcode = function () { 6430 $scope.ffc.form.data.postcodes = null; 6431 $scope.ffc.form.dealerquoteform.Show = false; 6432 } 6433 6434 $scope.updatePostcode = function (tag) { 6435 $scope.ffc.form.tagsLoading = false; 6436 $rootScope.$broadcast('visitor-details-cookie-change', { 6437 postCode: tag.data.postcode, 6438 suburb: tag.data.suburb, 6439 state: tag.data.state, 6440 pricingZone: tag.data.pricingZone 6441 }); 6442 6443 $scope.ffc.form.data.postcodes = []; 6444 $scope.ffc.form.data.postcodes[0] = tag; 6445 6446 $scope.dealerSearch(tag); 6447 } 6448 6449 $scope.loadBranches = function (dealerID) { 6450 $scope.ffc.form.dealersLoading = true; 6451 DealersService.setParam('dealerID', dealerID); 6452 DealersService.setParam('type', 'Sales'); 6453 DealersService.GetDealerBranches(); 6454 } 6455 6456 $scope.dealerSearch = function ($tag) { 6457 $scope.searchDealersNow(); 6458 } 6459 6460 $scope.searchDealersNow = function () { 6461 $scope.ffc.form.dealersLoading = true; 6462 $rootScope.$broadcast('visitor-details-change-autocomplete', $scope.ffc.form.data.postcodes[0].data); 6463 6464 6465 //Main Site 6466 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !$scope.isDealerSite) { 6467 $scope.searchNow(); 6468 } 6469 6470 //Dealer Site Multi Branch 6471 if ($scope.isDealerSite && $scope.isMultiBranchDealer) { 6472 $scope.ffc.form.data.dealerId = null; 6473 $scope.ffc.form.data.dealerName = null; 6474 $scope.loadBranches($scope.forceDealerId); 6475 } 6476 6477 //Dealer Site NOT Multi Branch 6478 if ($scope.isDealerSite && !$scope.isMultiBranchDealer && $scope.dealerState) { 6479 DealersService.setParam('dealerID', $scope.forceDealerId); 6480 DealersService.setParam('dealerState', $scope.dealerState); 6481 DealersService.setParam('type', 'Sales'); 6482 DealersService.GetResult(); 6483 } 6484 } 6485 6486 $scope.$on('dealer-search-results-received', function (event, data) { 6487 $scope.ffc.form.dealersLoading = false; 6488 $scope.ffc.form.dealers = data.Data; 6489 6490 $scope.checkDealersLoaded(); 6491 6492 if ($scope.ffc.form.dealerquoteform.Show) { 6493 $('html, body').animate({ 6494 scrollTop: ($('#scrollFormTop').offset().top) 6495 }, 200); 6496 } 6497 }); 6498 6499 //Do a sanity check to see if the bound dealers match the forceDealer if not clear the force dealer 6500 $scope.checkDealersLoaded = function () { 6501 var result = $scope.ffc.form.dealers.find(function (dealer) { 6502 return dealer.dealerCode == $scope.ffc.form.data.dealerId; 6503 }); 6504 if (!result) { 6505 $scope.ffc.form.data.dealerId = null; 6506 } 6507 6508 if ($scope.ffc.form.dealers.length == 1) 6509 $scope.ffc.form.data.dealerId = $scope.ffc.form.dealers[0].dealerCode; 6510 } 6511 6512 $scope.$on('dealer-search-result-received', function (event, data) { 6513 $scope.ffc.form.dealersLoading = false; 6514 $scope.ffc.form.dealer = data.Data; 6515 6516 if ($scope.ffc.form.dealerquoteform.Show) { 6517 $('html, body').animate({ 6518 scrollTop: ($('#scrollFormTop').offset().top) 6519 }, 200); 6520 } 6521 6522 $scope.ffc.form.dealerlocations = data.Data.locations; 6523 6524 if ($scope.ffc.form.dealerlocations == null) { 6525 $scope.ffc.form.dealerlocations = []; 6526 } 6527 //Multiple dealers for same dealerId - A bug to be corrected latter -wont require looping in that case on parent 6528 if (data.Data) { 6529 angular.forEach(data.Data, function (val) { 6530 if (val) { 6531 angular.forEach(val.locations, function (innerval) { 6532 this.push(innerval); 6533 }, $scope.ffc.form.dealerlocations); 6534 } 6535 }); 6536 } 6537 6538 if ($scope.ffc.form.dealerlocations.length == 1) 6539 $scope.ffc.form.data.locationId = $scope.ffc.form.dealerlocations[0].locationId; 6540 6541 //$("#additionalcomments").focus(); 6542 6543 }); 6544 6545 $scope.getData = function () { 6546 return { 6547 DriveAwayPrice: $scope.ffc.form.results.driveAwayPrice, 6548 Deposit: $scope.ffc.form.data.deposit, 6549 InterestRate: $scope.ffc.form.data.interestrate, 6550 LoanTerm: $scope.ffc.form.data.loanterm, 6551 BalloonPayment: $scope.ffc.form.data.balloonpayment 6552 }; 6553 } 6554 6555 $scope.isSectionDisabled = function (sectionName) { 6556 switch (sectionName) { // note: falls through to test multiple cases 6557 case 'summary':
6558 case 'loanDetails': 6559 if (!($scope.ffc.form.data.carmodel && $scope.ffc.form.data.engineVariantAndGrade)) { 6560 return true; 6561 } 6562 case 'vehicleDetails': 6563 if (!($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0)) { 6564 return true; 6565 } 6566 } 6567 return false; 6568 } 6569 6570 $scope.updateLoanType = function () { 6571 $scope.bindLoanTermOptions(); 6572 $scope.bindBalloonPaymentOptions(); 6573 $scope.interestRateCopy(); 6574 } 6575 6576 $scope.updateLoanTerm = function () { 6577 $scope.bindBalloonPaymentOptions(); 6578 } 6579 6580 $scope.interestRateCopy = function () { 6581 if ($scope.ffc.form.data.loantype.toLowerCase() === 'business') { 6582 $scope.ffc.form.data.interestRateCopy = $scope.ffc.form.data.interestRateBusiness > 0 ? $scope.ffc.form.data.interestRateBusiness : 6583 $scope.ffc.form.data.interestrate; 6584 } 6585 6586 if ($scope.ffc.form.data.loantype.toLowerCase() === 'personal') { 6587 $scope.ffc.form.data.interestRateCopy = $scope.ffc.form.data.interestRatePersonal > 0 ? $scope.ffc.form.data.interestRatePersonal : 6588 $scope.ffc.form.data.interestrate; 6589 } 6590 } 6591 6592 $scope.bindLoanTermOptions = function () { 6593 switch ($scope.ffc.form.data.loantype) { 6594 case 'personal': 6595 $scope.ffc.form.settings.loanTerm.max = $scope.ffc.form.settings.loanTerm.personalMax 6596 break; 6597 case 'business': 6598 $scope.ffc.form.settings.loanTerm.max = $scope.ffc.form.settings.loanTerm.businessMax 6599 break; 6600 } 6601 $scope.ffc.form.data.loanterm = Math.min($scope.ffc.form.settings.loanTerm.max, Math.max($scope.ffc.form.settings.loanTerm.min, $scope.ffc.form.data.loanterm)); 6602 } 6603 6604 $scope.bindBalloonPaymentOptions = function () { 6605 if ($scope.ffc.form.settings.balloonPayment.fixedValue) { 6606 return; 6607 } 6608 if ($scope.ffc.form.data.loantype && $scope.ffc.form.data.loanterm) { 6609 $http({ method: 'GET', url: $filter('formatArgs')(Lexus.API.Lookup.FinanceBalloonPaymentOptions, [Lexus.ID.Site, $scope.ffc.form.data.loantype, $scope.ffc.form.data.loanterm, $scope.ffc.form.data.loantype]) }) 6610 .then(function success(response) { 6611 if (response.data.Data) { 6612 $scope.ffc.form.settings.balloonPayment.min = response.data.Data.Min; 6613 $scope.ffc.form.settings.balloonPayment.step = response.data.Data.Step; 6614 $scope.ffc.form.data.balloonPayment = Math.min(response.data.Data.Max, Math.max(response.data.Data.Min, $scope.ffc.form.data.balloonPayment)); 6615 $scope.ffc.form.settings.balloonPayment.max = response.data.Data.Max; 6616 } 6617 $scope.ffc.form.settings.balloonPayment.disabled = response.data.Data.DisableBalloonPayments; 6618 $rootScope.$broadcast('balloon-payment-options-received'); 6619 }, function error(response) { 6620 $rootScope.$broadcast('open-modal-window', { 6621 content: $scope.ffc.form.settings.messages.apiError, 6622 variant: Lexus.ModalVariant.Content, 6623 closeOnEvent: 'close-modal-window', 6624 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6625 }); 6626 }) 6627 .finally(function () { 6628 6629 }); 6630 } 6631 } 6632 6633 //Watches: carmodel, enhancementPack, postcode, grade 6634 //Modifies: driveAwayPrice 6635 $scope.$watchGroup(['ffc.form.data.carmodel', 'ffc.form.data.enhancementPack', 'ffc.form.data.postcodes', 'ffc.form.data.engineVariantAndGrade'], function (newDataArray, oldDataArray, $scope) { 6636 var newData = {}; 6637 newData.carmodel = newDataArray[0]; 6638 newData.enhancementPack = newDataArray[1]; 6639 newData.postcodes = newDataArray[2]; 6640 newData.engineVariantAndGrade = newDataArray[3]; 6641 6642 //Something has changed since entering with a B&P Deeplink 6643 if ($scope.ffc.form.data.engineVariantAndGrade != newData.engineVariantAndGrade || $scope.ffc.form.data.enhancementPack != newData.enhancementPack) { 6644 $scope.ffc.form.data.trim = $scope.ffc.form.results.trim = null; 6645 $scope.ffc.form.data.colour = $scope.ffc.form.results.paint = null; 6646 } 6647 6648 $log.info("carmodel: " + newData.carmodel); 6649 $log.info("enhancementPack: " + newData.enhancementPack); 6650 $log.info("engineVariantAndGrade: " + newData.engineVariantAndGrade); 6651 var pricingZone = ""; 6652 if (newData.postcodes && newData.postcodes.length > 0) { 6653 var visitor = UserPreferencesService.splitAutoCompleteResult(newData.postcodes[0].text); 6654 pricingZone = newData.postcodes[0].data.pricingZone; 6655 if (!visitor.postCode) { 6656 // $scope.ffc.form.results.driveAwayPrice = 0; ? 6657 return; 6658 } 6659 } else { 6660 $scope.ffc.form.results.driveAwayPrice = 0; 6661 return; 6662 } 6663 6664 BuildPriceService.waitFor.call($scope, 'ffc.formfields.data.enhancementPacks', BuildPriceService.waitCondition.NOTEMPTY) 6665 .then(function (enhancementPacks) { 6666 6667 var selectedEnhancementPack = $scope.ffc.formfields.data.enhancementPacks.find(function (item) { 6668 return $scope.ffc.form.data.enhancementPack == item.uriName; 6669 }); 6670 6671 var selectedGrade = $scope.ffc.formfields.data.enginevariantsandgrades.find(function (item) { 6672 return $scope.ffc.form.data.engineVariantAndGrade == item.key; 6673 }); 6674 6675 if (selectedEnhancementPack && selectedEnhancementPack.mdmid) { 6676 6677 var selectedEnhancementPackMdmId = selectedEnhancementPack.mdmid; 6678 6679 if (!selectedGrade) { 6680 $scope.ffc.form.data.engineVariantAndGrade = undefined; 6681 return; 6682 } 6683 6684 var selectedGradeId = selectedGrade.gradeId; 6685 var selectedEngineVariant = $scope.ffc.form.data.engineVariant; 6686 PricingService.setParam("enablePricingByZone", $scope.ffc.form.settings.enablePricingByZone); 6687 if ($scope.ffc.form.data.trim && $scope.ffc.form.data.colour) //Deep Linked from B&P with a trim and paint 6688 { 6689 BuildPriceAPIService.getModels(function () { 6690 BuildPriceAPIService.getVariants(selectedEngineVariant, selectedGradeId, function () { 6691 var selectedVariant = BuildPriceAPIService.getVariantByName(selectedEngineVariant, selectedGradeId, $scope.ffc.form.data.enhancementPack);
6692 BuildPriceAPIService.getTrims(selectedEngineVariant, selectedGradeId, selectedVariant.mdmid, function () { 6693 var selectedTrim = BuildPriceAPIService.getTrimByName(selectedEngineVariant, selectedGradeId, selectedVariant.mdmid, $scope.ffc.form.data.trim); 6694 if (!selectedTrim) { 6695 selectedTrim = selectedVariant.trims.availableTrims[0]; 6696 $scope.ffc.form.data.trim = selectedTrim.uriName; 6697 } 6698 BuildPriceAPIService.getPaints(selectedEngineVariant, selectedGradeId, selectedVariant.mdmid, selectedTrim.id, function (availableColours, unavailableColours) { 6699 var selectedPaint = BuildPriceAPIService.getPaintByName(selectedEngineVariant, selectedGradeId, selectedVariant.mdmid, selectedTrim.id, $scope.ffc.form.data.colour); 6700 if (!selectedPaint) { 6701 selectedPaint = selectedTrim.paints.availableColours[0]; 6702 $scope.ffc.form.data.colour = selectedPaint.uriName; 6703 } 6704 PricingService.detailPriceByPaint( 6705 selectedGradeId, 6706 selectedEnhancementPackMdmId, 6707 selectedTrim.id, 6708 selectedPaint.materialCode, 6709 visitor.postCode, 6710 pricingZone 6711 ).then(function success(data) { 6712 if (data.status === "Success") { 6713 $scope.pricingResult(data.data.driveAway); 6714 $scope.ffc.form.results.driveAwayPrice = data.data.driveAway; 6715 $scope.ffc.form.results.paint = selectedPaint; 6716 $scope.ffc.form.results.trim = selectedTrim; 6717 } 6718 }, function failure(data) { 6719 $scope.pricingResult(false); 6720 $rootScope.$broadcast('open-modal-window', { 6721 content: $scope.ffc.form.settings.messages.apiError, 6722 variant: Lexus.ModalVariant.Content, 6723 closeOnEvent: 'close-modal-window', 6724 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6725 }); 6726 }); 6727 6728 }); 6729 }); 6730 }); 6731 }); 6732 6733 } 6734 else { 6735 PricingService.driveAwayByEnhancementPack(selectedGradeId, selectedEnhancementPackMdmId, visitor.postCode, pricingZone).then(function success(data) { 6736 if (data.status === "Success") { 6737 if (data.data && data.data.driveAway) { 6738 $scope.pricingResult(data.data.driveAway); 6739 6740 $scope.ffc.form.results.driveAwayPrice = data.data.driveAway; 6741 $scope.ffc.form.results.paint = data.data.paint; 6742 $scope.ffc.form.results.trim = data.data.trim; 6743 } else { 6744 $scope.pricingResult(0); 6745 } 6746 } 6747 }, function failure(data) { 6748 $scope.pricingResult(false); 6749 $rootScope.$broadcast('open-modal-window', { 6750 content: $scope.ffc.form.settings.messages.apiError, 6751 variant: Lexus.ModalVariant.Content, 6752 closeOnEvent: 'close-modal-window', 6753 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6754 }); 6755 }); 6756 } 6757 } 6758 else if (newData.engineVariantAndGrade && $scope.ffc.formfields.data.enginevariantsandgrades) { 6759 6760 6761 if (selectedGrade) { 6762 var selectedGradeId = selectedGrade.gradeId; 6763 6764 PricingService.driveAwayByGrade(selectedGradeId, visitor.postCode, pricingZone).then(function success(data) { 6765 if (data.status === "Success") { 6766 if(data.data && data.data.driveAway){ 6767 $scope.pricingResult(data.data.driveAway); 6768 6769 $scope.ffc.form.results.driveAwayPrice = data.data.driveAway; 6770 $scope.ffc.form.results.paint = data.data.paint; 6771 $scope.ffc.form.results.trim = data.data.trim; 6772 } else { 6773 $scope.pricingResult(0); 6774 } 6775 } 6776 }, function failure(data) { 6777 6778 $scope.pricingResult(false); 6779 $rootScope.$broadcast('open-modal-window', { 6780 content: $scope.ffc.form.settings.messages.apiError, 6781 variant: Lexus.ModalVariant.Content, 6782 closeOnEvent: 'close-modal-window', 6783 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6784 }); 6785 }); 6786 } 6787 } else { 6788 $scope.ffc.form.results.driveAwayPrice = 0; 6789 } 6790 6791 }); 6792 6793 }); 6794 6795 //Watches: driveAwayPrice, deposit, interestrate, loanterm, balloonpayment, loantype 6796 //Modifies: installmentPerWeek/PerMonth, finalBalloonPayment 6797 $scope.$watchGroup(['ffc.form.results.driveAwayPrice', 'ffc.form.data.deposit', 'ffc.form.data.interestrate', 'ffc.form.data.loanterm', 'ffc.form.data.balloonPayment', 'ffc.form.data.loantype'], function (newDataArray, oldDataArray, $scope) { 6798 var newData = {}; 6799 newData.driveAwayPrice = newDataArray[0]; 6800 newData.deposit = newDataArray[1]; 6801 newData.interestrate = newDataArray[2]; 6802 newData.loanterm = newDataArray[3]; 6803 newData.balloonPayment = newDataArray[4]; 6804 newData.loantype = newDataArray[5]; 6805 6806 if ($scope.delayedRecalc) { 6807 $timeout.cancel($scope.delayedRecalc); 6808 } 6809 if (newData.driveAwayPrice === 0) { 6810 $scope.ffc.form.results.installmentPerMonth = 0; 6811 $scope.ffc.form.results.installmentPerWeek = 0; 6812 $scope.ffc.form.results.finalBalloonPayment = 0; 6813 return; 6814 } 6815 if (newData.driveAwayPrice > 0 && newData.deposit && newData.interestrate && newData.loanterm && (newData.balloonPayment != null) && newData.loantype) { 6816 $scope.delayedRecalc = $timeout($scope.recalc, 500, true, newD
6816ata); 6817 } 6818 }); 6819 6820 $scope.pricingResult = function (value) { 6821 var status = (typeof value == "number") ? (value != 0) : (typeof value == "boolean") ? value : false; 6822 if (status) { 6823 angular.element('body').removeClass('pricing-error'); 6824 } else { 6825 angular.element('body').addClass('pricing-error'); 6826 } 6827 6828 $scope.pricingSuccess = status; 6829 6830 } 6831 6832 $scope.recalc = function (newData) { 6833 var interrestRate = $scope.ffc.form.data.interestrate; 6834 /// This is being added so we can Hack around the bad finance service. 6835 /// Personal loans for the L'Exhibition Campaign should show 1% but pass 0.00000000001 only for Personal 6836 /// Go check this ticket LDM-8 6837 if ($scope.ffc.form.data.interestRateOverride > 0 && $scope.ffc.form.data.loantype.toLowerCase() === 'personal') 6838 { 6839 interrestRate = $scope.ffc.form.data.interestRateOverride; 6840 } 6841 if ($scope.ffc.form.data.interestRateOverrideBusiness > 0 && $scope.ffc.form.data.loantype.toLowerCase() === 'business') { 6842 interrestRate = $scope.ffc.form.data.interestRateOverrideBusiness; 6843 } 6844 6845 6846 //temporary toString().replace() until deposit is fixed to always be an int 6847 $http({ method: 'GET', url: $filter('formatArgs')(Lexus.API.Lookup.FinanceCalculator, [Lexus.ID.Site, $scope.ffc.form.results.driveAwayPrice, $scope.ffc.form.data.deposit.toString().replace(/,/g, ''), interrestRate, $scope.ffc.form.data.loanterm, $scope.ffc.form.data.balloonPayment, $scope.ffc.form.data.loantype]) }) 6848 .then(function successCallback(response) { 6849 6850 if (response.data.Status == "Success") { 6851 $scope.ffc.form.results.installmentPerMonth = response.data.Data.InstallmentPerMonth; 6852 $scope.ffc.form.results.installmentPerWeek = response.data.Data.InstallmentPerWeek; 6853 $scope.ffc.form.results.finalBalloonPayment = response.data.Data.FinalBalloonPayment; 6854 $scope.ffc.form.failed = false; 6855 } 6856 else { 6857 $rootScope.$broadcast('open-modal-window', { 6858 content: response.data.ErrorMessage, 6859 variant: Lexus.ModalVariant.Content, 6860 closeOnEvent: 'close-modal-window', 6861 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6862 }); 6863 } 6864 6865 }, function errorCallback(error) { 6866 $scope.ffc.form.failed = true; 6867 6868 $rootScope.$broadcast('open-modal-window', { 6869 content: $scope.ffc.form.settings.messages.apiError, 6870 variant: Lexus.ModalVariant.Content, 6871 closeOnEvent: 'close-modal-window', 6872 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 6873 }); 6874 6875 }); 6876 6877 } 6878 6879 $scope.openDealerQuoteForm = function (vehicleIndex) { 6880 $scope.ffc.form.completed = false; 6881 $scope.ffc.form.dealerquoteform.Show = true; 6882 6883 $scope.createGenericMessage(vehicleIndex); 6884 $scope.searchDealersNow(); 6885 6886 //$("#additionalcomments").focus(); 6887 6888 } 6889 6890 $scope.getDataRequestQuoteData = function () { 6891 6892 var deposit = $scope.ffc.form.data.deposit.toString().replace(",", ""); 6893 6894 return { 6895 AdditionalComments: $scope.ffc.form.data.additionalcomments, 6896 Source: $scope.ffc.form.data.source, 6897 DealerId: $scope.ffc.form.data.dealerId, 6898 ContextDealerSiteId: $scope.forceDealerId, 6899 Message: $scope.ffc.form.data.messagedynamic, 6900 PostCode: $scope.ffc.form.data.postcode, 6901 Phone: $scope.ffc.form.data.phone, 6902 FirstName: $scope.ffc.form.data.firstname, 6903 LastName: $scope.ffc.form.data.lastname, 6904 Email: $scope.ffc.form.data.email, 6905 PreferredContactMethod: $scope.ffc.form.data.prefer, 6906 Subscribe: $scope.ffc.form.data.subscribe, 6907 PhoneType: $scope.ffc.form.data.phonetype, 6908 Captcha: $scope.ffc.form.data.captcha, 6909 Model: $scope.ffc.form.data.carmodel, 6910 EngineVariant: $scope.ffc.form.data.engineVariant, 6911 Grade: $scope.ffc.form.data.grade, 6912 EnhancementPack: $scope.ffc.form.data.enhancementPack,
6913 Paint: $scope.ffc.form.results ? $scope.ffc.form.results.paint.name : null, 6914 Trim: $scope.ffc.form.results ? $scope.ffc.form.results.trim.name : null, 6915 LoanType: $scope.ffc.form.data.loantype, 6916 InterestRate: $scope.ffc.form.data.interestrate, 6917 Deposit: deposit, 6918 LoanTerm: $scope.ffc.form.data.loanterm, 6919 BalloonPayment: $scope.ffc.form.data.balloonPayment, 6920 DriveAwayPrice: $scope.ffc.form.results.driveAwayPrice, 6921 MonthlyPayments: $scope.ffc.form.results.installmentPerMonth, 6922 FormUrl: ($scope.ffc.form.settings.disclaimerPage && $scope.ffc.form.settings.disclaimerPage != "" ? $scope.ffc.form.settings.disclaimerPage : $location.absUrl()) 6923 }; 6924 } 6925 6926 $rootScope.$on('submit-finance-calculator-form', function () { 6927 $scope.ffc.form.submitting = true; 6928 6929 var formData = $scope.getDataRequestQuoteData(); 6930 6931 eloquaService.attachEloquaFields(formData); 6932 6933 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 6934 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.RequestDealerQuoteUrl, [Lexus.ID.Site]), data: formData }). 6935 then(function success(response) { 6936 6937 if (response.data.Status == "Success") { 6938 $scope.submissionPass(response.data); 6939 } 6940 else { 6941 $scope.submissionFail(response.data); 6942 } 6943 }, function error(response) { 6944 $scope.submissionFail(response.data); 6945 }) 6946 .finally(function () { 6947 $rootScope.$broadcast('form-result'); 6948 }); 6949 }); 6950 6951 $scope.submissionPass = function (data) { 6952 // this callback will be called asynchronously 6953 // when the response is available 6954 $scope.ffc.form.completed = true; 6955 $scope.ffc.form.failed = false; 6956 $scope.ffc.form.submitting = false; 6957 var historyState = "RequestDealerQuoteForm=Pass"; 6958 $location.state(historyState); 6959 FormsService.ShowResult($scope.successContent[0]); 6960 $rootScope.$broadcast('gtm-form-success', 'Finance Calculator'); 6961 $rootScope.$broadcast('visitor-details-session-change', $scope.getDataRequestQuoteData()); 6962 }; 6963 6964 $scope.submissionFail = function (data) { 6965 // called asynchronously if an error occurs 6966 // or server returns response with an error status. 6967 $scope.ffc.form.failed = true; 6968 $scope.ffc.form.errors = data.Data; 6969 $scope.ffc.form.submitting = false; 6970 $scope.ffc.form.completed = true; 6971 var historyState = "RequestDealerQuoteForm=Fail"; 6972 $location.state(historyState); 6973 FormsService.ShowResult($scope.failureContent[0]); 6974 console.error(data.ErrorMessage); 6975 }; 6976 6977 6978 $scope.email = function () { 6979 6980 } 6981 6982 $scope.calculateNext = function (interestrate, interestrateInc, highestinterestrate, lowestinterestrate, type, obj) { 6983 var currentRate = Number($scope.ffc.form.data.interestrate); 6984 var maxRate = Number(highestinterestrate); 6985 var minRate = Number(lowestinterestrate); 6986 var increment = Number(interestrateInc); 6987 var adjustedRate; 6988 if (type == 'Increase') { 6989 adjustedRate = $scope.roundToIncrement(currentRate + increment, increment); 6990 if (adjustedRate > maxRate) { 6991 $scope.showInterestrateModal(lowestinterestrate, highestinterestrate) 6992 } 6993 else { 6994 $scope.ffc.form.data.interestrate = adjustedRate.toFixed(2); 6995 } 6996 } 6997 else if (type == 'Decrease') { 6998 adjustedRate = $scope.roundToIncrement(currentRate - increment, increment); 6999 if (adjustedRate < minRate || adjustedRate <= 0) { 7000 $scope.showInterestrateModal(lowestinterestrate, highestinterestrate) 7001 } 7002 else { 7003 $scope.ffc.form.data.interestrate = adjustedRate.toFixed(2); 7004 } 7005 } 7006 7007 $scope.formatNumberToDecimal($scope.ffc.form.data.interestrate, obj); 7008 7009 } 7010 7011 $scope.showInterestrateModal = function (lowestinterestrate, highestinterestrate) { 7012 $scope.$emit('open-modal-window', { 7013 content: 'Interest Rate should be between ' + lowestinterestrate + ' and ' + highestinterestrate + '', 7014 wrapper: ['<p class="lx-modal__paragraph">', '</p>'] 7015 }); 7016 } 7017 7018 $scope.filterValue = function ($event, val, type) { //Allow comma's ,dot and backspace 7019 var asciiVal = $event.keyCode || $event.charCode; 7020 if (isNaN(String.fromCharCode(asciiVal))) { 7021 if (asciiVal != 44 && asciiVal != 46 && asciiVal != 8) { 7022 $event.preventDefault(); 7023 } 7024 7025 if (type == 'interestrate') { 7026 if (asciiVal == 46) { 7027 if ($("#interestRate").val().indexOf(".") != -1) { 7028 $event.preventDefault(); 7029 } 7030 } 7031 7032 if (asciiVal == 44) { 7033 $event.preventDefault(); 7034 } 7035 } 7036 } 7037 7038 } 7039 7040 $scope.initDeposit = function (val, obj) { 7041 7042 var formattedNum = Math.floor(Number(val.toString().replace(',', ''))).toLocaleStr
7042ing('en', { useGrouping: true }); 7043 7044 $scope.ffc.form.data.deposit = formattedNum; 7045 } 7046 7047 $scope.validate = function (interestrate, interestrateInc, highestinterestrate, lowestinterestrate, obj) { 7048 var increment = Number(interestrateInc); 7049 var modifiedRate = $scope.roundToIncrement(Number($scope.ffc.form.data.interestrate), increment); 7050 var maxRate = Number(highestinterestrate); 7051 var minRate = Number(lowestinterestrate); 7052 7053 7054 if (modifiedRate > maxRate || modifiedRate < minRate || modifiedRate <= 0) { 7055 $scope.showInterestrateModal(lowestinterestrate, highestinterestrate) 7056 } 7057 7058 if (modifiedRate > maxRate) { 7059 $scope.ffc.form.data.interestrate = maxRate.toFixed(2); 7060 } else if (modifiedRate < minRate || modifiedRate <= 0 + increment) { 7061 $scope.ffc.form.data.interestrate = Math.max(minRate, 0 + increment).toFixed(2); 7062 } else { 7063 $scope.ffc.form.data.interestrate = modifiedRate.toFixed(2); 7064 } 7065 $scope.formatNumberToDecimal($scope.ffc.form.data.interestrate, obj); 7066 } 7067 7068 $scope.roundToIncrement = function (value, increment) { 7069 7070 if (typeof (value) != "number" || typeof (increment) != "number") { 7071 throw new Error("Value is not of type \"number\""); 7072 } 7073 7074 if (increment != 0) { 7075 var incRoundingFactor = 1 / increment; 7076 return (Math.round(value * incRoundingFactor) / incRoundingFactor); 7077 } else { 7078 return value; 7079 } 7080 } 7081 7082 $scope.formatNumber = function (val, obj) { 7083 if (obj != null) { 7084 var value; 7085 if (obj[formName] != null && !isNaN(value = Number(val.toString().replace(/,/g, '')))) { 7086 $scope.ffc.form.data.deposit = Math.floor(value).toLocaleString('en', { useGrouping: true }); 7087 } 7088 if (obj[formName] != null) 7089 $scope.ffc.form.data.deposit = $scope.ffc.form.data.deposit.replace('-', ''); 7090 } 7091 } 7092 7093 $scope.formatNumberToDecimal = function (val, obj) { 7094 if (obj != null) { 7095 if (obj[formName] != null && !isNaN(Number(val.replace(',', '')))) { 7096 if (val.replace(',', '').indexOf('.') == -1) 7097 $scope.ffc.form.data.interestrate = Number(val).toFixed(2); 7098 } 7099 if (obj[formName] != null) 7100 $scope.ffc.form.data.interestrate = $scope.ffc.form.data.interestrate.replace('-', ''); 7101 } 7102 7103 } 7104 7105 $scope.byAvailableGrades = function (engineVariantGrade) { 7106 return !$scope.ffc.form.settings.availableGrades || $scope.ffc.form.settings.availableGrades.includes(engineVariantGrade.mdmGradeId); 7107 }; 7108 } 7109} 7110 7111; 7112"use strict"; 7113/* Directives */ 7114angular.module('Lexus.Directives') 7115.directive('lxFormsFinanceContact', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 7116 var typeofForm = ''; 7117 formsFinanceContactController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'AddressSuggestService', 'UserPreferencesService', 'vcRecaptchaService', 'FormsService', 'API']; 7118 return { 7119 scope: true, 7120 restrict: 'A', 7121 controller: formsFinanceContactController, 7122 controllerAs: 'ffc', 7123 bindToController: true, 7124 link: function (scope, element, attrs, filter, http) { 7125 scope.successContent = element.find('.lx-form-success'); 7126 scope.failureContent = element.find('.lx-form-failure'); 7127 typeofForm = attrs.lxFormsType; 7128 } 7129 }; 7130 7131 function formsFinanceContactController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, AddressSuggestService, UserPreferencesService, vcRecaptchaService, FormsService, API) { 7132 var fcu = this; 7133 7134 $scope.init = function () { 7135 UserPreferencesService.getLexusVisitorSession().then(function (data) { 7136 7137 var visitorPreference = UserPreferencesService.getLexusVisitor(); 7138 $scope.ffc.form = { 7139 submitting: false, 7140 completed: false, 7141 errors: false, 7142 data: { 7143 subscribe: false, 7144 postcodes: [], 7145 postcode: "", 7146 email: data.Data.email, 7147 phonetype: data.Data.phoneType && data.Data.phoneType != '' ? data.Data.phoneType : 'home', 7148 firstname: data.Data.name, 7149 lastname: data.Data.surname, 7150 phone: data.Data.phone, 7151 prefer: data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 7152 captcha: '', 7153 requesttype: null 7154 } 7155 }; 7156 7157 var visitorPreference = UserPreferencesService.getLexusVisitor(); 7158 if (visitorPreference && visitorPreference.postCode && visitorPreference.suburb && visitorPreference.state) { 7159 $scope.ffc.form.data.postcodes.push(UserPreferencesService.getAutocompleteTagFromVisitor(visitorPreference)); 7160 } 7161 7162 }, function (reason) { 7163 }); 7164 } 7165 7166 $scope.getData = function () { 7167 var visitor = UserPreferencesService.splitAutoCompleteResult($scope.ffc.form.data.postcodes[0].text); 7168 return { 7169 Message: $scope.ffc.form.data.message, 7170 FirstName: $scope.ffc.form.data.firstname, 7171 LastName: $scope.ffc.form.data.lastname, 7172 Email: $scope.ffc.form.data.email,
7173 PostCode: visitor.postCode, 7174 Phone: $scope.ffc.form.data.phone, 7175 PhoneType: $scope.ffc.form.data.phonetype, 7176 PreferredContactMethod: $scope.ffc.form.data.prefer, 7177 Subscribe: $scope.ffc.form.data.subscribe.toString(), 7178 Captcha: $scope.ffc.form.data.captcha, 7179 RequestType: $scope.ffc.form.data.requesttype, 7180 }; 7181 } 7182 7183 7184 7185 $rootScope.$on('submit-financial-form', function () { 7186 7187 $rootScope.$broadcast('visitor-details-cookie-change-autocomplete', $scope.ffc.form.data.postcodes[0].text); 7188 7189 $scope.ffc.form.submitting = true; 7190 7191 7192 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 7193 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.FinanceContact, [Lexus.ID.Site]), data: $scope.getData() }). 7194 then(function success(response) { 7195 if (response.data.Status == "Success") { 7196 $scope.submissionPass(response.data); 7197 } 7198 else { 7199 $scope.submissionFail(response.data); 7200 } 7201 }, function error(response) { 7202 $scope.submissionFail(response.data); 7203 7204 }) 7205 .finally(function () { 7206 $rootScope.$broadcast('form-result'); 7207 }); 7208 }); 7209 7210 $scope.submissionPass = function (data) { 7211 // this callback will be called asynchronously 7212 // when the response is available 7213 $scope.ffc.form.completed = true; 7214 $scope.ffc.form.failed = false; 7215 $scope.ffc.form.submitting = false; 7216 var historyState = "FinanceForm=Pass"; 7217 $location.state(historyState); 7218 FormsService.ShowResult($scope.successContent[0]); 7219 $rootScope.$broadcast('gtm-form-success', 'Finance Contact'); 7220 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 7221 } 7222 7223 $scope.submissionFail = function (data) { 7224 // called asynchronously if an error occurs 7225 // or server returns response with an error status. 7226 $scope.ffc.form.failed = true; 7227 $scope.ffc.form.errors = data.Data; 7228 $scope.ffc.form.submitting = false; 7229 $scope.ffc.form.completed = true; 7230 var historyState = "FinanceForm=Fail"; 7231 $location.state(historyState); 7232 FormsService.ShowResult($scope.failureContent[0]); 7233 console.error(data.ErrorMessage); 7234 } 7235 7236 //$scope.loadTags = function (query) { 7237 // AddressSuggestService.setParam('term', query); 7238 // return AddressSuggestService.GetResults(); 7239 //}; 7240 7241 $scope.updatePostcode = function ($tag) { 7242 $scope.ffc.form.data.postcodes = []; 7243 $scope.ffc.form.data.postcodes[0] = $tag; 7244 }; 7245 7246 } 7247}]); 7248; 7249"use strict"; 7250/* Directives */ 7251angular.module('Lexus.Directives') 7252.directive('lxFormsInsuranceContact', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 7253 var typeofForm = ''; 7254 formsInsuranceContactController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'AddressSuggestService', 'UserPreferencesService', 'vcRecaptchaService', 'FormsService', 'API']; 7255 return { 7256 scope: true, 7257 restrict: 'A', 7258 controller: formsInsuranceContactController, 7259 controllerAs: 'ffc', 7260 bindToController: true, 7261 link: function (scope, element, attrs, filter, http) { 7262 scope.successContent = element.find('.lx-form-success'); 7263 scope.failureContent = element.find('.lx-form-failure'); 7264 typeofForm = attrs.lxFormsType; 7265 } 7266 }; 7267 7268 function formsInsuranceContactController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, AddressSuggestService, UserPreferencesService, vcRecaptchaService, FormsService, API) { 7269 var fcu = this; 7270 7271 $scope.init = function () { 7272 UserPreferencesService.getLexusVisitorSession().then(function (data) { 7273 7274 var visitorPreference = UserPreferencesService.getLexusVisitor(); 7275 $scope.ffc.form = { 7276 submitting: false, 7277 completed: false, 7278 errors: false, 7279 data: { 7280 subscribe: false, 7281 postcodes: [], 7282 postcode: "", 7283 email: data.Data.email, 7284 phonetype: data.Data.phoneType && data.Data.phoneType != '' ? data.Data.phoneType : 'home', 7285 firstname: data.Data.name, 7286 lastname: data.Data.surname, 7287 phone: data.Data.phone, 7288 prefer: data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 7289 captcha: '', 7290 requesttype: null 7291 } 7292 }; 7293 7294 7295 7296 var visitorPreference = UserPreferencesService.getLexusVisitor(); 7297 if (visitorPreference && visitorPreference.postCode && visitorPreference.suburb) { 7298 $scope.ffc.form.data.postcodes.push({ text: visitorPreference.suburb + " " + visitorPreference.postCode }); 7299 } 7300 7301 }, function (reason) { 7302 }); 7303 } 7304 7305 $scope.getData = function () { 7306 var visitor = UserPreferencesService.splitAutoCompleteResult($scope.ffc.form.data.postcodes[0].text); 7307 return { 7308 Message: $scope.ffc.form.data.message, 7309 FirstName: $scope.ffc.form.data.firstname, 7310 LastName: $scope.ffc.form.data.lastname, 7311 Email: $scope.ffc.form.data.email,
7312 PostCode: visitor.postCode, 7313 Phone: $scope.ffc.form.data.phone, 7314 PhoneType: $scope.ffc.form.data.phonetype, 7315 PreferredContactMethod: $scope.ffc.form.data.prefer, 7316 Subscribe: $scope.ffc.form.data.subscribe.toString(), 7317 Captcha: $scope.ffc.form.data.captcha, 7318 RequestType: $scope.ffc.form.data.requesttype, 7319 }; 7320 } 7321 7322 7323 7324 $rootScope.$on('submit-insurance-form', function () { 7325 7326 $rootScope.$broadcast('visitor-details-cookie-change-autocomplete', $scope.ffc.form.data.postcodes[0].text); 7327 7328 $scope.ffc.form.submitting = true; 7329 7330 7331 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 7332 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.InsuranceContact, [Lexus.ID.Site]), data: $scope.getData() }). 7333 then(function success(response) { 7334 if (response.data.Status == "Success") { 7335 $scope.submissionPass(response.data); 7336 } 7337 else { 7338 $scope.submissionFail(response.data); 7339 } 7340 }, function error(response) { 7341 $scope.submissionFail(response.data); 7342 }) 7343 .finally(function () { 7344 $rootScope.$broadcast('form-result'); 7345 }); 7346 }); 7347 7348 $scope.submissionPass = function (data) { 7349 // this callback will be called asynchronously 7350 // when the response is available 7351 $scope.ffc.form.completed = true; 7352 $scope.ffc.form.failed = false; 7353 $scope.ffc.form.submitting = false; 7354 var historyState = "InsuranceForm=Pass"; 7355 $location.state(historyState); 7356 FormsService.ShowResult($scope.successContent[0]); 7357 $rootScope.$broadcast('gtm-form-success', 'Insurance Contact'); 7358 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 7359 }; 7360 $scope.submissionFail = function (data) { 7361 // called asynchronously if an error occurs 7362 // or server returns response with an error status. 7363 $scope.ffc.form.failed = true; 7364 $scope.ffc.form.errors = data.Data; 7365 $scope.ffc.form.submitting = false; 7366 $scope.ffc.form.completed = true; 7367 var historyState = "InsuranceForm=Fail"; 7368 $location.state(historyState); 7369 FormsService.ShowResult($scope.failureContent[0]); 7370 console.error(data.ErrorMessage); 7371 }; 7372 7373 $scope.updatePostcode = function ($tag) { 7374 $scope.ffc.form.data.postcodes = []; 7375 $scope.ffc.form.data.postcodes[0] = $tag; 7376 }; 7377 7378 7379 7380 } 7381}]); 7382; 7383"use strict"; 7384/* Directives */ 7385angular.module('Lexus.Directives') 7386.directive('lxFormsRegisterInterest', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 7387 var formModel = ''; 7388 var formDealerId = ''; 7389 formsRegisterInterestController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'AddressSuggestService', 'UserPreferencesService', 'vcRecaptchaService', 'FormsService', 'EloquaService']; 7390 return { 7391 scope: true, 7392 restrict: 'A', 7393 controller: formsRegisterInterestController, 7394 controllerAs: 'ffc', 7395 bindToController: true, 7396 link: function (scope, element, attrs, filter, http) { 7397 scope.successContent = element.find('.lx-form-success'); 7398 scope.failureContent = element.find('.lx-form-failure'); 7399 formModel = attrs.lxFormsRegister; 7400 formDealerId = attrs.lxFormsDealerId; 7401 } 7402 }; 7403 7404 function formsRegisterInterestController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, AddressSuggestService, UserPreferencesService, vcRecaptchaService, FormsService, EloquaService) { 7405 var ffc = this; 7406 7407 $scope.init = function () { 7408 UserPreferencesService.getLexusVisitorSession().then(function (data) { 7409 data.Data = data.Data || {}; 7410 var visitorPreference = UserPreferencesService.getLexusVisitor(); 7411 $scope.ffc.form = { 7412 submitting: false, 7413 completed: false, 7414 errors: false, 7415 data: { 7416 subscribe: false, 7417 email: data.Data.email, 7418 firstname: data.Data.name, 7419 lastname: data.Data.surname, 7420 phone: data.Data.phone, 7421 daterange: '', 7422 model: formModel, 7423 vehicle: '', 7424 dealerId: formDealerId, 7425 captcha: '', 7426 purchasedelay: null, 7427 currentmake: null 7428 } 7429 }; 7430 7431 }, function (reason) { 7432 }); 7433 } 7434 7435 7436 $scope.getData = function () { 7437 var t= { 7438 Model: $scope.ffc.form.data.model, 7439 FirstName: $scope.ffc.form.data.firstname, 7440 LastName: $scope.ffc.form.data.lastname, 7441 Email: $scope.ffc.form.data.email, 7442 PlanToPurchase: $scope.ffc.form.data.purchasedelay, 7443 Phone: $scope.ffc.form.data.phone, 7444 VehicleTypeOwned: $scope.ffc.form.data.currentmake, 7445 Subscribe: $scope.ffc.form.data.subscribe.toString(), 7446 Captcha: $scope.ffc.form.data.captcha, 7447 DealerId: $scope.ffc.form.data.dealerId, 7448 //Leave alone this its to clear validation on the base type! 7449 //Its on the base type as we remember the value in session 7450 PhoneType: 'Not Specified' 7451 }; 7452 return t; 7453 } 7454 7455 7456 $rootScope.$on('submit-register-interest-form', function () { 7457 7458 $scope.ffc.form.submitting = true; 7459 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 7460 var formData = $scope.getData(); 7461 EloquaService.attachEloquaFields(formData); 7462 7463 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.FutureVehicleInterest, [Lexus.ID.Site]), data: formData }). 7464 then(function success(response) { 7465 if (response.data.Status == "Success") { 7466 $scope.submissionPass(response.data); 7467 } 7468 else { 7469 $scope.submissionFail(response.data); 7470 } 7471 }, function error(response) { 7472 $scope.submissionFail(response.data); 7473 }) 7474 .finally(function () { 7475 $rootScope.$broadcast('form-result'); 7476 }); 7477 }); 7478 7479
7480 $scope.submissionPass = function (data) { 7481 // this callback will be called asynchronously 7482 // when the response is available 7483 $scope.ffc.form.completed = true; 7484 $scope.ffc.form.failed = false; 7485 $scope.ffc.form.submitting = false; 7486 var historyState = "RegisterInterestForm=Pass"; 7487 $location.state(historyState); 7488 FormsService.ShowResult($scope.successContent[0]); 7489 $rootScope.$broadcast('gtm-form-success', 'Register Interest Form'); 7490 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 7491 }; 7492 $scope.submissionFail = function (data) { 7493 // called asynchronously if an error occurs 7494 // or server returns response with an error status. 7495 $scope.ffc.form.failed = true; 7496 $scope.ffc.form.errors = data.Data; 7497 $scope.ffc.form.submitting = false; 7498 $scope.ffc.form.completed = true; 7499 var historyState = "RegisterInterestForm=Fail"; 7500 $location.state(historyState); 7501 FormsService.ShowResult($scope.failureContent[0]); 7502 if (data.ErrorMessage) 7503 console.error(data.ErrorMessage); 7504 }; 7505 7506 } 7507}]); 7508; 7509(function () { 7510 7511 "use strict"; 7512 /* Directives */ 7513 angular.module('Lexus.Directives') 7514 .directive('lxFormsRequestBrochure', FormsRequestBrochureDirective); 7515 7516 FormsRequestBrochureDirective.$inject = [ 7517 "$filter", "$timeout", "$http", "$location", "API", "$rootScope", 7518 "UserPreferencesService", "FormsService", "EloquaService", 7519 "DealersService", "AddressSuggestService"]; 7520 7521 function FormsRequestBrochureDirective($filter, $timeout, $http, $location, API, $rootScope, 7522 userPreferencesService, formsService, eloquaService, 7523 dealersService, addressSuggestService) { 7524 7525 var brochureData; 7526 FormsRequestBrochureController.$inject = ['$scope']; 7527 return { 7528 scope: true, 7529 restrict: 'A', 7530 controller: FormsRequestBrochureController, 7531 controllerAs: 'ffc', 7532 bindToController: true, 7533 link: function (scope, element, attrs, filter, http) { 7534 scope.successContent = element.find('.lx-form-success'); 7535 scope.failureContent = element.find('.lx-form-failure'); 7536 7537 brochureData = JSON.parse(attrs.brochureData); 7538 } 7539 }; 7540 7541 function FormsRequestBrochureController($scope) { 7542 7543 function initialize() { 7544 7545 var urlParameters = $location.search(); 7546 7547 userPreferencesService.getLexusVisitorSession().then(function success(data) { 7548 var dataVehicle = userPreferencesService.getLexusVehicle(urlParameters); 7549 var dataDealer = userPreferencesService.getLexusDealer(urlParameters); 7550 var dataUser = userPreferencesService.getLexusVisitor(urlParameters); 7551 7552 $scope.ffc.form = { 7553 submitting: false, 7554 completed: false, 7555 errors: false, 7556 brochureUrl: null, 7557 disableAddressValidation: true, //address fields hidden by default, so validation is disabled by default 7558 dealerTagsLoading: false, 7559 data: { 7560 carmodel: dataVehicle.model, 7561 brochureType: 'digital-brochure', 7562 firstname: data.Data.name, 7563 lastname: data.Data.surname, 7564 address: data.Data.address, 7565 postcodes: [], 7566 dealerpostcodes: [], 7567 postcode: dataUser.postCode, 7568 pricingZone: dataUser.pricingZone, 7569 suburb: dataUser.suburb, 7570 state: dataUser.state, 7571 email: data.Data.email, 7572 phone: data.Data.phone, 7573 purchasedelay: null, 7574 currentmake: null, 7575 subscribe: false, 7576 captcha: '', 7577 dealerId: dataDealer.dealerID, 7578 dealerName: dataDealer.dealerName 7579 } 7580 }; 7581 if (dataUser.suburb && dataUser.postCode) { 7582 $scope.ffc.form.data.dealerpostcodes.push({ text: dataUser.suburb + " " + dataUser.postCode }); 7583 $scope.ffc.form.data.postcodes.push({ text: dataUser.suburb + " " + dataUser.postCode }); 7584 } 7585 }, function failure(data) { 7586 $scope.ffc.form = { 7587 submitting: false, 7588 completed: false, 7589 errors: false, 7590 brochureUrl: null, 7591 disableAddressValidation: true, 7592 data: { 7593 carmodel: null, 7594 brochureType: 'digital-brochure', 7595 firstname: null, 7596 lastname: null, 7597 address: null, 7598 postcodes: [], 7599 postcode: null, 7600 suburb: null, 7601 state: null, 7602 email: null, 7603 phone: null, 7604 purchasedelay: null, 7605 currentmake: null, 7606 subscribe: false, 7607 captcha: '' 7608 } 7609 }; 7610 }).finally(function () { 7611 //Main Site 7612 if ($scope.ffc.form.data.dealerpostcodes && $scope.ffc.form.data.dealerpostcodes.length > 0) { 7613 searchNow(); 7614 } 7615 7616 //Dealer Site Multi Branch 7617 if (brochureData.isDealerSite && brochureData.isMultiBranchDealership) { 7618 $scope.ffc.form.data.dealerId = null; 7619 $scope.ffc.form.data.dealerName = null; 7620 loadBranches(brochureData.forceDealerId); 7621 } 7622 7623 //Dealer Site NOT Multi Branch 7624 if (brochureData.isDealerSite && !brochureData.isMultiBranchDealership) { 7625 $scope.ffc.form.data.dealerId = brochureData.dealerCompositeID;
7626 $scope.ffc.form.data.dealerName = null; 7627 } 7628 7629 if ($scope.ffc.form.data.carmodel) { 7630 $rootScope.$broadcast('field-car-model-update-selected'); 7631 } 7632 }); 7633 7634 $scope.updateBrochureType(); 7635 7636 } 7637 7638 function loadBranches(dealerID) { 7639 $scope.ffc.form.dealersLoading = true; 7640 dealersService.setParam('dealerID', dealerID); 7641 dealersService.setParam('type', 'Sales'); 7642 dealersService.GetDealerBranches(); 7643 } 7644 7645 $scope.$on('dealer-search-results-received', function (event, data) { 7646 $scope.ffc.form.dealersLoading = false; 7647 $scope.ffc.form.dealers = data.Data; 7648 7649 var result = findDealer($scope.ffc.form.data.dealerId); 7650 7651 if (!result) { 7652 $scope.ffc.form.data.dealerId = null; 7653 } 7654 7655 if ($scope.ffc.form.dealers.length == 1) 7656 $scope.ffc.form.data.dealerId = $scope.ffc.form.dealers[0].dealerCode; 7657 }); 7658 7659 function findDealer(dealerCode) { 7660 return $scope.ffc.form.dealers.find(function (dealer) { 7661 return dealer.dealerCode == dealerCode; 7662 }); 7663 } 7664 7665 $scope.deselectDealer = function () { 7666 $scope.ffc.form.data.dealerId = $scope.ffc.form.data.dealerName = null; 7667 } 7668 7669 $scope.selectDealer = function (dealerInputId) { 7670 var scrollPos = $(document).scrollTop(); 7671 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 7672 if (scrollPos > maxPos) { 7673 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 7674 } 7675 } 7676 7677 $scope.dealerSearch = function ($tag) { 7678 $scope.ffc.form.dealersLoading = true; 7679 7680 //Main Site 7681 if ($scope.ffc.form.data.dealerpostcodes && $scope.ffc.form.data.dealerpostcodes.length > 0 && !$scope.isDealerSite) { 7682 searchNow(); 7683 } 7684 7685 //Dealer Site Multi Branch 7686 if (brochureData.isDealerSite && brochureData.isMultiBranchDealership) { 7687 $scope.ffc.form.data.dealerId = null; 7688 $scope.ffc.form.data.dealerName = null; 7689 loadBranches(brochureData.forceDealerId); 7690 } 7691 7692 //Dealer Site NOT Multi Branch 7693 if (brochureData.isDealerSite && !brochureData.isMultiBranchDealership && brochureData.dealerState) { 7694 dealersService.setParam('dealerID', brochureData.forceDealerId); 7695 dealersService.setParam('dealerState', brochureData.dealerState); 7696 dealersService.setParam('type', 'Sales'); 7697 dealersService.GetResult(); 7698 } 7699 } 7700 7701 $scope.$on('dealer-search-result-received', function (event, data) { 7702 $scope.ffc.form.dealersLoading = false; 7703 $scope.ffc.form.dealer = data.Data; 7704 $scope.ffc.form.dealerlocations = data.Data.locations; 7705 7706 if ($scope.ffc.form.dealerlocations == null) { 7707 $scope.ffc.form.dealerlocations = []; 7708 } 7709 //Multiple dealers for same dealerId - A bug to be corrected latter -wont require looping in that case on parent 7710 if (data.Data) { 7711 angular.forEach(data.Data, function (val) { 7712 //console.log(val.locations); 7713 if (val) { 7714 angular.forEach(val.locations, function (innerval) { 7715 console.log(innerval); 7716 this.push(innerval); 7717 }, $scope.ffc.form.dealerlocations); 7718 } 7719 }); 7720 } 7721 7722 if ($scope.ffc.form.dealerlocations.length == 1) 7723 $scope.ffc.form.data.locationId = $scope.ffc.form.dealerlocations[0].locationId; 7724 }); 7725 7726 $scope.updateBrochureType = function () { 7727 if ($scope.ffc && $scope.ffc.form && $scope.ffc.form.data && $scope.ffc.form.data.brochureType) { 7728 $scope.ffc.form.disableAddressValidation = ($scope.ffc.form.data.brochureType == "digital-brochure"); 7729 } 7730 } 7731 7732 $scope.minTags = function () { 7733 if ($scope.ffc && $scope.ffc.form && $scope.ffc.form.disableAddressValidation) { 7734 return $scope.ffc.form.disableAddressValidation ? '0' : '1'; 7735 } 7736 return '1'; 7737 } 7738 7739 $scope.clearDealerPostcode = function () { 7740 $scope.ffc.form.data.dealerpostcodes = null; 7741 } 7742 7743 $scope.clearPostcode = function () { 7744 $scope.ffc.form.data.postcodes = null; 7745 } 7746 7747 $scope.updateDealerPostcode = function ($tag) { 7748 $scope.ffc.form.data.dealerpostcodes = []; 7749 $scope.ffc.form.data.dealerpostcodes[0] = $tag; 7750 7751 $scope.dealerSearch($tag); 7752 7753 if (!$scope.ffc.form.data.postcode) { 7754 $scope.ffc.form.data.postcodes = []; 7755 $scope.ffc.form.data.postcodes.push({ text: $tag.data.suburb + " " + $tag.data.postcode }); 7756 $scope.ffc.form.data.postcode = $tag.data.postcode; 7757 $scope.ffc.form.data.suburb = $tag.data.suburb; 7758 $scope.ffc.form.data.state = $tag.data.state; 7759 $scope.ffc.form.data.pricingZone = $tag.data.pricingZone; 7760 7761 $rootScope.$broadcast('visitor-details-cookie-change', { 7762 postCode: $tag.data.postcode, 7763 suburb: $tag.data.suburb, 7764 state: $tag.data.state, 7765 pricingZone: $tag.data.pricingZone 7766 }); 7767 } 7768 } 7769 7770 $scope.updatePostcode = function ($tag) { 7771 $scope.ffc.form.data.postcodes = []; 7772 $scope.ffc.form.data.postcodes[0] = $tag; 7773 7774 $scope.ffc.form.data.postcode = $tag.data.postcode; 7775 $scope.ffc.form.data.suburb = $tag.data.suburb; 7776 $scope.ffc.form.data.state = $tag.data.state; 7777 $scope.ffc.form.data.pricingZone = $tag.data.pricingZone; 7778 7779 $rootScope.$broadcast('visitor-details-cookie-change', { 7780 postCode: $tag.data.postcode, 7781 suburb: $tag.data.suburb, 7782 state: $tag.data.state, 7783 pricingZone: $tag.data.pricingZone 7784 }); 7785 } 7786 7787 function searchNow() { 7788 $scope.ffc.form.dealersLoading = true; 7789 7790 var visitor = userPreferencesService.splitAutoCompleteResult($scope.ffc.form.data.dealerpostcodes[0].text); 7791 7792 dealersService.setParam('postCode', visitor.postCode); 7793 dealersService.setParam('suburb', visitor.suburb); 7794 dealersService.setParam('type', 'Sales'); 7795 7796 dealersService.GetResults(); 7797 } 7798 7799 function getFormData() { 7800 7801 var result = { 7802 Model: $scope.ffc.form.data.carmodel, 7803 DealerId: $scope.ffc.form.data.dealerId, 7804 ContextDealerSiteId: brochureData.forceDealerId, 7805 FirstName: $scope.ffc.form.data.firstname, 7806 LastName: $scope.ffc.form.data.lastname, 7807 BrochureType: $scope.ffc.form.data.brochureType, 7808 Address: $scope.ffc.form.data.address, 7809 Postcode: $scope.ffc.form.data.postcode, 7810 State: $scope.ffc.form.data.state, 7811 Suburb: $scope.ffc.form.data.suburb, 7812 Email: $scope.ffc.form.data.email, 7813 Phone: $scope.ffc.form.data.phone, 7814 PlanToPurchase: $scope.ffc.form.data.purchasedelay, 7815 VehicleTypeOwned: $scope.ffc.form.data.currentmake, 7816 Captcha: $scope.ffc.form.data.captcha, 7817 Subscribe: $scope.ffc.form.data.subscribe 7818 } 7819 return result; 7820 }; 7821 7822 $rootScope.$on('vehicle-preference-change', function (event, data) { 7823 $scope.ffc.form.data.carmodel = data.model; 7824 }); 7825 7826 $rootScope.$on('submit-request-brochure-form', function (event, data) { 7827 var formData = getFormData(); 7828 7829 eloquaService.attachEloquaFields(formData); 7830 7831 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.RequestBrochure, [Lexus.ID.Site]), data: formData }) 7832 .then(function success(response) { 7833 if (response.data.Status == "Success") { 7834 submissionPass(response.data); 7835 $rootScope.$broadcast('gtm-form-success', 'Request Brochure'); 7836 } 7837 else { 7838 submissionFail(response.data); 7839 } 7840 }, function error(response) { 7841 submissionFail(response.data); 7842 }) 7843 .finally(function () { 7844 $rootScope.$broadcast('form-result'); 7845 }); 7846 }); 7847 7848 7849 function submissionPass(data) { 7850 // this callback will be called asynchronously 7851 // when the response is available 7852 $scope.ffc.form.brochureUrl = data.Data.BrochureUrl; 7853 $scope.ffc.form.completed = true; 7854 $scope.ffc.form.failed = false; 7855 $scope.ffc.form.submitting = false; 7856 var historyState = "RequestBrochureForm=Pass"; 7857 $location.state(historyState); 7858 formsService.ShowResult($scope.successContent[0]); 7859 $rootScope.$broadcast('visitor-details-session-change', getFormData()); 7860 }; 7861 7862 function submissionFail(data) { 7863 // called asynchronously if an error occurs 7864 // or server returns response with an error status. 7865 $scope.ffc.form.failed = true; 7866 $scope.ffc.form.errors = data.Data; 7867 $scope.ffc.form.submitting = false; 7868 $scope.ffc.form.completed = true; 7869 var historyState = "RequestBrochureForm=Fail"; 7870 $location.state(historyState); 7871 formsService.ShowResult($scope.failureContent[0]); 7872 console.error(data.ErrorMessage); 7873 }; 7874 7875 $scope.loadDealerTags = function (query) { 7876 $scope.ffc.form.dealerTagsLoading = true; 7877 addressSuggestService.setParam('term', query); 7878 7879 var results = addressSuggestService.GetResults(function () { 7880 $scope.ffc.form.dealerTagsLoading = false; 7881 }); 7882 7883 return results; 7884 }; 7885 7886 initialize(); 7887 } 7888 } 7889 7890}()); 7891 7892; 7893"use strict"; 7894/* Directives */ 7895angular.module('Lexus.Directives')
7896.directive('lxFormsSubscribeNewsLetter', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 7897 var formDealerId = ''; 7898 formsSubscribeNewsLetterController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'AddressSuggestService', 'UserPreferencesService', 'vcRecaptchaService', 'FormsService']; 7899 return { 7900 scope: true, 7901 restrict: 'A', 7902 controller: formsSubscribeNewsLetterController, 7903 controllerAs: 'ffc', 7904 bindToController: true, 7905 link: function (scope, element, attrs, filter, http) { 7906 scope.successContent = element.find('.lx-form-success'); 7907 scope.failureContent = element.find('.lx-form-failure'); 7908 } 7909 }; 7910 7911 function formsSubscribeNewsLetterController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, AddressSuggestService, UserPreferencesService, vcRecaptchaService, FormsService) { 7912 var ffc = this; 7913 7914 $scope.init = function () { 7915 7916 UserPreferencesService.getLexusVisitorSession().then(function (data) { 7917 7918 var dataUser = UserPreferencesService.getLexusVisitor(); 7919 $scope.ffc.form = { 7920 submitting: false, 7921 completed: false, 7922 errors: false, 7923 data: { 7924 subscribe: false, 7925 email: data.Data.email, 7926 firstname: data.Data.name, 7927 lastname: data.Data.surname, 7928 phone: data.Data.phone, 7929 captcha: '' 7930 } 7931 }; 7932 7933 7934 }, function failure(data) { 7935 $scope.ffc.form = { 7936 submitting: false, 7937 completed: false, 7938 errors: false, 7939 data: { 7940 subscribe: false, 7941 email: null, 7942 firstname: null, 7943 lastname: null, 7944 phone: null, 7945 captcha: '' 7946 } 7947 }; 7948 }).finally(function () { 7949 7950 }); 7951 } 7952 7953 7954 $scope.getData = function () { 7955 var t= { 7956 FirstName: $scope.ffc.form.data.firstname, 7957 LastName: $scope.ffc.form.data.lastname, 7958 Email: $scope.ffc.form.data.email, 7959 Phone: $scope.ffc.form.data.phone, 7960 Subscribe: $scope.ffc.form.data.subscribe.toString(), 7961 Captcha: $scope.ffc.form.data.captcha, 7962 //Leave alone this its to clear validation on the base type! 7963 //Its on the base type as we remember the value in session 7964 PhoneType: 'Not Specified' 7965 }; 7966 return t; 7967 } 7968 7969 7970 $rootScope.$on('submit-subscribe-newsletter-form', function () { 7971 $scope.ffc.form.submitting = true; 7972 7973 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.SubscribeNewsletterUrl, [Lexus.ID.Site]), data: $scope.getData() }). 7974 then(function success(response) { 7975 if (response.data.Status == "Success") { 7976 $scope.submissionPass(response.data); 7977 } 7978 else { 7979 $scope.submissionFail(response.data); 7980 } 7981 }, function error(response) { 7982 $scope.submissionFail(response.data); 7983 }) 7984 .finally(function () { 7985 $rootScope.$broadcast('form-result'); 7986 }); 7987 }); 7988 7989 $scope.submissionPass = function (data) { 7990 // this callback will be called asynchronously 7991 // when the response is available 7992 $scope.ffc.form.completed = true; 7993 $scope.ffc.form.failed = false; 7994 $scope.ffc.form.submitting = false; 7995 var historyState = "SubscribeNewsLetterForm=Pass"; 7996 $location.state(historyState); 7997 FormsService.ShowResult($scope.successContent[0]); 7998 $rootScope.$broadcast('gtm-form-success', 'Subscribe Newsletter Form'); 7999 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 8000 }; 8001 8002 $scope.submissionFail = function (data) { 8003 // called asynchronously if an error occurs 8004 // or server returns response with an error status. 8005 $scope.ffc.form.failed = true; 8006 $scope.ffc.form.errors = data.Data; 8007 $scope.ffc.form.submitting = false; 8008 $scope.ffc.form.completed = true; 8009 var historyState = "SubscribeNewsLetterForm=Fail"; 8010 $location.state(historyState); 8011 FormsService.ShowResult($scope.failureContent[0]); 8012 console.error(data.ErrorMessage); 8013 }; 8014 8015 } 8016}]); 8017; 8018(function () { 8019 "use strict"; 8020 8021 /* Directives */ 8022 angular.module('Lexus.Directives') 8023 .directive("lxFormsTestDriveConcierge", TestDriveConciergeDirective); 8024 8025 TestDriveConciergeDirective.$inject = [ 8026 "$filter", "$http", "$location", "API", "$rootScope", "DealersService", 8027 "AddressSuggestService", "UserPreferencesService", "FormsService", "EloquaService"]; 8028 8029 function TestDriveConciergeDirective($filter, $http, $location, API, $rootScope, DealersService, 8030 AddressSuggestService, UserPreferencesService, FormsService, EloquaService) { 8031 FormsTestDriveConciergeController.$inject = ['$scope']; 8032 return { 8033 scope: true, 8034 restrict: 'A', 8035 controller: FormsTestDriveConciergeController, 8036 controllerAs: 'ffc', 8037 bindToController: true, 8038 link: function (scope, element, attrs, filter, http) { 8039 scope.successContent = element.find('.lx-form-success'); 8040 scope.failureContent = element.find('.lx-form-failure'); 8041 } 8042 }; 8043 8044 function FormsTestDriveConciergeController($scope) { 8045 var ftd = this; 8046 $scope.ffc.urlParameters = $location.search(); 8047 8048 $scope.init = function (forceDealerId, dealerCompositeID, isDealerSite, isMultiBranchDealer) { 8049 UserPreferencesService.getLexusVisitorSession().then(function success(data) { 8050 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); 8051 var dataDealer = UserPreferencesService.getLexusDealer($scope.ffc.urlParameters); 8052 var dataUser = UserPreferencesService.getLexusVisitor($scope.ffc.urlParameters); 8053 $scope.ffc.form = { 8054 submitting: false, 8055 completed: false, 8056 errors: false, 8057 dealers: [], 8058 data: { 8059 postcodes: [], 8060 carmodel: dataVehicle.model, 8061 grade: dataVehicle.grade, 8062 enginevariant: dataVehicle.engineVariant, 8063 contextDealerSiteId: forceDealerId, 8064 subscribe: false, 8065 postcode: "", 8066 email: data.Data.email, 8067 phonetype: data.Data.phoneType ? data.Data.phoneType : 'home', 8068 firstname: data.Data.name, 8069 lastname: data.Data.surname, 8070 phone: data.Data.phone, 8071 prefer: data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 8072 captcha: '', 8073 dealerId: dataDealer.dealerID, 8074 dealerName: dataDealer.dealerName, 8075 preferredlocation: 'home', 8076 purchasedelay: null, 8077 currentmake: null 8078 } 8079 }; 8080 if (dataUser.suburb && dataUser.postCode) { 8081 $scope.ffc.form.data.postcodes.push( 8082 { 8083 text: dataUser.suburb + " " + dataUser.postCode, 8084 data: { 8085 postCode: dataUser.postCode, 8086 suburb: dataUser.suburb 8087 } 8088 }); 8089 } 8090 }, function failure(data) { 8091 $scope.ffc.form = { 8092 submitting: false, 8093 completed: false, 8094 errors: false, 8095 dealers: [], 8096 data: { 8097 postcodes: [], 8098 carmodel: null, 8099 grade: null, 8100 subscribe: false, 8101 postcode: "", 8102 email: null, 8103 phonetype: 'home', 8104 firstname: null, 8105 lastname: null, 8106 phone: null, 8107 prefer: 'email', 8108 captcha: '', 8109 dealerId: null, 8110 dealerName: null, 8111 preferredlocation: 'home', 8112 purchasedelay: null, 8113 currentmake: null 8114 } 8115 }; 8116 }).finally(function () { 8117 if ($scope.ffc.form.data.carmodel) { 8118 $rootScope.$broadcast('field-car-model-engine-variant-update-selected'); 8119 } 8120 8121 //Main Site 8122 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !isDealerSite) { 8123 $scope.searchNow(); 8124 } 8125 8126 //Dealer Site Multi Branch 8127 if (isDealerSite && isMultiBranchDealer) { 8128 $scope.ffc.form.data.dealerId = null; 8129 $scope.ffc.form.data.dealerName = null; 8130 $scope.loadBranches(forceDealerId); 8131 } 8132 8133 //Dealer Site NOT Multi Branch 8134 if (isDealerSite && !isMultiBranchDealer) { 8135 $scope.ffc.form.data.dealerId = dealerCompositeID;
8136 $scope.ffc.form.data.dealerName = null; 8137 } 8138 8139 }); 8140 8141 8142 } 8143 8144 8145 //$scope.loadTags = function (query) { 8146 // AddressSuggestService.setParam('term', query); 8147 // return AddressSuggestService.GetResults(); 8148 //}; 8149 8150 $scope.deselectDealer = function () { 8151 $scope.ffc.form.data.dealerName = null; 8152 } 8153 8154 $scope.selectDealer = function (dealerInputId) { 8155 var scrollPos = $(document).scrollTop(); 8156 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 8157 if (scrollPos > maxPos) { 8158 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 8159 } 8160 try { 8161 var code = dealerInputId.replace('option-', ''); 8162 $scope.ffc.form.data.dealerName = $scope.ffc.form.dealers.find(function (dealer) { return dealer.dealerCode == code; }).dealerName; 8163 } catch (ex) { 8164 (console.error || console.log)(ex); 8165 } 8166 } 8167 8168 $scope.loadBranches = function (dealerID) { 8169 DealersService.setParam('dealerID', dealerID); 8170 DealersService.setParam('type', 'Sales'); 8171 DealersService.GetDealerBranches(); 8172 } 8173 8174 $scope.dealerSearch = function ($tag) { 8175 $scope.ffc.form.data.postcodes = []; 8176 $scope.ffc.form.data.postcodes[0] = $tag; 8177 $scope.searchNow(); 8178 } 8179 8180 $scope.searchNow = function () { 8181 $scope.ffc.form.dealersLoading = true; 8182 $rootScope.$broadcast('visitor-details-change-autocomplete', $scope.ffc.form.data.postcodes[0].data); 8183 DealersService.setParam('postCode', $scope.ffc.form.data.postcodes[0].data.postCode); //Dummy Implementation needs to be changed 8184 DealersService.setParam('suburb', $scope.ffc.form.data.postcodes[0].data.suburb); //Dummy Implementation needs to be changed 8185 DealersService.setParam('type', 'Sales'); 8186 DealersService.GetResults(); 8187 8188 } 8189 8190 $rootScope.$on('vehicle-preference-change', function (event, data) { 8191 $scope.ffc.form.data.carmodel = data.model; 8192 $scope.ffc.form.data.enginevariant = data.engineVariant; 8193 }); 8194 8195 $scope.$on('dealer-search-results-received', function (event, data) { 8196 $scope.ffc.form.dealersLoading = false; 8197 $scope.ffc.form.dealers = data.Data; 8198 $scope.checkDealersLoaded(); 8199 }); 8200 8201 //Do a sanity check to see if the bound dealers match the forceDealer if not clear the force dealer 8202 $scope.checkDealersLoaded = function () { 8203 var result = $scope.ffc.form.dealers.find(function (dealer) { 8204 return dealer.dealerCode == $scope.ffc.form.data.dealerId; 8205 }); 8206 if (!result) { 8207 $scope.ffc.form.data.dealerId = null; 8208 } 8209 8210 if ($scope.ffc.form.dealers.length == 1) 8211 $scope.ffc.form.data.dealerId = $scope.ffc.form.dealers[0].dealerCode; 8212 } 8213 8214 8215 $scope.getData = function () { 8216 var utmParameters = UserPreferencesService.getUtmParameters(); 8217 var postcode = null; 8218 if ($scope.ffc.form.data.postcodes.length > 0 && $scope.ffc.form.data.postcodes[0].text) { 8219 postcode = parseInt($scope.ffc.form.data.postcodes[0].text.split(' ').reverse()[0]); 8220 } 8221 return { 8222 FirstName: $scope.ffc.form.data.firstname, 8223 LastName: $scope.ffc.form.data.lastname, 8224 Email: $scope.ffc.form.data.email, 8225 Phone: $scope.ffc.form.data.phone, 8226 PreferredContactMethod: $scope.ffc.form.data.prefer, 8227 Model: $scope.ffc.form.data.carmodel, 8228 Grade: $scope.ffc.form.data.grade, 8229 EngineVariant: $scope.ffc.form.data.enginevariant, 8230 ContextDealerSiteId: $scope.ffc.form.data.contextDealerSiteId, 8231 DealerId: $scope.ffc.form.data.dealerId, 8232 Subscribe: $scope.ffc.form.data.subscribe.toString(), 8233 Captcha: $scope.ffc.form.data.captcha, 8234 PreferredLocation: $scope.ffc.form.data.preferredlocation, 8235 PlanToPurchase: $scope.ffc.form.data.purchasedelay, 8236 VehicleTypeOwned: $scope.ffc.form.data.currentmake, 8237 //Leave alone this its to clear validation on the base type! 8238 //Its on the base type as we remember the value in session 8239 PhoneType: 'Not Specified', 8240 UtmSource: utmParameters.source, 8241 UtmMedium: utmParameters.medium, 8242 UtmCampaign: utmParameters.campaign, 8243 UtmContent: utmParameters.content, 8244 Postcode: postcode, 8245 DealerName: $scope.ffc.form.data.dealerName 8246 }; 8247 } 8248 8249 $rootScope.$on('submit-test-drive-concierage-form', function () { 8250 var formData = $scope.getData(); 8251 8252 EloquaService.attachEloquaFields(formData); 8253 8254 $scope.ffc.form.submitting = true; 8255 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 8256 $http({ 8257 method: 'POST', 8258 url: $filter('formatArgs')(Lexus.API.FormSubmission.TestDriveConcierge, [Lexus.ID.Site]), 8259 data: formData 8260 }) 8261 .then(function success(response) { 8262 if (response.data.Status == "Success") { 8263 $scope.submissionPass(response.data); 8264 } 8265 else { 8266 $scope.submissionFail(response.data); 8267 } 8268 }, function error(response) { 8269 $scope.submissionFail(response.data); 8270 }) 8271 .finally(function () { 8272 $rootScope.$broadcast('form-result'); 8273 }); 8274 }); 8275
8276 $scope.submissionPass = function (data) { 8277 // this callback will be called asynchronously 8278 // when the response is available 8279 $scope.ffc.form.completed = true; 8280 $scope.ffc.form.failed = false; 8281 $scope.ffc.form.submitting = false; 8282 var historyState = "ConcierageTestDriveForm=Pass"; 8283 $location.state(historyState); 8284 FormsService.ShowResult($scope.successContent[0]); 8285 $rootScope.$broadcast('gtm-form-success', 'Test Drive Concierge'); 8286 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 8287 }; 8288 $scope.submissionFail = function (data) { 8289 // called asynchronously if an error occurs 8290 // or server returns response with an error status. 8291 $scope.ffc.form.failed = true; 8292 $scope.ffc.form.errors = data.Data; 8293 $scope.ffc.form.submitting = false; 8294 $scope.ffc.form.completed = true; 8295 var historyState = "ConcierageTestDriveForm=Fail"; 8296 $location.state(historyState); 8297 FormsService.ShowResult($scope.failureContent[0]); 8298 console.error(data.ErrorMessage); 8299 }; 8300 } 8301 } 8302 8303 8304}()); 8305 8306; 8307(function () { 8308 8309 "use strict"; 8310 8311 angular.module('Lexus.Directives') 8312 .directive('lxFormsTestDrivePreLaunch', FormsTestDrivePreLaunchDirective); 8313 8314 FormsTestDrivePreLaunchDirective.$inject = [ 8315 "$filter", "$http", "$location", "API", "$rootScope", "DealersService", 8316 "AddressSuggestService", "UserPreferencesService", "FormsService", "EloquaService"]; 8317 8318 function FormsTestDrivePreLaunchDirective($filter, $http, $location, API, $rootScope, DealersService, 8319 AddressSuggestService, UserPreferencesService, FormsService, EloquaService) { 8320 8321 var formFutureModel = ''; 8322 FormsTestDrivePreLaunchController.$inject = ['$scope']; 8323 return { 8324 scope: true, 8325 restrict: 'A', 8326 controller: FormsTestDrivePreLaunchController, 8327 controllerAs: 'ffc', 8328 bindToController: true, 8329 link: function (scope, element, attrs, filter, http) { 8330 scope.successContent = element.find('.lx-form-success'); 8331 scope.failureContent = element.find('.lx-form-failure'); 8332 formFutureModel = attrs.lxFormsFutureModel; 8333 } 8334 }; 8335 8336 function FormsTestDrivePreLaunchController($scope) { 8337 var ftd = this; 8338 $scope.ffc.urlParameters = $location.search(); 8339 8340 $scope.init = function (forceDealerId, dealerCompositeID, isDealerSite, isMultiBranchDealer) { 8341 UserPreferencesService.getLexusVisitorSession().then(function success(data) { 8342 //var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); Wont be passed from URL or cookies for future vehicles 8343 var dataDealer = UserPreferencesService.getLexusDealer($scope.ffc.urlParameters); 8344 var dataUser = UserPreferencesService.getLexusVisitor($scope.ffc.urlParameters); 8345 $scope.ffc.form = { 8346 submitting: false, 8347 completed: false, 8348 errors: false, 8349 dealers: [], 8350 data: { 8351 postcodes: [], 8352 carmodel: formFutureModel, 8353 subscribe: false, 8354 postcode: "", 8355 email: data.Data.email, 8356 phonetype: data.Data.phoneType ? data.Data.phoneType : 'home', 8357 firstname: data.Data.name, 8358 lastname: data.Data.surname, 8359 phone: data.Data.phone, 8360 prefer: data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 8361 captcha: '', 8362 contextDealerSiteId: forceDealerId, 8363 dealerId: dataDealer.dealerID, 8364 dealerName: dataDealer.dealerName, 8365 preferredlocation: 'home', 8366 purchasedelay: null, 8367 currentmake: null 8368 } 8369 }; 8370 if (dataUser.suburb && dataUser.postCode) { 8371 $scope.ffc.form.data.postcodes.push( 8372 { 8373 text: dataUser.suburb + " " + dataUser.postCode, 8374 data: { 8375 postCode: dataUser.postCode, 8376 suburb: dataUser.suburb 8377 } 8378 }); 8379 } 8380 }, function failure(data) { 8381 $scope.ffc.form = { 8382 submitting: false, 8383 completed: false, 8384 errors: false, 8385 dealers: [], 8386 data: { 8387 postcodes: [], 8388 carmodel: formFutureModel, 8389 subscribe: false, 8390 postcode: "", 8391 email: null, 8392 phonetype: 'home', 8393 firstname: null, 8394 lastname: null, 8395 phone: null, 8396 prefer: 'email', 8397 captcha: '', 8398 dealerId: null, 8399 dealerName: null, 8400 preferredlocation: 'home', 8401 purchasedelay: null, 8402 currentmake: null 8403 } 8404 }; 8405 }).finally(function () { 8406 //Main Site 8407 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !isDealerSite) { 8408 $scope.searchNow(); 8409 } 8410 8411 //Dealer Site Multi Branch 8412 if (isDealerSite && isMultiBranchDealer) { 8413 $scope.ffc.form.data.dealerId = null; 8414 $scope.ffc.form.data.dealerName = null; 8415 $scope.loadBranches(forceDealerId); 8416 } 8417 8418 //Dealer Site NOT Multi Branch 8419 if (isDealerSite && !isMultiBranchDealer) { 8420 $scope.ffc.form.data.dealerId = dealerCompositeID;
8421 $scope.ffc.form.data.dealerName = null; 8422 } 8423 8424 }); 8425 } 8426 8427 //$scope.loadTags = function (query) { 8428 // AddressSuggestService.setParam('term', query); 8429 // return AddressSuggestService.GetResults(); 8430 //}; 8431 8432 $scope.deselectDealer = function () { 8433 $scope.ffc.form.data.dealerName = null; 8434 } 8435 8436 $scope.selectDealer = function (dealerInputId) { 8437 var scrollPos = $(document).scrollTop(); 8438 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 8439 if (scrollPos > maxPos) { 8440 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 8441 } 8442 try { 8443 var code = dealerInputId.replace('option-', ''); 8444 $scope.ffc.form.data.dealerName = $scope.ffc.form.dealers.find(function (dealer) { return dealer.dealerCode == code; }).dealerName; 8445 } catch(ex) { 8446 (console.error || console.log)(ex); 8447 } 8448 } 8449 8450 $scope.loadBranches = function (dealerID) { 8451 DealersService.setParam('dealerID', dealerID); 8452 DealersService.setParam('type', 'Sales'); 8453 DealersService.GetDealerBranches(); 8454 } 8455 8456 $scope.dealerSearch = function ($tag) { 8457 $scope.ffc.form.data.postcodes = []; 8458 $scope.ffc.form.data.postcodes[0] = $tag; 8459 $scope.searchNow(); 8460 } 8461 8462 $scope.searchNow = function () { 8463 $scope.ffc.form.dealersLoading = true; 8464 $rootScope.$broadcast('visitor-details-change-autocomplete', $scope.ffc.form.data.postcodes[0].data); 8465 DealersService.setParam('postCode', $scope.ffc.form.data.postcodes[0].data.postCode); //Dummy Implementation needs to be changed 8466 DealersService.setParam('suburb', $scope.ffc.form.data.postcodes[0].data.suburb); //Dummy Implementation needs to be changed 8467 DealersService.setParam('type', 'Sales'); 8468 DealersService.GetResults(); 8469 8470 } 8471 8472 $scope.$on('dealer-search-results-received', function (event, data) { 8473 $scope.ffc.form.dealersLoading = false; 8474 $scope.ffc.form.dealers = data.Data; 8475 $scope.checkDealersLoaded(); 8476 }); 8477 8478 //Do a sanity check to see if the bound dealers match the forceDealer if not clear the force dealer 8479 $scope.checkDealersLoaded = function () { 8480 var result = $scope.ffc.form.dealers.find(function (dealer) { 8481 return dealer.dealerCode == $scope.ffc.form.data.dealerId; 8482 }); 8483 if (!result) { 8484 $scope.ffc.form.data.dealerId = null; 8485 } 8486 8487 if ($scope.ffc.form.dealers.length == 1) 8488 $scope.ffc.form.data.dealerId = $scope.ffc.form.dealers[0].dealerCode; 8489 } 8490 8491 8492 $scope.getData = function () { 8493 var utmParameters = UserPreferencesService.getUtmParameters(); 8494 var postcode = null; 8495 if ($scope.ffc.form.data.postcodes.length > 0 && $scope.ffc.form.data.postcodes[0].text) { 8496 postcode = parseInt($scope.ffc.form.data.postcodes[0].text.split(' ').reverse()[0]); 8497 } 8498 return { 8499 FirstName: $scope.ffc.form.data.firstname, 8500 LastName: $scope.ffc.form.data.lastname, 8501 Email: $scope.ffc.form.data.email, 8502 Phone: $scope.ffc.form.data.phone, 8503 PreferredContactMethod: $scope.ffc.form.data.prefer, 8504 Model: formFutureModel, 8505 DealerId: $scope.ffc.form.data.dealerId, 8506 ContextDealerSiteId: $scope.ffc.form.data.contextDealerSiteId, 8507 Subscribe: $scope.ffc.form.data.subscribe.toString(), 8508 Captcha: $scope.ffc.form.data.captcha, 8509 PlanToPurchase: $scope.ffc.form.data.purchasedelay, 8510 VehicleTypeOwned: $scope.ffc.form.data.currentmake, 8511 PreferredLocation: $scope.ffc.form.data.preferredlocation, 8512 //Leave alone this its to clear validation on the base type! 8513 //Its on the base type as we remember the value in session 8514 PhoneType: 'Not Specified', 8515 UtmSource: utmParameters.source, 8516 UtmMedium: utmParameters.medium, 8517 UtmCampaign: utmParameters.campaign, 8518 UtmContent: utmParameters.content, 8519 Postcode: postcode, 8520 DealerName: $scope.ffc.form.data.dealerName 8521 }; 8522 } 8523 8524 $rootScope.$on('submit-test-drive-prelaunch-form', function () { 8525 var formData = $scope.getData(); 8526 8527 EloquaService.attachEloquaFields(formData); 8528 8529 $scope.ffc.form.submitting = true; 8530 //Code to be changed once actual client side validation is in place on finance form to refer to actual api 8531 $http({ 8532 method: 'POST', 8533 url: $filter('formatArgs')(Lexus.API.FormSubmission.PreLaunchTestDriveUrl, [Lexus.ID.Site]), 8534 data: formData 8535 }) 8536 .then(function success(response) { 8537 if (response.data.Status == "Success") { 8538 $scope.submissionPass(response.data); 8539 } 8540 else { 8541 $scope.submissionFail(response.data); 8542 } 8543 8544 }, function error(response) { 8545 $scope.submissionFail(response.data); 8546 }) 8547 .finally(function () { 8548 $rootScope.$broadcast('form-result'); 8549 }); 8550 }); 8551
8552 $scope.submissionPass = function (data) { 8553 // this callback will be called asynchronously 8554 // when the response is available 8555 $scope.ffc.form.completed = true; 8556 $scope.ffc.form.failed = false; 8557 $scope.ffc.form.submitting = false; 8558 var historyState = "PreBookTestDriveForm=Pass"; 8559 $location.state(historyState); 8560 FormsService.ShowResult($scope.successContent[0]); 8561 $rootScope.$broadcast('gtm-form-success', 'Test Drive Prelaunch'); 8562 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 8563 8564 }; 8565 8566 $scope.submissionFail = function (data) { 8567 // called asynchronously if an error occurs 8568 // or server returns response with an error status. 8569 $scope.ffc.form.failed = true; 8570 $scope.ffc.form.errors = data.Data; 8571 $scope.ffc.form.submitting = false; 8572 $scope.ffc.form.completed = true; 8573 var historyState = "PreBookTestDriveForm=Fail"; 8574 $location.state(historyState); 8575 FormsService.ShowResult($scope.failureContent[0]); 8576 console.error(data.ErrorMessage); 8577 }; 8578 } 8579 } 8580 8581}()); 8582 8583; 8584"use strict"; 8585/* Directives */ 8586angular.module('Lexus.Directives') 8587 .directive('lxFormsTestDrive', 8588 [ 8589 "$rootScope", "$filter", "$http", "$location", "API", "DealersService", "AddressSuggestService", "UserPreferencesService", "FormsService", "EloquaService", 8590 function ($rootScope, $filter, $http, $location, API, DealersService, AddressSuggestService, UserPreferencesService, FormsService, EloquaService) 8591 { 8592 FormsTestDriveController.$inject = ['$scope']; 8593 return { 8594 scope: true, 8595 restrict: 'A', 8596 controller: FormsTestDriveController, 8597 controllerAs: 'ffc', 8598 bindToController: true, 8599 link: function (scope, element, attrs, filter, http) { 8600 scope.successContent = element.find('.lx-form-success'); 8601 scope.failureContent = element.find('.lx-form-failure'); 8602 } 8603 }; 8604 8605 function FormsTestDriveController($scope) { 8606 var ftd = this; 8607 $scope.ffc.urlParameters = $location.search(); 8608 8609 $scope.init = function (forceDealerId, dealerCompositeID, isDealerSite, isMultiBranchDealer) { 8610 UserPreferencesService.getLexusVisitorSession().then(function success(data) { 8611 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); 8612 var dataDealer = UserPreferencesService.getLexusDealer($scope.ffc.urlParameters); 8613 var dataUser = UserPreferencesService.getLexusVisitor($scope.ffc.urlParameters); 8614 $scope.ffc.form = { 8615 submitting: false, 8616 completed: false, 8617 errors: false, 8618 dealers: null, 8619 data: { 8620 postcodes: [], 8621 carmodel: dataVehicle.model, 8622 grade: dataVehicle.grade, 8623 enginevariant: dataVehicle.engineVariant, 8624 subscribe: false, 8625 postcode: "", 8626 email: data.Data.email, 8627 phonetype: data.Data.phoneType ? data.Data.phoneType : 'home', 8628 firstname: data.Data.name, 8629 lastname: data.Data.surname, 8630 phone: data.Data.phone, 8631 prefer: data.Data.preferredContactMethod ? data.Data.preferredContactMethod : 'email', 8632 captcha: '', 8633 dealerId: dataDealer.dealerID, 8634 dealerName: dataDealer.dealerName, 8635 purchasedelay: null, 8636 currentmake: null, 8637 contextDealerSiteId: forceDealerId 8638 } 8639 }; 8640 if (dataUser.suburb && dataUser.postCode) { 8641 $scope.ffc.form.data.postcodes.push( 8642 { 8643 text: dataUser.suburb + " " + dataUser.postCode, 8644 data: { 8645 postCode: dataUser.postCode, 8646 suburb: dataUser.suburb 8647 } 8648 }); 8649 } 8650 }, function failure(data) { 8651 $scope.ffc.form = { 8652 submitting: false, 8653 completed: false, 8654 errors: false, 8655 dealers: null, 8656 data: { 8657 postcodes: [], 8658 carmodel: null, 8659 grade: null, 8660 subscribe: false, 8661 postcode: "", 8662 email: null, 8663 phonetype: 'home', 8664 firstname: null, 8665 lastname: null, 8666 phone: null, 8667 prefer: 'email', 8668 captcha: '', 8669 dealerId: null, 8670 dealerName: null, 8671 purchasedelay: null, 8672 currentmake: null 8673 } 8674 }; 8675 }).finally(function () { 8676 if ($scope.ffc.form.data.carmodel) { 8677 $rootScope.$broadcast('field-car-model-engine-variant-update-selected'); 8678 } 8679 8680 //Main Site 8681 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !isDealerSite) { 8682 //Do nothing, Pass empty dealer ID 8683 $scope.searchNow(); 8684 } 8685 8686 //Dealer Site Multi Branch 8687 if (isDealerSite && isMultiBranchDealer) { 8688 $scope.ffc.form.data.dealerId = null; 8689 $scope.ffc.form.data.dealerName = null; 8690 $scope.loadBranches(forceDealerId); 8691 } 8692 8693 //Dealer Site NOT Multi Branch 8694 if (isDealerSite && !isMultiBranchDealer) { 8695 $scope.ffc.form.data.dealerId = dealerCompositeID;
8696 $scope.ffc.form.data.dealerName = null; 8697 } 8698 8699 }); 8700 } 8701 8702 $scope.deselectDealer = function () { 8703 $scope.ffc.form.data.dealerName = null; 8704 } 8705 8706 $scope.selectDealer = function (dealerInputId) { 8707 var scrollPos = $(document).scrollTop(); 8708 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 8709 if (scrollPos > maxPos) { 8710 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 8711 } 8712 try { 8713 var code = dealerInputId.replace('option-', ''); 8714 $scope.ffc.form.data.dealerName = $scope.ffc.form.dealers.find(function (dealer) { return dealer.dealerCode == code; }).dealerName; 8715 } catch (ex) { 8716 (console.error || console.log)(ex); 8717 } 8718 } 8719 8720 $scope.loadBranches = function (dealerID) { 8721 $scope.ffc.form.dealersLoading = true; 8722 DealersService.setParam('dealerID', dealerID); 8723 DealersService.setParam('type', 'Sales'); 8724 DealersService.GetDealerBranches(); 8725 } 8726 8727 $scope.dealerSearch = function ($tag) { 8728 $scope.ffc.form.data.postcodes = []; 8729 $scope.ffc.form.data.postcodes[0] = $tag; 8730 $scope.searchNow(); 8731 } 8732 8733 $scope.$on('dealer-search-results-received', function (event, data) { 8734 $scope.ffc.form.dealersLoading = false; 8735 $scope.ffc.form.dealers = data.Data; 8736 $scope.checkDealersLoaded(); 8737 }); 8738 8739 //Do a sanity check to see if the bound dealers match the forceDealer if not clear the force dealer 8740 $scope.checkDealersLoaded = function () { 8741 var result = $scope.ffc.form.dealers.find(function (dealer) { 8742 return dealer.dealerCode == $scope.ffc.form.data.dealerId; 8743 }); 8744 if (!result) { 8745 $scope.ffc.form.data.dealerId = null; 8746 } 8747 8748 if ($scope.ffc.form.dealers.length == 1) 8749 $scope.ffc.form.data.dealerId = $scope.ffc.form.dealers[0].dealerCode; 8750 } 8751 8752 8753 $scope.searchNow = function () { 8754 $scope.ffc.form.dealersLoading = true; 8755 $rootScope.$broadcast('visitor-details-change-autocomplete', $scope.ffc.form.data.postcodes[0].data); 8756 DealersService.setParam('postCode', $scope.ffc.form.data.postcodes[0].data.postCode); //Dummy Implementation needs to be changed 8757 DealersService.setParam('suburb', $scope.ffc.form.data.postcodes[0].data.suburb); //Dummy Implementation needs to be changed 8758 DealersService.setParam('type', 'Sales'); 8759 DealersService.GetResults(); 8760 8761 } 8762 8763 $scope.getData = function () { 8764 var utmParameters = UserPreferencesService.getUtmParameters(); 8765 var postcode = null; 8766 if ($scope.ffc.form.data.postcodes.length > 0 && $scope.ffc.form.data.postcodes[0].text) { 8767 postcode = parseInt($scope.ffc.form.data.postcodes[0].text.split(' ').reverse()[0]); 8768 } 8769 8770 var result = { 8771 Model: $scope.ffc.form.data.carmodel, 8772 EngineVariant: $scope.ffc.form.data.enginevariant, 8773 DealerId: $scope.ffc.form.data.dealerId, 8774 ContextDealerSiteId: $scope.ffc.form.data.contextDealerSiteId, 8775 FirstName: $scope.ffc.form.data.firstname, 8776 LastName: $scope.ffc.form.data.lastname, 8777 Email: $scope.ffc.form.data.email, 8778 Phone: $scope.ffc.form.data.phone, 8779 PreferredContactMethod: $scope.ffc.form.data.prefer, 8780 PlanToPurchase: $scope.ffc.form.data.purchasedelay, 8781 VehicleTypeOwned: $scope.ffc.form.data.currentmake, 8782 Captcha: $scope.ffc.form.data.captcha, 8783 Subscribe: $scope.ffc.form.data.subscribe, 8784 UtmSource: utmParameters.source, 8785 UtmMedium: utmParameters.medium, 8786 UtmCampaign: utmParameters.campaign, 8787 UtmContent: utmParameters.content, 8788 Postcode: postcode, 8789 DealerName: $scope.ffc.form.data.dealerName 8790 }; 8791 8792 return result; 8793 }; 8794 8795 $rootScope.$on('vehicle-preference-change', function (event, data) { 8796 $scope.ffc.form.data.carmodel = data.model; 8797 $scope.ffc.form.data.enginevariant = data.engineVariant; 8798 }); 8799 8800 $rootScope.$on('submit-test-drive-form', function (event, data) { 8801 var formData = $scope.getData(); 8802 8803 EloquaService.attachEloquaFields(formData); 8804 8805 $scope.ffc.form.submitting = true; 8806 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.TestDrive, [Lexus.ID.Site]), data: formData }) 8807 .then(function success(response) { 8808 if (response.data.Status == "Success") { 8809 $scope.submissionPass(response.data); 8810 } 8811 else { 8812 $scope.submissionFail(response.data); 8813 } 8814 }, function error(response) { 8815 $scope.submissionFail(response.data); 8816 }) 8817 .finally(function () { 8818 $rootScope.$broadcast('form-result'); 8819 }); 8820 }); 8821 8822
8823 $scope.submissionPass = function (data) { 8824 // this callback will be called asynchronously 8825 // when the response is available 8826 $scope.ffc.form.completed = true; 8827 $scope.ffc.form.failed = false; 8828 $scope.ffc.form.submitting = false; 8829 var historyState = "TestDriveForm=Pass"; 8830 $location.state(historyState); 8831 FormsService.ShowResult($scope.successContent[0]); 8832 $rootScope.$broadcast('gtm-form-success', 'Test Drive'); 8833 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 8834 }; 8835 $scope.submissionFail = function (data) { 8836 // called asynchronously if an error occurs 8837 // or server returns response with an error status. 8838 $scope.ffc.form.failed = true; 8839 $scope.ffc.form.errors = data.Data; 8840 $scope.ffc.form.submitting = false; 8841 $scope.ffc.form.completed = true; 8842 var historyState = "TestDriveForm=Fail"; 8843 $location.state(historyState); 8844 FormsService.ShowResult($scope.failureContent[0]); 8845 console.error(data.ErrorMessage); 8846 }; 8847 8848 } 8849 } 8850]); 8851 8852 8853 8854; 8855"use strict" 8856/* Directives */ 8857 8858angular.module('Lexus.Directives') 8859.directive('lxFormsUpdateDetail', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 8860 formUpdateDetailController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'vcRecaptchaService', 'API', 'FormsService', 'UserPreferencesService']; 8861 return { 8862 scope: true, 8863 restrict: 'A', 8864 controller: formUpdateDetailController, 8865 controllerAs: 'ffc', 8866 bindToController: true, 8867 link: function (scope, element, attrs, filter, http) { 8868 scope.successContent = element.find('.lx-form-success'); 8869 scope.failureContent = element.find('.lx-form-failure'); 8870 } 8871 }; 8872 8873 function formUpdateDetailController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, vcRecaptchaService, API, FormsService, UserPreferencesService) { 8874 var fcu = this; 8875 8876 $scope.init = function (optionValue) { 8877 $scope.ffc.form = { 8878 submitting: false, 8879 completed: false, 8880 errors: false, 8881 data: { 8882 subscribe: false, 8883 firstname: '', 8884 lastname: '', 8885 address: '', 8886 postcodes: [], 8887 email: '', 8888 phonetype: '', 8889 updatetype: '', 8890 phone: '', 8891 prefer: 'email', 8892 captcha: '', 8893 vin: '', 8894 registration: '', 8895 requesttype: '' 8896 } 8897 }; 8898 $scope.ffc.form.data.updatetype = optionValue; 8899 } 8900 8901 $rootScope.$on('submit-update-detail-form', function () { 8902 var formData = $scope.getData(); 8903 8904 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.UpdateDetails, [Lexus.ID.Site]), data: formData }) 8905 .then(function success(response) { 8906 if (response.data.Status == "Success") { 8907 $scope.submissionPass(response.data); 8908 } 8909 else { 8910 $scope.submissionFail(response.data); 8911 } 8912 }, function error(response) { 8913 $scope.submissionFail(response.data); 8914 }) 8915 .finally(function () { 8916 $rootScope.$broadcast('form-result'); 8917 }); 8918 }); 8919 8920 $rootScope.$on('vin-change', function (event, data) { 8921 if (!$scope.ffc.form.data.vin) { 8922 $rootScope.$broadcast('vin-lookup-success'); 8923 return; 8924 } 8925 var formData = $scope.getData(); 8926 8927 $scope.ffc.form.submitting = true; 8928 API.post($filter('formatArgs')(Lexus.API.Lookup.VINLookupTakata, [Lexus.ID.Site]), $scope.getVinData()) 8929 .then(function success(response) { 8930 if (response.Status == "Success") { 8931 $rootScope.$broadcast('vin-lookup-success'); 8932 } 8933 else { 8934 $rootScope.$broadcast('vin-lookup-failed'); 8935 } 8936 }, function error(response) { 8937 $rootScope.$broadcast('vin-lookup-failed'); 8938 }) 8939 }); 8940 8941 $scope.getData = function () { 8942 var visitor = UserPreferencesService.splitAutoCompleteResult($scope.ffc.form.data.postcodes[0].text); 8943 var result = { 8944 UpdateType: $scope.ffc.form.data.updatetype, 8945 FirstName: $scope.ffc.form.data.firstname, 8946 LastName: $scope.ffc.form.data.lastname, 8947 Email: $scope.ffc.form.data.email, 8948 Phone: $scope.ffc.form.data.phone, 8949 StreetAddress: $scope.ffc.form.data.address, 8950 Postcode: visitor.postCode, 8951 PhoneType: $scope.ffc.form.data.phonetype, 8952 PreferredContactMethod: $scope.ffc.form.data.prefer, 8953 Captcha: $scope.ffc.form.data.captcha, 8954 Vin: $scope.ffc.form.data.vin, 8955 Registration: $scope.ffc.form.data.registration, 8956 StateRegistered: $scope.ffc.form.data.requesttype, 8957 Subscribe: $scope.ffc.form.data.subscribe 8958 }; 8959 return result; 8960 8961 }; 8962 8963 $scope.getVinData = function () { 8964 var result = { 8965 Vin: $scope.ffc.form.data.vin 8966 }; 8967 return result; 8968 8969 }; 8970
8971 $scope.submissionPass = function (data) { 8972 $scope.ffc.form.completed = true; 8973 $scope.ffc.form.failed = false; 8974 $scope.ffc.form.submitting = false; 8975 var historyState = "UpdateDetails=Pass"; 8976 $location.state(historyState); 8977 FormsService.ShowResult($scope.successContent[0]); 8978 $rootScope.$broadcast('gtm-form-success', 'Update Details'); 8979 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 8980 }; 8981 8982 $scope.submissionFail = function (data) { 8983 $scope.ffc.form.failed = true; 8984 $scope.ffc.form.errors = data.Data; 8985 $scope.ffc.form.submitting = false; 8986 $scope.ffc.form.completed = true; 8987 var historyState = "UpdateDetails=Fail"; 8988 $location.state(historyState); 8989 FormsService.ShowResult($scope.failureContent[0]); 8990 console.error(data.ErrorMessage); 8991 }; 8992 } 8993 8994}]); 8995; 8996"use strict"; 8997angular.module('Lexus.Directives') 8998.directive('lxGoogleMap', ['$window', '$timeout', '$filter', '$http', function ($window, $timeout, $filter, $http) { 8999 googleMapController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval']; 9000 return { 9001 scope: true, 9002 restrict: 'A', 9003 controller: googleMapController, 9004 controllerAs: 'gm', 9005 bindToController: true, 9006 link: function (scope, element, attrs, filter, http) { 9007 9008 var mapStyles = [{"featureType":"all","elementType":"geometry.fill","stylers":[{"color":"#d7d3c6"},{"saturation":"0"}]},{"featureType":"administrative","elementType":"all","stylers":[{"color":"#f0eee7"}]},{"featureType":"administrative","elementType":"geometry","stylers":[{"color":"#d7d3c6"}]},{"featureType":"administrative","elementType":"labels.text.fill","stylers":[{"color":"#232635"}]},{"featureType":"administrative","elementType":"labels.icon","stylers":[{"color":"#ca4b19"}]},{"featureType":"administrative.country","elementType":"all","stylers":[{"color":"#d7d3c6"}]},{"featureType":"landscape","elementType":"all","stylers":[{"color":"#d7d3c6"}]},{"featureType":"landscape.man_made","elementType":"geometry.fill","stylers":[{"color":"#d7d3c6"}]},{"featureType":"landscape.man_made","elementType":"labels.text.fill","stylers":[{"color":"#313649"}]},{"featureType":"landscape.natural.landcover","elementType":"geometry.fill","stylers":[{"color":"#d7d3c6"}]},{"featureType":"landscape.natural.landcover","elementType":"labels.text.fill","stylers":[{"color":"#313649"}]},{"featureType":"landscape.natural.terrain","elementType":"geometry.fill","stylers":[{"color":"#d7d3c6"}]},{"featureType":"poi","elementType":"all","stylers":[{"visibility":"off"},{"color":"#ca4b19"}]},{"featureType":"road","elementType":"all","stylers":[{"saturation":-100},{"lightness":45}]},{"featureType":"road","elementType":"labels.text.fill","stylers":[{"color":"#ffffff"}]},{"featureType":"road","elementType":"labels.text.stroke","stylers":[{"color":"#f0eee7"}]},{"featureType":"road.highway","elementType":"all","stylers":[{"visibility":"simplified"}]},{"featureType":"road.highway","elementType":"geometry.fill","stylers":[{"color":"#f0eee7"}]},{"featureType":"road.highway","elementType":"labels.text.fill","stylers":[{"color":"#313649"}]},{"featureType":"road.highway","elementType":"labels.text.stroke","stylers":[{"color":"#f0eee7"}]},{"featureType":"road.arterial","elementType":"geometry.fill","stylers":[{"color":"#f0eee7"}]},{"featureType":"road.arterial","elementType":"labels.text.fill","stylers":[{"color":"#313649"}]},{"featureType":"road.arterial","elementType":"labels.text.stroke","stylers":[{"color":"#f0eee7"}]},{"featureType":"road.arterial","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"road.local","elementType":"geometry.fill","stylers":[{"color":"#e4e1d7"}]},{"featureType":"road.local","elementType":"geometry.stroke","stylers":[{"visibility":"simplified"},{"color":"#f0eee7"}]},{"featureType":"road.local","elementType":"labels.text.fill","stylers":[{"color":"#313649"}]},{"featureType":"road.local","elementType":"labels.text.stroke","stylers":[{"color":"#f0eee7"}]},{"featureType":"transit","elementType":"all","stylers":[{"visibility":"off"},{"color":"#beb4b2"}]},{"featureType":"transit","elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit.station.rail","elementType":"all","stylers":[{"visibility":"off"}]},{"featureType":"water","elementType":"all","stylers":[{"color":"#313649"},{"visibility":"on"}]}]; 9009 9010 if (inViewport(element[0])) { 9011 loadMap(element[0], attrs); 9012 scope.loaded = true; 9013 } 9014 else { 9015 scope.loaded = false; 9016 var runEvent = true; 9017 angular.element($window).bind("scroll", function () { 9018 if (runEvent) { 9019 runEvent = false; 9020 $timeout(function () { 9021 if (!scope.loaded && inViewport(element[0])) { 9022 loadMap(element[0], attrs); 9023 scope.loaded = true; 9024 } 9025 runEvent = true; 9026 }, 2000); 9027 } 9028 }); 9029 } 9030 9031 // dealerStyles 9032 function loadMap(el, att) { 9033 var myLatLng = { lat: Number(att.lat), lng: Number(att.lng) }; 9034 var map = new google.maps.Map(el, { 9035 center: myLatLng, 9036 zoom: 13 9037 }); 9038 map.setOptions({ styles: mapStyles, 9039 zoomControl: true, 9040 mapTypeControl: false, 9041 scaleControl: false, 9042 streetViewControl: true, 9043 rotateControl: false, 9044 fullscreenControl: false 9045 }); 9046 google.maps.event.trigger(map, 'resize'); 9047 var icon; 9048 if (att.iconAnchorX && att.icon) { 9049 icon = { 9050 url: att.icon, 9051 size: new google.maps.Size(att.iconWidth, att.iconHeight), 9052 origin: new google.maps.Point(att.iconOriginX, att.iconOriginY), 9053 anchor: new google.maps.Point(att.iconAnchorX, att.iconAnchorY) 9054 }; 9055 } else if (att.icon) { 9056 icon = att.icon; 9057 } else { 9058 icon = ''; 9059 } 9060 var marker = new google.maps.Marker({ 9061 position: myLatLng, 9062 map: map, 9063 title: att.dealername, 9064 icon: icon 9065 }); 9066 } 9067 9068 function inViewport(el) { 9069 var r, html; 9070 if (!el || 1 !== el.nodeType) { return false; } 9071 html = document.documentElement; 9072 r = el.getBoundingClientRect(); 9073 9074 return (!!r 9075 && r.bottom >= 0 9076 && r.right >= 0 9077 && r.top <= html.clientHeight 9078 && r.left <= html.clientWidth 9079 ); 9080 } 9081 } 9082 } 9083 9084 function googleMapController($scope, $http, $filter, $timeout, $window, $interval) { 9085 var gm = this; 9086 } 9087}]); 9088 9089; 9090"use strict"; 9091 9092angular.module('Lexus.Directives') 9093.directive('buttonClick', [function () { 9094 return function (scope, element, attrs) { 9095 $(element).click(function (event) { 9096 event.preventDefault(); 9097 }); 9098 }; 9099}]) 9100.directive('runOnBlur', [function () { 9101 return function (scope, element, attrs) { 9102 element.blur(function () { 9103 if (angular.isDefined(attrs.runOnBlur)) { 9104 scope.$apply(function () { 9105 scope.$eval(attrs.runOnBlur); 9106 }); 9107 } 9108 }); 9109 }; 9110}]) 9111.directive('onFinishRender', ['$timeout', function ($timeout) { 9112 return { 9113 restrict: 'A', 9114 link: function (scope, element, attr) { 9115 if (scope.$last === true) { 9116 $timeout(function () { 9117 scope.$emit('ngRepeatFinished'); 9118 }); 9119 } 9120 } 9121 } 9122}]) 9123.directive('enterPress', [function () { 9124 return function (scope, element, attrs) { 9125 element.bind('keydown keypress', function (event) { 9126 if (event.which === 13) { 9127 scope.$apply(function () { 9128 scope.$eval(attrs.enterPress); 9129 }); 9130 9131 event.preventDefault(); 9132 } 9133 }); 9134 }; 9135}]) 9136.directive('backImg', function(){ 9137 return function(scope, element, attrs){ 9138 var url = attrs.backImg; 9139 element.css('background-image', 'url(' + url +')'); 9140 }; 9141}) 9142.directive('forceFocusOnClick', [function () {
9143 // This directive forces focus on devices that don't support focus on non input/anchor elements (ipads + other ios devices) 9144 return function (scope, element, attrs) { 9145 element.bind('click', function (event) { 9146 if (this != document.activeElement){ 9147 event.stopPropagation(); 9148 this.focus(); 9149 } 9150 }); 9151 }; 9152}]) 9153.directive('lxSmallLoader', [function () { 9154 9155 return { 9156 scope: { 9157 showLoader: '=', 9158 transition: '@' 9159 }, 9160 restrict: 'AE', 9161 transclude: true, 9162 template: 9163 '<div class="lx-small-loader" ' + 9164 'data-ng-class="{\'is-loading\': showLoader, \'lx-small-loader--with-transition\': transition}">' + 9165 '<div class="lx-small-loader__container" data-ng-class="{\'lx-small-loader__transitionable\': transition}" data-ng-show="showLoader">' + 9166 new Array(12 + 1).join('<i class="lx-small-loader__circle">•</i>') + 9167 '</div>' + 9168 '<div data-ng-class="{\'lx-small-loader__transitionable\': transition}" data-ng-transclude data-ng-hide="showLoader"></div>' + 9169 '</div>' 9170 }; 9171 9172}]) 9173.directive('mouseDetected', ['$rootScope', 'MouseDetectionService', function ($rootScope, MouseDetectionService) { 9174 return { 9175 restrict: 'A', 9176 scope: { 9177 onMouseDetected: '&mouseDetected' 9178 }, 9179 link: function(scope, elem, attrs) { 9180 $rootScope.$on('did-detect-mouse', function() { 9181 //console.log('about to call', scope.onMouseDetected); 9182 scope.onMouseDetected(); 9183 scope.$apply(); 9184 }); 9185 } 9186 } 9187}]) 9188.directive('scrollTopOnFocus', ['$window', function ($window) { 9189 return function (scope, element, attrs) { 9190 element.bind('click', function (event) { 9191 var scrollYPos = $(element[0]).offset().top; 9192 event.preventDefault(); 9193 if ($window.innerWidth <= Lexus.Breakpoint.ExtraSmall) { 9194 TweenLite.to(window, 1, { scrollTo: { y: scrollYPos, x: 0 }, ease: Power4.easeOut }); 9195 } 9196 }); 9197 }; 9198}]) 9199.directive('scrollToIdOnClick', [function() { 9200 return function (scope, element, attrs) { 9201 element.bind('click', function () { 9202 var duration = attrs.scrollDuration != null ? attrs.scrollDuration : 2; 9203 var $element = $('#' + attrs.scrollTarget); 9204 9205 if (!$element.length) { 9206 return; 9207 } 9208 9209 TweenMax.to(window, duration, { scrollTo: { y: '#' + attrs.scrollTarget, offsetY: attrs.scrollOffset, ease: Power4.easeOut, autoKill: false } }); 9210 }); 9211 }; 9212}]); 9213; 9214(function () { 9215 "use strict"; 9216 9217 angular.module('Lexus.Directives') 9218 .directive('lxImageDisclaimer', ImageDisclaimerDirective); 9219 9220 function ImageDisclaimerDirective() { 9221 return { 9222 scope: { 9223 'cssClass': '@' 9224 }, 9225 restrict: 'A', 9226 transclude: true, 9227 template: '<div class="{{cssClass}}" ' + 9228 'ng-class="{\'is-open\': isMouse && isMouseInside || !isMouse && isToggled}" ' + 9229 'mouse-detected="isMouse = true" ' + 9230 'ng-click="isToggled = !isToggled" ' + 9231 'ng-mouseenter="isMouseInside = true" ' + 9232 'ng-mouseleave="isMouseInside = false"><ng-transclude></ng-transclude></div>' 9233 }; 9234 } 9235}());; 9236"use strict"; 9237/* Directives */ 9238angular.module('Lexus.Directives') 9239.directive('lazyLoadImages', [function () { // Lazy load images. 9240 return { 9241 link: function (scope, element, attrs) { 9242 var _window = angular.element(window), 9243 bLazy; 9244 9245 function initImages() { 9246 var _images = element.find('.b-lazy'); 9247 9248 angular.forEach(_images, function (value, key) { 9249 var _image = angular.element(value), 9250 src = _image.data('src'), 9251 mw = _image.data('src-mw'), 9252 q = _image.data('src-q'), 9253 mwXxs = Math.round(Lexus.Breakpoint.ExtraExtraSmall * 1.5), 9254 mwXs = Math.round(Lexus.Breakpoint.ExtraSmall * 1.5), 9255 mwSm = Math.round(Lexus.Breakpoint.Small * 1.5), 9256 mwMd = Math.round(Lexus.Breakpoint.Medium), 9257 imgQuery = ''; 9258 9259 // Check for extra image settings. 9260 if (angular.isDefined(mw)) { 9261 imgQuery += 'mw=' + mw;
9262 mwXs = mwSm = mwMd = mw; 9263 } 9264 9265 if (angular.isDefined(q)) { 9266 if (angular.isDefined(mw)) { 9267 imgQuery += '&'; 9268 } 9269 9270 imgQuery += 'q=' + q; 9271 } 9272 9273 if (imgQuery) { 9274 _image.attr('data-src', src + '?' + imgQuery); 9275 } 9276 9277 _image 9278 .attr('data-src-xxs', src + '?mw=' + mwXxs + '&q=95') 9279 .attr('data-src-xs', src + '?mw=' + mwXs + '&q=95') 9280 .attr('data-src-sm', src + '?mw=' + mwSm + '&q=95') 9281 .attr('data-src-md', src + '?mw=' + mwMd + '&q=95'); 9282 }); 9283 } 9284 9285 function initBLazy() { 9286 bLazy = new Blazy({ 9287 offset: 600, 9288 breakpoints: [{ 9289 width: Lexus.Breakpoint.ExtraExtraSmall, // mobile 9290 src: 'data-src-xxs' 9291 }, { 9292 width: Lexus.Breakpoint.ExtraSmall, // small tabet 9293 src: 'data-src-xs' 9294 }, { 9295 width: Lexus.Breakpoint.Small, // tablet 9296 src: 'data-src-sm' 9297 }, { 9298 width: Lexus.Breakpoint.Medium, // medium destkop 9299 src: 'data-src-md' 9300 }] 9301 }); 9302 } 9303 9304 initImages(); 9305 9306 initBLazy(); 9307 9308 // Watch app for lazy load rescan. 9309 scope.$on('broadcast.lazyLoad', function (event, args) { 9310 initImages(); 9311 9312 bLazy.revalidate(); 9313 }); 9314 9315 scope.$on('broadcast.lazyLoadRevalidate', function (event, args){ 9316 bLazy.revalidate(); 9317 }); 9318 9319 // On resize. 9320 _window.on('resize', function () { 9321 bLazy.revalidate(); 9322 }); 9323 } 9324 }; 9325}]) 9326.directive('initLazyLoadImage', ['$rootScope', '$timeout', function ($rootScope, $timeout) { // Lazy load new images. 9327 return { 9328 link: function (scope, element, attrs) { 9329 element.on('click', function () { 9330 9331 // Lazy load new images. 9332 $timeout(function () { 9333 $rootScope.$broadcast('broadcast.lazyLoad'); 9334 }, 300); 9335 }); 9336 } 9337 }; 9338}]); 9339; 9340"use strict"; 9341/* Directives */ 9342angular.module('Lexus.Directives') 9343.directive('lxModal', [function () { 9344 modalController.$inject = ['$scope', '$timeout', '$sce', '$rootScope']; 9345 return { 9346 scope: true, 9347 restrict: 'A', 9348 controller: modalController, 9349 controllerAs: 'modal', 9350 bindToController: true, 9351 link: function (scope, element, attrs) { 9352 } 9353 }; 9354 9355 function modalController($scope,$timeout, $sce, $rootScope) { 9356 var modal = this; 9357 9358 modal = modalStateUpdate(modal, false); 9359 $scope.modalContent = ''; 9360 9361 function modalStateUpdate(modal,set) { 9362 modal.modalIsOpen = set; 9363 return modal; 9364 } 9365 9366 $scope.modalClose = function () { 9367 modal.isClosing = 'is-closing'; 9368 modal = modalStateUpdate(modal,false); 9369 $timeout(function() { $scope.modalContent = '' }, 250); 9370 } 9371 9372 $scope.modalOpen = function(callback) { 9373 modal = modalStateUpdate(modal,true); 9374 if (callback) { 9375 callback(event); 9376 } 9377 } 9378 9379 /* Event Args: 9380 * arg : { 9381 * content : 'html-content' 9382 * [variant : Lexus.ModalVariant.[Content|Spinner]], 9383 * [closeOnEvent : 'event-name-to-listen-for'], 9384 * [wrapper : ['html-before','html-after']], 9385 * } 9386 */ 9387 $rootScope.$on('open-modal-window', function (events, arg) { 9388 9389 modal.variantClass = arg.variant; 9390 modal.closeOnEvent = (arg.variant == Lexus.ModalVariant.Spinner); 9391 9392 if (arg.wrapper) { 9393 arg.content = addModalWrapper(arg.wrapper, arg.content); 9394 } 9395
9396 //caution: using trusted html, so be careful putting user generated content in the modal 9397 $scope.modalContent = $sce.trustAsHtml(arg.content); 9398 $scope.modalOpen(); 9399 }); 9400 9401 $rootScope.$on('close-modal-window', function (events, arg) { 9402 $scope.modalClose(); 9403 }); 9404 9405 function addModalWrapper(wrapper, content) { 9406 return content = wrapper[0] 9407 + content + wrapper[1]; 9408 } 9409 9410 function getScrollbarWidth() { 9411 var outer = document.createElement("div"); outer.style.visibility = "hidden"; outer.style.width = "100px"; outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps 9412 9413 document.body.appendChild(outer); 9414 9415 var widthNoScroll = outer.offsetWidth; 9416 // force scrollbars 9417 outer.style.overflow = "scroll"; 9418 9419 // add innerdiv 9420 var inner = document.createElement("div"); 9421 inner.style.width = "100%"; 9422 outer.appendChild(inner); 9423 9424 var widthWithScroll = inner.offsetWidth; 9425 9426 // remove divs 9427 outer.parentNode.removeChild(outer); 9428 9429 var scrollBarWidth = widthNoScroll - widthWithScroll; 9430 document.styleSheets[0].insertRule(".is-locked { padding-right:" + scrollBarWidth + "px;}", document.styleSheets[0].cssRules.length); 9431 } 9432 9433 if (window.innerWidth > 480) { 9434 getScrollbarWidth(); 9435 } 9436 9437 } 9438 9439}]); 9440; 9441"use strict"; 9442 9443const attributes = { 9444 stepSpeed: "@animStepSpeed", 9445 minX: "@animMinX", 9446 maxX: "@animMaxX", 9447 minY: "@animMinY", 9448 maxY: "@animMaxY", 9449 case: "@animCase", 9450 enabledMobile: "@animEnabledMobile", 9451 triggerOffsetY: "@animTriggerOffsetY", 9452}; 9453 9454const cases = { 9455 x: "<div data-du-parallax='true' x='controller.animatorFunc'><ng-transclude/></div>", 9456 y: "<div data-du-parallax='true' y='controller.animatorFunc'><ng-transclude/></div>", 9457 fade: "<div data-du-parallax='true' custom='controller.scrollFade'><ng-transclude/></div>", 9458}; 9459 9460const checkIsAnimated = (window) => (attributes) => { 9461 const isMobile = window.innerWidth < Lexus.Breakpoint.Small; 9462 return !isMobile || (isMobile && attributes.animEnabledMobile === "1"); 9463}; 9464 9465const animations = { 9466 x: (controller) => 9467 controller.initXY(+controller.stepSpeed, +controller.maxX, +controller.minX, +controller.triggerOffsetY), 9468 y: (controller) => 9469 controller.initXY(+controller.stepSpeed, +controller.maxY, +controller.minY, +controller.triggerOffsetY), 9470 fade: (controller) => controller.initScrollFade(+controller.stepSpeed, +controller.triggerOffsetY), 9471}; 9472 9473/* Directives */ 9474angular.module("Lexus.Directives").directive("lxParallax", [ 9475 "$window", 9476 "parallaxHelper", 9477 function ($window, parallaxHelper) { 9478 const checkIsAnimatedWithWindow = checkIsAnimated($window); 9479 const windowHeight = $window.innerHeight; 9480 9481 return { 9482 scope: attributes, 9483 restrict: "A", 9484 controller: parallaxController, 9485 controllerAs: "controller", 9486 bindToController: true, 9487 transclude: true, 9488 template: (_, attrs) => (checkIsAnimatedWithWindow(attrs) ? cases[attrs.animCase] : "<ng-transclude/>"), 9489 link: function ({ controller }, _, attrs) { 9490 if (checkIsAnimatedWithWindow(attrs)) { 9491 animations[controller.case]?.(controller); 9492 } 9493 }, 9494 }; 9495 9496 function parallaxController() { 9497 this.initXY = (stepSpeed, max, min, triggerOffsetY) => { 9498 this.animatorFunc = parallaxHelper.createAnimator(stepSpeed, max, min, triggerOffsetY); 9499 }; 9500 9501 this.initScrollFade = (stepSpeed, triggerOffsetY) => { 9502 const factor = windowHeight * stepSpeed; 9503 const offset = windowHeight * triggerOffsetY; 9504 9505 this.scrollFade = ({ elemY }) => { 9506 const opacity = (elemY + offset) / factor; 9507 const correctedOpacity = Math.max(0, Math.min(1, opacity)); 9508 return { 9509 opacity: correctedOpacity, 9510 }; 9511 }; 9512 }; 9513 } 9514 }, 9515]); 9516; 9517(function () { 9518 "use strict"; 9519 /* Directives */ 9520 angular.module('Lexus.Directives') 9521 .directive('lxSearchResults', ['$window', '$timeout', '$filter', '$http', '$location', function ($window, $timeout, $filter, $http, $location) { 9522 searchResultsController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location']; 9523 return { 9524 scope: true, 9525 restrict: 'A', 9526 controller: searchResultsController, 9527 controllerAs: 'src', 9528 bindToController: true, 9529 link: function (scope, element, attrs, filter, http) { 9530 } 9531 }; 9532 9533 function searchResultsController($scope, $http, $filter, $timeout, $window, $interval, $location) { 9534 var src = this; 9535 $scope.init = function () { 9536 $scope.src = { 9537 searchTerm: $location.search().q 9538 }; 9539 } 9540 9541 $scope.runSearch = function () { 9542 $window.location.href = Lexus.URI.SearchResultsPage + "?q=" + $scope.src.searchTerm; 9543 } 9544 } 9545 }]); 9546}()); 9547; 9548 9549"use strict"; 9550/* Directives */ 9551angular.module('Lexus.Directives') 9552.directive('lxMobileCarousel', [function () { 9553 mobileCarouselController.$inject = ['$scope']; 9554 return { 9555 scope: true, 9556 restrict: 'A', 9557 controller: mobileCarouselController, 9558 controllerAs: 'mc', 9559 bindToController: true, 9560 link: function (scope, element, attrs ) { 9561 } 9562 }; 9563 9564 function mobileCarouselController($scope) { 9565 var mc = this; 9566 9567 $scope.init= function(slide){ 9568 mc.isShowing = 2; 9569 if(slide) { 9570 mc.isShowing = slide; 9571 } 9572 9573 mc.showingClass = ['is-showing-right','is-showing-left','is-showing-']; 9574 mc = classUpdate(mc); 9575 } 9576 9577 9578 function classUpdate(scope){ 9579 scope.mainClass = mc.showingClass[2] + scope.isShowing; 9580 scope.firstSecClass = firstClassUpdate(scope.isShowing, scope.showingClass[0]); 9581 scope.secondSecClass = secondClassUpdate(scope.isShowing, scope.showingClass); 9582 scope.thirdSecClass = thirdClassUpdate(scope.isShowing, scope.showingClass[1]); 9583 9584 return scope; 9585 } 9586 9587 function firstClassUpdate(showing,classSet){ 9588 var className = ''; 9589 if(showing > 1) { 9590 className = classSet; 9591 } 9592 return className; 9593 }; 9594 9595 function thirdClassUpdate(showing,classSet){ 9596 var className = ''; 9597 if(showing < 3) { 9598 className = classSet; 9599 } 9600 return className; 9601 }; 9602 9603 function secondClassUpdate(showing,classList){ 9604 var className = ''; 9605 if(showing === 3) { 9606 className = classList[0]; 9607 } else if(mc.isShowing === 1) { 9608 className = classList[1]; 9609 } 9610 return className; 9611 }; 9612 9613 $scope.prevSec= function(){ 9614 if (mc.isShowing > 1) { 9615 mc.isShowing--; 9616 } 9617 9618 mc = classUpdate(mc); 9619 } 9620 9621 $scope.nextSec= function(){ 9622 if (mc.isShowing < 3) { 9623 mc.isShowing++; 9624 } 9625 9626 mc = classUpdate(mc); 9627 } 9628 } 9629 9630}]); 9631; 9632"use strict"; 9633/* Directives */ 9634angular.module('Lexus.Directives') 9635.directive('lxStickToTop', ['$window', function ($window) { 9636 return { 9637 link: function ($scope, $element, $attrs) { 9638 var repaintState; 9639 var repaintStateOverrides; 9640 var restoreOverflowAnchorTimeout = null; 9641 var BUFFER_DIST = 50 9642 9643 function getElementHeightInclMargins($el) { 9644 var boundingRect = $el.get(0).getBoundingClientRect(); 9645 var rawHeight = boundingRect.bottom - boundingRect.top; 9646 var marginTop = parseInt($el.css('margin-top').match(/([0-9]+(\.[0-9])?)/g)[0], 10); 9647 var marginBottom = parseInt($el.css('margin-bottom').match(/([0-9]+(\.[0-9])?)/g)[0], 10); 9648 return rawHeight + marginTop + marginBottom; 9649 } 9650 9651 function setPlaceholderVisibility(visible) { 9652 $placeholder.css({ 9653 'height': visible ? (getElementHeightInclMargins($element) + 'px') : '0', 9654 'visibility': visible ? '' : 'hidden' 9655 }); 9656 if ($pusher) { 9657 $pusher.css({ 9658 'height': visible ? (repaintState.topBeforeFixed + 'px') : '0', 9659 'visibility': visible ? '' : 'hidden' 9660 }); 9661 } 9662 } 9663 9664 function repaint(repaintState) { 9665 var $html = $('html'); 9666 $html.css('overflow-anchor', 'none'); 9667 $window.clearTimeout(restoreOverflowAnchorTimeout); 9668 if (repaintState.isFixed) { 9669 // fix the element to the viewport, the same offset from the top. (this should stop it from actually moving anywhere) 9670 // transform translate3d forces ipad to load position fixed on scroll 9671 9672 $element.css({ 9673 position: 'fixed', 9674 top: repaintState.topWhenFixed,
9675 transform: 'translate3d(0,0,0)' 9676 }); 9677 9678 $element.addClass($attrs.lxStickyHeaderClass || 'lx-sticky-header'); 9679 9680 } else { 9681 // put the nav back where it was 9682 $element.css({ 9683 position: '', 9684 top: 0, 9685 transform: 'translate3d(0,0,0)' 9686 }); 9687 $element.removeClass($attrs.lxStickyHeaderClass || 'lx-sticky-header'); 9688 } 9689 9690 setPlaceholderVisibility(repaintState.isPlaceholderTopOutsideViewport || repaintState.isFixed, repaintState); 9691 9692 restoreOverflowAnchorTimeout = $window.setTimeout(function () { 9693 $html.css('overflow-anchor', ''); 9694 }, 100) 9695 } 9696 9697 function recalc() { 9698 var allPlaceholders = $('.lx-stick-to-top-placeholder').toArray(); 9699 var previousPlaceholders = allPlaceholders.slice(0, allPlaceholders.indexOf($placeholder.get(0))); 9700 var sumOfPreviousPlaceholderHeights = 0; 9701 angular.forEach(previousPlaceholders, function (el, index) { 9702 sumOfPreviousPlaceholderHeights += getElementHeightInclMargins($(el)); 9703 }); 9704 9705 //repaintState.isPlaceholderTopOutsideViewport = $placeholder.get(0).getBoundingClientRect().top < sumOfPreviousPlaceholderHeights; 9706 var placeHolderTop = $placeholder.get(0).getBoundingClientRect().top; 9707 var eleHeight = getElementHeightInclMargins($element); 9708 var distanceTravelled = eleHeight - BUFFER_DIST; 9709 9710 if (!$element.hasClass($attrs.lxStickyHeaderClass)) { 9711 repaintState.topBeforeFixed = distanceTravelled; 9712 } 9713 9714 if ($element.hasClass($attrs.lxStickyHeaderClass)) { 9715 distanceTravelled = repaintState.topBeforeFixed; 9716 } 9717 9718 repaintState.isPlaceholderTopOutsideViewport = -placeHolderTop > distanceTravelled; 9719 repaintState.isFixed = repaintState.isPlaceholderTopOutsideViewport; 9720 9721 repaintState.topWhenFixed = sumOfPreviousPlaceholderHeights; 9722 9723 if (repaintStateOverrides) { 9724 $.extend(repaintState, repaintStateOverrides); 9725 } 9726 9727 repaint(repaintState); 9728 } 9729 9730 function setRepaintStateOverrides(newRepaintStateOverrides) { 9731 if (newRepaintStateOverrides === null || typeof newRepaintStateOverrides === 'undefined') { 9732 repaintStateOverrides = undefined; 9733 } else { 9734 repaintStateOverrides = newRepaintStateOverrides; 9735 } 9736 recalc(); 9737 } 9738 9739 var exports = { 9740 setRepaintOverrides: setRepaintStateOverrides, 9741 clearRepaintOverrides: function () { setRepaintStateOverrides(null); } 9742 }; 9743 9744 var $placeholder; 9745 var $pusher; 9746 9747 function init() { 9748 repaintState = {}; 9749 9750 // publish API for availability to other components, e.g. secondary-nav
9751 $element.data('lxStickToTop', exports); 9752 9753 // put in a placeholder element to take up the space the initial element took up 9754 $placeholder = $('<div class="' + ($attrs.lxStickToTopPlaceholderClass || '') + ' lx-stick-to-top-placeholder"></div>'); 9755 $element.before($placeholder); 9756 if (($attrs.lxUsePusher || true) == true) { 9757 $pusher = $('<div class="lx-stick-to-top-pusher"></div>'); 9758 $element.after($pusher); 9759 } 9760 9761 var $window = $(window); 9762 $window.on('scroll', recalc); 9763 $window.on('resize', recalc); 9764 recalc(); 9765 } 9766 9767 init(); 9768 9769 $scope.$on('$destroy', function () { 9770 $placeholder.remove(); 9771 9772 var $window = $(window); 9773 $window.off('scroll', recalc); 9774 $window.off('resize', recalc); 9775 }); 9776 } 9777 } 9778}]); 9779; 9780 9781"use strict"; 9782angular.module('Lexus.Directives') 9783 .directive('lxNumberAnimator', [function () { 9784 return { 9785 scope: { 9786 source: "<ngModel", 9787 roundingModel: "@round" 9788 }, 9789 restrict: 'E', 9790 template: '{{animatedValue}}', 9791 link: function (scope, element, attrs) { 9792 scope.source = 0; 9793 scope.validRoundingModels = ["floor", "round", "ceiling"]; 9794 init(scope, element, attrs); 9795 }, 9796 }; 9797 9798 function init(scope, elem, attrs) { 9799 9800 //set/validate rounding - default to floor 9801 scope.roundingModel = scope.roundingModel || "floor"; 9802 if (scope.validRoundingModels.indexOf(scope.roundingModel) == -1) { 9803 var msg = "Invalid rounding model '" + scope.roundingModel + "' - value should be 'floor', 'round' or 'ceiling'"; 9804 console.error ? console.error(msg) : console.log("ERROR: " + msg); 9805 scope.roundingModel = "floor"; 9806 } 9807 9808 scope.animatedValue = 0; 9809 scope.interimValue = { value: 0 }; 9810 scope.$watch('source', function (newVal) { 9811 if (typeof newVal === 'number') { 9812 //scope.localValue = newVal; 9813 TweenLite.to(scope.interimValue, 1.0, { 9814 ease: Expo.easeOut, 9815 value: newVal, onUpdate: function () { 9816 var roundedValue; 9817 if (scope.roundingModel === "floor") { 9818 roundedValue = Math.floor(scope.interimValue.value); 9819 } else if (scope.roundingModel === "ceiling") { 9820 roundedValue = Math.ceil(scope.interimValue.value); 9821 } else { 9822 roundedValue = Math.round(scope.interimValue.value); 9823 } 9824 9825 scope.animatedValue = roundedValue.toLocaleString('en', { /*style: 'currency', currency: 'AUD',*/ useGrouping: true }); 9826 scope.$digest(); 9827 } 9828 }); 9829 } 9830 }); 9831 } 9832 9833 9834 }]); 9835; 9836(function () { 9837 9838 "use strict"; 9839 /* Directives */ 9840 angular.module('Lexus.Directives') 9841 .directive('lxRangeDealerLookup', RangeDealerLookupDirective); 9842 9843 RangeDealerLookupDirective.$inject = ['UserPreferencesService', 'DealersService']; 9844 9845 function RangeDealerLookupDirective(userPreferencesService, dealersService){ 9846 rangeDealerLookupController.$inject = ['$scope']; 9847 return { 9848 scope: true, 9849 restrict: 'A', 9850 controller: rangeDealerLookupController, 9851 controllerAs: 'rdl', 9852 bindToController: true, 9853 link: function (scope, element, attrs) { 9854 scope.rdl = {}; 9855 scope.rdl.data = {}; 9856 9857 scope.rdl.data.isDealerSite = (attrs.isDealerSite === 'true'); 9858 scope.rdl.data.dealerID = attrs.dealerId; 9859 scope.rdl.data.dealerState = attrs.dealerState; 9860 scope.rdl.data.dealerToShow = false; 9861 scope.rdl.data.isMultiBranch = (attrs.dealerIsMultiBranch === 'true'); 9862 scope.rdl.data.branchCode = attrs.dealerBranchCode; 9863 scope.rdl.data.serviceTypeToShow = attrs.serviceTypeToShow; 9864 9865 scope.init(); 9866 } 9867 }; 9868 9869 9870 9871 function rangeDealerLookupController($scope) { 9872 var rdl = this; 9873 9874 $scope.init = function () { 9875 $scope.ds = { 9876 loading: true 9877 }; 9878 9879 var dealerPreference = userPreferencesService.getLexusDealer(); 9880 $scope.rdl.data.hasPreferredDealer = (dealerPreference && dealerPreference.dealerID); 9881 9882 //Mainsite 9883 if (!$scope.rdl.data.isDealerSite && $scope.rdl.data.hasPreferredDealer) { 9884 $scope.rdl.data.dealerState = dealerPreference.dealerState; 9885 9886 var dealerDetails = dealersService.DeconstructCompositeID(dealerPreference.dealerID); 9887 9888 $scope.rdl.data.dealerID = dealerDetails.dealerID; 9889 $scope.rdl.data.dealerToShow = true; 9890 dealersService.setParam('dealerID', $scope.rdl.data.dealerID); 9891 dealersService.setParam('branchCode', $scope.rdl.data.branchCode || dealerDetails.branchCode); 9892 dealersService.GetDealerBranch(); 9893 } 9894 //Dealer Site, ex Brisbane 9895 else if ($scope.rdl.data.isDealerSite && !$scope.rdl.data.isMultiBranch) { 9896 dealersService.setParam('dealerID', $scope.rdl.data.dealerID); 9897 dealersService.setParam('dealerState', $scope.rdl.data.dealerState); 9898 dealersService.setParam('type', $scope.rdl.data.serviceTypeToShow); 9899 $scope.rdl.data.dealerToShow = true; 9900 9901 dealersService.GetDealerBranches(); 9902 } 9903 //All other Dealer Sites 9904 else if ($scope.rdl.data.isDealerSite && $scope.rdl.data.isMultiBranch) { 9905 dealersService.setParam('dealerID', $scope.rdl.data.dealerID); 9906 dealersService.setParam('type', $scope.rdl.data.serviceTypeToShow); 9907 $scope.rdl.data.dealerToShow = true; 9908 9909 dealersService.GetDealerBranches(); 9910 } 9911 } 9912 9913 $scope.checkServiceType = function (result) { 9914 var serviceString = ''; 9915 if (typeof result == 'string') { 9916 serviceString = result; 9917 } 9918 else if (typeof result == 'object' && result != null) { 9919 serviceString = result.serviceType; 9920 } 9921 9922 console.log('$scope.checkServiceType: ', serviceString); 9923 9924 return serviceString.toLowerCase().match(/^service$/) ? true : false; 9925 } 9926 9927 //Plural 9928 $scope.$on('dealer-search-results-received', function (event, data) { 9929 var dealers = data.Data; 9930 $scope.ds.results = dealers; 9931 $scope.ds.showChangeDealer = !$scope.rdl.data.isDealerSite; 9932 $scope.ds.loading = false; 9933 9934 }); 9935 9936 //Singular 9937 $scope.$on('dealer-search-result-received', function (event, data) { 9938 var dealers = []; 9939 dealers.push(data.Data); 9940 $scope.ds.results = dealers; 9941 $scope.ds.showChangeDealer = !$scope.rdl.data.isDealerSite; 9942 $scope.ds.loading = false; 9943 9944 }); 9945 } 9946 } 9947 9948}()); 9949 9950 9951; 9952(function (undefined) { 9953 9954 "use strict"; 9955 /* Directives */ 9956 angular.module('Lexus.Directives') 9957 .directive('lxRangeEngineVariant', RangeEngineVariantDirective); 9958 9959 RangeEngineVariantDirective.$inject = ['$location', '$rootScope', 'UserPreferencesService']; 9960 9961 function RangeEngineVariantDirective($location, $rootScope, UserPreferencesService) { 9962 9963 var engineVariants = null; 9964 var showSeats = false; 9965 9966 rangeEngineVariantController.$inject = ['$scope']; 9967 return { 9968 scope: true, 9969 restrict: 'A', 9970 controller: rangeEngineVariantController, 9971 controllerAs: 'revModal', 9972 link: link 9973 }; 9974 9975 function selectVariant(variantName) { 9976 var selectedIndex = null; 9977 for (var index = 0; index < engineVariants.length; index++) { 9978 if (engineVariants[index].engineVariant === variantName) { 9979 engineVariants[index].selected = true; 9980 selectedIndex = index; 9981 $rootScope.$broadcast('vehicle-preference-change', { 9982 model: engineVariants[index].model, 9983 engineVariant: engineVariants[index].engineVariant, 9984 grade: engineVariants[index].grade, 9985 }); 9986 } else { 9987 engineVariants[index].selected = false; 9988 } 9989 } 9990 9991 $rootScope.$broadcast('broadcast.lazyLoadRevalidate'); 9992 return selectedIndex; 9993 } 9994 9995 function link(scope, element, attrs) { 9996 engineVariants = angular.fromJson(attrs.engineVariants); 9997 showSeats = attrs.showSeats == 'true'; 9998 9999 for (var index = 0; index < engineVariants.length; index++) { 10000 engineVariants[index].selected = false; 10001 } 10002 10003 var dataVehicle = UserPreferencesService.getLexusVehicle($location.search()); 10004 10005 if (dataVehicle) { 10006 var foundVariant = null; 10007 var variantIndex = null; 10008 10009 for (var index = 0; index < engineVariants.length; index++) { 10010 if (engineVariants[index].engineVariant === dataVehicle.engineVariant) { 10011 foundVariant = dataVehicle.engineVariant; 10012 break; 10013 } 10014 } 10015 10016 if (foundVariant) { 10017 variantIndex = selectVariant(dataVehicle.engineVariant); 10018 } else { 10019 variantIndex = selectVariant(engineVariants[0].engineVariant); 10020 } 10021 } 10022 else { 10023 variantIndex = selectVariant(engineVariants[0].engineVariant); 10024 } 10025 10026 if (variantIndex != null) { 10027 scope.setFilterKey(engineVariants[variantIndex].seats, engineVariants[variantIndex].engineVariant); 10028 } 10029 } 10030 10031 function rangeEngineVariantController($scope) { 10032 var revModal = this; 10033 10034 $scope.select = selectVariant; 10035 10036 $scope.isSelected = function(variantName) { 10037 for (var index = 0; index < engineVariants.length; index++) { 10038 if (engineVariants[index].engineVariant === variantName) { 10039 return engineVariants[index].selected; 10040 } 10041 } 10042 } 10043 10044 $scope.setFilterKey = function (seats, variantName) { 10045 $scope.filterKey = seats; 10046 if (!$scope.isSelected(variantName)) { 10047 $scope.select(variantName); 10048 } 10049 } 10050 10051 $scope.displayTab = function (seats) { 10052 return seats == $scope.filterKey; 10053 } 10054 } 10055 } 10056}()); 10057 10058; 10059"use strict"; 10060angular.module('Lexus.Directives') 10061 .directive('lxLifestyleEngineVariant', function () { 10062 lxLifestyleEngineVariantController.$inject = ['$scope', '$attrs', '$filter', '$rootScope']; 10063 return { 10064 scope: true, 10065 restrict: 'A', 10066 controller: lxLifestyleEngineVariantController, 10067 controllerAs: 'lev',
10068 bindToController: true, 10069 link: function (scope, element, attrs, controller) { 10070 scope.lifestyleSlider = element.find('.lx-lifestyle-engine-variant__lifestyles'); 10071 scope.itemWidth = scope.lifestyleSlider.find('.lx-lifestyle-engine-variant__lifestyle-image').first().width(); 10072 10073 scope.lifestyleTabs = element.find('.lx-lifestyle-engine-variant__lifestyle-selector__inner'); 10074 scope.tabContainerWidth = scope.lifestyleTabs.first().width(); 10075 } 10076 } 10077 10078 function lxLifestyleEngineVariantController($scope, $attrs, $filter, $rootScope) { 10079 $scope.lifestyles = []; 10080 $scope.selectedLifestyleIndex = 0; 10081 10082 $scope.variants = []; 10083 $scope.selectedVariant = null; 10084 $scope.selectedVariantImage = null; 10085 $scope.selectedVariantDescription = null; 10086 10087 this.addLifeStyle = function (lifestyle) { 10088 $scope.lifestyles.push(lifestyle); 10089 if ($scope.selectedLifestyleIndex == 0) { 10090 broadcastLifestyle($scope.lifestyles[$scope.selectedLifestyleIndex]); 10091 } 10092 } 10093 10094 this.setSelectedLifestyle = function (lifestyleIndex) { 10095 if (lifestyleIndex >= 0 && lifestyleIndex < $scope.lifestyles.length) { 10096 scrollTabsToIndex(lifestyleIndex); 10097 scrollToIndex(lifestyleIndex); 10098 $scope.selectedLifestyleIndex = lifestyleIndex; 10099 var lifestyle = $scope.lifestyles[$scope.selectedLifestyleIndex]; 10100 broadcastLifestyle(lifestyle); 10101 } 10102 } 10103 10104 this.addVariant = function (variant) { 10105 $scope.variants.push(variant); 10106 if ($scope.selectedVariant == null) { 10107 setSelectedVariant(variant); 10108 } 10109 } 10110 10111 this.setSelectedVariant = function (variant) { 10112 var filtered = $filter("filter")($scope.variants, { name: variant }); 10113 var item = filtered != null && filtered.length > 0 ? filtered[0] : null; 10114 if (item != null) { 10115 setSelectedVariant(item); 10116 } 10117 } 10118 10119 this.prevLifestyle = function () { 10120 this.setSelectedLifestyle($scope.selectedLifestyleIndex - 1); 10121 } 10122 10123 this.nextLifestyle = function () { 10124 this.setSelectedLifestyle($scope.selectedLifestyleIndex + 1); 10125 } 10126 10127 $scope.$on("variant-selected", function (event, args) { 10128 var item = $scope.variants[args.selectedVariantIndex]; 10129 if (item != null) { 10130 setSelectedVariant(item); 10131 } 10132 }); 10133 10134 var _window = angular.element(window); 10135 10136 _window.resize(function () { 10137 $scope.itemWidth = $scope.lifestyleSlider.find('.lx-lifestyle-engine-variant__lifestyle-image').first().width(); 10138 $scope.tabContainerWidth = $scope.lifestyleTabs.first().width(); 10139 }); 10140 10141 function setSelectedVariant(variant) { 10142 $scope.selectedVariant = variant.name; 10143 $scope.selectedVariantDescription = variant.description; 10144 broadcastVehicle(); 10145 10146 var _size = 1200; 10147 if (_window.width() <= Lexus.Breakpoint.ExtraExtraSmall) { _size = Lexus.Breakpoint.ExtraExtraSmall; } 10148 else if (_window.width() <= Lexus.Breakpoint.ExtraSmall) { _size = Lexus.Breakpoint.ExtraSmall; } 10149 else if (_window.width() <= Lexus.Breakpoint.Small) { _size = Lexus.Breakpoint.Small; } 10150 10151 var resolvedImage = variant.image + '?q=95&w=' + _size; 10152 $scope.selectedVariantImage = resolvedImage; 10153 } 10154 10155 function scrollToIndex(lifestyleIndex) { 10156 var left = $scope.itemWidth * lifestyleIndex; 10157 TweenLite.to($scope.lifestyleSlider, 1, { scrollTo: { x: (left) }, ease: $scope.easingFunction }); 10158 } 10159 10160 function scrollTabsToIndex(lifestyleIndex) { 10161 var tabItems = $scope.lifestyleTabs.find('.lx-tabs__item'); 10162 var left = 0; 10163 if (lifestyleIndex > 0) { 10164 left = tabItems[lifestyleIndex].offsetLeft - ($scope.tabContainerWidth * Lexus.Tabs.CenterFactor); 10165 } 10166 TweenLite.to($scope.lifestyleTabs, 1, { scrollTo: { x: (left) }, ease: $scope.easingFunction }); 10167 } 10168 10169 function broadcastVehicle() { 10170 $rootScope.$broadcast('vehicle-preference-change', { 10171 model: 'UX',//get model 10172 engineVariant: $scope.selectedVariant, 10173 }); 10174 } 10175 10176 function broadcastLifestyle(lifestyle) { 10177 if (!lifestyle) 10178 return; 10179 10180 $rootScope.$broadcast('personalization-change', { 10181 lifestyle: { 10182 name: lifestyle.name, 10183 image: lifestyle.image, 10184 }, 10185 }); 10186 } 10187 } 10188 }) 10189 .directive('lxLifestyle', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 10190 return { 10191 scope: true, 10192 restrict: 'A', 10193 require: '^lxLifestyleEngineVariant',
10194 link: function (scope, element, attrs, lxLifestyleEngineVariantController) { 10195 lxLifestyleEngineVariantController.addLifeStyle(attrs); 10196 } 10197 } 10198 }]) 10199 .directive('lxVariant', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 10200 return { 10201 scope: true, 10202 restrict: 'A', 10203 require: '^lxLifestyleEngineVariant', 10204 link: function (scope, element, attrs, lxLifestyleEngineVariantController) { 10205 lxLifestyleEngineVariantController.addVariant(attrs); 10206 } 10207 } 10208 }]); 10209; 10210"use strict"; 10211/* Directives */ 10212angular.module('Lexus.Directives') 10213.directive('lxRangeExploreBodyTypeSelector', function () { 10214 exploreRangeBodyTypeSelectorController.$inject = ['$scope', '$window', '$rootScope']; 10215 return { 10216 scope: true, 10217 restrict: 'A', 10218 controller: exploreRangeBodyTypeSelectorController, 10219 controllerAs: 'erbts', 10220 bindToController: true, 10221 link: function (scope, element, attrs) { 10222 } 10223 }; 10224 10225 function exploreRangeBodyTypeSelectorController($scope, $window, $rootScope) { 10226 var erbts = this; 10227 10228 $scope.init = function () { 10229 $scope.erbts.bodyTypeSelectors = []; 10230 $scope.highlightBox(angular.element('.lx-explore-range__body-type-item:eq(0)')); 10231 } 10232 10233 $scope.addBodyType = function (index, bodyType) { 10234 $scope.erbts.bodyTypeSelectors[index] = {}; 10235 $scope.erbts.bodyTypeSelectors[index].bodyType = bodyType 10236 $scope.erbts.bodyTypeSelectors[index].active = (index == 0 ? true : false); 10237 } 10238 10239 $scope.switchActiveBodyType = function ($event, index) { 10240 $scope.highlightBox(angular.element($event.currentTarget)); 10241 10242 angular.forEach($scope.erbts.bodyTypeSelectors, function (value, key) { 10243 if (key == index) { 10244 value.active = true; 10245 $rootScope.$broadcast('filter-body-type', value.bodyType); 10246 } 10247 else { 10248 value.active = false; 10249 } 10250 }); 10251 } 10252 10253 $scope.highlightBox = function (target) { 10254 var myTarget = target; 10255 var left = myTarget.offset().left - myTarget.parent().offset().left; 10256 10257 angular.element('.lx-explore-range__body-type-box').css({ 'width': myTarget[0].clientWidth, 'transform': 'translate3d(' + left + 'px,0,0)' }); 10258 angular.element('.lx-explore-range__body-type-box').css({ 'opacity': 1 }); 10259 } 10260 10261 angular.element($window).bind('resize', function () { 10262 $scope.highlightBox(angular.element('.lx-explore-range__body-type-item.is-active')); 10263 }); 10264 10265 $rootScope.$on('set-body-type', function (event, args) { 10266 angular.forEach($scope.erbts.bodyTypeSelectors, function (value, key) { 10267 if (value.bodyType == args) { 10268 $scope.switchActiveBodyType(key); 10269 } 10270 }); 10271 10272 }); 10273 10274 } 10275 10276}) 10277.directive('lxRangeExploreHero', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 10278 exploreRangeController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location']; 10279 return { 10280 scope: true, 10281 restrict: 'A', 10282 controller: exploreRangeController, 10283 controllerAs: 'er', 10284 bindToController: true, 10285 link: function (scope, element, attrs, filter, http) { 10286 } 10287 }; 10288 10289 10290 function exploreRangeController($scope, $http, $filter, $timeout, $window, $interval, $location) { 10291 var er = this, 10292 _window = angular.element(window), 10293 _currentSize = 0, 10294 _newSize = 0, 10295 _sizeFilter = '', 10296 _panelBkg = angular.element('.lx-explore-range__image-panel').attr('data-background'); 10297 10298 $scope.resolvedImage = null; 10299
10300 function init() { 10301 updateBackgroundImage(); 10302 } 10303 10304 $rootScope.$on('change-active-vehicle', function (event, args) { 10305 $scope.er.activeVehicle = args; 10306 updateBackgroundImage(args.imageSrc); 10307 }); 10308 10309 function updateBackgroundImage(imageSrc) { 10310 10311 if (_window.width() <= Lexus.Breakpoint.ExtraExtraSmall) { _newSize = Lexus.Breakpoint.ExtraExtraSmall; } 10312 else if (_window.width() <= Lexus.Breakpoint.ExtraSmall) { _newSize = Lexus.Breakpoint.ExtraSmall; } 10313 else if (_window.width() <= Lexus.Breakpoint.Small) { _newSize = Lexus.Breakpoint.Small; } 10314 else { _newSize = Lexus.Breakpoint.Medium; } 10315 10316 if (_currentSize != _newSize) { 10317 _sizeFilter = '?q=95&w=' + _newSize; 10318 _currentSize = _newSize; 10319 if (_newSize <= Lexus.Breakpoint.Small) { 10320 _sizeFilter = ''; 10321 } 10322 } 10323 10324 if ($scope.resolvedImage != (imageSrc + _sizeFilter)) { 10325 if (_sizeFilter == '') { 10326 $scope.resolvedimage = null; 10327 } else { 10328 $scope.resolvedImage = imageSrc + _sizeFilter; 10329 } 10330 //console.log(' resolvedBackground: ', _sizeFilter, '\n imageSrc: ', imageSrc, '\n imageSrc + _sizeFilter: ',imageSrc + _sizeFilter, '\n $scope.resolvedImage: ', $scope.resolvedImage); 10331 } 10332 10333 } 10334 10335 _window.resize(function () {
10336 updateBackgroundImage($scope.er.activeVehicle.imageSrc); 10337 }); 10338 10339 10340 $scope.init = function () { 10341 $scope.er = { 10342 activeVehicle: { 10343 } 10344 }; 10345 } 10346 10347 } 10348}]) 10349.directive('lxRangeExploreSlider', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 10350 exploreRangeSliderController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope']; 10351 return { 10352 scope: true, 10353 restrict: 'A', 10354 controller: exploreRangeSliderController, 10355 controllerAs: 'ers', 10356 bindToController: true, 10357 link: function (scope, element, attrs, filter, http) { 10358 10359 $rootScope.$on('calculate-widths', function (event, args) { 10360 scope.carouselSlider = element; 10361 scope.activeMarker = element.find('.lx-explore-range__marker-js'); 10362 scope.$innerContainer = scope.carouselSlider.children().first('.lx-explore-range__scroll-container'); 10363 scope.itemWidth = scope.$innerContainer.find('.lx-explore-range__subpanel').first().width(); 10364 10365 scope.outerContainerWidth = scope.carouselSlider.width(); 10366 scope.maxScrollX = scope.$innerContainer.width() - scope.outerContainerWidth; 10367 10368 10369 //use native swipe scrolling for touch devices, If its a laptop with touch and wide screen assume they are using K&M 10370 if (!Modernizr.touchevents || angular.element($window).width() >= Lexus.Breakpoint.Medium) { 10371 scope.carouselSlider.mousemove(function (event) { scope.smoothScrollTo(event); }); 10372 scope.carouselSlider.mouseleave(function (event) { scope.smoothSnapToNearest(event); }); 10373 } 10374 10375 10376 angular.forEach(scope.$innerContainer.children('.lx-explore-range__subpanel'), function (value, key) { 10377 value.className = value.className; 10378 }); 10379 //scope.smoothSnapToNearest(event); 10380 }); 10381 10382 angular.element($window).bind('resize', function () { 10383 $rootScope.$broadcast('calculate-widths'); 10384 }); 10385 } 10386 } 10387 10388 10389 function exploreRangeSliderController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope) { 10390 var ers = this; 10391 10392 $scope.init = function (overscrollPadding, markerRadius) { 10393 $scope.overscrollPadding = overscrollPadding; 10394 $scope.markerRadius = markerRadius; 10395 $scope.carouselTweenTime = 1; 10396 $scope.markerTweenTime = 1; 10397 $scope.easingFunction = Power2.easeOut; 10398 $scope.sliderItemCollection = []; 10399 } 10400 10401 $scope.smoothScrollToIndex = function (index) { 10402 var left = $scope.itemWidth * index; 10403 left = left + $scope.overscrollPadding; 10404 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: (left) }, ease: $scope.easingFunction }); 10405 $rootScope.$broadcast('pause-smooth-scroll-to', ''); 10406 } 10407 10408 $rootScope.$on('pause-smooth-scroll-to', function (event, args) { 10409 $rootScope.pauseSmoothScrollTo = true; 10410 setTimeout(function () { 10411 $rootScope.pauseSmoothScrollTo = false; 10412 }, 1500); 10413 }); 10414 10415 $scope.smoothScrollTo = function (event) { 10416 if($rootScope.pauseSmoothScrollTo === true){ 10417 return; 10418 } 10419 var offsetX = $scope.carouselSlider.position().left; 10420 var posInPc = (event.clientX - offsetX) / $scope.outerContainerWidth; 10421 $scope.carouselPos = $scope.maxScrollX * posInPc; 10422 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: ($scope.carouselPos) }, ease: $scope.easingFunction }); 10423 } 10424 10425 $scope.smoothSnapToNearest = function (event) { 10426 var offset = $scope.overscrollPadding; 10427 var snapWidth = $scope.itemWidth; 10428 10429 var misalignment = ($scope.carouselPos % snapWidth) - offset; 10430 var previousSnapPoint = $scope.carouselPos - misalignment; 10431 var nextSnapPoint = $scope.carouselPos - misalignment + snapWidth; 10432 10433 if (misalignment === 0) { 10434 return; 10435 } else if (misalignment < (snapWidth / 2)) { 10436 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: previousSnapPoint }, ease: $scope.easingFunction }); 10437 } else { 10438 TweenLite.to($scope.carouselSlider, $scope.carouselTweenTime, { scrollTo: { x: nextSnapPoint }, ease: $scope.easingFunction }); 10439 } 10440 } 10441 10442 $scope.setMarkerPosition = function (failCount) { 10443 var i = failCount || 0; 10444 if (!$scope.activeMarker && i < 10) { 10445 setTimeout(function () { 10446 $scope.setMarkerPosition(i + 1); 10447 }, 100); 10448 return; 10449 } 10450 var newPosition = Math.round($scope.overscrollPadding + ($scope.carouselPos * $scope.itemWidth) + ($scope.itemWidth * 0.5) - $scope.markerRadius); 10451 $scope.activeMarker.css('left', newPosition + 'px'); 10452 //why? $scope.smoothScrollToIndex($scope.carouselPos); 10453 } 10454 10455 $scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) { 10456 $scope.sliderItemCollection[0].style = { "margin-left": $scope.overscrollPadding + "px" }; 10457 $scope.sliderItemCollection[$scope.sliderItemCollection.length - 1].style = { "margin-right": $scope.overscrollPadding + "px" }; 10458 $timeout(function () { $rootScope.$broadcast('calculate-widths') }, 100); 10459 $scope.setMarkerPosition(); 10460 }); 10461 10462 this.addSliderItem = function (data) { 10463 $scope.sliderItemCollection[data.index] = data; 10464 $scope.sliderItemCollection[data.index].disabled = false; 10465 $scope.sliderItemCollection[data.index].style = {}; 10466 if (data.init) { 10467 $scope.carouselPos = parseInt(data.index); 10468 $scope.sliderItemCollection[data.index].active = true; 10469 $timeout(function () { $rootScope.$broadcast('change-active-vehicle', data) }, 100); 10470 } 10471 else { 10472 $scope.sliderItemCollection[data.index].active = false; 10473 } 10474 } 10475 10476 $scope.changeActiveVehicleClick = function (index) { 10477 10478 if ($scope.sliderItemCollection[index].disabled) { 10479 $rootScope.$broadcast('set-body-type', 'all'); 10480 } 10481 10482 $scope.carouselPos = index; 10483 angular.forEach($scope.sliderItemCollection, function (value, key) { 10484 value.active = (key == index); 10485 }); 10486 $scope.setMarkerPosition(); 10487 $timeout(function () { $rootScope.$broadcast('change-active-vehicle', $scope.sliderItemCollection[index]) }, 100); 10488 10489 10490 10491 } 10492 10493 10494 10495 $rootScope.$on('filter-body-type', function (event, args) { 10496 var newActiveIndex = 0; 10497 var needtoApplyNewIndex = false; 10498 angular.forEach($scope.sliderItemCollection, function (value, key) { 10499 var isDisabled = !(args == 'all' || args == value.bodyType); 10500 value.disabled = isDisabled; 10501 if (isDisabled && value.active) { 10502 value.active = false; 10503 needtoApplyNewIndex = true; 10504 } 10505 }); 10506 if (needtoApplyNewIndex) { 10507 var keepGoing = true; 10508 angular.forEach($scope.sliderItemCollection, function (value, key) { 10509 if (keepGoing) { 10510 if (!value.disabled) { 10511 value.active = true; 10512 $scope.smoothScrollToIndex(key); 10513 keepGoing = false; 10514 $timeout(function () { 10515 $rootScope.$broadcast('change-active-vehicle', value); 10516 $scope.changeActiveVehicleClick(value.index); 10517 }, 100); 10518 } 10519 } 10520 }); 10521 } 10522 }); 10523 10524 10525 } 10526}]) 10527.directive('lxRangeExploreSliderItem', ['$window', '$timeout', '$filter', '$http', '$location', '$rootScope', function ($window, $timeout, $filter, $http, $location, $rootScope) { 10528 return { 10529 scope: true, 10530 restrict: 'AE', 10531 require: '^lxRangeExploreSlider', 10532 link: function (scope, element, attrs, exploreRangeSliderController) { 10533 exploreRangeSliderController.addSliderItem(attrs); 10534 } 10535 } 10536 10537}]); 10538; 10539(function (undefined) { 10540 "use strict"; 10541 /* Directives */ 10542 angular.module('Lexus.Directives')
10543 .directive('lxRangeTechData', RangeTechDataDirective); 10544 10545 RangeTechDataDirective.$inject = ['$http', '$filter', '$timeout', '$interval', 10546 '$location', '$rootScope', 'UserPreferencesService', 'API', '$sce', '$log']; 10547 10548 function RangeTechDataDirective($http, $filter, $timeout, $interval, $location, $rootScope, UserPreferencesService, API, $sce, $log) { 10549 rangeTechDataController.$inject = ['$scope']; 10550 return { 10551 scope: true, 10552 restrict: 'A', 10553 controller: rangeTechDataController, 10554 controllerAs: 'rtd', 10555 bindToController: true 10556 }; 10557 10558 function rangeTechDataController($scope) { 10559 var rtd = this; 10560 $scope.rtd.urlParameters = $location.search(); 10561 10562 rtd.apiService = API; 10563 10564 $scope.init = function () { 10565 $scope.rtd = $scope.rtd || {}; 10566 10567 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.rtd.urlParameters); 10568 $scope.rtd.data = { 10569 model: UserPreferencesService.getLexusVehicle().model ? UserPreferencesService.getLexusVehicle().model : null, 10570 grade: UserPreferencesService.getLexusVehicle() ? UserPreferencesService.getLexusVehicle().grade : null, 10571 engineVariant: null, 10572 featuresData: null, 10573 featuresByCategory: [] 10574 }; 10575 10576 $scope.rtd.data.engineVariants = []; 10577 10578 $scope.rtd.featuresByCategoryRendering = false; 10579 10580 if (dataVehicle) { 10581 $scope.rtd.data.engineVariant = dataVehicle.engineVariant; 10582 } 10583 10584 if ($scope.rtd.data.engineVariant) { 10585 updateVehicleSelection($scope.rtd.data.model, $scope.rtd.data.engineVariant, $scope.rtd.data.grade); 10586 } 10587 }; 10588 10589 $scope.loadLazyImages = function () { 10590 $rootScope.$broadcast('broadcast.lazyLoadRevalidate'); 10591 }; 10592 10593 $scope.getActiveClass = function (counter, variant, totalVariants) { 10594 10595 if (counter === 0) { 10596 $scope.defaultTab = variant; 10597 } 10598 10599 if ($scope.rtd.data.engineVariant === variant || !$scope.rtd.data.engineVariant && counter === 0) { 10600 $scope.defaultTab = variant; 10601 if ($scope.selectedTab === undefined) { 10602 $scope.updateVehicleSelectionIndex(counter, true); 10603 } 10604 $scope.selectedTab = counter; 10605 return 'active'; 10606 } 10607 10608 if (counter === totalVariants - 1 && $scope.selectedTab === undefined) { 10609 $("#" + $scope.defaultTab.replace(" ", "")).addClass("active"); 10610 10611 $scope.rtd.data.engineVariant = $scope.defaultTab; 10612 10613 $scope.selectedTab = 0; 10614 //update the cookie to default tab 10615 $scope.updateVehicleSelectionIndex(0, true); 10616 } 10617 10618 return ''; 10619 }; 10620 10621 function updateVehicleSelection(model, engineVariant, grade) { 10622 10623 $scope.rtd.data.engineVariant = engineVariant; 10624 10625 $rootScope.$broadcast('vehicle-preference-change', { 10626 model: model, 10627 grade: grade, 10628 engineVariant: engineVariant 10629 }); 10630 10631 fetchTechDataDetails(); 10632 } 10633 10634 $scope.updateVehicleSelectionIndex = function (index) { 10635 10636 updateVehicleSelection($scope.rtd.data.engineVariants[index].model, $scope.rtd.data.engineVariants[index].engineVariant, $scope.rtd.data.engineVariants[index].grade); 10637 }; 10638 10639 $scope.addEngineVariant = function (index, model, engineVariant, grade) { 10640 $scope.rtd.data.engineVariants[index] = { 'model': model, 'engineVariant': engineVariant, 'grade': grade }; 10641 }; 10642 10643 $scope.findValueByKey = function (grade, feature) { 10644 if (feature.specs) { 10645 return feature.specs[grade]; 10646 } 10647 }; 10648
10649 function fetchTechDataDetails() { 10650 $scope.rtd.featuresByCategoryLoading = true; 10651 10652 API.get($filter('formatArgs')(Lexus.API.Lookup.RangeTechDataFeatures, [ 10653 Lexus.ID.Site, 10654 $scope.rtd.data.engineVariant 10655 ])) 10656 .then(function (data) { 10657 if (!data) { 10658 return; 10659 } 10660 10661 $scope.rtd.featuresByCategoryRendering = true; 10662 $timeout(function () { 10663 10664 $scope.rtd.data.featuresByCategory = data.data; 10665 $scope.rtd.featuresByCategoryRendering = false; 10666 }, 1); 10667 10668 $rootScope.$broadcast('refresh-gtm', 'Tech Data'); 10669 10670 $scope.rtd.featuresByCategoryLoading = false; 10671 }, function (error) { 10672 $log.error(error); 10673 $scope.rtd.featuresByCategoryLoading = false; 10674 }); 10675 }; 10676 } 10677 } 10678 10679}()); 10680 10681 10682 10683; 10684"use strict"; 10685/* Directives */ 10686angular.module('Lexus.Directives') 10687.directive('lxRepairerLookup', ['$rootScope', 'RepairersService', function () { 10688 RepairerLookupController.$inject = ['$scope', '$rootScope', '$http', 'RepairersService', 'AddressSuggestService', 'UserPreferencesService']; 10689 return { 10690 scope: true, 10691 restrict: 'A', 10692 controller: RepairerLookupController, 10693 controllerAs: 'dlc', 10694 bindToController: true, 10695 link: function (scope, element, attrs) { 10696 10697 } 10698 }; 10699 10700 function RepairerLookupController($scope, $rootScope, $http, RepairersService, AddressSuggestService) { 10701 var dlc = this; 10702 10703 $scope.init = function () { 10704 $scope.ds = { 10705 state: 'nsw', 10706 results: [], 10707 loading: false 10708 }; 10709 $scope.repairerSearch(); 10710 } 10711 10712 $scope.repairerInit = function () { 10713 10714 } 10715 10716 $scope.repairerSearch = function () { 10717 $scope.ds.loading = true; 10718 RepairersService.setParam('state', $scope.ds.state); //Dummy Implementation needs to be changed 10719 RepairersService.GetResults(); 10720 } 10721 10722 $scope.$on('repairers-search-results-received', function (event, data) { 10723 $scope.ds.results = data.Data; 10724 $scope.ds.loading = false; 10725 }); 10726 10727 10728 10729 } 10730 10731}]); 10732; 10733"use strict"; 10734/* Directives */ 10735angular.module('Lexus.Directives') 10736.directive('lxResponsiveSet', [function () { 10737 responsiveSetController.$inject = ['$scope', '$window']; 10738 return { 10739 scope: true, 10740 restrict: 'A', 10741 controller: responsiveSetController, 10742 controllerAs: 'rs', 10743 bindToController: true, 10744 link: function (scope, element, attrs) { 10745 } 10746 }; 10747 10748 10749 function responsiveSetController($scope, $window) { 10750 var rs = this; 10751 rs.breakpoint = Lexus.Breakpoint.Small; 10752 10753 function responsiveSet(type, breakPoint, set) { 10754 function isMobile() { 10755 return (breakPoint >= window.innerWidth); 10756 }; 10757 10758 if (isMobile() && type === 'mobile') { 10759 return set; 10760 } 10761 if (!isMobile() && type === 'desktop') { 10762 return set; 10763 } 10764 10765 return ''; 10766 } 10767 10768 $scope.desktopSet = function (set) { 10769 return responsiveSet('desktop', rs.breakpoint, set); 10770 }; 10771 10772 window.addEventListener('resize', function () { 10773 10774 setTimeout(function () { 10775 $scope.$digest(); 10776 }, 50); 10777 }); 10778 } 10779}]); 10780; 10781(function () { 10782 10783 angular.module('Lexus.Directives') 10784 .directive("lxUnsubscribeQuestion", UnsubscribeQuestionDirective); 10785 10786 function UnsubscribeQuestionDirective() { 10787 10788 return { 10789 replace: true, 10790 scope: { 10791 name: "@", 10792 label: "@", 10793 description: "@", 10794 ngModel: "=" 10795 }, 10796 template: '<div class="lx-form-text-label lx-form-unsubscribe" for="{{name}}">' + 10797 '<input class="lx-form-checkbox" type="checkbox" id="{{name}}" name="{{name}}" ng-model="ngModel"/>' + 10798 '<label class="lx-form-checkbox-label lx-form-unsubscribe__label" for="{{name}}" data-gtm-label="{{label}}"> {{label}}</label>' + 10799 '<p class="lx-form-unsubscribe__explanation">{{description}}</p>' + 10800 '</div>' 10801 }; 10802 } 10803 10804}());; 10805(function () { 10806 10807 angular.module('Lexus.Directives') 10808 .directive('lxFormsUnsubscribeMarketingEmails', formsUnsubscribeMarketingEmailsDirective); 10809 10810 formsUnsubscribeMarketingEmailsDirective.$inject = ["EloquaService", "$http", "$filter", "FormsService", "$location", "$rootScope"]; 10811 10812 function formsUnsubscribeMarketingEmailsDirective(EloquaService, $http, $filter, formsService, $location, $rootScope) { 10813 formsUnsubscribeMarketingEmailsController.$inject = ['$scope']; 10814 return { 10815 scope: true, 10816 restrict: 'A', 10817 controllerAs: 'ffc', 10818 bindToController: true, 10819 controller: formsUnsubscribeMarketingEmailsController, 10820 link: link 10821 }; 10822 10823 function link(scope, element, attrs, filter, http) { 10824 scope.successContent = element.find('.lx-form-success'); 10825 scope.failureContent = element.find('.lx-form-failure'); 10826 10827 scope.ffc.form = { 10828 submitting: false, 10829 completed: false, 10830 failed: false 10831 }; 10832 10833 scope.ffc.formData = JSON.parse(attrs['formData']); 10834 scope.ffc.fullUnsubscribe = (attrs["fullUnsubscribe"] === "true"); 10835 } 10836 10837 function formsUnsubscribeMarketingEmailsController($scope) { 10838 10839 var ffc = this; 10840 10841 $scope.$on('submit-unsubscribe-marketing-emails-form', function () { 10842 10843 EloquaService.attachEloquaFields(ffc.formData); 10844 10845 var params = $location.search(); 10846 10847 ffc.formData.ename = params.ename; 10848 ffc.formData.emailAddress = params.email; 10849 10850 ffc.form.submitting = true; 10851 10852 var formSubmission = ''; 10853 10854 if (ffc.fullUnsubscribe) { 10855 formSubmission = Lexus.API.FormSubmission.UnsubscribeMarketingEmailsOwner; 10856 } 10857 else { 10858 formSubmission = Lexus.API.FormSubmission.UnsubscribeMarketingEmailProspect; 10859 } 10860 10861 var url = $filter('formatArgs')(formSubmission, [Lexus.ID.Site]); 10862 10863 $http({ 10864 method: 'POST', 10865 url: url, 10866 data: ffc.formData 10867 }) 10868 .then(function success(response) { 10869 if (response.data.Status == "Success") { 10870 ffc.form.completed = true; 10871 ffc.form.failed = false; 10872 ffc.form.submitting = false; 10873 $rootScope.$broadcast('gtm-form-success', 'Unsubscribe Marketing Emails'); 10874 formsService.ShowResult($scope.successContent[0]); 10875 } 10876 else { 10877 submissionFail(response.data); 10878 } 10879 }, function error(response) { 10880 submissionFail(response.data); 10881 }) 10882 .finally(function () { 10883 $rootScope.$broadcast('form-result'); 10884 }); 10885 }); 10886 10887 function submissionFail(data) { 10888 ffc.form.failed = true; 10889 ffc.form.submitting = false; 10890 ffc.form.completed = true; 10891 10892 formsService.ShowResult($scope.failureContent[0]); 10893 } 10894 } 10895 10896 } 10897 10898 10899}());; 10900//Only allowed to watch rangeBuildPrice.collections.enhancementpacks[]
10901//Only allowed to emit the enhancement pack selected 10902(function (undefined) { 10903 10904 "use strict"; 10905 /* Directives */ 10906 angular.module('Lexus.Directives') 10907 .directive('lxBuildPriceEnhancementPack', [function () { 10908 buildPriceEnhancementPackController.$inject = ['$scope', '$q', 'VehicleService', 'BuildPriceService', 'BuildPriceAPIService', 'PricingService', '$log', '$timeout']; 10909 return { 10910 scope: { 10911 engineVariant: '<variant', 10912 grade: '<grade', 10913 enhancementPack: '<enhancement', 10914 trim: '<trim', 10915 colour: '<colour', 10916 paintId: '<paintId', 10917 specifics: '<specifics', 10918 postCode: '<postcode', 10919 pricingZone: '<pricingZone', 10920 vehicleImage: '<vehicleImage', 10921 disableDiffPricing: '<disableDiffPricing', 10922 enablePricingByZone: '<enablePricingZone', 10923 }, 10924 restrict: 'A', 10925 controller: buildPriceEnhancementPackController, 10926 controllerAs: 'bpEnPack', 10927 bindToController: true, 10928 transclude: true, 10929 link: function (scope, element, attrs, ctrl, transclude) { 10930 transclude(scope, function (clone) { 10931 element.append(clone); 10932 }); 10933 scope.init(); 10934 } 10935 } 10936 10937 10938 function buildPriceEnhancementPackController($scope, $q, VehicleService, BuildPriceService, BuildPriceAPIService, PricingService, $log, $timeout) { 10939 var bpEnPack = this; 10940 bpEnPack.variants = []; 10941 10942 bpEnPack.setSelection = setSelection; 10943 bpEnPack.isSelected = isSelected; 10944 bpEnPack.isNotSelected = isNotSelected; 10945 bpEnPack.previousPage = previousPage; 10946 bpEnPack.nextPage = nextPage; 10947 //bpEnPack.image = ''; 10948 bpEnPack.gradeObj = null; 10949 bpEnPack.pricingSuccess = true; 10950 bpEnPack.holdPricingCalls = true; 10951 10952 $scope.BuildPriceService = BuildPriceService; 10953 10954 $scope.$on(BuildPriceService.events.postcodeChanged, function (event, data) { 10955 getDifferentialPrices(); 10956 }); 10957 10958 $scope.$on(BuildPriceService.events.holdPricingCallsRelay, function (event, data) { 10959 //console.info("bpEnPack received holdPricingCalls " + data) 10960 bpEnPack.holdPricingCalls = data; 10961 }); 10962 10963 $scope.$watch('bpEnPack.specifics', $scope.BuildPriceService.watchDebounce(function (newValue, oldValue) { 10964 if (newValue != null) { 10965 calculateDifferentialPrices(); 10966 } 10967 }, 50), true); 10968 10969 $scope.$watch('bpEnPack.grade', $scope.BuildPriceService.watchDebounce(function (newValue, oldValue) { 10970 if (newValue != null) { 10971 console.info("%c 2. buildPriceEnhancementPackController received GRADE: ", "color: mediumvioletred;", newValue + " (with VARIANT: " + bpEnPack.engineVariant + ")", bpEnPack); 10972 getSelectedGrade(bpEnPack.engineVariant, newValue); 10973 } 10974 }, 50), true); 10975 10976 function getSelectedGrade(engineVariantName, gradeName, clearDownstream) { 10977 var engineVariant = BuildPriceAPIService.findEngineVariantInVehicleData(engineVariantName); 10978 if (engineVariant) { 10979 10980 var grade = engineVariant.grades.find(function (grade) { 10981 return grade.uriName == gradeName; 10982 }); 10983 10984 if (grade && grade.id) { 10985 bpEnPack.gradeObj = grade; //Set it so it can be accessed by the promise response 10986 10987 bpEnPack.variants = []; 10988 10989 BuildPriceAPIService.getVariants(bpEnPack.engineVariant, grade.id, enhancementPacksReceived); 10990 } else { 10991 console.error("buildPriceEnhancementPackController cannot load enhancement packs for EngineVariant: " + bpEnPack.engineVariant + " + Grade: " + bpEnPack.grade); 10992 } 10993 } 10994 } 10995 10996 function enhancementPacksReceived(response) { 10997 bpEnPack.variants = response; 10998 10999 getDifferentialPrices(); 11000 11001 $scope.$emit(BuildPriceService.events.enhancementPacksReceived, bpEnPack.enhancementPack); 11002 getPackSelectionInGrade(); 11003 } 11004 11005 function getDifferentialPrices() { 11006 if (bpEnPack.postCode) { 11007 for (var index = 0; index < bpEnPack.variants.length; index++) { 11008 bpEnPack.variants[index].showSpinner = true; 11009 } 11010 if (!bpEnPack.disableDiffPricing) { 11011 //console.info("bpEnPack waiting for holdPricingCalls to clear"); 11012 BuildPriceService.waitFor.call($scope, 'bpEnPack.holdPricingCalls', BuildPriceService.waitCondition.ISSTRICTLYFALSE). 11013 then(function success(value) { 11014 //console.info("holdPricingCalls cleared in bpEnPack"); 11015 getPrices().then(calculateDifferentialPrices, ajaxFailure); 11016 }); 11017 } 11018 } 11019 } 11020 11021 function getPrices() { 11022 var promises = []; 11023 11024 for (var index = 0; index < bpEnPack.variants.length; index++) { 11025 promises.push(getPromise(bpEnPack.variants[index])); 11026 } 11027 11028 return $q.all(promises).then(function (responses) { 11029 bpEnPack.pricingSuccess = true; 11030 11031 for (var returnIndex = 0; returnIndex < responses.length; returnIndex++) { 11032 //console.log("bpEnPack -> responses[returnIndex].data.driveAway: ", responses[returnIndex].data.driveAway); 11033 var resp = responses[returnIndex]; 11034 if (resp.status != "Success") { 11035 bpEnPack.pricingSuccess = false; 11036 } else if (resp.data && resp.data.driveAway) { 11037 bpEnPack.variants[returnIndex].driveAwayPrice = parseFloat(resp.data.driveAway); 11038 } else { 11039 //success but no price 11040 } 11041 } 11042 pricingReport(); 11043 11044 }, ajaxPriceFailure); 11045 11046 function getPromise(variant) { 11047 PricingService.setParam("enablePricingByZone", bpEnPack.enablePricingByZone); 11048 return PricingService.driveAwayByEnhancementPack(bpEnPack.gradeObj.id, variant.mdmid, bpEnPack.postCode, bpEnPack.pricingZone); 11049 } 11050 } 11051 11052 function calculateDifferentialPrices() { 11053 11054 var selectedVariant = BuildPriceAPIService.getVariantByName(bpEnPack.engineVariant, bpEnPack.gradeObj.id, bpEnPack.enhancementPack); 11055 if (!bpEnPack.variants) { 11056 return; 11057 } 11058 11059 for (var index = 0; index < bpEnPack.variants.length; index++) { 11060 if (!isSelected(bpEnPack.variants[index]) && selectedVariant) { 11061 bpEnPack.variants[index].differentialPrice = bpEnPack.variants[index].driveAwayPrice - selectedVariant.driveAwayPrice; 11062 } 11063 else { 11064 bpEnPack.variants[index].differentialPrice = null; 11065 } 11066 11067 bpEnPack.variants[index].showSpinner = false; 11068 } 11069 } 11070 11071 function ajaxFailure(data) { 11072 console.error('BuildPrice AjaxFailure -> EnPack: ', data); 11073 11074 $scope.$emit('open-modal-window', { 11075 content: 'Oops, something went wrong while obtaining the details. If the problem persists, please contact your dealer directly.', 11076 wrapper: ['<p class="lx-modal__paragraph">', '</p>'] 11077 }); 11078 } 11079 11080 function ajaxPriceFailure(data) { 11081 console.error('BuildPrice AjaxPriceFailure -> EnPack: ', data); 11082 11083 //$scope.$emit('open-modal-window', { 11084 // content: 'Oops, something went wrong while obtaining the details. If the problem persists, please contact your dealer directly.', 11085 // wrapper: ['<p class="lx-modal__paragraph">', '</p>'] 11086 //}); 11087 } 11088 11089 function pricingReport() { 11090 if (bpEnPack.pricingSuccess) { 11091 angular.element('.lx-build-price-enhancement-pack').removeClass('pricing-error'); 11092 } else { 11093 console.log("bpGrade pricingSuccess: ", bpEnPack.pricingSuccess); 11094 angular.element('.lx-build-price-enhancement-pack').addClass('pricing-error'); 11095 } 11096 } 11097 11098 function getPackSelectionInGrade() { 11099 //check if existing selection is in valid set, if it is, don't change the selection 11100 11101 var selectionValid = false; 11102 11103 if (bpEnPack.enhancementPack) { 11104 if (bpEnPack.variants.find(function (ep) { 11105 return ep.uriName === bpEnPack.enhancementPack; 11106 }) || bpEnPack.variants.find(function (ep) { 11107 return ep.enhancementPackName === bpEnPack.enhancementPack; 11108 })) { 11109 selectionValid = true; 11110 } 11111 } 11112 11113 var selectionNotNull = bpEnPack.enhancementPack != null; 11114 11115 if (bpEnPack.variants.length > 0 && !selectionValid) { 11116 var defaultSelection = getDefaultEnhancementPack(); 11117 if (selectionNotNull) { 11118 //trigger invalid selection error 11119 var invalidSelectionData = { 11120 controllerName: $scope.BuildPriceService.stepIds.ENHANCEMENT_PACK, 11121 $scope: $scope, 11122 defaultValue: defaultSelection.uriName, 11123 invalidValue: bpEnPack.enhancementPack, 11124 /* 11125 * Once we have a user-initiated selection process implement these variables 11126 userInitiated: true/false, 11127 clearDownstreamFrom: userInitiated ? 3 : null 11128 */ 11129 }; 11130 $scope.BuildPriceService.emitInvalidSelection(invalidSelectionData) 11131 } 11132 11133 bpEnPack.enhancementPack = defaultSelection.uriName; 11134 } 11135 11136 $scope.$emit(BuildPriceService.events.enhancementPackSelected, bpEnPack.enhancementPack); 11137 11138 bpEnPack.currentPage = setCurrentPage(indexOfPack(bpEnPack.enhancementPack)); 11139 } 11140 11141 function getDefaultEnhancementPack() { 11142 return bpEnPack.variants.find(function (variant) { 11143 return variant.isBaseVariant == true; 11144 }); 11145 } 11146 11147 function getSelectedEnhancementPack() { 11148 return (bpEnPack.variants || []).find(function (item) { 11149 return item.uriName == bpEnPack.enhancementPack; 11150 }); 11151 } 11152 11153 function setSelection(pack) { 11154 11155 var packName = (bpEnPack.enhancementPack === pack.uriName) ? getDefaultEnhancementPack().uriName : pack.uriName; 11156 11157 bpEnPack.packIndex = (indexOfPack(packName)) ? indexOfPack(packName) : 0; 11158 bpEnPack.currentPage = setCurrentPage(bpEnPack.packIndex, true); 11159 if (bpEnPack.enhancementPack != packName) { 11160 11161 $scope.$emit(BuildPriceService.events.userSelection, 'Enhancement Pack selected'); 11162 11163 emitPackSelection(packName, true, true, bpEnPack.trim, bpEnPack.colour); 11164 } 11165 return false; 11166 } 11167 11168 function isSelected(pack) { 11169 return bpEnPack.enhancementPack === pack.uriName; 11170 } 11171 11172 function isNotSelected(pack) { 11173 var notSelected = false; 11174 11175 if (getDefaultEnhancementPack()) { 11176 if (bpEnPack.enhancementPack != getDefaultEnhancementPack().uriName) { 11177 if (bpEnPack.enhancementPack != pack.uriName) { 11178 notSelected = true; 11179 } 11180 } 11181 } 11182 11183 return notSelected; 11184 } 11185 11186 function isCurrentStep(current) { 11187 var current = current != null ? current : false; 11188 bpEnPack.isCurrentStep = current; 11189 } 11190 11191 function indexOfPack(packName) { 11192 var packs = bpEnPack.variants;
11193 for (var i = 0; i < packs.length; i++) { 11194 if (packs[i].uriName === packName) { 11195 return i; 11196 } 11197 } 11198 $log.error('Enhancement Pack ' + packName + ' not found'); 11199 } 11200 11201 function setCurrentPage(packIndex, user) { 11202 var user = user != null ? user : false; 11203 var page = (user) ? bpEnPack.currentPage : 0; 11204 if (packIndex != 0) { 11205 page = packIndex - 2; 11206 } 11207 return page; 11208 } 11209 11210 function previousPage() { 11211 if (bpEnPack.currentPage > 0) bpEnPack.currentPage--; 11212 } 11213 11214 function nextPage() { 11215 if (bpEnPack.currentPage <= ((bpEnPack.variants.length - 2) - bpEnPack.currentPage)) bpEnPack.currentPage++; 11216 } 11217 11218 function emitPackSelection(packName, clearDownstream, userInitiated, revertTrim, revertColour) { 11219 var data = { 11220 clearDownstream: clearDownstream, 11221 selection: packName, 11222 userInitiated: userInitiated, 11223 revertTrim: revertTrim, 11224 revertColour: revertColour 11225 11226 }; 11227 $scope.$emit(BuildPriceService.events.enhancementPackSelected, data); 11228 } 11229 11230 //#region EVENTS 11231 $scope.$on(BuildPriceService.events.pageNavigationBroadcast, function (e, target) { 11232 var isCurrent = target.id == 'enhancement'; 11233 bpEnPack.isCurrentStep = isCurrent; 11234 11235 // If on phone scroll to currently selected enhancement pack. 11236 if (isCurrent && indexOfPack(bpEnPack.enhancementPack) != 0 && window.matchMedia("(max-width: 767px)").matches) { 11237 setTimeout(function () { 11238 window.scrollTo(0, angular.element('.' + bpEnPack.enhancementPack.replace(/ /g, ''))[0].offsetTop + 250); 11239 }); 11240 } 11241 }); 11242 11243 $scope.$on(BuildPriceService.events.threeSixtyLoad, function (event, data) { 11244 console.info("%c buildPriceEnhancementPackController received threeSixtyLoad: ", "color: mediumvioletred;", data); 11245 }); 11246 11247 $scope.init = function () { 11248 } 11249 } 11250 }]); 11251 11252}());; 11253(function(undefined) { 11254 'use strict'; 11255 11256 /* Directives */ 11257 angular.module('Lexus.Directives').directive('lxBuildPriceExterior', [ 11258 function() { 11259 buildPriceExteriorController.$inject = [ 11260 '$scope', 11261 '$timeout', 11262 '$element', 11263 'BuildPriceService', 11264 'BuildPriceAPIService', 11265 'ViewportService' 11266 ]; 11267 11268 return { 11269 scope: { 11270 engineVariant: '<variant', 11271 trim: '<trim', 11272 colour: '<colour' 11273 }, 11274 restrict: 'A', 11275 controller: buildPriceExteriorController, 11276 controllerAs: 'bpExterior', 11277 template: '<div data-ng-transclude></div>', 11278 bindToController: true, 11279 transclude: true, 11280 require: '^lxBuildPricePaintTrim', 11281 link: function(scope, element, attrs, ctrl, transclude) { 11282 scope.loadingExterior = true; 11283 ctrl.registerExterior(scope.bpExterior); 11284 } 11285 }; 11286 11287 function buildPriceExteriorController( 11288 $scope, 11289 $timeout, 11290 $element, 11291 BuildPriceService, 11292 BuildPriceAPIService, 11293 ViewportService 11294 ) { 11295 var bpExterior = this; 11296 11297 bpExterior.loadExterior = function(data) { 11298 $scope.loadingExterior = true; 11299 $scope.$emit(BuildPriceService.events.threeSixtyLoad, data); 11300 loadImages(data.gradeId, data.variantId, data.trimId, data.materialCode); 11301 }; 11302 11303 $scope.$on('bp-user-selection', function(event) { 11304 console.info("%c 3. buildPriceExteriorController 'bp-user-selection': ", 'color: blue; ', event); 11305 }); 11306 11307 function loadImages(gradeId, variantId, trimId, materialCode) { 11308 BuildPriceAPIService.getExteriorImages( 11309 bpExterior.engineVariant, 11310 gradeId, 11311 variantId, 11312 trimId, 11313 materialCode, 11314 function(images) { 11315 var reelElement = $($element) 11316 .find('img') 11317 .first(); 11318 initReel(reelElement, images); 11319 $scope.$emit(BuildPriceService.events.threeSixtyLoaded); 11320 } 11321 ); 11322 $scope.$emit(BuildPriceService.events.holdPricingCalls, false); 11323 }; 11324 11325 function initReel($element, images) { 11326 console.log('is loading reel'); 11327 var bestFrame = 18; 11328 11329 images = ViewportService.isDesktop() 11330 ? images.threeSixtyImagesDesktop 11331 : images.threeSixtyImagesMobile; 11332 11333 // Prevent image flickering back to old one as Reel performs teardown 11334 if ($element.reel('backup')) { 11335 $element.reel('backup').attr.src = $element.src; 11336 } 11337 11338 // Preserve angle if reel already exists 11339 if ($element.reel('frame')) { 11340 bestFrame = $element.reel('frame'); 11341 } 11342 11343 $element.unreel(); 11344 $element 11345 .reel({ 11346 opening: 0, 11347 speed: 0, 11348 images: images, 11349 frame: bestFrame, 11350 frames: images.length, 11351 laziness: 1, // don't "underclock" mobile framerate 11352 scrollable: true, 11353 wheelable: false 11354 }) 11355 .on('loaded', function(ev) { 11356 if ($scope.loadingExterior) { 11357 $scope.$apply(function() { 11358 $scope.loadingExterior = false; 11359 }); 11360 } 11361 }) 11362 .on('pan', function() { 11363 if (bpExterior.reelPanTimeout) { 11364 $timeout.cancel(bpExterior.reelPanTimeout); 11365 } 11366 11367 bpExterior.reelPanTimeout = $timeout(function() { 11368 $scope.$emit(BuildPriceService.events.gtmEvent, { source: '360' });
11369 }, 50); // Don't bother showing "loading" for <100ms 11370 }); 11371 }; 11372 } 11373 } 11374 ]); 11375})(); 11376; 11377(function (undefined) { 11378 11379 "use strict"; 11380 11381 angular.module("Lexus.Directives") 11382 .directive("buildPriceGradeFeature", BuildPriceGradeFeatureDirective); 11383 11384 function BuildPriceGradeFeatureDirective() { 11385 return { 11386 scope: { 11387 expression: "=" 11388 }, 11389 restrict: "E", 11390 replace: false, 11391 template: '<span class="variant-feature" ng-bind-html="expression"></span><br />' 11392 }; 11393 } 11394 11395})();; 11396//Only Allowed to watch 11397//BuildPriceAPIService.data[ct200h].grades 11398//Only allowed to emit the grade selected 11399(function (undefined) { 11400 11401 "use strict"; 11402 /* Directives */ 11403 angular.module('Lexus.Directives') 11404 .directive('lxBuildPriceGrade', [function () { 11405 BuildPriceGradeController.$inject = ['$scope', 'PricingService', '$q', 'VehicleService', 'BuildPriceService', 'BuildPriceAPIService']; 11406 return { 11407 scope: {}, 11408 restrict: 'A', 11409 controller: BuildPriceGradeController, 11410 controllerAs: 'bpGrade', 11411 bindToController: { 11412 engineVariant: '<variant', 11413 grade: '<grade', 11414 enhancementPack: '<enhancement', 11415 trim: '<trim', 11416 colour: '<colour', 11417 postCode: '<postcode', 11418 pricingZone: '<pricingZone', 11419 specifics: '<specifics', 11420 disableDiffPricing: '<disableDiffPricing', 11421 enablePricingByZone: '<enablePricingZone', 11422 }, 11423 transclude: true, 11424 link: function (scope, element, attrs, ctrl, transclude) { 11425 transclude(scope, function (clone) { 11426 element.append(clone); 11427 }); 11428 scope.init(); 11429 } 11430 } 11431 11432 11433 11434 11435 function BuildPriceGradeController($scope, PricingService, $q, VehicleService, BuildPriceService, BuildPriceAPIService) { 11436 var bpGrade = this; 11437 11438 //bpGrade.setSelection = setSelection; 11439 bpGrade.getPreviousGrade = getPreviousGrade; 11440 bpGrade.getNextGrade = getNextGrade; 11441 //bpGrade.BuildPriceService = BuildPriceService; 11442 //bpGrade.BuildPriceAPIService = BuildPriceAPIService; 11443 bpGrade.isSelected = isSelected; 11444 bpGrade.pricingSuccess = true; 11445 bpGrade.holdPricingCalls = true; 11446 11447 $scope.bpGrade.setSelection = function (grade) { 11448 bpGrade.gradeIndex = indexOfGrade(grade.name); 11449 11450 $scope.$emit(BuildPriceService.events.onOfferText, grade.onOfferText); 11451 11452 if (bpGrade.grade != grade.uriName) { 11453 11454 $scope.$emit(BuildPriceService.events.userSelection, 'Grade selected'); 11455 11456 emitGradeSelection(grade.uriName, true, true, bpGrade.enhancementPack, bpGrade.trim, bpGrade.colour); 11457 } 11458 return false; 11459 } 11460 11461 $scope.$on(BuildPriceService.events.holdPricingCallsRelay, function (event, data) { 11462 //console.info("bpGrade received holdPricingCalls: ", data) 11463 bpGrade.holdPricingCalls = data; 11464 }); 11465 11466 11467 $scope.$on(BuildPriceService.events.postcodeChanged, function (event, data) { 11468 getDifferentialPrices(); 11469 }); 11470 11471 $scope.$watch('bpGrade.specifics', BuildPriceService.watchDebounce(function (newValue, oldValue) { 11472 if (newValue && oldValue && newValue != oldValue) { 11473 // if (newValue != null) { 11474 console.info("%c buildPriceGradeController received SPECIFICS: ", "color: gold;", newValue); 11475 VehicleService.getVehicleImages(newValue.gradeId, newValue.variantId, newValue.trimId, newValue.materialCode).then(function (response) { 11476 bpEnPack.image = response.data.threeSixtyImagesDesktop[2]; 11477 }); 11478 } 11479 }, 50), true); 11480 11481 $scope.$watch('bpGrade.grade', BuildPriceService.watchDebounce(function (newValue, oldValue) { 11482 if (oldValue && newValue != oldValue) { 11483 calculateDifferentialPrices(); 11484 } 11485 }, 50), true); 11486 11487 $scope.$watch('bpGrade.engineVariant', BuildPriceService.watchDebounce(function (newValue, oldValue) { 11488 if (newValue != null) { 11489 11490 console.info("%c 1. buildPriceGradeController $watch ENGINE VARIANT: ", "color: gold; ", newValue); 11491 11492 var previousSelectionNull = (oldValue == null); 11493 var selectionChanged = (oldValue !== newValue); 11494 11495 $scope.getGradeSelectionInVariant(newValue, (selectionChanged && !previousSelectionNull), true); 11496 } 11497 }, 50), true); 11498 11499 11500 $scope.getGradeSelectionInVariant = function (engineVariant, clearDownstream, userInitiated) { 11501 11502 var variantData = BuildPriceAPIService.findEngineVariantInVehicleData(engineVariant); 11503 11504 bpGrade.grades = variantData.grades; 11505 11506 for (var index = 0; index < bpGrade.grades.length; index++) { 11507 bpGrade.grades[index].showSpinner = false; 11508 bpGrade.grades[index].driveAwayPrice = 0; 11509 } 11510 11511 //check if existing selection is in valid set, if it is, don't change the selection 11512 var selectionValid = bpGrade.grade ? bpGrade.grades.find(function (grade) { return grade.uriName === bpGrade.grade; }) != null : false; 11513 var selectionNotNull = bpGrade.grade != null; 11514 11515 if (bpGrade.grades.length > 0 && !selectionValid) { 11516 if (selectionNotNull) { 11517 //trigger invalid selection error 11518 var invalidSelectionData = { 11519 controllerName: BuildPriceService.stepIds.GRADE, 11520 $scope: $scope, 11521 defaultValue: bpGrade.grades[0].uriName, 11522 invalidValue: bpGrade.grade, 11523 userInitiated: userInitiated, 11524 clearDownstreamFrom: userInitiated ? 2 : null 11525 }; 11526 BuildPriceService.emitInvalidSelection(invalidSelectionData); 11527 } 11528 emitGradeSelection(getDefaultGrade().uriName, (clearDownstream || !selectionValid), false); 11529 bpGrade.gradeIndex = indexOfGrade(getDefaultGrade().name); 11530 11531 $scope.$emit(BuildPriceService.events.onOfferText, getDefaultGrade().onOfferText); 11532 11533 } else { 11534 var selectedGrade = BuildPriceAPIService.getGradeByName(engineVariant, bpGrade.grade); 11535 if (selectedGrade) { 11536 emitGradeSelection(selectedGrade.uriName, (clearDownstream || !selectionValid), false); 11537 bpGrade.gradeIndex = indexOfGrade(selectedGrade.name); 11538 11539 $scope.$emit(BuildPriceService.events.onOfferText, selectedGrade.onOfferText); 11540 11541 } 11542 } 11543 11544 getFeatures(); 11545 11546 getDifferentialPrices(); 11547 11548 } 11549 11550 $scope.isOnOffer = function (obj) { 11551 var bool = obj.onOffer; 11552 return bool 11553 } 11554 11555 function getDifferentialPrices() { 11556 //console.info("%c 1B. buildPriceGradeController getGradesDetails: -> bpGrade.postCode", "color: gold; ", bpGrade.postCode); 11557 if (bpGrade.postCode) { 11558 //console.info("bpGrade waiting for holdPricingCalls to clear"); 11559 BuildPriceService.waitFor.call($scope, 'bpGrade.holdPricingCalls', BuildPriceService.waitCondition.ISSTRICTLYFALSE). 11560 then(function success(value) { 11561 console.info("holdPricingCalls cleared in bpGrade"); 11562 getPrices() 11563 //.then(getFeatures, ajaxFailure) 11564 .then(calculateDifferentialPrices, ajaxFailure); 11565 }); 11566 } 11567 } 11568 11569 function getDefaultGrade() { 11570 return bpGrade.grades ? bpGrade.grades[0] : undefined; 11571 } 11572 11573 function getPrices() { 11574 var promises = []; 11575 11576 for (var index = 0; index < bpGrade.grades.length; index++) { 11577 promises.push(getPromise(bpGrade.grades[index])); 11578 if (!isSelected(bpGrade.grades[index])) { 11579 bpGrade.grades[index].showSpinner = true; 11580 } 11581 } 11582 11583 return $q.all(promises).then(function (responses) { 11584 11585 bpGrade.pricingSuccess = true; 11586 11587 for (var returnIndex = 0; returnIndex < responses.length; returnIndex++) { 11588 var resp = responses[returnIndex]; 11589 if (resp.status != "Success") { 11590 bpGrade.pricingSuccess = false; 11591 } else if (resp.data && resp.data.driveAway) { 11592 bpGrade.grades[returnIndex].driveAwayPrice = parseFloat(resp.data.driveAway); 11593 } else { 11594 //success but no price 11595 bpGrade.pricingSuccess = false; 11596 } 11597 } 11598 11599 pricingReport(); 11600 }, ajaxPriceFailure); 11601 11602 function getPromise(grade) { 11603 PricingService.setParam("enablePricingByZone", bpGrade.enablePricingByZone); 11604 return PricingService.driveAwayByGrade(grade.id, bpGrade.postCode, bpGrade.pricingZone); 11605 } 11606 } 11607 11608 function getFeatures() { 11609 11610 11611 var promises = []; 11612 11613 for (var index = 0; index < bpGrade.grades.length; index++) { 11614 promises.push(getPromise(bpGrade.grades[index])); 11615 } 11616 11617 return $q.all(promises).then(function (responses) { 11618 for (var index = 0; index < responses.length; index++) { 11619 bpGrade.grades[index].features = angular.copy(responses[index].data[0].features); 11620 11621 Object.defineProperty(bpGrade.grades[index], "featureComparisonTitle", { 11622 enumerable: true, 11623 configurable: false, 11624 writable: false, 11625 value: responses[index].data[0].featureComparisonTitle 11626 }); 11627 } 11628 }, ajaxFailure); 11629 11630 function getPromise(grade) { 11631 return VehicleService.getVariants(grade.id); 11632 } 11633 } 11634 11635 function ajaxFailure(data) { 11636 console.error('BuildPrice AjaxFailure -> Grade: ', data); 11637 11638 $scope.$emit('open-modal-window', { 11639 content: 'Oops, something went wrong while obtaining the details. If the problem persists, please contact your dealer directly.', 11640 wrapper: ['<p class="lx-modal__paragraph">', '</p>'] 11641 }); 11642 } 11643 11644 function ajaxPriceFailure(data) { 11645 console.error('BuildPrice AjaxPriceFailure -> Grade: ', data); 11646 11647 //$scope.$emit('open-modal-window', { 11648 // content: 'Oops, something went wrong while obtaining the details. If the problem persists, please contact your dealer directly.', 11649 // wrapper: ['<p class="lx-modal__paragraph">', '</p>'] 11650 //}); 11651 } 11652 11653 function pricingReport() { 11654 if (bpGrade.pricingSuccess) { 11655 angular.element('.lx-build-price-grade').removeClass('pricing-error'); 11656 } else { 11657 //console.log("bpGrade pricingSuccess: ", bpGrade.pricingSuccess); 11658 angular.element('.lx-build-price-grade').addClass('pricing-error'); 11659 } 11660 } 11661 11662 function calculateDifferentialPrices() { 11663 11664 var selectedGrade = BuildPriceAPIService.getGradeByName(bpGrade.engineVariant, bpGrade.grade) || getDefaultGrade(); 11665 11666 if (!bpGrade.grades) { return; } 11667 11668 for (var index = 0; index < bpGrade.grades.length; index++) { 11669 if (!isSelected(bpGrade.grades[index]) && selectedGrade) { 11670 bpGrade.grades[index].differentialPrice = 11671 bpGrade.grades[index].driveAwayPrice - selectedGrade.driveAwayPrice; 11672 } 11673 else { 11674 bpGrade.grades[index].differentialPrice = 0; 11675 } 11676 11677 bpGrade.grades[index].showSpinner = false; 11678 } 11679 } 11680 11681 function isSelected(grade) { 11682 return bpGrade.grade === grade.uriName; 11683 } 11684 11685 function indexOfGrade(gradeName) { 11686 var grades = bpGrade.grades; 11687 for (var i = 0; i < grades.length; i++) { 11688 if (grades[i].name === gradeName) { 11689 return i; 11690 } 11691 } 11692 throw new Error('Grade ' + gradeName + ' not found'); 11693 } 11694 11695 function getPreviousGrade(grade, wrap) { 11696 var previousGradeIndex = indexOfGrade(grade) - 1; 11697 if (wrap) { 11698 previousGradeIndex = (previousGradeIndex + bpGrade.grades.length) % bpGrade.grades.length; 11699 } else { 11700 previousGradeIndex = Math.max(previousGradeIndex, 0); 11701 } 11702 return bpGrade.grades[previousGradeIndex]; 11703 } 11704 11705 function getNextGrade(grade, wrap) { 11706 var nextGradeIndex = indexOfGrade(grade) + 1; 11707 if (wrap) { 11708 nextGradeIndex = nextGradeIndex % bpGrade.grades.length; 11709 } else { 11710 nextGradeIndex = Math.min(nextGradeIndex, bpGrade.grades.length - 1); 11711 } 11712 return bpGrade.grades[nextGradeIndex]; 11713 } 11714 11715 function emitGradeSelection(gradeName, clearDownstream, userInitiated, revertEnhancementPack, revertTrim, revertColour) { 11716 var data = { 11717 selection: gradeName, 11718 clearDownstream: clearDownstream, 11719 userInitiated: userInitiated, 11720 revertEnhancementPack: revertEnhancementPack, 11721 revertTrim: revertTrim, 11722 revertColour: revertColour 11723 }; 11724 $scope.$emit(BuildPriceService.events.gradeSelected, d
11724ata); 11725 } 11726 11727 $scope.init = function () { 11728 } 11729 11730 } 11731 }]); 11732 11733}()); 11734; 11735(function (undefined) { 11736 11737 "use strict"; 11738 /* Directives */ 11739 angular.module('Lexus.Directives') 11740 .directive('lxBuildPriceInterior', [function () { 11741 buildPriceInteriorController.$inject = ['$scope', '$filter', 'BuildPriceService', 'VehicleService']; 11742 return { 11743 scope: { 11744 engineVariant: '<variant', 11745 trim: '<trim', 11746 colour: '<colour', 11747 paintId: '<paintId', 11748 specifics: '<specifics', 11749 tab: '<tab' 11750 }, 11751 restrict: 'A', 11752 controller: buildPriceInteriorController, 11753 controllerAs: 'bpInterior', 11754 template: '<div data-ng-transclude></div>', 11755 bindToController: true, 11756 transclude: true, 11757 require: '^lxBuildPricePaintTrim', 11758 link: function (scope, element, attrs, ctrl, transclude) { 11759 scope.loadingInterior = true; 11760 11761 ctrl.registerInterior(scope.bpInterior); 11762 } 11763 } 11764 11765 11766 function buildPriceInteriorController($scope, $filter, BuildPriceService, VehicleService) { 11767 var bpInterior = this; 11768 11769 bpInterior.vlookat = null; 11770 bpInterior.hlookat = null; 11771 bpInterior.pano = { 11772 id: null, 11773 panoControl: null 11774 }; 11775 11776 bpInterior.ensurePanoRemoved = ensurePanoRemoved; 11777 11778 //When the trim is changed the available paints need to be found 11779 //which gives us new paints and Material Codes 11780 $scope.$watch('bpInterior.trim', BuildPriceService.watchDebounce(function (newValue, oldValue) { 11781 if (newValue != null) { 11782 console.info("%c 5. buildPriceInteriorController received Trim: ", "color: purple; ", newValue + " (with VARIANT: " + bpInterior.engineVariant + ")"); 11783 } 11784 },50)); 11785 11786 $scope.$watch('bpInterior.specifics', BuildPriceService.watchDebounce(function (newValue, oldValue) { 11787 if (!bpInterior.tabExterior) { 11788 loadPano(newValue, true); 11789 } 11790 else { 11791 //Warms the API call without actually loading krpano 11792 loadPano(newValue, false); 11793 } 11794 11795 }, 50), true); 11796 11797 11798 function ensurePanoRemoved() { 11799 if (bpInterior.pano) { 11800 removepano(bpInterior.pano.id); 11801 bpInterior.pano.panoControl = null; 11802 } 11803 bpInterior.pano = null; 11804 } 11805 11806 this.loadInterior = loadInterior; 11807 11808 function loadInterior(data) { 11809 loadPano(data, true); 11810 } 11811 11812 $scope.$on(BuildPriceService.events.pageNavigationBroadcast, function (e, target) { 11813 //console.info("%c buildPriceInteriorController pageNaigation: ", "color: purple; ", target); 11814 var isCurrent = target.id == 'colour'; 11815 bpInterior.isCurrentStep = isCurrent; 11816 if (bpInterior.specifics) loadPano(bpInterior.specifics, true); 11817 }); 11818 11819 function loadPano(data, runEmbed) { 11820 //Added this to allow us to test for web WebGL issues on mobile browsers. 11821 //To skip loading interior Pano add ?loadInterior=false 11822 var loadInterior = (window.location.search.match(/loadInterior\=false/)) ? false : true; 11823 11824 if (data && data.gradeId && data.variantId && data.trimId && data.materialCode && loadInterior && bpInterior.isCurrentStep) { 11825 11826 $scope.loadingInterior = true; 11827 11828 var xml = VehicleService.getVehiclePanoXMLUrl(data.gradeId, data.variantId, data.trimId, data.materialCode); 11829 if (runEmbed) { 11830 // Data source didn't even change? No work to do. 11831 if (bpInterior.pano && bpInterior.pano.xml === xml) 11832 return; 11833 11834 ensurePanoRemoved(); 11835 11836 console.info("%c buildPriceInteriorController loadPano: ", "color: purple; ", xml); 11837 11838 bpInterior.pano = bpInterior.pano || {}; 11839 bpInterior.pano.id = 'krpano_' + $scope.$id; 11840 bpInterior.pano.xml = xml; 11841 11842 var settings = {};
11843 settings["events.onviewchange"] = $scope.viewChange; 11844 if (bpInterior.hlookat && bpInterior.vlookat) { 11845 settings["view.hlookat"] = bpInterior.hlookat; 11846 settings["view.vlookat"] = bpInterior.vlookat; 11847 } 11848 11849 embedpano({ 11850 id: bpInterior.pano.id, 11851 xml: xml, 11852 target: "interiorPano", 11853 html5: "only", 11854 mobilescale: 1.0, 11855 onready: function (krPano) { 11856 $scope.loadingInterior = false; 11857 }, 11858 vars: settings 11859 }); 11860 } 11861 } 11862 } 11863 11864 $scope.viewChange = function () { 11865 //krpano.get("view.hlookat"); 11866 if (!bpInterior.pano.panoControl) { 11867 bpInterior.pano.panoControl = document.getElementById(bpInterior.pano.id) 11868 } 11869 11870 if (bpInterior.pano.panoControl) { 11871 //console.info('Change View ' + krpano.get("view.hlookat") + ' ' + krpano.get("view.vlookat")); 11872 bpInterior.hlookat = bpInterior.pano.panoControl.get("view.hlookat"); 11873 bpInterior.vlookat = bpInterior.pano.panoControl.get("view.vlookat"); 11874 } 11875 } 11876 } 11877 }]); 11878 11879}());; 11880//Only Allowed to watch 11881//BuildPriceAPIService.data 11882 11883//Only Allowed to emit 11884//model selected 11885//engine variant selected 11886 11887(function (undefined) { 11888 11889 "use strict"; 11890 /* Directives */ 11891 angular.module('Lexus.Directives') 11892 .directive('lxBuildPriceModel', [function () { 11893 buildPriceModelController.$inject = ['$scope', '$timeout', 'VehicleService', 'BuildPriceService', 'BuildPriceAPIService']; 11894 return { 11895 11896 scope: { 11897 selectedModel: '<carmodel', 11898 selectedEngineVariant: '<variant' 11899 }, 11900 restrict: 'A', 11901 controller: buildPriceModelController, 11902 controllerAs: 'bpModel', 11903 bindToController: true, 11904 transclude: true, 11905 link: function (scope, element, attrs, ctrl, transclude) { 11906 transclude(scope, function (clone) { 11907 element.append(clone); 11908 }); 11909 scope.bpModel.currentPage = 0; 11910 } 11911 }; 11912 11913 11914 11915 function buildPriceModelController($scope, $timeout, VehicleService, BuildPriceService, BuildPriceAPIService) { 11916 var bpModel = this; 11917 bpModel.vehicleData = null; 11918 bpModel.modelSelected = false; 11919 bpModel.previousPage = previousPage; 11920 bpModel.nextPage = nextPage; 11921 11922 function setCurrentPage(packIndex, user) { 11923 var user = user != null ? user : false; 11924 var page = (user) ? bpModel.currentPage : 0; 11925 if (packIndex != 0) { 11926 page = packIndex - 2; 11927 } 11928 return page; 11929 } 11930 11931 function previousPage() { 11932 if (bpModel.currentPage > 0) bpModel.currentPage--; 11933 } 11934 11935 function nextPage(variantsLength) { 11936 if (bpModel.currentPage <= ((variantsLength - 2) - bpModel.currentPage)) bpModel.currentPage++; 11937 } 11938 11939 $scope.setModelHeights = function () { 11940 $timeout(function () { 11941 if (window.innerWidth > 767) { 11942 var choosers = angular.element('.lx-build-price-model-chooser__models'); 11943 11944 for (var c = 0, clen = choosers.length; c < clen; c++) { 11945 var models = choosers[c].querySelectorAll('.lx-build-price-model-chooser-model'); 11946 var modelHeights = [], lastHeight = 0; 11947 for (var m = 0, mlen = models.length; m < mlen; m++) { modelHeights.push(models[m].clientHeight); } 11948 modelHeights.sort(); 11949 lastHeight = modelHeights[modelHeights.length - 1]; 11950 if (modelHeights[0] != lastHeight) { 11951 for (var m = 0, mlen = models.length; m < mlen;
11951 m++) { models[m].setAttribute('style', 'height:' + lastHeight + 'px;'); } 11952 } 11953 } 11954 } 11955 }, 0, false); 11956 } 11957 11958 $scope.emitEngineVariantSelected = function (engineVariant, currentSelection, userInitiated) { 11959 var data = { 11960 selection: currentSelection === engineVariant.uriName ? null : engineVariant.uriName, 11961 clearDownstream: (engineVariant != currentSelection && currentSelection != null), 11962 userInitiated: userInitiated 11963 }; 11964 $scope.$emit(BuildPriceService.events.userSelection, 'Model + Variant selected'); 11965 11966 $scope.$emit(BuildPriceService.events.engineVariantSelected, data); 11967 }; 11968 11969 $scope.variantHasOffer = function (model) { 11970 var hasOffer = false; 11971 model.modelEngineVariants.forEach(function (variant) { 11972 if ($scope.isOnOffer(variant)) { 11973 hasOffer = true; 11974 } 11975 }); 11976 11977 return hasOffer; 11978 }; 11979 11980 $scope.isOnOffer = function (obj) { 11981 var bool = obj.onOffer; 11982 return bool; 11983 } 11984 11985 $scope.emitModelSelected = function (model, currentSelection, userInitiated, modelElement) { 11986 //reset 11987 bpModel.currentPage = 0; 11988 11989 if (userInitiated) { 11990 var shortModel = modelElement.replace(/\s+/g, ''); 11991 setTimeout(function () { 11992 $('html, body').animate({ scrollTop: $(shortModel).offset().top - 10 }, 250) 11993 }, 500); 11994 } 11995 11996 $scope.$emit(BuildPriceService.events.onOfferText, null); 11997 11998 var data = { 11999 selection: currentSelection === model.uriName ? null : model.uriName, 12000 clearDownstream: (model != currentSelection && currentSelection != null), 12001 userInitiated: userInitiated 12002 }; 12003 $scope.$emit(BuildPriceService.events.modelSelected, data); 12004 }; 12005 12006 $scope.ReceiveModels = function () { 12007 bpModel.currentPage = setCurrentPage(0); 12008 bpModel.vehicleData = BuildPriceAPIService.data; 12009 console.info("%c 0. buildPriceModelController -> ReceiveModels: ", "color: darkblue; ", BuildPriceAPIService.data); 12010 $scope.$emit(BuildPriceService.events.overviewDataReceived, BuildPriceAPIService.data); 12011 $scope.setModelHeights(); 12012 }; 12013 12014 $scope.$on(BuildPriceService.events.pageNavigationBroadcast, function (e, target) { 12015 var isCurrent = target.id == 'model'; 12016 bpModel.isCurrentStep = isCurrent; 12017 }); 12018 12019 $scope.$watch('bpModel.selectedModel', function (newValue, oldValue) { 12020 if (newValue != null && bpModel.isCurrentStep && !bpModel.modelSelected) { 12021 var shortModel = '.contains-model--' + newValue.replace(/\s+/g, ''); 12022 12023 setTimeout(function () { 12024 $('html, body').animate({ scrollTop: $(shortModel).offset().top - 10 }, 250) 12025 }, 500); 12026 12027 bpModel.modelSelected = true; 12028 } 12029 }); 12030 12031 function init() { 12032 //console.log('bpModel init: ', BuildPriceAPIService.getModels($scope.ReceiveModels)); 12033 BuildPriceAPIService.getModels().then($scope.ReceiveModels); 12034 } 12035 12036 init(); 12037 } 12038 }]); 12039 12040}());; 12041"use strict"; 12042/* Directives */ 12043angular.module("Lexus.Directives").directive("lxBuildPriceNavigation", [ 12044 function () { 12045 buildPriceNavigationController.$inject = ["$scope", "$window", "$interpolate", "$element", "BuildPriceService"]; 12046 return { 12047 scope: { 12048 model: "<carmodel", 12049 engineVariant: "<variant", 12050 enhancementPack: "<enhancement", 12051 grade: "<grade", 12052 colour: "<colour", 12053 trim: "<trim", 12054 driveAwayPrice: "<price", 12055 driveAwayPriceLoading: "<priceLoading", 12056 vehicleLoading: "<vehicleLoading", 12057 steps: "<steps", 12058 activeStepIdx: "<activeIndex", 12059 paintResolved: "<paintresolved", 12060 paintId: "<paintId", 12061 onOfferText: "<onOfferText", 12062 toggleSbp: "<toggleSbp", 12063 hideSaveBuild: "<hideSaveBuild", 12064 postcode: "<postcode", 12065 }, 12066 restrict: "A",
12067 controller: buildPriceNavigationController, 12068 controllerAs: "bpNav", 12069 bindToController: true, 12070 transclude: true, 12071 link: function (scope, element, attrs, ctrl, transclude) { 12072 transclude(scope, function (clone) { 12073 element.append(clone); 12074 }); 12075 scope.init(); 12076 }, 12077 }; 12078 12079 function buildPriceNavigationController($scope, $window, $interpolate, $element, BuildPriceService) { 12080 var bpNav = this; 12081 bpNav.activeStep = null; 12082 bpNav.toggleSbp = false; 12083 bpNav.lastEngineVariant = null; 12084 12085 $scope.isLastStep = function () { 12086 return $scope.bpNav.activeStepIdx + 1 < $scope.bpNav.steps.length; 12087 }; 12088 12089 $scope.shiftMenu = function (targetIndex) { 12090 var overflow = angular.element(".lx-c-nav__menu-group"); 12091 12092 overflow.scrollLeft(0); 12093 12094 var windowwidth = $window.innerWidth; 12095 var p = angular.element(".lx-bp-nav__item-" + targetIndex + ""); 12096 12097 var scrollPositionCenter = p.offset().left - p.width() / 2; 12098 var pRight = p.offset().left + p.width(); 12099 12100 if (overflow[0].scrollWidth > windowwidth && pRight > windowwidth / 3) { 12101 if (pRight < windowwidth / 2) { 12102 overflow.scrollLeft(0); 12103 } else { 12104 overflow.scrollLeft(scrollPositionCenter + 10); 12105 } 12106 } 12107 }; 12108 12109 //#region EVENTS 12110 12111 //allows navigation by index or id 12112 $scope.emitNavigation = function (data, $event) { 12113 console.log("emitNavigation: ", bpNav); 12114 12115 if (bpNav.vehicleLoading) { 12116 return; 12117 } 12118 if (typeof data == "number") { 12119 if (bpNav.steps[data].disabled) { 12120 return; 12121 } 12122 } else { 12123 if ( 12124 bpNav.steps.find(function (step) { 12125 return step.id === data; 12126 }).disabled 12127 ) { 12128 return; 12129 } 12130 } 12131 12132 $scope.$emit("bp-page-navigation", data); 12133 }; 12134 //#endregion 12135 12136 $scope.$watch( 12137 function (scope) { 12138 return scope.bpNav.activeStepIdx; 12139 }, 12140 function (newVal, oldVal) { 12141 if (typeof newVal == "number") { 12142 bpNav.activeStep = bpNav.steps[newVal]; 12143 12144 $scope.shiftMenu(bpNav.activeStep.id); 12145 } 12146 }, 12147 ); 12148 12149 $scope.$watch( 12150 function (scope) { 12151 return scope.bpNav.engineVariant; 12152 }, 12153 function (newVal, oldVal) { 12154 if (typeof oldVal == "string") { 12155 bpNav.lastEngineVariant = oldVal; 12156 } 12157 if (newVal != null && newVal != oldVal) { 12158 setTimeout(function () { 12159 var stickyHeight = angular.element(".lx-footer-sticky")[0].clientHeight + 40 + "px"; 12160 angular.element(".lx-footer").css({ "padding-bottom": stickyHeight }); 12161 }, 100); 12162 } 12163 }, 12164 ); 12165 12166 // SF Personaliation - Build & Price tool 12167 $scope.$watch( 12168 "bpNav.activeStep.id", 12169 BuildPriceService.watchDebounce(function (newVal, oldVal) { 12170 let navTitle = newVal.toLowerCase(); 12171 if (navTitle === "colour") { 12172 navTitle = "colour & trim"; 12173 } 12174 if (typeof window !== "undefined") { 12175 const sfCustomEvent = new CustomEvent("build-and-price-nav-change", { 12176 detail: { navTitle }, 12177 }); 12178 window.document.dispatchEvent(sfCustomEvent); 12179 } 12180 }, 600), 12181 true, 12182 ); 12183 12184 $scope.encodeUriFragment = function (fragment) { 12185 return BuildPriceService.encodeUriFragment(fragment); 12186 }; 12187 12188 $scope.getUrl = function (prefix, route) { 12189 return prefix + route; 12190 }; 12191 12192 $scope.init = function () {}; 12193 12194 $scope.openNav = function () { 12195 bpNav.toggleSbp 12196 ? $scope.$emit(BuildPriceService.events.triggerCloseSaveBuildPriceDialog, {}) 12197 : $scope.$emit(BuildPriceService.events.triggerSaveBuildPriceDialog, {}); 12198 }; 12199 12200 $scope.openPostcodeModal = function () { 12201 $scope.$emit(BuildPriceService.events.openPostcodeDialog); 12202 }; 12203 12204 $scope.isStickyFooterVisible = function () { 12205 var result = (bpNav.model && bpNav.engineVariant) || !bpNav.hideSaveBuild; 12206 $scope.$emit("sticky-footer-visible", result); 12207 return result; 12208 }; 12209 12210 $scope.openPostcodeSlideout = function () { 12211 $scope.$emit(BuildPriceService.events.openPostcodeSlideout); 12212 }; 12213 } 12214 }, 12215]); 12216;
12217//Only Allowed to watch 12218//rangeBuildPrice.collections.trims[] 12219//rangeBuildPrice.collections.colours[] 12220//rangeBuildPrice.collections.exteriorImages[] 12221//rangeBuildPrice.collections.interiorImages[] 12222 12223//Only allowed to emit 12224//trim selected 12225//colour selected 12226 12227(function (undefined) { 12228 12229 "use strict"; 12230 /* Directives */ 12231 angular.module('Lexus.Directives') 12232 .directive('lxBuildPricePaintTrim', [function () { 12233 12234 var bpInteriorCtrl = null; 12235 var bpExteriorCtrl = null; 12236 buildPricePaintTrimController.$inject = ['$scope', 'BuildPriceService', 'BuildPriceAPIService', 'VehicleService', '$timeout', '$log']; 12237 return { 12238 scope: { 12239 engineVariant: '<variant', 12240 grade: '<grade', 12241 trim: '<trim', 12242 enhancementPack: '<enhancement', 12243 colour: '<colour', 12244 paintId: '<paintId', 12245 specifics: '<specifics' 12246 }, 12247 restrict: 'A', 12248 controller: buildPricePaintTrimController, 12249 controllerAs: 'bpPaintTrim', 12250 bindToController: true, 12251 transclude: true, 12252 link: function (scope, element, attrs, ctrl, transclude) { 12253 transclude(scope, function (clone) { 12254 element.append(clone); 12255 }); 12256 } 12257 }; 12258 12259 12260 function buildPricePaintTrimController($scope, BuildPriceService, BuildPriceAPIService, VehicleService, $timeout, $log) { 12261 var bpPaintTrim = this; 12262 12263 bpPaintTrim.selectedPaintName = ''; 12264 bpPaintTrim.selectedPaintCode = ''; 12265 bpPaintTrim.selectedTrimName = ''; 12266 12267 bpPaintTrim.setSelectedPaint = setSelectedPaint; 12268 bpPaintTrim.setSelectedTrim = setSelectedTrim; 12269 bpPaintTrim.isTrimSelected = isTrimSelected; 12270 12271 bpPaintTrim.registerInterior = function (controller) { 12272 bpInteriorCtrl = controller; 12273 }; 12274 12275 bpPaintTrim.registerExterior = function (controller) { 12276 bpExteriorCtrl = controller; 12277 }; 12278 12279 function setSelectedPaint(paint) { 12280 12281 bpPaintTrim.selectedPaintCode = paint.code; 12282 bpPaintTrim.selectedPaintName = paint.shortName; 12283 setColour(bpPaintTrim.specifics.gradeId, bpPaintTrim.specifics.variantId, bpPaintTrim.specifics.trimId); 12284 } 12285 12286 function setSelectedTrim(trim) { 12287 12288 bpPaintTrim.selectedTrimName = trim.name; 12289 if (bpPaintTrim.trim !== trim.uriName) { 12290 emitTrimSelection(trim.uriName, true, true, bpPaintTrim.colour); 12291 } 12292 } 12293 12294 function isTrimSelected(trim) { 12295 return bpPaintTrim.trim === trim.uriName; 12296 } 12297 12298 BuildPriceService = BuildPriceService; 12299 12300 var unloadExteriorPromise = null; 12301 12302 $scope.exterior = function () { 12303 //Set scope to exterior. 12304 $scope.tabExterior = true;
12305 if (bpInteriorCtrl) 12306 { 12307 bpInteriorCtrl.ensurePanoRemoved(); 12308 } 12309 }; 12310 12311 $scope.interior = function () { 12312 //Set scope to interior. 12313 $scope.tabExterior = false; 12314 12315 if ($scope.bpPaintTrim.specifics) { 12316 bpInteriorCtrl.loadInterior($scope.bpPaintTrim.specifics); 12317 } 12318 }; 12319 12320 $scope.$watch('bpPaintTrim.specifics', BuildPriceService.watchDebounce(function (newValue, oldValue) { 12321 if (newValue) { 12322 //setColours(newValue.gradeId, newValue.variantId, newValue.trimId); 12323 console.info("%c 6. BuildPricePaintTrimController received SPECIFICS: ", "color: teal; ", [newValue]); 12324 } 12325 }, 50), true); 12326 12327 //Need to rebind trims when colour changes to show which trims are available and unavailable in that colour 12328 //$scope.$watch('bpPaintTrim.colour', BuildPriceService.watchDebounce(function trimReceived(newValue, oldValue) { 12329 // if (newValue && newValue != oldValue) { 12330 // setAvailableTrimsBasedOnPaint(bpPaintTrim.engineVariant, bpPaintTrim.grade, bpPaintTrim.enhancementPack); 12331 // } 12332 //}, 50)); 12333 12334 $scope.$watch('bpPaintTrim.trim', BuildPriceService.watchDebounce(function trimReceived(newValue, oldValue) { 12335 if (newValue) { 12336 console.info("%c 3. buildPricePaintTrimController received TRIM: ", "color: teal; ", newValue); 12337 12338 var previousSelectionNull = (oldValue == null); 12339 var selectionChanged = (oldValue !== newValue); 12340 12341 getSelectedEnhancementPack(bpPaintTrim.engineVariant, bpPaintTrim.grade, bpPaintTrim.enhancementPack); 12342 12343 BuildPriceService.waitFor.call($scope, 'bpPaintTrim.availableTrims', BuildPriceService.waitCondition.NOTNULL) 12344 .then(function (value) { 12345 validateTrimSelection(newValue, value, (selectionChanged && !previousSelectionNull), true); 12346 }); 12347 } 12348 }, 50), true); 12349 12350 $scope.$watch('bpPaintTrim.grade', BuildPriceService.watchDebounce(function (newValue, oldValue) { 12351 if (bpPaintTrim.allTrims) delete bpPaintTrim.allTrims; 12352 }, 50), true); 12353 12354 $scope.$watch('bpPaintTrim.enhancementPack', BuildPriceService.watchDebounce(function (newValue, oldValue) { 12355 if (newValue && newValue != oldValue) { 12356 console.info("%c 4. buildPricePaintTrimController received Enhancement Pack: ", "color: teal; ", newValue); 12357 12358 getSelectedEnhancementPack(bpPaintTrim.engineVariant, bpPaintTrim.grade, newValue); 12359 } 12360 }, 50), true); 12361 12362 function setAvailableTrimsBasedOnPaint() { } 12363 12364 //This method still gets called twice on load with a deeplink, wouldnt mind fixing that 12365 function getSelectedEnhancementPack(engineVariantName, gradeName, enhancementPack, callback) { 12366 var engineVariant = BuildPriceAPIService.findEngineVariantInVehicleData(engineVariantName); 12367 var grade = BuildPriceAPIService.getGradeByName(engineVariantName, gradeName); 12368 12369 BuildPriceAPIService.getVariants(engineVariantName, grade.id, function (variants) { 12370 12371 var variant = BuildPriceAPIService.getVariantByName(engineVariantName, grade.id, enhancementPack); 12372 12373 BuildPriceAPIService.getTrims(engineVariantName, grade.id, variant.mdmid, function (availableTrims, unavailableTrims, allTrims) { 12374 //This is setting trims based on the MV response 12375 setTrims(availableTrims, unavailableTrims, allTrims, false); 12376 12377 bpPaintTrim.allTrims = allTrims; 12378 12379 setTrim(engineVariantName, grade.id, variant.mdmid); 12380 12381 12382 if (bpPaintTrim.trim) { 12383 var trim = BuildPriceAPIService.getTr
12383imByName(engineVariantName, grade.id, variant.mdmid, bpPaintTrim.trim); 12384 12385 BuildPriceAPIService.getPaints(engineVariantName, grade.id, variant.mdmid, trim.id, function (availableColours, unavailableColours) { 12386 12387 setColours(availableColours, unavailableColours); 12388 setColour(grade.id, variant.mdmid, trim.id); 12389 12390 }); 12391 } 12392 12393 12394 }); 12395 }); 12396 } 12397 12398 function validateTrimSelection(trim, trims, clearDownstream, userInitiated) { 12399 var trimObj = {}; 12400 12401 for (var index = 0; index < trims.length; index++) { 12402 if (trims[index].uriName == trim) { 12403 trimObj = trims[index]; 12404 break; 12405 } 12406 } 12407 12408 if (!trimObj) { 12409 var defaultSelection = getDefaultTrim(); 12410 12411 var invalidSelectionData = { 12412 controllerName: BuildPriceService.stepIds.PAINT_TRIM, 12413 $scope: $scope, 12414 defaultValue: defaultSelection.uriName, 12415 invalidValue: bpPaintTrim.trim, 12416 userInitiated: userInitiated, 12417 clearDownstreamFrom: userInitiated ? 4 : null 12418 }; 12419 12420 BuildPriceService.emitInvalidSelection(invalidSelectionData); 12421 12422 emitTrimSelection(defaultSelection.uriName, clearDownstream, userInitiated); 12423 } else { 12424 bpPaintTrim.selectedTrimName = trimObj.name; 12425 } 12426 } 12427 12428 function validatePaintSelection(paint) { 12429 var selectedPaint = {}; 12430 12431 for (var index = 0; index < bpPaintTrim.availableColours.length; index++) { 12432 if (bpPaintTrim.availableColours[index].uriName == paint) { 12433 selectedPaint = bpPaintTrim.availableColours[index]; 12434 break; 12435 } 12436 } 12437 12438 if (!selectedPaint) { 12439 selectedPaint = getDefaultPaint(); 12440 12441 var invalidSelectionData = { 12442 controllerName: 'buildPricePaintTrimController (expected - incomplete)', 12443 $scope: $scope, 12444 defaultValue: selectedPaint.uriName, 12445 invalidValue: bpPaintTrim.colour 12446 /* 12447 * Once we have a user-initiated selection process implement these variables 12448 userInitiated: true/false, 12449 clearDownstreamFrom: userInitiated ? 5 : null 12450 */ 12451 }; 12452 BuildPriceService.emitInvalidSelection(invalidSelectionData); 12453 } 12454 12455 12456 bpPaintTrim.selectedPaintName = selectedPaint.shortName; 12457 bpPaintTrim.selectedPaintCode = selectedPaint.code; 12458 emitPaintSelection(selectedPaint); 12459 } 12460 12461 function getDefaultPaint() { 12462 return bpPaintTrim.availableColours[0]; 12463 } 12464 12465 function getDefaultTrim() { 12466 return bpPaintTrim.availableTrims[0]; 12467 } 12468 12469 //#region Events 12470 12471 function emitPaintSelection(paintObj) { 12472 $scope.$emit(BuildPriceService.events.paintSelected, paintObj); 12473 }; 12474 12475 function emitPaintsReceived(paints) { 12476 $scope.$emit(BuildPriceService.events.paintsReceived, paints); 12477 }; 12478 12479 function emitTrimSelection(trimName, clearDownstream, userInitiated, revertColour) { 12480 var data = { 12481 clearDownstream: clearDownstream, 12482 selection: trimName, 12483 userInitiated: userInitiated, 12484 revertColour: revertColour 12485 }; 12486 12487 $scope.$emit(BuildPriceService.events.trimSelected, data) 12488 }; 12489 12490 function emitTrimsReceived(trims) { 12491 $scope.$emit(BuildPriceService.events.trimsReceived, trims); 12492 }; 12493 12494 //#endregion 12495 12496 function setTrims(availableTrims, unAvailableTrims, allTrims, showTrims) { 12497 //console.info("%c 3b. buildPricePaintTrimController setTrims
12497-> allTrims: ", "color: teal; ", allTrims.map(function (v, i) { return (i + 1) + ". " + v.code + "" }).join(', ')); 12498 //console.info("%c 3c. buildPricePaintTrimController setTrims -> available: ", "color: teal; ", availableTrims.map(function (v, i) { return (i + 1) + ". " + v.code + "" }).join(', ')); 12499 //console.info("%c 3d. buildPricePaintTrimController setTrims -> unavailable: ", "color: teal; ", unAvailableTrims.map(function (v, i) { return (i + 1) + ". " + v.code + "" }).join(', ')); 12500 bpPaintTrim.availableTrims = availableTrims; 12501 bpPaintTrim.unavailableTrims = unAvailableTrims; 12502 emitTrimsReceived(bpPaintTrim.availableTrims); 12503 bpPaintTrim.showTrims = showTrims; 12504 } 12505 12506 function setTrim(engineVariant, gradeId, variantId) { 12507 if (!bpPaintTrim.trim && bpPaintTrim.availableTrims.length > 0) { 12508 var defaultTrim = getDefaultTrim(); 12509 bpPaintTrim.selectedTrimName = defaultTrim.name; 12510 emitTrimSelection(defaultTrim.uriName, true, false); 12511 } 12512 else { 12513 var trimobj = BuildPriceAPIService.getTrimByName(engineVariant, gradeId, variantId, bpPaintTrim.trim); 12514 12515 if (trimobj) { 12516 bpPaintTrim.selectedTrimName = trimobj.name; 12517 emitTrimSelection(trimobj.uriName, true, false); 12518 } 12519 else { //Matching Trim couldnt be found revert to the default 12520 bpPaintTrim.selectedTrimName = bpPaintTrim.availableTrims[0].name; 12521 emitTrimSelection(bpPaintTrim.availableTrims[0].uriName, true, false); 12522 } 12523 } 12524 } 12525 12526 function setColours(availableColours, unavailableColours) { 12527 var maxColoursCanBeShown = 12; 12528 if (availableColours && unavailableColours && ((availableColours.length + unavailableColours.length) > maxColoursCanBeShown)) 12529 { 12530 unavailableColours = null; 12531 } 12532 12533 bpPaintTrim.availableColours = availableColours; 12534 bpPaintTrim.unavailableColours = unavailableColours; 12535 emitPaintsReceived(bpPaintTrim.availableColours); 12536 12537 if (!bpPaintTrim.colour && bpPaintTrim.availableColours.length > 0) { 12538 var defaultPaint = getDefaultPaint(); 12539 bpPaintTrim.selectedPaintName = defaultPaint.shortName; 12540 } 12541 if(!bpPaintTrim.selectedPaintName){ 12542 bpPaintTrim.selectedPaintName = bpPaintTrim.colour; 12543 } 12544 12545 bpPaintTrim.showColours = (availableColours.length > 0) ? true : false; 12546 } 12547 12548 function setColour(gradeId, variantMDMId, trimId) { 12549 //Need to find by URI name if its being reversed from the path, 12550 //need to use shortname if its triggered by a swatch click 12551 var paintobj = BuildPriceAPIService.getPaintByName(bpPaintTrim.engineVariant, gradeId, variantMDMId, trimId, bpPaintTrim.selectedPaintName); 12552 12553 if (!paintobj) { 12554 paintobj = bpPaintTrim.availableColours[0]; 12555 } 12556 12557 //$log.info("paintobj"); 12558 //$log.info(paintobj); 12559 12560 bpPaintTrim.selectedPaintName = paintobj.shortName; 12561 bpPaintTrim.selectedPaintCode = paintobj.code; 12562 12563 var myGrade = BuildPriceAPIService.getGradeByID(bpPaintTrim.engineVariant, gradeId); 12564 12565 emitPaintSelection(paintobj, true, false); 12566 12567 bpExteriorCtrl.loadExterior( 12568 { 12569 gradeId: gradeId, 12570 gradeMDMId: myGrade.gradeID, 12571 variantId: variantMDMId, 12572 trimId: trimId, 12573 materialCode: paintobj.materialCode, 12574 paintId: paintobj.id 12575 }); 12576 12577
12578 BuildPriceAPIService.getTrims(bpPaintTrim.engineVariant, gradeId, variantMDMId, function (availableTrims, unavailableTrims, allTrims) { 12579 12580 var currentTrims = BuildPriceAPIService.getUnavailableTrimsBasedOnPaint(bpPaintTrim.engineVariant, gradeId, variantMDMId, trimId, bpPaintTrim.selectedPaintName); 12581 12582 //This needs to be filtered so we get the nice name from Grade it isn't pretty but data is lacking. 12583 var currentUnavailable = BuildPriceAPIService.GetUnAvailableCollection(allTrims, currentTrims.availableTrims); 12584 var currentAvailable = BuildPriceAPIService.FilterAvailableCollection(availableTrims, currentTrims.availableTrims); 12585 //This is setting trims based on the Paint Response 12586 setTrims(currentAvailable, currentUnavailable, allTrims, true); 12587 }); 12588 12589 } 12590 } 12591 }]); 12592 12593}()); 12594 12595; 12596(function (undefined) { 12597 "use strict"; 12598 /* Directives */ 12599 angular.module('Lexus.Directives') 12600 .directive('lxBuildPriceSummary', [function () { 12601 BuildPriceSummaryController.$inject = ['$rootScope', '$scope', '$timeout', '$httpParamSerializer', 'PricingService', 'BuildPriceService', 'BuildPriceAPIService', 'VehicleService']; 12602 return { 12603 scope: {}, 12604 restrict: 'A', 12605 controller: BuildPriceSummaryController, 12606 controllerAs: 'bpSummary', 12607 bindToController: { 12608 emailDeeplinkUrlParameters: '<emailDeeplinkUrlParameters', 12609 model: '<model', 12610 engineVariant: '<variant', 12611 grade: '<grade', 12612 enhancementPack: '<enhancement', 12613 trim: '<trim', //INTERIOR value 12614 colour: '<colour', //EXTERIOR value 12615 postcode: '<postcode', 12616 pricingZone: '<pricingZone', 12617 paintId: '<paintId', 12618 specifics: '<specifics', 12619 vehicleImage: '<vehicleImage', 12620 enablePricingByZone: '<enablePricingZone', 12621 hostOrigin: '<hostOrigin', 12622 }, 12623 transclude: true, 12624 link: function (scope, element, attrs, ctrl, transclude) { 12625 transclude(scope, function (clone) { 12626 element.append(clone); 12627 }); 12628 12629 scope.showContactDealer = false; 12630 } 12631 }; 12632 12633 function BuildPriceSummaryController($rootScope, $scope, $timeout, $httpParamSerializer, PricingService, BuildPriceService, BuildPriceAPIService, VehicleService) { 12634 var bpSummary = this; 12635 bpSummary.loadingData = false; 12636 bpSummary.pricingSuccess = true; 12637 bpSummary.holdPricingCalls = true; 12638 12639 $scope.$on(BuildPriceService.events.holdPricingCallsRelay, function (event, data) { 12640 bpSummary.holdPricingCalls = data; 12641 }); 12642 12643 $scope.$watch("bpSummary.paintId", BuildPriceService.watchDebounce(function (newValue, oldValue) { 12644 if (newValue !== null) { 12645 getDetailPriceByPaint(); 12646 } 12647 }, 50), true); 12648 12649 $scope.$watch('bpSummary.specifics', BuildPriceService.watchDebounce(function (newValue, oldValue) { 12650 if (newValue !== null) { 12651 console.info("%c 7. BuildPriceSummaryController received SPECIFICS: ", "color: green; ", newValue); 12652 $rootScope.$broadcast('refresh-gtm', 'Build and Price'); 12653 } 12654 }, 50), true); 12655 12656 $scope.$watch("bpSummary.postcode", BuildPriceService.watchDebounce(function (newValue, oldValue) { 12657 if (newValue !== null) { 12658 console.info("%c BuildPriceSummaryController received POSTCODE: ", "color: green; ", newValue); 12659 getDetailPriceByPaint(); 12660 } 12661 }, 50), true); 12662 12663 function getDetailPriceByPaint() { 12664 PricingService.setParam("enablePricingByZone", bpSummary.enablePricingByZone); 12665 if (bpSummary.paintId && bpSummary.postcode && $scope.bpSummary.specifics) { 12666 12667 BuildPriceService.waitFor.call($scope, 'bpSummary.holdPricingCalls', BuildPriceService.waitCondition.ISSTRICTLYFALSE) 12668 .then(function success(val) { 12669 PricingService.detailPriceByPaint( 12670 $scope.bpSummary.specifics.gradeId, 12671 $scope.bpSummary.specifics.variantId, 12672 $scope.bpSummary.specifics.trimId, 12673 bpSummary.paintId, 12674 bpSummary.postcode, 12675 bpSummary.pricingZone) 12676 .then(function (data) { 12677 if (data.status === "Success") { 12678 if (data.data && data.data.listPriceIncGST && data.data.driveAway) { 12679 if (bpSummary.driveAwayPriceLoadingTimeout) { 12680 $timeout.cancel(bpSummary.driveAwayPriceLoadingTimeout); 12681 } 12682 12683 bpSummary.pricingSuccess = true; 12684 bpSummary.details = data.data; 12685 emitDriveAwayPriceReceived(data.data); 12686 } else { 12687 //success but no price 12688 bpSummary.pricingSuccess = false; 12689 } 12690 12691 } else { 12692 bpSummary.pricingSuccess = false; 12693 } 12694 }, function (reason) { ajaxPriceFailure(reason, "PricingService.detailPriceByPaint"); }) 12695 .finally(function (data) { 12696 12697 emitDriveAwayPriceDidExitLoading(data); 12698 pricingReport(); 12699 bpSummary.loadingData = false; 12700 }); 12701 emitDriveAwayPriceDidEnterLoading(); 12702 bpSummary.loadingData = true; 12703 var variant = BuildPriceAPIService.getVariantByName(bpSummary.engineVariant, bpSummary.specifics.gradeId, bpSummary.enhancementPack);
12704 var trim = BuildPriceAPIService.getTrimByName(bpSummary.engineVariant, bpSummary.specifics.gradeId, variant.mdmid, bpSummary.trim); 12705 var paint = BuildPriceAPIService.getPaintByName(bpSummary.engineVariant, bpSummary.specifics.gradeId, variant.mdmid, trim.id, bpSummary.colour); 12706 bpSummary.enhancementPackName = variant.enhancementPackName; 12707 bpSummary.trimName = trim.name; 12708 bpSummary.colourName = paint.shortName; 12709 }); 12710 } 12711 } 12712 12713 bpSummary.navigate = navigate; 12714 12715 //#region Events 12716 function emitDriveAwayPriceDidEnterLoading(data) { 12717 $scope.$emit(BuildPriceService.events.priceLoad, data); 12718 console.log('%c $$$$$$$$ priceLoad $$$$$$$$', 'color: limegreen; font-weight: bold;'); 12719 } 12720 12721 function emitDriveAwayPriceDidExitLoading(data) { 12722 $scope.$emit(BuildPriceService.events.priceDone, data); 12723 console.log('%c $$$$$$$$ priceDone $$$$$$$$', 'color: limegreen; font-weight: bold;'); 12724 } 12725 12726 function emitDriveAwayPriceReceived(data) { 12727 $scope.$emit(BuildPriceService.events.priceReceived, data); 12728 console.log('%c $$$$$$$$ priceReceived $$$$$$$$', 'color: limegreen; font-weight: bold;'); 12729 } 12730 12731 function ajaxPriceFailure(data, source) { 12732 12733 bpSummary.pricingSuccess = false; 12734 console.log('%c ajaxPriceFailure ', 'color: red; font-weight: bold;', source); 12735 12736 pricingReport(); 12737 12738 $scope.$emit(BuildPriceService.events.priceError, { source: "bpSummary" }); 12739 12740 } 12741 12742 12743 function pricingReport() { 12744 console.log("bpSummary -> pricingReport: ", bpSummary.pricingSuccess); 12745 12746 var delay = 500; // milliseconds to delay the loading. 12747 12748 bpSummary.driveAwayPriceLoadingTimeout = $timeout(function () { 12749 12750 console.log("bpSummary -> pricingReport: timeout finished", bpSummary.pricingSuccess); 12751 12752 if (bpSummary.pricingSuccess) { 12753 angular.element('.lx-build-price-summary').removeClass('pricing-error'); 12754 angular.element('.lx-footer-sticky').removeClass('pricing-error'); 12755 } else { 12756 angular.element('.lx-build-price-summary').addClass('pricing-error'); 12757 angular.element('.lx-footer-sticky').addClass('pricing-error'); 12758 } 12759 12760 }, delay); // Don't bother showing "loading" for time in delay 12761 } 12762 12763 $scope.$on(BuildPriceService.events.vehicleDataRelay, function (event, data) { 12764 bpSummary.vehicleData = data; 12765 }); 12766 12767 $scope.$on(BuildPriceService.events.threeSixtyLoad, function (event, data) { 12768 console.info("%c BuildPriceSummaryController received threeSixtyLoad: ", "color: green; ", data); 12769 }); 12770 12771 //#endregion 12772 12773 $scope.$on('hide-build-price-contact-dealer-form', function (event, data) { 12774 $scope.toggleContactDealerForm(); 12775 }); 12776 12777 $scope.toggleContactDealerForm = function () { 12778 $scope.$broadcast('toggle-build-price-contact-dealer-form', getVehicleData()); 12779 bpSummary.showContactDealer = !(bpSummary.showContactDealer || false); 12780 }; 12781 12782 $scope.getGradeNameFromId = BuildPriceService.getGradeNameFromId; 12783 12784 function navigate(page) { 12785 $scope.$emit('bp-page-navigation', page); 12786 } 12787 12788 function getVehicleData() { 12789 return { 12790 model: bpSummary.model, 12791 engineVariant: bpSummary.engineVariant, 12792 grade: bpSummary.grade, 12793 enhancementPack: bpSummary.enhancementPack, 12794 trim: bpSummary.trim, 12795 colour: bpSummary.colour 12796 }; 12797 } 12798 12799 function updateModelFromVehicle(vehicleData) { 12800 bpSummary.bookTestDriveUrlParameters = $httpParamSerializer(vehicleData); 12801 } 12802 12803 $scope.openPostcodeModal = function () { 12804 $scope.$emit(BuildPriceService.events.openPostcodeDialog); 12805 }; 12806 } 12807 }]); 12808}()); 12809 12810; 12811"use strict"; 12812/* Directives */ 12813angular.module('Lexus.Directives') 12814.directive('lxFormsBuildPriceContactDealer', [function () { 12815 FormsBuildPriceContactDealerController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$location', '$rootScope', 'DealersService', 'AddressSuggestService', 'UserPreferencesService', 'VehicleService', 'vcRecaptchaService', 'FormsService', 'ngDialog', 'EloquaService']; 12816 return { 12817 scope: true, 12818 restrict: 'A', 12819 controller: FormsBuildPriceContactDealerController, 12820 controllerAs: 'ffc', 12821 bindToController: true, 12822 link: function (scope, element, attrs, filter, http) { 12823 scope.successContent = element.find('.lx-form-success'); 12824 scope.failureContent = element.find('.lx-form-failure'); 12825 scope.initVars = { 12826 showForm: attrs.showForm, 12827 forceDealerId: attrs.forceDealerId, 12828 dealerCompositeId: attrs.dealerCompositeId, 12829 isDealerSite: attrs.isDealerSite, 12830 isMultiBranchDealership: attrs.isMultiBranchDealership, 12831 12832 } 12833 } 12834 }; 12835 12836 function FormsBuildPriceContactDealerController($scope, $http, $filter, $timeout, $window, $interval, $location, $rootScope, DealersService, AddressSuggestService, UserPreferencesService, VehicleService, vcRecaptchaService, FormsService, ngDialog, EloquaService) { 12837 var ffc = this; 12838 $scope.ffc.urlParameters = $location.search(); 12839 $scope.ffc.formInitialized = false; 12840 $scope.$watch('bpSummary.showContactDealer', function (newValue, oldValue) { 12841 if (newValue) { 12842 $scope.ffc.formInitialized = true; 12843 $scope.init($scope.initVars.forceDealerId, $scope.initVars.dealerCompositeId, $scope.initVars.isDealerSite === 'true', $scope.initVars.isMultiBranchDealership === 'true'); 12844 } 12845 }); 12846 12847 $scope.init = function (forceDealerId, dealerCompositeID, isDealerSite, isMultiBranchDealer) { 12848 UserPreferencesService.getLexusVisitorSession().then(function success(data) { 12849 var dataVehicle = UserPreferencesService.getLexusVehicle($scope.ffc.urlParameters); 12850 var dataDealer = UserPreferencesService.getLexusDealer($scope.ffc.urlParameters); 12851 var dataUser = UserPreferencesService.getLexusVisitor($scope.ffc.urlParameters); 12852 $scope.ffc.form = { 12853 submitting: false, 12854 completed: false, 12855 errors: false, 12856 dealers: null, 12857 data: { 12858 postcodes: [], 12859 carmodel: dataVehicle.model, 12860 grade: dataVehicle.grade, 12861 enginevariant: dataVehicle.engineVariant, 12862 subscribe: false, 12863 postcode: "", 12864 suburb: "", 12865 pricingZone: "", 12866 additionalcomments: "", 12867 email: data.Data.email, 12868 firstname: data.Data.name, 12869 lastname: data.Data.surname, 12870 phone: data.Data.phone, 12871 captcha: "", 12872 dealerId: dataDealer.dealerID, 12873 dealerName: dataDealer.dealerName, 12874 contextDealerSiteId: forceDealerId, 12875 mcpUserId: window.SalesforceInteractions.getAnonymousId() 12876 }, 12877 }; 12878 if (dataUser.suburb && dataUser.postCode && dataUser.state && dataUser.pricingZone) { 12879 $scope.ffc.form.data.postcodes.push(UserPreferencesService.getAutocompleteTagFromVisitor(dataUser));
12880 $scope.ffc.form.data.postcode = dataUser.postCode; 12881 $scope.ffc.form.data.suburb = dataUser.suburb; 12882 $scope.ffc.form.data.state = dataUser.state; 12883 $scope.ffc.form.data.pricingZone = dataUser.pricingZone; 12884 } 12885 }, function failure(data) { 12886 $scope.ffc.form = { 12887 submitting: false, 12888 completed: false, 12889 errors: false, 12890 dealers: null, 12891 data: { 12892 postcodes: [], 12893 carmodel: null, 12894 grade: null, 12895 subscribe: false, 12896 postcode: '', 12897 additionalcomments: '', 12898 email: null, 12899 firstname: null, 12900 lastname: null, 12901 phone: null, 12902 captcha: '', 12903 dealerId: null, 12904 dealerName: null 12905 } 12906 }; 12907 }).finally(function () { 12908 if ($scope.ffc.form.data.carmodel) { 12909 $rootScope.$broadcast('field-car-model-engine-variant-update-selected'); 12910 } 12911 12912 //Main Site 12913 if ($scope.ffc.form.data.postcodes && $scope.ffc.form.data.postcodes.length > 0 && !isDealerSite) { 12914 $scope.searchNow(); 12915 } 12916 12917 //Dealer Site Multi Branch 12918 if (isDealerSite && isMultiBranchDealer) { 12919 $scope.ffc.form.data.dealerId = null; 12920 $scope.ffc.form.data.dealerName = null; 12921 $scope.loadBranches(forceDealerId); 12922 } 12923 12924 //Dealer Site NOT Multi Branch 12925 if (isDealerSite && !isMultiBranchDealer) { 12926 $scope.ffc.form.data.dealerId = dealerCompositeID; 12927 $scope.ffc.form.data.dealerName = null; 12928 } 12929 }); 12930 } 12931 12932 $scope.loadTags = function (query) { 12933 AddressSuggestService.setParam('term', query); 12934 return AddressSuggestService.GetResults(); 12935 }; 12936 12937 $scope.deselectDealer = function () { 12938 $scope.ffc.form.data.dealerId = $scope.ffc.form.data.dealerName = null; 12939 } 12940 12941 $scope.selectDealer = function (dealerInputId) { 12942 var scrollPos = $(document).scrollTop(); 12943 var maxPos = $('#' + dealerInputId).parents('.lx-form__find-dealer-js').offset().top; 12944 if (scrollPos > maxPos) { 12945 TweenLite.to(window, 0.5, { scrollTo: { y: maxPos }, ease: Power2.easeOut }); 12946 } 12947 } 12948 12949 $scope.loadBranches = function (dealerID) { 12950 $scope.ffc.form.dealersLoading = true; 12951 DealersService.setParam('dealerID', dealerID); 12952 DealersService.setParam('type', 'Sales'); 12953 DealersService.GetDealerBranches(); 12954 } 12955 12956 $scope.searchNow = function () { 12957 $scope.ffc.form.dealersLoading = true; 12958 $rootScope.$broadcast("visitor-details-change-autocomplete", { 12959 postCode: $scope.ffc.form.data.postcode, 12960 suburb: $scope.ffc.form.data.suburb, 12961 state: $scope.ffc.form.data.state, 12962 pricingZone: $scope.ffc.form.data.pricingZone, 12963 }); 12964 DealersService.setParam('postCode', $scope.ffc.form.data.postcode); //Dummy Implementation needs to be changed 12965 DealersService.setParam('suburb', $scope.ffc.form.data.suburb); //Dummy Implementation needs to be changed 12966 DealersService.setParam('type', 'Sales'); 12967 DealersService.GetResults(); 12968 12969 } 12970 12971 $scope.getData = function () { 12972 var visitor; 12973 if($scope.ffc.form.data.postcodes.length>0 && $scope.ffc.form.data.postcodes[0].text){ 12974 visitor=UserPreferencesService.splitAutoCompleteResult($scope.ffc.form.data.postcodes[0].text); 12975 } 12976 var result = { 12977 vehicle: { 12978 url: window.location.toString(), 12979 model: $scope.bpSummary.model, 12980 engineVariant: $scope.bpSummary.engineVariant, 12981 grade: $scope.bpSummary.grade, 12982 enhancementPack: $scope.bpSummary.enhancementPack, 12983 trim: $scope.bpSummary.trim, 12984 paint: $scope.bpSummary.colour, 12985 materialCode: $scope.bpSummary.paintId 12986 }, 12987 pricingEstimate: { 12988 driveAway: $scope.bpSummary?.details?.driveAway, 12989 ctpInsuranceAmount: $scope.bpSummary?.details?.ctpInsuranceAmount, 12990 dealerDelivery: $scope.bpSummary?.details?.dealerDelivery,
12991 enhancementPackValue: $scope.bpSummary?.details?.enhancementPackValue, 12992 listPriceIncGST: $scope.bpSummary?.details?.listPriceIncGST, 12993 luxuryCarTax: $scope.bpSummary?.details?.luxuryCarTax, 12994 onRoadCosts: $scope.bpSummary?.details?.onRoadCosts, 12995 paintPrice: $scope.bpSummary?.details?.paintPrice, 12996 registrationAmount: $scope.bpSummary?.details?.registrationAmount, 12997 stampDuty: $scope.bpSummary?.details?.stampDuty, 12998 finance: { 12999 deposit: $scope.bpSummary.deposit, 13000 interestRate: $scope.bpSummary.interestRate, 13001 loanTerm: $scope.bpSummary.loanTerm, 13002 loanType: $scope.bpSummary.loanType, 13003 installmentPerMonth: $scope.bpSummary?.details?.installmentPerMonth, 13004 balloonPayment: $scope.bpSummary.balloonPayment 13005 } 13006 }, 13007 dealerId: $scope.ffc.form.data.dealerId, 13008 firstName: $scope.ffc.form.data.firstname, 13009 lastName: $scope.ffc.form.data.lastname, 13010 email: $scope.ffc.form.data.email, 13011 additionalComments: $scope.ffc.form.data.additionalcomments, 13012 phone: $scope.ffc.form.data.phone, 13013 suburb: $scope.ffc.form.data.suburb, 13014 state: $scope.ffc.form.data.state, 13015 postcode: $scope.ffc.form.data.postcode, 13016 captcha: $scope.ffc.form.data.captcha, 13017 subscribe: $scope.ffc.form.data.subscribe, 13018 contextDealerSiteId: $scope.ffc.form.data.contextDealerSiteId, 13019 mcpUserId: $scope.ffc.form.data.mcpUserId 13020 } 13021 EloquaService.attachEloquaFields(result); 13022 return result; 13023 }; 13024 $scope.resetForm = function () { 13025 $scope.init(); 13026 $scope.hideContactDealerForm(); 13027 } 13028 $rootScope.$on('submit-build-price-contact-dealer-form', function (event, data) { 13029 var formData = $scope.getData(); 13030 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.BuildPriceContactDealer, [Lexus.ID.Site]), data: formData }) 13031 .then(function success(response) { 13032 // this callback will be called asynchronously 13033 // when the response is available 13034 $scope.ffc.form.completed = true; 13035 $scope.ffc.form.failed = false; 13036 $scope.ffc.form.submitting = false; 13037 var historyState = "BuildPriceContactDealerForm=Pass"; 13038 $location.state(historyState); 13039 FormsService.ShowResult($scope.successContent[0]); 13040 $rootScope.$broadcast('visitor-details-session-change', $scope.getData()); 13041 $rootScope.$broadcast('gtm-form-success', 'Build Price Contact Dealer'); 13042 }, function error(response) { 13043 // called asynchronously if an error occurs 13044 // or server returns response with an error status. 13045 $scope.ffc.form.failed = true; 13046 $scope.ffc.form.errors = data.Data; 13047 $scope.ffc.form.submitting = false; 13048 $scope.ffc.form.completed = true; 13049 var historyState = "BuildPriceContactDealerForm=Fail"; 13050 $location.state(historyState); 13051 FormsService.ShowResult($scope.failureContent[0]); 13052 13053 $window.LexusComponents.Foundation.Shared.renderToast(true); 13054 }) 13055 .finally(function () { 13056 $rootScope.$broadcast('form-result'); 13057 }); 13058 }); 13059 13060 $scope.$on('dealer-search-results-received', function (event, data) { 13061 $scope.ffc.form.dealersLoading = false; 13062 $scope.ffc.form.dealers = data.Data; 13063 $scope.checkDealersLoaded(); 13064 13065 }); 13066 13067 //Do a sanity check to see if the bound dealers match the forceDealer if not clear the force dealer 13068 $scope.checkDealersLoaded = function () { 13069 var result = $scope.ffc.form.dealers.find(function (dealer) { 13070 return dealer.dealerCode == $scope.ffc.form.data.dealerId; 13071 }); 13072 if (!result) { 13073 $scope.ffc.form.data.dealerId = null; 13074 } 13075 } 13076 13077 13078 $scope.$on('toggle-build-price-contact-dealer-form', function (event, data) { 13079 var formYPos = $("#contact-dealer-btn").offset().top; 13080 TweenLite.to(window, 1, { scrollTo: { y: formYPos, x: 0 }, ease: Power4.easeOut }); 13081 $scope.updatePreferenceDetails(data); 13082 }); 13083 13084 $scope.hideContactDealerForm = function () { 13085 $scope.$emit('hide-build-price-contact-dealer-form'); 13086 var navYPos = $("[lx-build-price-summary]").offset().top; 13087 TweenLite.to(window, 1, { scrollTo: { y: navYPos - 20, x: 0 }, ease: Power4.easeOut }); 13088 } 13089 13090 $scope.$on('postcode-changed', function () { 13091 if (!($scope.initVars.isDealerSite === 'true')) 13092 { 13093 var dataUser = UserPreferencesService.getLexusVisitor(); 13094 if (dataUser && dataUser.postCode && dataUser.suburb && $scope.ffc.form) { 13095 $scope.ffc.form.data.postcodes = []; 13096 $scope.ffc.form.data.postcodes.push({ text: dataUser.suburb + " " + dataUser.postCode }); 13097 $scope.ffc.form.data.postcode = dataUser.postCode; 13098 $scope.ffc.form.data.suburb = dataUser.suburb; 13099 $scope.ffc.form.data.state = dataUser.state; 13100 $scope.ffc.form.data.pricingZone = dataUser.pricingZone; 13101 $scope.deselectDealer(); 13102 $scope.searchNow(); 13103 } 13104 } 13105 13106 }); 13107 13108 // to do: Let's get the vehicle details directly from the model instead of the cookie change event for the sake of consistency 13109 /*$rootScope.$on('vehicle-preference-change', function (event, data) { 13110 $scope.updatePreferenceDetails(data); 13111 $scope.resetForm(); 13112 13113 }); 13114 */ 13115 13116 $scope.updatePreferenceDetails = function (data) { 13117 if ($scope.ffc.form && $scope.ffc.form.data) { 13118 $scope.ffc.form.data.vehicledetails = $filter('formatArgs')('Model: {0} \nGrade: {1} \nEngine Variant: {2} \nEnhancement Pack: {3}\nURL: {4}', [data.model, data.grade, data.enginevariant, data.enhancementPack, $location.$$absUrl]); 13119 } 13120 } 13121 13122 $scope.openUpdatePostcodeDialog = function () { 13123 $scope.$emit('open-change-postcode'); 13124 } 13125 13126 $scope.closeUpdatePostcodeDialog = function () {
13127 $scope.$emit('close-change-postcode'); 13128 } 13129 13130 13131 13132 } 13133}]); 13134; 13135//How the directive communication works with an example 13136//Changing a enhancement Pack 13137//#1 Fires an event in the EP directive 13138//#2 EP directive EMITs the change back to the parent directive 13139//#3 Parent Directive then updates its model 13140//#4 All the other directives Watch that Model Property and do stuff 13141 13142(function (undefined) { 13143 "use strict"; 13144 /* Directives */ 13145 angular.module('Lexus.Directives') 13146 .config(["$rootScopeProvider", function ($rootScopeProvider) { 13147 $rootScopeProvider.digestTtl(1000); 13148 }]) 13149 .directive('lxRangeBuildPrice', [function () { 13150 rangeBuildPriceController.$inject = ['$scope', '$rootScope', '$timeout', '$location', '$http', '$filter', 'UserPreferencesService', 'DealersService', 'PricingService', 'AddressSuggestService', 'BuildPriceService', 'ngDialog', '$anchorScroll', 'BuildPriceAPIService', 'EloquaService', 'HttpPendingRequestsService', 'Geodecode']; 13151 return { 13152 scope: true, 13153 restrict: 'A', 13154 controller: rangeBuildPriceController, 13155 controllerAs: 'bp', 13156 bindToController: true, 13157 link: function (scope, element, attrs) { 13158 scope.bp = scope.bp || {}; 13159 try { 13160 scope.bp.settings = JSON.parse(attrs.bpSettings); 13161 } catch (ex) { 13162 console.error(ex.message); 13163 } 13164 scope.bp.settings = scope.bp.settings || {}; 13165 scope.bp.settings.debug = scope.bp.settings.debug === 'true' ? true : false; 13166 scope.bp.settings.disableDiffPricing = scope.bp.settings.disableDiffPricing === 'true' ? true : false; 13167 scope.bp.settings.hideSaveBuild = scope.bp.settings.hideSaveBuild === 'true' ? true : false; 13168 scope.bp.settings.enablePricingByZone = scope.bp.settings.enablePricingByZone === 'true' ? true : false; 13169 13170 scope.bp.roadblockData = {}; 13171 scope.bp.data = { 13172 steps: $.makeArray(element.find('.lx-range-build-price__section-js').map(function (idx, item) { 13173 var $item = $(item); 13174 return { 13175 id: $item.attr('data-id'), 13176 label: $item.attr('data-label'), 13177 disabled: (($item.attr('data-disabled') || '').toLowerCase() == 'true'), 13178 route: $item.attr('data-route'), 13179 nextLabel: $item.attr('data-label-next') || 'Next', 13180 element: $item 13181 } 13182 })), 13183 userInteraction: false, 13184 activeIndex: 0, 13185 paintResolved: false, 13186 13187 vehicleLoading: false, 13188 overviewDataReceived: false, 13189 driveAwayPriceLoading: false, 13190 pricingErrors: [], 13191 openSaveBuildPriceDialog: false, 13192 onOfferText: null, 13193 13194 vehicle: { 13195 carmodel: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.carmodel) ? scope.bp.data.vehicle.carmodel : null, 13196 engineVariant: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.engineVariant) ? scope.bp.data.vehicle.engineVariant : null, 13197 grade: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.grade) ? scope.bp.data.vehicle.grade : null, 13198 postcode: '', 13199 enhancementPack: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.enhancementPack) ? scope.bp.data.vehicle.enhancementPack : null, 13200 colour: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.colour) ? scope.bp.data.vehicle.colour : null, 13201 trim: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.trim) ? scope.bp.data.vehicle.trim : null, 13202 colourId: (scope.bp && scope.bp.data && scope.bp.data.vehicle && scope.bp.data.vehicle.colourId) ? scope.bp.data.vehicle.colourId : null, 13203 pricingZone: '', 13204 }, 13205 vehicleImage: '', 13206 apiResults: { 13207 vehicleData: {}, 13208 enhancementPacks: {}, 13209 colours: {}, 13210 trims: {} 13211 }, 13212 postcodes: [], 13213 pricing: { 13214 driveAway: '', 13215 driveAwayPerMonth: '', 13216 itemised: { 13217 rrp: '', 13218 premiumPaint: '', 13219 enhancementPack: '', 13220 dealerDelivery: '' 13221 }, 13222 onroads: { 13223 total: '', 13224 registration: '', 13225 ctp: '', 13226 stampDuty: '', 13227 luxuryCarTax: '' 13228 } 13229 }, 13230 hostOrigin: '' 13231 }; 13232 scope.init(); 13233 scope.bp.showSlideOutTray = false; 13234 } 13235 }; 13236 13237 function rangeBuildPriceController($scope, $rootScope, $timeout, $location, $http, $filter, UserPreferencesService, DealersService, PricingService, AddressSuggestService, BuildPriceService, ngDialog, $anchorScroll, BuildPriceAPIService, EloquaService, HttpPendingRequestsService, Geodecode) { 13238 var bp = this; 13239 13240 13241 $scope.UserPreferencesService = UserPreferencesService; 13242 $scope.BuildPriceService = BuildPriceService; 13243 13244 $scope.init = function () { 13245 $scope.navigateToPage(0); 13246 $scope.tagsLoading = false; 13247 var visitor = $scope.UserPreferencesService.getLexusVisitor(); 13248 if (visitor && visitor.postCode && visitor.suburb && visitor.state) { 13249 var postcodeSelection = UserPreferencesService.getAutocompleteTagFromVisitor(visitor); 13250 $scope.bp.data.postcodes.push(postcodeSelection); 13251 var postcodeData = postcodeSelection.data; 13252 updateVehicleWithPostcodeData(postcodeData); 13253 13254 //$scope.bp.test.push(postcodeSelection); 13255 } 13256 13257 if ($scope.bp.settings.firstVisit = !UserPreferencesService.isPageVisited($scope.bp.settings.pageGuid)) { 13258 $rootScope.$broadcast('record-page-visit', $scope.bp.settings.pageGuid); 13259 } 13260 13261 if ($scope.bp.data.postcodes.length != 0 && !$scope.bp.settings.firstVisit) { 13262 $scope.$broadcast(BuildPriceService.events.gtmEvent, { 13263 source: 'Postcode Roadblock', data: {
13264 dialogDisplayed: false, 13265 firstVisit: $scope.bp.settings.firstVisit, 13266 postcode: $scope.bp.data.postcodes 13267 } 13268 }); 13269 } 13270 13271 $scope.bp.data.hostOrigin = $location.protocol() + '://' + $location.host(); 13272 }; 13273 13274 $scope.loadUserPreferences = function () { 13275 var vCookie = $scope.UserPreferencesService.getLexusVehicle(); 13276 var sbdv = $scope.bp.data.vehicle;//For Brevity 13277 //Clear mismatched downstream values between current cookie and deeplinks 13278 if (sbdv.carmodel != vCookie.model) 13279 { 13280 vCookie.engineVariant = vCookie.grade = vCookie.enhancementPack = vCookie.trim = vCookie.colour = null; 13281 } 13282 13283 if (sbdv.engineVariant != vCookie.engineVariant) { 13284 vCookie.grade = vCookie.enhancementPack = vCookie.trim = vCookie.colour = null; 13285 } 13286 13287 if (sbdv.grade != vCookie.grade) { 13288 vCookie.enhancementPack = vCookie.trim = vCookie.colour = null; 13289 } 13290 13291 if (sbdv.enhancementPack != vCookie.enhancementPack) { 13292 vCookie.trim = vCookie.colour = null; 13293 } 13294 13295 if (sbdv.trim != vCookie.trim) { 13296 vCookie.colour = null; 13297 } 13298 13299 if (vCookie) { 13300 // current value => cookie value if parent model value not null (eg. if model exists, we can use the enginevariant cookie value) => null 13301 sbdv.carmodel = sbdv.carmodel ? sbdv.carmodel : vCookie.model; 13302 sbdv.engineVariant = sbdv.engineVariant ? sbdv.engineVariant : (sbdv.carmodel ? vCookie.engineVariant : null); 13303 sbdv.grade = sbdv.grade ? sbdv.grade : (sbdv.engineVariant ? vCookie.grade : null); 13304 sbdv.enhancementPack = sbdv.enhancementPack ? sbdv.enhancementPack : (sbdv.grade ? vCookie.enhancementPack : null); 13305 sbdv.trim = sbdv.trim ? sbdv.trim : (sbdv.colour ? vCookie.trim : null); 13306 sbdv.colour = sbdv.colour ? sbdv.colour : (sbdv.enhancementPack ? vCookie.colour : null); 13307 13308 } 13309 } 13310 13311 $scope.loadTags = function (query) { 13312 $scope.tagsLoading = true; 13313 AddressSuggestService.setParam('term', query); 13314 return AddressSuggestService.GetResults($scope.tagsLoaded); 13315 }; 13316 13317 $scope.tagsLoaded = function () { 13318 $scope.tagsLoading = false; 13319 } 13320 13321 $scope.autocompleteLoading = function () { 13322 return $scope.tagsLoading; 13323 }; 13324 13325 $scope.updatePostcode = function ($tag, focusElement) { 13326 $scope.bp.data.postcodes = [$tag]; 13327 focusElement = focusElement != null && focusElement.length > 0 ? focusElement : '.lx-postcode-dialog__choose'; 13328 var button = angular.element(focusElement)[0]; 13329 $timeout(function () { button.focus(); }, 10, false); 13330 }; 13331 13332 $scope.clearPostcode = function () { 13333 $scope.bp.data.postcodes = []; 13334 }; 13335 13336 $scope.navigateToPage = function (pageIdOrIdx) { 13337 var userInitiated = (arguments.length > 1) ? arguments[1] : true; 13338 for (var i = 0; i < $scope.bp.data.steps.length; i++) { 13339 if (pageIdOrIdx === i || pageIdOrIdx === $scope.bp.data.steps[i].id) { 13340 $scope.bp.data.steps[i].visible = true; 13341 $scope.bp.data.activeIndex = i; 13342 window.scrollTo(0, angular.element('.lx-range-build-price')[0].offsetTop); 13343 $scope.$broadcast(BuildPriceService.events.pageNavigationBroadcast, $scope.bp.data.steps[i]); 13344 } else { 13345 $scope.bp.data.steps[i].visible = false; 13346 } 13347 } 13348 13349 $rootScope.$broadcast('refresh-gtm', 'Build and Price'); 13350 13351 if (userInitiated && pageIdOrIdx + 1 == $scope.bp.data.steps.length || pageIdOrIdx == 'summary') { 13352 $scope.$broadcast(BuildPriceService.events.gtmEvent, { source: 'Summary', data: { ...$scope.bp.data.vehicle, dealerName: $scope.bp.settings.dealerName } }); 13353 } 13354 }; 13355 13356 $scope.clearDownstream = function (level, data) { 13357 13358 if(data.userInitiated) 13359 HttpPendingRequestsService.cancelAll(); 13360 13361 //Model = 5 13362 if (level >= 5) $scope.bp.data.vehicle.engineVariant = null; 13363 //Variant = 4 13364 if (level >= 4) $scope.bp.data.vehicle.grade = null; 13365 //Grade = 3 13366 if (level >= 3) $scope.bp.data.vehicle.enhancementPack = null; 13367 if (level >= 3) $scope.bp.data.vehicleImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsYAAAGRCAQAAADMAr3sAAAEOUlEQVR42u3UIQEAAAzDsM+/6SsYHkkkFDQHwFwkADBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjCQDMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGoHq/RgGSYZc9owAAAABJRU5ErkJggg=='; 13368 13369 //Enhancement pack = 2 13370 if (level >= 2) $scope.bp.data.vehicle.colour = null; 13371 if (level >= 2) $scope.bp.data.vehicle.trim = null; 13372 if (level >= 2) $scope.bp.data.vehicleImageLoading = true; 13373 13374 //Trim = 1 13375 if (level >= 1) $scope.bp.data.vehicle.colourId = null; 13376 13377 $scope.broadcastHoldPricingCalls(true); 13378 }; 13379 13380 $scope.broadcastHoldPricingCalls = function(val){ 13381 $scope.$broadcast(BuildPriceService.events.holdPricingCallsRelay, val); 13382 } 13383 13384 $scope.$on("sticky-footer-visible", function (evt, data) { 13385 $rootScope.$broadcast("shift-promo-tiles-up", data); 13386 }); 13387 13388 $scope.closePostcodeSlideout = function () { 13389 closePostcodeSlideout(); 13390 } 13391 13392 $scope.findLocation = function () { 13393 Geodecode().then( 13394 //success 13395 function (response) { 13396 if (response.isSuccessfull) { 13397 console.log("Postcode-" + response.data.postcode); 13398 console.log("Suburb-" + response.data.suburb); 13399 response["text"] = response.data.suburb + " " + response.data.postcode; 13400 $scope.bp.data.postcodes = [response]; 13401 savePostcodeAndBroadcastEvent(); 13402 closePostcodeSlideout(); 13403 } 13404 }, 13405 //failed 13406 function (response) { 13407 console.log("Geo Location Failed"); 13408 } 13409 ).finally(function () { 13410 }); 13411 } 13412 //#region EVENTS 13413 $scope.$on(BuildPriceService.events.holdPricingCalls, function (event, data) { 13414 //console.info("Relaying holdPricingCalls: " + data); 13415 $scope.broadcastHoldPricingCalls(data); 13416 }); 13417 13418 $scope.$on(BuildPriceService.events.pageNavigation, function (event, data) { 13419 $scope.navigateToPage(data); 13420 }); 13421 13422 $scope.$on(BuildPriceService.events.userInteraction, function () { 13423 $scope.bp.data.userInteraction = true; 13424 }); 13425 13426 $scope.$on(BuildPriceService.events.overviewDataReceived, function () { 13427 $scope.bp.data.overviewDataReceived = true; 13428 $scope.loadUserPreferences(); 13429 }); 13430 13431 $scope.$on(BuildPriceService.events.openPostcodeDialog, function () { 13432 $scope.$broadcast(BuildPriceService.events.gtmEvent, { 13433 source: 'Postcode Roadblock', data: { 13434 dialogDisplayed: true,
13435 firstVisit: $scope.bp.settings.firstVisit, 13436 postcode: $scope.bp.data.postcodes 13437 } 13438 }); 13439 13440 $scope.ngDialog = ngDialog; 13441 ngDialog.open({ 13442 template: 'updatePostcodeDialogTemplate', 13443 controller: '', 13444 className: 'ngdialog-theme-default', 13445 scope: $scope, // this line wasn't here before 13446 plain: false, 13447 showClose: false, 13448 closeByDocument: true, 13449 disableAnimation: true, 13450 closeByEscape: true, 13451 appendTo: false, 13452 preCloseCallback: function (value) { 13453 //setPageVisited needs to be run here to catch the click-outside / pressing ESC case 13454 13455 13456 return (value === '$document' || value === '$closeButton' || value === '$escape') ? true : ($scope.bp.data.postcodes.length > 0) && $scope.setPageVisited(); 13457 } 13458 }); 13459 }); 13460 13461 $scope.$on(BuildPriceService.events.closePostcodeDialog, function () { 13462 console.log('BuildPriceService.events.closePostcodeDialog', arguments); 13463 ngDialog.close(); 13464 $scope.$broadcast(BuildPriceService.events.postcodeChanged); 13465 savePostcodeAndBroadcastEvent(); 13466 }); 13467 13468 $scope.$on(BuildPriceService.events.openPostcodeSlideout, function () { 13469 $scope.$broadcast(BuildPriceService.events.gtmEvent, { 13470 source: 'Postcode Roadblock', data: { 13471 dialogDisplayed: true, 13472 firstVisit: $scope.bp.settings.firstVisit, 13473 postcode: $scope.bp.data.postcodes 13474 } 13475 }); 13476 13477 $scope.bp.showSlideOutTray = true; 13478 $('body').addClass("modal-open"); 13479 }); 13480 13481 $scope.$on(BuildPriceService.events.confirmPostcodeFromSlideout, function () { 13482 closePostcodeSlideout(); 13483 console.log('BuildPriceService.events.confirmPostcodeFromSlideout', arguments); 13484 savePostcodeAndBroadcastEvent(); 13485 }); 13486 13487 $scope.$on(BuildPriceService.events.onOfferText, function (event, data) { 13488 $scope.bp.data.onOfferText = data; 13489 }); 13490 13491 $scope.$on(BuildPriceService.events.gtmEvent, function (event, data) { 13492 $rootScope.$broadcast('gtm-buildPrice', data); 13493 }); 13494 13495 $scope.errorText = function (length, min, data, value) { 13496 return "Postcode required" 13497 } 13498 13499 $scope.openUpdatePostcodeDialog = function (openDialog) { 13500 if (openDialog) { 13501 $scope.$broadcast(BuildPriceService.events.openPostcodeDialog); 13502 return; 13503 } 13504 13505 Geodecode().then( 13506 //success 13507 function (response) { 13508 if (response.isSuccessfull) { 13509 console.log("Postcode-" + response.data.postcode); 13510 console.log("Suburb-" + response.data.suburb); 13511 response["text"] = response.data.suburb + " " + response.data.postcode; 13512 $scope.updatePostcode(response); 13513 } 13514 }, 13515 //failed 13516 function (response) { 13517 console.log("Geo Location Failed"); 13518 $scope.$broadcast(BuildPriceService.events.openPostcodeDialog); 13519 } 13520 ).finally(function () { 13521 }); 13522 } 13523 13524 $scope.openPostcodeSlideout = function () { 13525 $scope.$emit(BuildPriceService.events.openPostcodeSlideout); 13526 } 13527 13528 $scope.setPageVisited = function () { 13529 $scope.bp.settings.firstVisit = false; 13530 return true; 13531 } 13532 13533 $scope.closeUpdatePostcodeDialog = function () { 13534 console.log('BuildPriceService.events.closePostcodeDialog', arguments); 13535 angular.element('tags-input').addClass('is-submitted'); 13536 $scope.$broadcast(BuildPriceService.events.closePostcodeDialog); 13537 $scope.sendRoadblockForm(); 13538 } 13539 13540 $scope.closeUpdatePostcodeSlideout = function () { 13541 console.log('BuildPriceService.events.confirmPostcodeFromSlideout', arguments); 13542 angular.element('tags-input').addClass('is-submitted'); 13543 $scope.$broadcast(BuildPriceService.events.confirmPostcodeFromSlideout); 13544 } 13545 13546 function closePostcodeSlideout () { 13547 $scope.bp.showSlideOutTray = false; 13548 $('body').removeClass("modal-open"); 13549 } 13550 13551 function savePostcodeAndBroadcastEvent() { 13552 var postcodeData = $scope.bp.data.postcodes[0].data; 13553 updateVehicleWithPostcodeData(postcodeData); 13554 13555 $scope.$emit('visitor-details-cookie-change', { 13556 postCode: postcodeData.postcode, 13557 suburb: postcodeData.suburb, 13558 state: postcodeData.state, 13559 pricingZone: postcodeData.pricingZone, 13560 }); 13561 $scope.$broadcast(BuildPriceService.events.postcodeChanged); 13562 } 13563 13564 $scope.getRoadblockData = function(){ 13565 var dataVehicle = UserPreferencesService.getLexusVehicle(); 13566 13567 var postcode; 13568 if($scope.bp.data.postcodes && $scope.bp.data.postcodes.length > 0 && $scope.bp.data.postcodes[0].data){ 13569 postcode = $scope.bp.data.postcodes[0].data.postcode; 13570 } 13571 var data = EloquaService.attachEloquaFields({ 13572 Email: $scope.bp.roadblockData.email, 13573 FirstName: $scope.bp.roadblockData.firstname, 13574 EngineVariant: $scope.bp.data.vehicle.engineVariant 13575 ? $scope.bp.data.vehicle.engineVariant 13576 : dataVehicle.engineVariant, 13577 Postcode: postcode, 13578 Model: $scope.bp.data.vehicle.carmodel, 13579 }); 13580 return data; 13581 } 13582 13583 $scope.setUserInteraction = function (data) { 13584 if (data.userInitiated) { 13585 $scope.bp.data.userInteraction = true; 13586 } 13587 } 13588 13589 $scope.sendRoadblockForm = function(){ 13590 if ($scope.bp.roadblockData.email) { 13591 $http({ method: 'POST', url: $filter('formatArgs')(Lexus.API.FormSubmission.Roadblock, [Lexus.ID.Site]), data: $scope.getRoadblockData() }) 13592 .then(function success(response) { 13593 var msg = "Roadblock form sent."; 13594 console.info ? console.info(msg) : console.log(msg); 13595 }, function failure(response) { 13596 var msg = "Roadblock form could not be sent."; 13597 console.error ? console.error(response)
13597: console.log(msg); 13598 }); 13599 } 13600 } 13601 13602 $scope.hasLocation = function() { 13603 return bp.data.vehicle.postcode && bp.data.vehicle.postcode.length > 0; 13604 } 13605 13606 $scope.$on(BuildPriceService.events.triggerSaveBuildPriceDialog, function () { 13607 $scope.bp.data.openSaveBuildPriceDialog = true; 13608 $scope.$broadcast(BuildPriceService.events.openSaveBuildPriceDialog, $scope.bp.data.vehicle); 13609 }); 13610 13611 $scope.$on(BuildPriceService.events.triggerCloseSaveBuildPriceDialog, function () { 13612 $scope.bp.data.openSaveBuildPriceDialog = false; 13613 }); 13614 13615 //#region vehicle selection listeners 13616 //each listener sets the selected value, then sets null on all downstream vehicle selections 13617 $scope.$on(BuildPriceService.events.modelSelected, function (event, data) { 13618 if (data.clearDownstream) $scope.clearDownstream(5, data); 13619 13620 $scope.setUserInteraction(data); 13621 $scope.bp.data.vehicle.carmodel = data.selection; 13622 13623 13624 $scope.saveCurrentState(); 13625 }); 13626 13627 $scope.$on(BuildPriceService.events.engineVariantSelected, function (event, data) { 13628 if (data.clearDownstream) $scope.clearDownstream(4, data); 13629 $scope.setUserInteraction(data); 13630 $scope.bp.data.vehicle.engineVariant = data.selection; 13631 13632 13633 $scope.saveCurrentState(); 13634 }); 13635 13636 $scope.$on(BuildPriceService.events.gradeSelected, function (event, data) { 13637 if (data.clearDownstream) $scope.clearDownstream(3, data); 13638 13639 $scope.setUserInteraction(data); 13640 $scope.bp.data.vehicle.grade = data.selection; 13641 13642 $scope.saveCurrentState(); 13643 }); 13644 13645 $scope.$on(BuildPriceService.events.enhancementPackSelected, function (event, data) { 13646 if (data.clearDownstream) $scope.clearDownstream(2, data); 13647 13648 $scope.setUserInteraction(data); 13649 $scope.bp.data.vehicle.enhancementPack = (data.selection) ? data.selection : data; 13650 13651 13652 $scope.saveCurrentState(); 13653 $scope.setUserInteraction(data); 13654 }); 13655 13656 $scope.$on(BuildPriceService.events.trimSelected, function (event, data) { 13657 if (data.clearDownstream) $scope.clearDownstream(1, data); 13658 13659 $scope.setUserInteraction(data); 13660 $scope.bp.data.vehicle.trim = data.selection; 13661 13662 }); 13663 13664 $scope.$on(BuildPriceService.events.paintSelected, function (event, paintObj) { 13665 $scope.clearDownstream(0, { 'userInitiated': false }); 13666 13667 $scope.setUserInteraction(paintObj); 13668 $scope.bp.data.vehicle.colour = paintObj.uriName; 13669 $scope.bp.data.vehicle.colourId = paintObj.materialCode; 13670 $scope.saveCurrentState(); 13671 }); 13672 13673 $scope.$on(BuildPriceService.events.threeSixtyLoad, function (event, data) { 13674 $scope.bp.data.vehicle.specifics = data; 13675 13676 BuildPriceAPIService.getExteriorImages($scope.bp.data.vehicle.engineVariant, data.gradeId, data.variantId, data.trimId, data.materialCode, function (images) { 13677 $scope.bp.data.vehicleImage = images.threeSixtyImagesDesktop[2]; 13678 }); 13679 13680 $scope.bp.data.paintResolved = false; 13681 }); 13682 13683 $scope.$on(BuildPriceService.events.threeSixtyLoaded, function (event, data) { 13684 $scope.bp.data.paintResolved = true; 13685 }); 13686 13687 $scope.$on(BuildPriceService.events.userSelection, function (event, data) { 13688 13689 //HttpPendingRequestsService.cancelAll(); 13690 13691 var delay = 250; // milliseconds to delay the loading. 13692 13693 $scope.bp.data.driveAwayPriceLoadingTimeout = $timeout(function () { 13694 $scope.bp.data.driveAwayPriceLoading = true; 13695 }, delay); // Don't bother showing "loading" for time in delay 13696 13697 $scope.bp.data.vehicleLoadingTimeout = $timeout(function () { 13698 $scope.bp.data.vehicleLoading = true; 13699 }, delay); // Don't bother showing "loading" for time in delay 13700 13701 console.log('BuildPriceService.events.userSelection: ', data, '\n driveAwayPriceLoading', $scope.bp.data.driveAwayPriceLoading, '\n vehicleLoading: ', $scope.bp.data.vehicleLoading); 13702 }); 13703 13704 $scope.$on(BuildPriceService.events.priceLoad, function (event, data) { 13705 if ($scope.bp.data.driveAwayPriceLoadingTimeout) { 13706 $timeout.cancel($scope.bp.data.driveAwayPriceLoadingTimeout); 13707 } 13708 $scope.bp.data.driveAwayPriceLoadingTimeout = $timeout(function() { 13709 $scope.bp.data.driveAwayPriceLoading = true; 13710 }, 100); // Don't bother showing "loading" for <100ms 13711 }); 13712 13713 $scope.$on(BuildPriceService.events.priceDone, function (event, data) { 13714 13715 if ($scope.bp.data.driveAwayPriceLoadingTimeout) { 13716 $timeout.cancel($scope.bp.data.driveAwayPriceLoadingTimeout); 13717 } 13718 $scope.bp.data.driveAwayPriceLoading = false; 13719 13720 }); 13721 13722 $scope.$on(BuildPriceService.events.priceReceived, function (event, data) { 13723 $scope.bp.data.apiResults.price = data; 13724 $scope.bp.data.pricing.driveAway = data.driveAway; 13725 $scope.bp.data.pricing.driveAwayPerMonth = data.installmentPerMonth; 13726 $scope.bp.data.pricing.itemised.rrp = data.listPriceIncGST; 13727 $scope.bp.data.pricing.itemised.premiumPaint = data.paintPrice; 13728 $scope.bp.data.pricing.itemised.enhancementPack = data.enhancementPackValue; 13729 $scope.bp.data.pricing.itemised.dealerDelivery = data.dealerDelivery; 13730 $scope.bp.data.pricing.onroads.total = data.onRoadCosts; 13731 $scope.bp.data.pricing.onroads.registration = data.registrationAmount; 13732 $scope.bp.data.pricing.onroads.ctp = data.ctpInsuranceAmount; 13733 $scope.bp.data.pricing.onroads.stampDuty = data.stampDuty; 13734 $scope.bp.data.pricing.onroads.luxuryCarTax = data.luxuryCarTax; 13735 }); 13736 13737 $scope.$on(BuildPriceService.events.priceError, function (event, data) { 13738 console.log('priceError: ', data); 13739 13740 $scope.bp.data.pricing.driveAway = 'n/a'; 13741 13742 }); 13743 13744 $scope.$on(BuildPriceService.events.vehicleDataReceived, function (event, data) { 13745 BuildPriceService.vehicleData = data; 13746 $scope.$broadcast(BuildPriceService.events.vehicleDataRelay, bp.data.apiResults.vehicleData); 13747 }); 13748 13749 $scope.$on(BuildPriceService.events.enhancementPacksReceived, function (event, data) { 13750 bp.data.apiResults.enhancementPacks = data; 13751 }); 13752 13753 $scope.$on(BuildPriceService.events.trimsReceived, function (event, data) { 13754 bp.data.apiResults.trims = data; 13755 }); 13756 13757 $scope.$on(BuildPriceService.events.paintsReceived, function (event, data) { 13758 bp.data.apiResults.colours = data; 13759 $scope.$broadcast(BuildPriceService.events.paintDataRelay, bp.data.apiResults.colours); 13760 }); 13761 13762 $scope.$on(BuildPriceService.events.invalidSelectionError, function (event, data) { 13763 var clearDownstreamTargets = (data.clearDownstreamTargets != null ? data.clearDownstreamTargets : [1, 2, 3, 4, 5]); 13764 var downstreamTargets = ['carmodel', 'engineVariant', 'grade', 'enhancementPack', 'trim', 'colour']; 13765 13766 13767 if (!$scope.bp.data.userInteraction) { 13768 $scope.navigateToPage(0); 13769 } 13770 var message; 13771 if (!$scope.bp.data.userInteraction) {
13772 //deep link invalid case 13773 console.warn("Deep link caused validation error downstream from " + data.controllerName); 13774 message = "One or more of your preferences is unavailable for your current selection. Please reconfigure your vehicle."; 13775 } else { 13776 switch (data.controllerName) { 13777 case BuildPriceService.stepIds.MODEL: 13778 console.warn("Reselection caused validation error downstream from " + data.controllerName); 13779 message = "One or more of your preferences is unavailable for your current selection. Please reconfigure your vehicle."; 13780 clearDownstreamTargets = $scope.bp.data.userInteraction ? [1, 2, 3, 4, 5] : clearDownstreamTargets; 13781 break; 13782 case BuildPriceService.stepIds.GRADE: 13783 console.warn("Reselection caused validation error downstream from " + data.controllerName); 13784 message = "One or more of your preferences is unavailable for your current selection. Please reconfigure your vehicle."; 13785 clearDownstreamTargets = $scope.bp.data.userInteraction ? [2, 3, 4, 5] : clearDownstreamTargets; 13786 break; 13787 case BuildPriceService.stepIds.ENHANCEMENT_PACK: 13788 console.warn("Reselection caused validation error downstream from " + data.controllerName); 13789 message = "One or more of your preferences is unavailable for your current selection. Please reconfigure your vehicle."; 13790 clearDownstreamTargets = $scope.bp.data.userInteraction ? [3, 4, 5] : clearDownstreamTargets; 13791 break; 13792 case BuildPriceService.stepIds.PAINT_TRIM: 13793 console.warn("Reselection caused validation error downstream from " + data.controllerName); 13794 message = "One or more of your preferences is unavailable for your current selection. Please reconfigure your vehicle."; 13795 clearDownstreamTargets = $scope.bp.data.userInteraction ? [4, 5] : clearDownstreamTargets; 13796 break; 13797 } 13798 } 13799 for (var i = 0; i < clearDownstreamTargets.length; i++) { 13800 $scope.bp.data.vehicle[downstreamTargets[clearDownstreamTargets[i]]] = null; 13801 } 13802 13803 $scope.saveCurrentState(); 13804 $scope.$emit('open-modal-window', { 13805 content: message, 13806 wrapper: ["<p style='padding: 20px 65px 0px 20px; text-align: left'>", "</p>"] 13807 }); 13808 13809 }); 13810 //#endregion 13811 13812 $scope.$watch('bp.data.vehicle', function (newValue, oldValue) { 13813 console.log("%c bp.data.vehicle changed:", "color: blue;", newValue); 13814 }); 13815 13816 $scope.$watchGroup([ 'bp.data.vehicle.carmodel', 'bp.data.vehicle.engineVariant', 'bp.data.vehicle.specifics.paintId', 'bp.data.vehicle.colourId'], function (newData, oldData, $scope) { 13817 13818 13819 for (var i in newData) { 13820 if (!newData[i]) { 13821 return; //I only care if all values are populated 13822 } 13823 } 13824 13825 if ($scope.bp.data.activeIndex == 0) { 13826 $scope.$broadcast(BuildPriceService.events.gtmEvent, { source: 'Default', data: $scope.bp.data.vehicle }); 13827 } 13828 13829 $timeout.cancel($scope.bp.data.vehicleLoadingTimeout); 13830 13831 //Set Vehicle loading to false if all of these items are available 13832 $scope.bp.data.vehicleLoading = false; 13833 13834 13835 13836 }, true); 13837 13838 $scope.saveCurrentState = function () { 13839 $scope.pushURI($scope.bp.data.vehicle); 13840 $scope.$emit('vehicle-preference-change', { 13841 model: $scope.bp.data.vehicle.carmodel, 13842 grade: $scope.bp.data.vehicle.grade, 13843 engineVariant: $scope.bp.data.vehicle.engineVariant, 13844 enhancementPack: $scope.bp.data.vehicle.enhancementPack, 13845 trim: $scope.bp.data.vehicle.trim, 13846 colour: $scope.bp.data.vehicle.colour, 13847 // colourId stores the paint's materialCode value, set in paintSelected handler via paintObj.materialCode 13848 materialCode: $scope.bp.data.vehicle.colourId 13849 }); 13850 } 13851 13852 //$scope.$on('bp-did-select-postcode', function (event, data) { 13853 // console.log('rangeDealerLookupController on(bp-did-select-postcode): ' + data); 13854 //}); 13855 13856 //$scope.broadcastGetPostcode = function (data) { 13857 // $scope.$broadcast('bp-get-postcode', data); 13858 //} 13859 13860 $scope.$watchGroup(['bp.data.vehicle.carmodel', 'bp.data.vehicle.engineVariant', 'bp.data.postcodes'], function (newDataArray, oldDataArray, $scope) { 13861 13862 if ($scope.bp.data.vehicle.carmodel && $scope.bp.data.vehicle.engineVariant) { 13863 $scope.bp.data.steps.forEach( 13864 function (step) { 13865 step.disabled = false; 13866 }); 13867 } else { 13868 $scope.bp.data.steps.forEach( 13869 function (step) { 13870 step.disabled = true; 13871 }); 13872 $scope.bp.data.steps[0].disabled = false; 13873 } 13874 13875 //A CarModel Changed happened Broadcast to the top Nav 13876 if (newDataArray[0]) { 13877 // create and dispatch the event 13878 if(typeof document !== "undefined") { 13879 const event = new CustomEvent(BuildPriceService.events.modelSelectedUpdateMenu, { 13880 detail: newDataArray[0] 13881 }); 13882 document.dispatchEvent(event); 13883 } 13884 $rootScope.$broadcast(BuildPriceService.events.modelSelectedUpdateMenu, newDataArray[0]); 13885 } 13886 13887 }); 13888 13889 function updateVehicleWithPostcodeData(postcodeData) { 13890 $scope.bp.data.vehicle.postcode = postcodeData.postcode; 13891 $scope.bp.data.vehicle.suburb = postcodeData.suburb; 13892 $scope.bp.data.vehicle.state = postcodeData.state; 13893 $scope.bp.data.vehicle.pricingZone = postcodeData.pricingZone; 13894 } 13895 //#endregion 13896 } 13897 13898 }]) 13899 .controller('lxBuildPriceRouteController', ['$scope', '$location', 'BuildPriceService', function ($scope, $location, BuildPriceService) { 13900 $scope.bp = $scope.bp || {}; 13901 $scope.bp.routing = BuildPriceService.routingSettings; 13902 13903 $scope.routeInit = function (obj) { 13904 if (obj && obj.baseUrl) { 13905 $scope.bp.routing.baseUrl = obj.baseUrl; 13906 } 13907 //parseURI(); 13908 }; 13909 13910 function ensureSuffix(suffix, value) { 13911 return value + (value[value.length - 1] === suffix ? '' : suffix); 13912 } 13913 13914 $scope.getArgPath = function () { 13915 var baseUrl = ensureSuffix('/', $scope.bp.routing.baseUrl); 13916 return ensureSuffix('/', $location.$$path).replace(baseUrl, ''); 13917 }; 13918 13919 //to do: passed in variables require validation 13920 function parseURI() { 13921 var argPath = $scope.getArgPath(); 13922 if (argPath == '') return; 13923 13924 $scope.bp.routing.currentUri = BuildPriceService.encodeUriFragment(argPath); 13925 13926 var args = argPath.split('/'); 13927 //ensure object path exists 13928 (($scope.bp = $scope.bp || {}).data = $scope.bp.data || {}
13928).vehicle = $scope.bp.data.vehicle || {}; 13929 13930 var i; 13931 for (i = 0; i < args.length; i++) { 13932 //set values in url 13933 //set upper case as the deep link steps are strict types 13934 if(i===0){ 13935 $scope.bp.data.vehicle[$scope.bp.routing.argIdx[i]] = BuildPriceService.decodeUriFragment(args[i].toUpperCase()); 13936 }else{ 13937 $scope.bp.data.vehicle[$scope.bp.routing.argIdx[i]] = BuildPriceService.decodeUriFragment(args[i]); 13938 } 13939 } 13940 for (i = i; i < $scope.bp.routing.argIdx.length; i++) { 13941 //clear remaining values 13942 $scope.bp.data.vehicle[$scope.bp.routing.argIdx[i]] = null; 13943 } 13944 13945 //additional parameters - jump to step 13946 if (args.length > $scope.bp.routing.argIdx.length) { 13947 var step = parseInt(args[$scope.bp.routing.argIdx.length]); 13948 if (!isNaN(step)) { 13949 step--; 13950 BuildPriceService.waitFor.call($scope, 'bp.data.steps', BuildPriceService.waitCondition.NOTNULL) 13951 .then(function (value) { 13952 if (value.length > step) { 13953 $scope.navigateToPage(step,false); 13954 } 13955 }); 13956 } 13957 } 13958 13959 $scope.$broadcast(BuildPriceService.events.gtmEvent, { source: 'Initial', data: $scope.bp.data.vehicle }); 13960 13961 } 13962 13963 $scope.pushURI = function (vehicleModel) { 13964 // TODO: Migrate to use the same data as _Navigation.cshtml i.e. RangeBuildPriceRepository.GetRangeBuildPriceData() 13965 // 13966 // ...because the URIs you get from clicking each step in _Navigation.cshtml 13967 // do not have hyphens in them like these URIs do. 13968 // 13969 // This means email links will NOT work if you just clicked on a step, but WILL work just after 13970 // saveCurrentState (i.e. 'bp-did-select-engine-variant' / 'bp-did-select-model' events). 13971 13972 var argPath = ""; 13973 var fullSpecification = true; 13974 for (var i = 0; i < $scope.bp.routing.argIdx.length; i++) { 13975 if (!$scope.bp.data.vehicle[$scope.bp.routing.argIdx[i]]) { 13976 fullSpecification = false; 13977 break; 13978 } 13979 argPath += "/" + BuildPriceService.encodeUriFragment($scope.bp.data.vehicle[$scope.bp.routing.argIdx[i]]); 13980 } 13981 13982 //if fully specified, also push "go to last page" into url 13983 if (fullSpecification) { 13984 argPath += "/" + $scope.bp.data.steps.length; 13985 } 13986 13987 var uri = BuildPriceService.encodeUriPath(argPath); 13988 13989 $scope.bp.routing.currentUri = uri; 13990 13991 if (history.pushState) { 13992 $location.path($scope.bp.routing.baseUrl + uri); 13993 } 13994 13995 } 13996 13997 $scope.$on(BuildPriceService.events.overviewDataReceived, function () { 13998 parseURI(); 13999 }); 14000 14001 }]); 14002 14003}()); 14004; 14005 14006(function (undefined) { 14007 "use strict"; 14008 /* Directives */ 14009 angular.module('Lexus.Directives') 14010 .config(["$rootScopeProvider", function ($rootScopeProvider) { 14011 $rootScopeProvider.digestTtl(1000); 14012 }]) 14013 .directive('lxRangePreLaunch', [function () { 14014 rangePreLaunchController.$inject = ['$scope', '$rootScope', '$timeout', '$location', '$http', '$filter', 'UserPreferencesService', 'DealersService', 'PricingService', 'AddressSuggestService', 'BuildPriceService', 'ngDialog', '$anchorScroll', 'PreLaunchAPIService', 'EloquaService', 'HttpPendingRequestsService', 'Geodecode']; 14015 return { 14016 scope: true, 14017 restrict: 'A', 14018 controller: rangePreLaunchController, 14019 controllerAs: 'pl', 14020 bindToController: true, 14021 link: function (scope, element, attrs) { 14022 scope.pl = scope.pl || {}; 14023 try { 14024 scope.pl.settings = JSON.parse(attrs.plSettings); 14025 } catch (ex) { 14026 console.error(ex.message); 14027 } 14028 scope.pl.settings = scope.pl.settings || {}; 14029 scope.pl.data = { 14030 vehicle: { 14031 carmodel: null, 14032 engineVariant: null, 14033 grade: null, 14034 postcode: '', 14035 enhancementPack: null, 14036 colour: null, 14037 trim: null, 14038 colourId: null, 14039 }, 14040 lifestyle: null, 14041 overviewDataReceived: false, 14042 }; 14043 scope.init(); 14044 } 14045 }; 14046 14047 function rangePreLaunchController($scope, $rootScope, $timeout, $location, $http, $filter, UserPreferencesService, DealersService, PricingService, AddressSuggestService, BuildPriceService, ngDialog, $anchorScroll, PreLaunchAPIService, EloquaService, HttpPendingRequestsService, Geodecode) { 14048 var pl = this; 14049 $scope.UserPreferencesService = UserPreferencesService; 14050 14051 $scope.init = function () { 14052 $scope.loadUserPreferences(); 14053 var personalization = $scope.UserPreferencesService.getPersonalizationState(); 14054 $scope.pl.data.lifestyle = personalization; 14055 PreLaunchAPIService.getModels().then($scope.ReceiveModels); 14056 }; 14057 14058 $scope.loadUserPreferences = function () { 14059 var vCookie = $scope.UserPreferencesService.getLexusVehicle(); 14060 var sbdv = $scope.pl.data.vehicle;//For Brevity 14061 14062 if (vCookie) { 14063 sbdv.carmodel = sbdv.carmodel ? sbdv.carmodel : vCookie.model; 14064 sbdv.engineVariant = sbdv.engineVariant ? sbdv.engineVariant : (sbdv.carmodel ? vCookie.engineVariant : null); 14065 } 14066 } 14067 14068 $scope.ReceiveModels = function () { 14069 pl.vehicleData = PreLaunchAPIService.data; 14070 pl.data.overviewDataReceived = true; 14071 console.info("%c 0. lxRangePreLaunch -> ReceivedOverviewData: ", "color: darkblue; ", PreLaunchAPIService.data); 14072 }; 14073 14074 $rootScope.$on('personalization-change', function (event, data) { 14075 if (data && data.lifestyle) { 14076 $scope.pl.data.lifestyle = data; 14077 } 14078 }); 14079 14080 $rootScope.$on('vehicle-preference-change', function (event, data) { 14081 if (data && data.engineVariant) { 14082 $scope.pl.data.vehicle.engineVariant = data.engineVariant; 14083 } 14084 }); 14085 14086 $scope.$on('pre-launch-gtm-event', function (event, data) { 14087 updateVehicle(data); 14088 $rootScope.$broadcast('gtm-preLaunch', angular.copy(data)); 14089 }); 14090 14091 function updateVehicle(data) { 14092 var vehicle = data.data; 14093 for (var vProp in vehicle) { 14094 pl.data.vehicle[vProp] = vehicle[vProp]; 14095 } 14096 data.data = pl.data.vehicle; 14097 } 14098 14099 } 14100 14101 }]) 14102 .controller('lxPreLaunchRouteController', ['$scope', '$location', 'BuildPriceService', function ($scope, $location, BuildPriceService) { 14103 $scope.pl = $scope.pl || {}; 14104 14105 $scope.routeInit = function (obj) { 14106 }; 14107 14108 }]); 14109 14110}());; 14111//Only Allowed to watch 14112//BuildPriceAPIService.data 14113 14114//Only Allowed to emit 14115//model selected 14116//engine variant selected 14117 14118(function (undefined) { 14119 14120 "use strict"; 14121 /* Directives */ 14122 angular.module('Lexus.Directives') 14123 .directive('lxPreLaunchInterior', [function () {
14124 preLaunchInteriorController.$inject = ['$scope', '$timeout', 'PreLaunchVehicleService', 'PreLaunchAPIService']; 14125 return { 14126 14127 scope: { 14128 selectedModel: '<carmodel', 14129 selectedEngineVariant: '<variant', 14130 overviewDataReceived:'<overview' 14131 }, 14132 restrict: 'A', 14133 controller: preLaunchInteriorController, 14134 controllerAs: 'plInterior', 14135 bindToController: true, 14136 transclude: true, 14137 link: function (scope, element, attrs, ctrl, transclude) { 14138 transclude(scope, function (clone) { 14139 element.append(clone); 14140 }); 14141 } 14142 }; 14143 14144 14145 14146 function preLaunchInteriorController($scope, $timeout, PreLaunchVehicleService, PreLaunchAPIService) { 14147 var plInterior = this; 14148 plInterior.vehicleData = null; 14149 plInterior.gradesList = null; 14150 plInterior.trims = null; 14151 plInterior.currentGradeIndex = 0; 14152 14153 $scope.$watch('plInterior.overviewDataReceived', function (newValue, oldValue) { 14154 if (newValue != null && newValue === true) { 14155 plInterior.gradesList = PreLaunchAPIService.getGradesList(plInterior.selectedEngineVariant); 14156 $scope.gradeChange(plInterior.gradesList[0], true); 14157 } 14158 }); 14159 14160 $scope.$watch('plInterior.selectedEngineVariant', function (newValue, oldValue) { 14161 if (newValue != null && plInterior.overviewDataReceived) { 14162 plInterior.gradesList = PreLaunchAPIService.getGradesList(newValue); 14163 $scope.gradeChange(plInterior.gradesList[0]); 14164 } 14165 }); 14166 14167 function init() { 14168 14169 } 14170 14171 $scope.activeTab = function (grade) { 14172 return grade == $scope.filterKey; 14173 } 14174 14175 $scope.gradeChange = function (grade, firstCall) { 14176 var gradeIndex = plInterior.gradesList.indexOf(grade); 14177 plInterior.currentGradeIndex = gradeIndex > 0 ? gradeIndex : 0; 14178 setGrade(grade, firstCall); 14179 } 14180 14181 $scope.nextGrade = function () { 14182 if (plInterior.currentGradeIndex + 1 < plInterior.gradesList.length) { 14183 plInterior.currentGradeIndex++; 14184 setGrade(plInterior.gradesList[plInterior.currentGradeIndex]); 14185 } 14186 } 14187 14188 $scope.prevGrade = function () { 14189 if (plInterior.currentGradeIndex - 1 >= 0) { 14190 plInterior.currentGradeIndex--; 14191 setGrade(plInterior.gradesList[plInterior.currentGradeIndex]); 14192 } 14193 } 14194 14195 function setGrade(grade, firstCall) { 14196 $scope.filterKey = grade; 14197 plInterior.trims = PreLaunchAPIService.getInteriorsByGradeName(plInterior.selectedEngineVariant, grade) 14198 || []; 14199 plInterior.activeTrim = plInterior.trims[0]; 14200 if (plInterior.trims.length > 0) { 14201 $scope.$emit('pre-launch-gtm-event', { source: (firstCall == true) ? 'Initial' : 'interior', data: { grade: grade, trim: plInterior.activeTrim.name } }); 14202 } 14203 } 14204 14205 init(); 14206 } 14207 }]); 14208 14209}());; 14210//Only Allowed to watch 14211//BuildPriceAPIService.data 14212 14213//Only Allowed to emit 14214//model selected 14215//engine variant selected 14216 14217(function (undefined) { 14218 14219 "use strict"; 14220 /* Directives */ 14221 angular.module('Lexus.Directives') 14222 .directive('lxPreLaunchExterior', [function () { 14223 preLaunchExteriorController.$inject = ['$scope', '$timeout', 'PreLaunchVehicleService', 'PreLaunchAPIService']; 14224 return { 14225 14226 scope: { 14227 selectedModel: '<carmodel', 14228 selectedEngineVariant: '<variant',
14229 overviewDataReceived: '<overview', 14230 lifestyle: '<lifestyle', 14231 }, 14232 restrict: 'A', 14233 controller: preLaunchExteriorController, 14234 controllerAs: 'plExterior', 14235 bindToController: true, 14236 transclude: true, 14237 link: function (scope, element, attrs, ctrl, transclude) { 14238 transclude(scope, function (clone) { 14239 element.append(clone); 14240 }); 14241 } 14242 }; 14243 14244 14245 14246 function preLaunchExteriorController($scope, $timeout, PreLaunchVehicleService, PreLaunchAPIService) { 14247 var plExterior = this; 14248 plExterior.gradesList = null; 14249 plExterior.paints = null; 14250 plExterior.lifestyleImg = null; 14251 plExterior.currentGradeIndex = 0; 14252 14253 $scope.$watch('plExterior.overviewDataReceived', function (newValue, oldValue) { 14254 if (newValue != null && newValue === true) { 14255 plExterior.gradesList = PreLaunchAPIService.getGradesList(plExterior.selectedEngineVariant); 14256 $scope.gradeChange(plExterior.gradesList[0], true); 14257 } 14258 }); 14259 14260 $scope.$watch('plExterior.selectedEngineVariant', function (newValue, oldValue) { 14261 if (newValue != null && plExterior.overviewDataReceived) { 14262 plExterior.gradesList = PreLaunchAPIService.getGradesList(newValue); 14263 $scope.gradeChange(plExterior.gradesList[0]); 14264 } 14265 }); 14266 14267 $scope.$watch('plExterior.lifestyle', function (newValue, oldValue) { 14268 if (newValue != null && newValue.lifestyle) { 14269 plExterior.lifestyleImg = newValue.lifestyle.image; 14270 } 14271 }); 14272 14273 function init() { 14274 14275 } 14276 14277 $scope.activeTab = function (grade) { 14278 return grade == $scope.filterKey; 14279 } 14280 14281 $scope.nextGrade = function () { 14282 if (plExterior.currentGradeIndex + 1 < plExterior.gradesList.length) { 14283 plExterior.currentGradeIndex++; 14284 setGrade(plExterior.gradesList[plExterior.currentGradeIndex]); 14285 } 14286 } 14287 14288 $scope.prevGrade = function () { 14289 if (plExterior.currentGradeIndex - 1 >= 0) { 14290 plExterior.currentGradeIndex--; 14291 setGrade(plExterior.gradesList[plExterior.currentGradeIndex]); 14292 } 14293 } 14294 14295 $scope.gradeChange = function (grade, firstCall) { 14296 var gradeIndex = plExterior.gradesList.indexOf(grade); 14297 plExterior.currentGradeIndex = gradeIndex > 0 ? gradeIndex : 0; 14298 setGrade(grade, firstCall); 14299 } 14300 14301 function setGrade(grade, firstCall) { 14302 $scope.filterKey = grade; 14303 plExterior.paints = PreLaunchAPIService.getExteriorsByGradeName(plExterior.selectedEngineVariant, grade) 14304 || []; 14305 plExterior.activePaint = plExterior.paints[0]; 14306 if (plExterior.paints.length > 0) { 14307 $scope.$emit('pre-launch-gtm-event', { source: (firstCall == true) ? 'Initial' : 'exterior', data: { grade: grade, colour: plExterior.activePaint.name } }); 14308 } 14309 } 14310 14311 init(); 14312 } 14313 }]); 14314 14315}());; 14316// Only Allowed to watch 14317// Only Allowed to emit 14318// model selected 14319// engine variant selected 14320 14321(function(undefined) { 14322 'use strict'; 14323 14324 var EVENT_CAROUSEL_ITEMS_FINISHED_RENDERING = 'EVENT_CAROUSEL_ITEMS_FINISHED_RENDERING'; 14325 14326 /* Directives */ 14327 angular 14328 .module('Lexus.Directives') 14329 .directive('lxGradeSelector', [ 14330 function() {
14331 gradeSelectorController.$inject = [ 14332 '$scope', 14333 '$element', 14334 '$timeout', 14335 'PreLaunchVehicleService', 14336 'PreLaunchAPIService' 14337 ]; 14338 14339 return { 14340 scope: { 14341 selectedModel: '<carmodel', 14342 selectedEngineVariant: '<variant', 14343 overviewDataReceived: '<overview', 14344 startPosition: '=?startPosition' 14345 }, 14346 restrict: 'A', 14347 controller: gradeSelectorController, 14348 controllerAs: 'gi', 14349 bindToController: true, 14350 transclude: true, 14351 link: function(scope, element, attrs, ctrl, transclude) { 14352 transclude(scope, function(clone) { 14353 element.append(clone); 14354 }); 14355 } 14356 }; 14357 14358 function gradeSelectorController( 14359 $scope, 14360 $element, 14361 $timeout, 14362 PreLaunchVehicleService, 14363 PreLaunchAPIService 14364 ) { 14365 var gi = this; 14366 var $owlCarousel; 14367 var carouselOptions; 14368 14369 gi.gradesList = null; 14370 carouselOptions = { 14371 responsive: { 14372 0: { 14373 items: 1, 14374 autoWidth: false, 14375 dots: true, 14376 stagePadding: 20 14377 }, 14378 768: { 14379 items: 2 14380 }, 14381 992: { 14382 items: 3, 14383 dots: false 14384 } 14385 }, 14386 margin: 10, 14387 startPosition: $scope.startPosition || 0 14388 }; 14389 14390 $scope.$watch('gi.overviewDataReceived', function(newValue, oldValue) { 14391 if (newValue !== null && newValue === true) { 14392 gi.gradesList = PreLaunchAPIService.getGradesByEngineVariant('UX 200'); 14393 } 14394 }); 14395 14396 $scope.$watch('gi.selectedEngineVariant', function(newValue, oldValue) { 14397 if (newValue !== null && gi.overviewDataReceived) { 14398 if (typeof $owlCarousel !== 'undefined') { 14399 $owlCarousel.trigger('destroy.owl.carousel'); 14400 $owlCarousel.find('.owl-stage-outer').children().unwrap(); 14401 } 14402 14403 gi.gradesList = PreLaunchAPIService.getGradesByEngineVariant(newValue); 14404 } 14405 }); 14406 14407 $scope.$on(EVENT_CAROUSEL_ITEMS_FINISHED_RENDERING, function() { 14408 if (typeof $owlCarousel === 'undefined') { 14409 $owlCarousel = $($element).find('.js-owl-carousel'); 14410 } 14411 14412 $timeout(function() { 14413 $owlCarousel.owlCarousel(carouselOptions); 14414 }); 14415 }); 14416 } 14417 } 14418 ]) 14419 .directive('lxGradeSelectorCarouselItems', [ 14420 function() { 14421 return { 14422 restrict: 'A', 14423 link: function($scope) { 14424 if ($scope.$last) { 14425 $scope.$emit(EVENT_CAROUSEL_ITEMS_FINISHED_RENDERING); 14426 } 14427 } 14428 }; 14429 } 14430 ]); 14431})(); 14432; 14433(function () { 14434 "use strict"; 14435 14436 angular.module('Lexus.Directives') 14437 .directive('lxSwatchChooser', [SwatchChooserDirective]); 14438 14439 function SwatchChooserDirective() { 14440 SwatchChooserController.$inject = ['$scope', '$window']; 14441 return { 14442 scope: { 14443 'swatchChooserModel': '=swatchChooserModel', 14444 'selectedSwatch': '=selectedSwatch' 14445 }, 14446 controller: SwatchChooserController, 14447 controllerAs: '$ctrl', 14448 restrict: 'A', 14449 transclude: true, 14450 14451 link: function(scope, element, attr, ctrl, transclude) { 14452 transclude(scope, function(clone, scope) { 14453 element.append(clone); 14454 }); 14455 } 14456 }; 14457 14458 14459 function SwatchChooserController($scope, $window) { 14460 var $ctrl = this; 14461 $ctrl.selectedSwatch = $scope.selectedSwatch; 14462 } 14463 } 14464}());; 14465//Only Allowed to watch 14466//BuildPriceAPIService.data 14467 14468//Only Allowed to emit 14469//models selected 14470//engine variants selected 14471 14472(function (undefined) { 14473 14474 "use strict"; 14475 /* Directives */ 14476 angular.module('Lexus.Directives') 14477 .directive('lxCompareVehiclesModel', [function () { 14478 compareVehiclesModelController.$inject = ['$scope', '$timeout', 'VehicleService', 'BuildPriceService', 'BuildPriceAPIService']; 14479 return { 14480 14481 scope: { 14482 selectedModel: '<carmodel', 14483 selectedEngineVariant: '<variant',
14484 modelsBrowsed: '<modelsbrowsed', 14485 compareVariantsSelected: '<variantsselected', 14486 compareVehiclesCount: '<compareVehiclesCount', 14487 compareModelsSelected: '<modelsselected', 14488 compareVehicleTriggered: '<comparecomplete' 14489 }, 14490 restrict: 'A', 14491 controller: compareVehiclesModelController, 14492 controllerAs: 'cvModel', 14493 bindToController: true, 14494 transclude: true, 14495 link: function (scope, element, attrs, ctrl, transclude) { 14496 transclude(scope, function (clone) { 14497 element.append(clone); 14498 }); 14499 } 14500 }; 14501 14502 14503 14504 function compareVehiclesModelController($scope, $timeout, VehicleService, BuildPriceService, BuildPriceAPIService) { 14505 var cvModel = this; 14506 cvModel.vehicleData = null; 14507 cvModel.modelSelected = false; 14508 14509 $scope.setModelHeights = function () { 14510 $timeout(function () { 14511 if (window.innerWidth > 767) { 14512 var choosers = angular.element('.lx-range-compare-model-chooser__models'); 14513 14514 for (var c = 0, clen = choosers.length; c < clen; c++) { 14515 var models = choosers[c].querySelectorAll('.lx-range-compare-model-chooser-model'); 14516 var modelHeights = [], lastHeight = 0; 14517 for (var m = 0, mlen = models.length; m < mlen; m++) { modelHeights.push(models[m].clientHeight); } 14518 modelHeights.sort(); 14519 lastHeight = modelHeights[modelHeights.length - 1]; 14520 if (modelHeights[0] != lastHeight) { 14521 for (var m = 0, mlen = models.length; m < mlen; m++) { models[m].setAttribute('style', 'height:' + lastHeight + 'px;'); } 14522 } 14523 } 14524 } 14525 }, 0, false); 14526 } 14527 14528 $scope.emitEngineVariantSelected = function (engineVariant, currentSelection, userInitiated, carModel) { 14529 var data = { 14530 selection: engineVariant.uriName, 14531 clearDownstream: (engineVariant != currentSelection && currentSelection != null), 14532 userInitiated: userInitiated, 14533 carModel: { 14534 name: carModel.name, 14535 imageSrc: carModel.imageSrc, 14536 imageAlt: carModel.imageAlt 14537 } 14538 }; 14539 $scope.$emit(BuildPriceService.events.engineVariantSelected, data); 14540 }; 14541 14542 $scope.variantHasOffer = function (model) { 14543 var hasOffer = false;
14544 model.modelEngineVariants.forEach(function (variant) { 14545 if ($scope.isOnOffer(variant)) { 14546 hasOffer = true; 14547 } 14548 }); 14549 14550 return hasOffer; 14551 }; 14552 14553 $scope.isOnOffer = function (obj) { 14554 var bool = obj.onOffer; 14555 return bool; 14556 } 14557 14558 $scope.emitModelSelected = function (model, currentSelection, userInitiated, modelElement, bodyType) { 14559 14560 if (userInitiated) { 14561 var shortModel = modelElement.replace(/\s+/g, ''); 14562 setTimeout(function () { 14563 $('html, body').animate({ scrollTop: $(shortModel).offset().top - 10 }, 250) 14564 }, 500); 14565 } 14566 14567 $scope.$emit(BuildPriceService.events.onOfferText, null); 14568 14569 var data = { 14570 selection: currentSelection === model.uriName ? null : model.uriName, 14571 clearDownstream: (model != currentSelection && currentSelection != null), 14572 userInitiated: userInitiated, 14573 modelTouched: model.uriName, 14574 bodyType: bodyType 14575 }; 14576 $scope.$emit(BuildPriceService.events.modelSelected, data); 14577 }; 14578 14579 $scope.ReceiveModels = function () { 14580 14581 cvModel.vehicleData = BuildPriceAPIService.data; 14582 console.info("%c 0. buildPriceModelController -> ReceiveModels: ", "color: darkblue; ", BuildPriceAPIService.data); 14583 $scope.$emit(BuildPriceService.events.overviewDataReceived, BuildPriceAPIService.data); 14584 $scope.setModelHeights(); 14585 }; 14586 14587 $scope.$on(BuildPriceService.events.pageNavigationBroadcast, function (e, target) { 14588 var isCurrent = target.id == 'model'; 14589 cvModel.isCurrentStep = isCurrent; 14590 }); 14591 14592 $scope.$watch('cvModel.selectedModel', function (newValue, oldValue) { 14593 if (newValue != null && !cvModel.modelSelected) { 14594 var shortModel = '.contains-model--' + newValue.replace(/\s+/g, ''); 14595 setTimeout(function () { 14596 $('html, body').animate({ scrollTop: $(shortModel).offset().top - 10 }, 250); 14597 }, 600); 14598 14599 cvModel.modelSelected = true; 14600 } 14601 }); 14602 14603 function init() { 14604 BuildPriceAPIService.getModels().then($scope.ReceiveModels); 14605 } 14606 14607 init(); 14608 } 14609 }]); 14610 14611}());; 14612"use strict"; 14613/* Directives */ 14614angular.module('Lexus.Directives') 14615.directive('lxCompareVehiclesFooter', [function () { 14616 compareVehiclesFooterController.$inject = ['$scope', '$window', '$element', 'BuildPriceService']; 14617 return { 14618 scope: { 14619 compareVariantsSelected: '<variantsselected', 14620 compareVehiclesCount: '<compareVehiclesCount', 14621 vehicleData: '<vehicleData', 14622 removeVariant: '&removeSelectedVariant', 14623 hideFooter: '<hideFooter' 14624 }, 14625 restrict: 'A', 14626 controller: compareVehiclesFooterController, 14627 controllerAs: 'cvFtr', 14628 bindToController: true, 14629 transclude: true, 14630 link: function(scope, element, attrs, ctrl, transclude) { 14631 transclude(scope, function (clone) { 14632 element.append(clone); 14633 }); 14634 scope.init(); 14635 } 14636 } 14637 14638 14639 function compareVehiclesFooterController($scope, $window, $element, BuildPriceService) { 14640 var cvFtr = this; 14641 14642 $scope.init = function () { 14643 14644 } 14645 14646 $scope.compareVehicles = function () { 14647 $scope.$emit(BuildPriceService.events.onCompareVehicles, {}); 14648 } 14649 14650 $scope.getImageSource = function (index) { 14651 if (!cvFtr.compareVariantsSelected) 14652 return Lexus.Paths.RangeCompareSilhouette + '?w=600'; 14653 14654 return ((cvFtr.compareVariantsSelected.length > index && cvFtr.compareVariantsSelected[index] != '' 14655 && cvFtr.vehicleData[cvFtr.compareVariantsSelected[index]] != 'undefined') ? 14656 cvFtr.vehicleData[cvFtr.compareVariantsSelected[index]].imageSrc : Lexus.Paths.RangeCompareSilhouette) + '?w=600'; 14657 } 14658 14659 $scope.getImageAlt = function (index) { 14660 if (!cvFtr.compareVariantsSelected) 14661 return ''; 14662 14663 return ((cvFtr.compareVariantsSelected.length > index && cvFtr.compareVariantsSelected[index] != '') ? 14664 cvFtr.vehicleData[cvFtr.compareVariantsSelected[index]].imageAlt: ''); 14665 } 14666 } 14667}]);; 14668"use strict"; 14669/* Directives */ 14670angular.module('Lexus.Directives') 14671.directive('lxCompareVehiclesVehicle', [function () { 14672 compareVehiclesVehicleController.$inject = ['$scope', '$rootScope', '$window', '$element', '$timeout', 'BuildPriceAPIService', 'BuildPriceService', 'PricingService']; 14673 return { 14674 scope: { 14675 compareModelsSelected: '<modelsselected', 14676 compareVariantsSelected: '<variantsselected', 14677 compareVehiclesCount: '<compareVehiclesCount', 14678 vehicleData: '<vehicleData', 14679 removeVariant: '&removeSelectedVariant',
14680 activeVehicleIndex: '<activeVehicleIndex', 14681 postcode: '<postcode', 14682 vehicleSelected: '&onVehicleSelected', 14683 }, 14684 restrict: 'A', 14685 controller: compareVehiclesVehicleController, 14686 controllerAs: 'ffc', 14687 bindToController: true, 14688 transclude: true, 14689 link: function(scope, element, attrs, ctrl, transclude) { 14690 transclude(scope, function (clone) { 14691 element.append(clone); 14692 }); 14693 scope.ffc = scope.ffc || {}; 14694 scope.ffc.vehicleIndex = attrs.vehicleIndex || "0"; 14695 scope.ffc.engineVariant = null; 14696 scope.ffc.carModelObject = null; 14697 scope.ffc.variantInit = false; 14698 scope.ffc.imageTransitionInProgress = false; 14699 scope.ffc.grade = null; 14700 scope.ffc.gradeId = null; 14701 scope.ffc.driveAwayPrice = null; 14702 scope.ffc.driveAwayPriceLoading = false; 14703 scope.ffc.pricingSuccess = true; 14704 14705 //defaults 14706 scope.ffc.form = { 14707 data: { 14708 carmodel: null, 14709 grade: null, 14710 engineVariant: null, 14711 engineVariantAndGrade: null, 14712 enhancementPack: null, 14713 trim: null, 14714 colour: null, 14715 }, 14716 settings: { 14717 hideDefaultSelectOption: true 14718 }, 14719 }; 14720 scope.init(); 14721 } 14722 } 14723 14724 14725 function compareVehiclesVehicleController($scope, $rootScope, $window, $element, $timeout, BuildPriceAPIService, BuildPriceService, PricingService) { 14726 var cvv = this; 14727 14728 $scope.$watch("ffc.postcode", BuildPriceService.watchDebounce(function (newValue, oldValue) { 14729 if (newValue != null) { 14730 console.info("%c compareVehiclesVehicleController received POSTCODE: ", "color: green; ", newValue); 14731 getPriceByGrade(); 14732 } 14733 }, 50), true); 14734 14735 $scope.$watch("ffc.gradeId", BuildPriceService.watchDebounce(function (newValue, oldValue) { 14736 if (newValue != null) { 14737 console.info("%c compareVehiclesVehicleController gradeID Changed: ", "color: blue; ", newValue); 14738 getPriceByGrade(); 14739 } 14740 }, 50), true); 14741 14742 function getPriceByGrade() { 14743 14744 if ($scope.ffc.gradeId && $scope.ffc.postcode) { 14745 $scope.ffc.driveAwayPriceLoading = true; 14746 PricingService.driveAwayByGrade($scope.ffc.gradeId, 14747 $scope.ffc.postcode).then(function (data) { 14748 if (data.status === "Success") { 14749 if (data.data && data.data.driveAway) { 14750 $scope.ffc.driveAwayPrice = data.data.driveAway; 14751 $scope.ffc.pricingSuccess = true; 14752 } 14753 else { 14754 $scope.ffc.driveAwayPrice = 'n/a'; 14755 $scope.ffc.pricingSuccess = false; 14756 } 14757 } 14758 else { 14759 $scope.ffc.driveAwayPrice = 'n/a'; 14760 $scope.ffc.pricingSuccess = false; 14761 } 14762 }, function (reason) { 14763 $scope.ffc.driveAwayPrice = 'n/a'; 14764 $scope.ffc.pricingSuccess = false; 14765 }).finally(function (data) { 14766 $scope.ffc.driveAwayPriceLoading = false; 14767 pricingReport(); 14768 });; 14769 } 14770 } 14771 14772 function pricingReport() { 14773 if ($scope.ffc.pricingSuccess) { 14774 $element.removeClass('pricing-error'); 14775 } else { 14776 $element.addClass('pricing-error'); 14777 } 14778 } 14779 14780 function getImageSource(index) { 14781 if (!cvv.compareVariantsSelected) 14782 return Lexus.Paths.RangeCompareSilhouette + '?w=600'; 14783 14784 return ((cvv.compareVariantsSelected.length > index && cvv.compareVariantsSelected[index] != '' 14785 && cvv.vehicleData[cvv.compareVariantsSelected[index]] != 'undefined') ? 14786 cvv.vehicleData[cvv.compareVariantsSelected[index]].imageSrc : Lexus.Paths.RangeCompareSilhouette) + '?w=600'; 14787 } 14788 14789 function updateVehicleImageAndAnimate() { 14790 $scope.ffc.imageTransitionInProgress = true; 14791 $timeout(function () { 14792 $scope.ffc.vehicleImageSource = $scope.ffc.carModelObject.imageSrc+ '?w=600'; 14793 }, 250); 14794 $timeout(function () { 14795 $scope.ffc.imageTransitionInProgress = false; 14796 }, 500); 14797 } 14798 14799 function setEngineVariantObjects() { 14800 14801 if (!$scope.ffc.variantInit) { 14802 //OnInit Get details from compareState 14803 if ($scope.ffc.compareVariantsSelected && $scope.ffc.compareVariantsSelected.length > 0) { 14804 $scope.ffc.variantInit = true; 14805 $scope.ffc.engineVariant = BuildPriceAPIService.findEngineVariantInVehicleData($scope.ffc.compareVariantsSelected[$scope.ffc.vehicleIndex]); 14806 } 14807 } 14808 else if ($scope.ffc.form.data.engineVariantAndGrade == null) { 14809 //When Updated Model 14810 $scope.ffc.engineVariant = ($scope.ffc.carModelObject && $scope.ffc.carModelObject.modelEngineVariants 14811 && $scope.ffc.carModelObject.modelEngineVariants.length > 0) ? $scope.ffc.carModelObject.modelEngineVariants[0] : null; 14812 } 14813 else { 14814 //From FormsCarModelEngineVariantGradeAndPacks variant dropdown model 14815 $scope.ffc.engineVariant = BuildPriceAPIService.findEngineVariantInVehicleData($scope.ffc.form.data.engineVariant); 14816 $scope.ffc.grade = getGradeFromVariant($scope.ffc.form.data.grade); 14817 $scope.ffc.gradeId = $scope.ffc.grade.gradeID; 14818 return;//do not set 14819 } 14820 14821 $scope.ffc.form.data.engineVariantAndGrade = getEngineVariantAndGrade(); 14822 $scope.ffc.grade = getGradeFromVariant(null); 14823 $scope.ffc.gradeId = $scope.ffc.grade.gradeID; 14824 14825 } 14826 14827 function getGradeFromVariant(grade) { 14828 //Default Grade
14829 if ($scope.ffc.engineVariant && $scope.ffc.engineVariant.grades 14830 && $scope.ffc.engineVariant.grades.length > 0) { 14831 14832 var gradeMappedArray = $scope.ffc.engineVariant.grades.map(function (currentValue, index, array) { 14833 return { 14834 name: currentValue.name, 14835 gradeID: currentValue.id, 14836 gradeMDM: currentValue.gradeID, 14837 paints: currentValue.availablePaints, 14838 trims:currentValue.availableTrims 14839 } 14840 }); 14841 14842 return (grade == null) ? gradeMappedArray[0] : findGradeInGrades(grade, gradeMappedArray); 14843 } 14844 14845 return null; 14846 } 14847 14848 function findGradeInGrades(grade, grades) { 14849 var gradeObj = grades.find(function (gradeItem) { 14850 return gradeItem.name === grade; 14851 }); 14852 return gradeObj; 14853 }; 14854 14855 function getEngineVariantAndGrade() { 14856 //For FormsCarModelEngineVariantGradeAndPacks support 14857 var grade = getGradeFromVariant(null); 14858 return $scope.ffc.engineVariant.name + ";" + ((grade) ? grade.name : ''); 14859 } 14860 14861 function enhancementPacksReceived(response) { 14862 if (response && response.length > 0) { 14863 $scope.ffc.form.data.enhancementPack = response[0].uriName; 14864 14865 $scope.$emit(BuildPriceService.events.enhancementPackSelected, { 14866 enhancementPack: $scope.ffc.form.data.enhancementPack, 14867 vehicleIndex: $scope.ffc.vehicleIndex 14868 }); 14869 } 14870 } 14871 14872 $rootScope.$on('vehicle-preference-change', function (event, data) { 14873 //This is a global Event, Update only if it is meant for this vehicle 14874 if (data.vehicleIndex == $scope.ffc.vehicleIndex) { 14875 $scope.ffc.carModelObject = BuildPriceAPIService.findModelInVehicleData(data.model); 14876 updateVehicleImageAndAnimate($scope); 14877 setEngineVariantObjects(); 14878 BuildPriceAPIService.getVariants($scope.ffc.engineVariant.name, $scope.ffc.gradeId, enhancementPacksReceived); 14879 14880 $scope.$emit(BuildPriceService.events.gradeSelected, { 14881 carmodel:$scope.ffc.carModelObject.name, 14882 engineVariant:$scope.ffc.engineVariant.name, 14883 grade: $scope.ffc.grade.name, 14884 enhancementPack:$scope.ffc.form.data.enhancementPack, 14885 trim:$scope.ffc.grade.trims[0].shortName, 14886 colour:$scope.ffc.grade.paints[0].shortName, 14887 gradeId: $scope.ffc.grade.gradeMDM, 14888 vehicleIndex: $scope.ffc.vehicleIndex }); 14889 } 14890 }); 14891 14892 $scope.init = function () { 14893 $scope.ffc.vehicleImageSource = getImageSource($scope.ffc.vehicleIndex); 14894 $scope.ffc.form.data.carmodel = ($scope.ffc.compareModelsSelected && $scope.ffc.compareModelsSelected.length > 0) ? 14895 $scope.ffc.compareModelsSelected[$scope.ffc.vehicleIndex] : ''; 14896 $scope.ffc.carModelObject = BuildPriceAPIService.findModelInVehicleData($scope.ffc.form.data.carmodel); 14897 $scope.ffc.engineVariant = BuildPriceAPIService.findEngineVariantInVehicleData($scope.ffc.compareVariantsSelected[$scope.ffc.vehicleIndex]); 14898 $rootScope.$broadcast('field-car-model-engine-variant-update-selected', { vehicleIndex: $scope.ffc.vehicleIndex }); 14899 setTimeout(function () { 14900 window.scrollTo(0, angular.element('.lx-range-compare-vehicles')[0].offsetTop); 14901 }, 600); 14902 14903 } 14904 14905 $scope.getImageAlt = function (index) { 14906 if (!cvv.compareVariantsSelected) 14907 return ''; 14908 14909 return ((cvv.compareVariantsSelected.length > index && cvv.compareVariantsSelected[index] != '') ? 14910 cvv.vehicleData[cvv.compareVariantsSelected[index]].imageAlt : ''); 14911 } 14912 14913 $scope.onVehicleSectionClick = function(){ 14914 $scope.$emit(BuildPriceService.events.compareVehicleActiveSelection, $scope.ffc.vehicleIndex); 14915 } 14916
14917 $scope.updatePostCode = function () { 14918 $scope.$emit(BuildPriceService.events.openPostcodeDialog); 14919 } 14920 14921 $scope.headerLink = function (configuredPath, fallBack) { 14922 if (!configuredPath) { 14923 return fallBack + "/" + $scope.getBuildPriceLink(); 14924 } 14925 return configuredPath; 14926 } 14927 14928 $scope.getBuildPriceLink = function () { 14929 //No deeplink if epack is not set 14930 if ($scope.ffc.form && $scope.ffc.form.data && $scope.ffc.form.data.enhancementPack) 14931 { 14932 var vehicle = { 14933 carmodel: $scope.ffc.carModelObject.name, 14934 engineVariant: $scope.ffc.engineVariant.name, 14935 grade: $scope.ffc.grade.name, 14936 enhancementPack: $scope.ffc.form.data.enhancementPack, 14937 colour: ($scope.ffc.grade.paints.length > 0) ? $scope.ffc.grade.paints[0].shortName : '', 14938 trim: ($scope.ffc.grade.trims.length > 0) ? $scope.ffc.grade.trims[0].shortName : '' 14939 }; 14940 14941 return BuildPriceService.getBuildPriceLink(vehicle, 3); 14942 14943 } 14944 return ''; 14945 } 14946 14947 14948 } 14949}]);; 14950"use strict"; 14951/* Directives */ 14952angular.module('Lexus.Directives') 14953.directive('lxCompareRangeSpec', [function () { 14954 compareRangeSpecController.$inject = ['$scope', '$http', '$filter', '$timeout', '$interval', 14955 '$location', '$rootScope', 'API', '$sce', '$log', 'BuildPriceService']; 14956 return { 14957 scope: { 14958 compareGradesSelected: '<gradesselected', 14959 }, 14960 restrict: 'A', 14961 controller: compareRangeSpecController, 14962 controllerAs: 'rtd', 14963 bindToController: true, 14964 transclude: true, 14965 link: function (scope, element, attrs, ctrl, transclude) { 14966 transclude(scope, function (clone) { 14967 element.append(clone); 14968 }); 14969 scope.init(); 14970 scope.rtd.mdmIds = attrs.mdmList || ""; 14971 } 14972 } 14973 14974 function compareRangeSpecController($scope, $http, $filter, $timeout, $interval, $location, $rootScope, API, $sce, $log, BuildPriceService) { 14975 var rtd = this; 14976 var APPEND_GRADE_ID = "_V2"; 14977 14978 $scope.rtd.urlParameters = $location.search(); 14979 14980 $scope.$watch("rtd.compareGradesSelected", BuildPriceService.watchDebounce(function (newValue, oldValue) { 14981 if (newValue != null) { 14982 console.info("%c compareGradesSelected grade updated: ", "color: green; ", newValue.join('+')); 14983 fetchTechDataDetails(); 14984 } 14985 }, 50), true); 14986 14987 rtd.apiService = API; 14988 14989 $scope.init = function () { 14990 $scope.rtd = $scope.rtd || {}; 14991 14992 $scope.rtd.data = { 14993 featuresData: null, 14994 featuresByCategory: [] 14995 }; 14996 $scope.rtd.filteredFeatures = []; 14997 $scope.rtd.rawCustomizedFeatures = []; 14998 $scope.rtd.data.engineVariants = []; 14999 $scope.rtd.comparingSameVehicle = false; 15000 $scope.rtd.allFilter = true; 15001 15002 $scope.rtd.featuresByCategoryRendering = false; 15003 15004 if ($scope.rtd.compareGradesSelected.length >= 2) { 15005 fetchTechDataDetails(); 15006 } 15007 }; 15008 15009 $scope.findValueByKey = function (grade, feature) { 15010 if (feature.specs) { 15011 return (grade.indexOf(APPEND_GRADE_ID) > -1) ? feature.specs[grade.replace(APPEND_GRADE_ID, '')] : feature.specs[grade]; 15012 } 15013 15014 } 15015 15016 $scope.filterFeatures = function (diff) { 15017 if (diff) { 15018 $scope.rtd.allFilter = false; 15019 var filteredArray = []; 15020 15021 $scope.rtd.rawCustomizedFeatures.map(function (arr) { 15022 var filteredFeatures = []; 15023 var modifiedArray = angular.copy(arr, {}); 15024 15025 var same = false; 15026 15027 var keys = Object.keys(arr.grades); 15028 var filteredFeatures = []; 15029 arr.features.map(function (feature) { 15030 15031 if (feature.specs) { 15032 same = $scope.findValueByKey(keys[0], feature) == $scope.findValueByKey(keys[1], feature); 15033 } 15034 if (!same) { 15035 filteredFeatures.push(feature); 15036 same = false; 15037 } 15038 15039 }); 15040 modifiedArray.features = filteredFeatures; 15041 filteredArray.push(modifiedArray);
15042 15043 }); 15044 $scope.rtd.filteredFeatures = filteredArray; 15045 return; 15046 } 15047 15048 $scope.rtd.allFilter = true; 15049 $scope.rtd.filteredFeatures = $scope.rtd.rawCustomizedFeatures.map(function (a) { return angular.copy(a, {}); }); 15050 } 15051 15052 function fetchTechDataDetails() { 15053 if ($scope.rtd.compareGradesSelected.length < 2) { 15054 return; 15055 } 15056 15057 $scope.rtd.featuresByCategoryLoading = true; 15058 $scope.rtd.comparingSameVehicle = $scope.rtd.compareGradesSelected[0] == $scope.rtd.compareGradesSelected[1]; 15059 15060 var getRequest = ($scope.rtd.comparingSameVehicle) ? API.get($filter('formatArgs')(Lexus.API.Lookup.RangeTechDataByGrade, [ 15061 Lexus.ID.Site, 15062 $scope.rtd.compareGradesSelected[0] 15063 ])) : API.get($filter('formatArgs')(Lexus.API.Lookup.RangeTechDataByGrade, [ 15064 Lexus.ID.Site, 15065 $scope.rtd.compareGradesSelected[0], 15066 $scope.rtd.compareGradesSelected[1] 15067 ])); 15068 15069 getRequest 15070 .then(function (data) { 15071 if (!data) { 15072 return; 15073 } 15074 15075 $scope.rtd.featuresByCategoryRendering = true; 15076 15077 $timeout(function () { 15078 15079 $scope.rtd.data.featuresByCategory = data.data; 15080 15081 var cloneData = data.data.map(function (a) { return angular.copy(a, {}); }); 15082 15083 $scope.rtd.rawCustomizedFeatures = filterKeyFeatures(cloneData, "id", $scope.rtd.mdmIds); 15084 15085 $scope.filterFeatures(!$scope.rtd.allFilter); 15086 15087 $scope.rtd.featuresByCategoryRendering = false; 15088 }, 1); 15089 15090 $scope.rtd.featuresByCategoryLoading = false; 15091 }, function (error) { 15092 $log.error(error); 15093 $scope.rtd.featuresByCategoryLoading = false; 15094 }); 15095 }; 15096 15097 function filterKeyFeatures(rawArray, propId, filterContent) { 15098 //if empty returns the raw 15099 if (!filterContent) { 15100 if ($scope.rtd.comparingSameVehicle) { 15101 transformSpecsForSameVehicle(rawArray); 15102 } 15103 return rawArray; 15104 } 15105 15106 15107 var filteredArray = []; 15108 15109 rawArray.map(function (arr) { 15110 var filteredFeatures = []; 15111 var content = false; 15112 15113 arr.features.map(function (feature) { 15114 15115 if (!feature.hasOwnProperty(propId)) 15116 return; 15117 15118 var matchExpr = new RegExp("(?:^|\\b)(" + feature[propId] + ")(?=\\b|$)"); 15119 15120 if (filterContent.match(matchExpr) != null) { 15121 filteredFeatures.push(feature); 15122 content = true; 15123 } 15124 15125 }); 15126 if (content) { 15127 //update features 15128 arr.features = filteredFeatures; 15129 //Duplicate the grades - FE 15130 if ($scope.rtd.comparingSameVehicle) { 15131 transformSpecsForSameVehicle([arr]); 15132 } 15133 15134 filteredArray.push(arr); 15135 content = false; 15136 } 15137 15138 }); 15139 15140 return filteredArray; 15141 }; 15142 15143 function transformSpecsForSameVehicle(arr) { 15144 arr.map(function (a) { 15145 var keys = Object.keys(a.grades); 15146 if (keys.length == 1) { 15147 a.grades[keys[0] + APPEND_GRADE_ID] = a.grades[keys[0]]; 15148 } 15149 }); 15150 15151 15152 return arr; 15153 } 15154 } 15155}]); 15156 15157 15158 15159; 15160"use strict"; 15161/* Directives */ 15162angular.module('Lexus.Directives') 15163.directive('lxCompareVehiclesCta', [function () { 15164 compareVehiclesCtaController.$inject = ['$scope', '$rootScope', '$window', '$element', '$timeout', 'BuildPriceAPIService', 'BuildPriceService', 'PricingService']; 15165 return { 15166 scope: { 15167 compareModelsSelected: '<modelsselected', 15168 compareVariantsSelected: '<variantsselected', 15169 compareGradesSelected: '<gradesselected', 15170 compareEpacksSelected: '<epacksselected', 15171 comparePaintsSelected: '<paintsselected', 15172 compareTrimsSelected: '<trimsselected', 15173 vehicleSelected: '&onVehicleSelected', 15174 }, 15175 restrict: 'A', 15176 controller: compareVehiclesCtaController, 15177 controllerAs: 'cvcta', 15178 bindToController: true, 15179 transclude: true, 15180 link: function(scope, element, attrs, ctrl, transclude) { 15181 transclude(scope, function (clone) { 15182 element.append(clone); 15183 }); 15184 scope.cvcta = scope.cvcta || {}; 15185 } 15186 } 15187 15188 15189 function compareVehiclesCtaController($scope, $rootScope, $window, $element, $timeout, BuildPriceAPIService, BuildPriceService, PricingService) { 15190 var cvcta = this; 15191 15192 $scope.headerLink = function (configuredPath, fallBack, vehicleIndex) { 15193 if (!configuredPath) { 15194 return fallBack + "/" + $scope.getBuildPriceLink(vehicleIndex); 15195 } 15196 return configuredPath; 15197 } 15198 15199 $scope.getBuildPriceLink = function (vehicleIndex) { 15200 15201 var vehicle = { 15202 carmodel: $scope.cvcta.compareModelsSelected[vehicleIndex], 15203 engineVariant: $scope.cvcta.compareVariantsSelected[vehicleIndex], 15204 grade: $scope.cvcta.compareGradesSelected[vehicleIndex], 15205 enhancementPack: $scope.cvcta.compareEpacksSelected[vehicleIndex], 15206 colour: $scope.cvcta.comparePaintsSelected[vehicleIndex], 15207 trim: $scope.cvcta.compareTrimsSelected[vehicleIndex], 15208 }; 15209 15210 return BuildPriceService.getBuildPriceLink(vehicle, 3); 15211 } 15212 15213 15214 } 15215}]);; 15216 15217(function (undefined) { 15218 "use strict"; 15219 /* Directives */ 15220 angular.module('Lexus.Directives') 15221 .config(["$rootScopeProvider", function ($rootScopeProvider) { 15222 $rootScopeProvider.digestTtl(1000); 15223 }]) 15224 .directive('lxRangeCompareVehicles', [function () { 15225 rangeCompareVehiclesController.$inject = ['$scope', '$rootScope', '$timeout', '$location', '$http', '$filter', 'UserPreferencesService', 'BuildPriceService', '$anchorScroll', 'BuildPriceAPIService', 'HttpPendingRequestsService', 'ngDialog', 'AddressSuggestService']; 15226 return { 15227 scope: true, 15228 restrict: 'A', 15229 controller: rangeCompareVehiclesController, 15230 controllerAs: 'cv', 15231 bindToController: true, 15232 link: function (scope, element, attrs) { 15233 scope.cv = scope.cv || {}; 15234 try { 15235 scope.cv.settings = JSON.parse(attrs.bpSettings); 15236 } catch (ex) { 15237 console.error(ex.message); 15238 } 15239 scope.cv.settings = scope.cv.settings || {}; 15240 scope.cv.settings.debug = scope.cv.settings.debug === 'true' ? true : false; 15241 scope.cv.settings.disableDiffPricing = scope.cv.settings.disableDiffPricing === 'true' ? true : false; 15242 scope.cv.data = { 15243 userInteraction: false, 15244 activeIndex: 0, 15245 activeVehicleIndex:0, 15246 compareVehiclesTriggered:false, 15247 vehicleLoading: false, 15248 onOfferText: null, 15249 compareVehicles: { 15250 selectedCount: 0, 15251 variantsAdded: [], 15252 modelsBrowsed: [], 15253 modelsAdded: [], 15254 gradesAdded: [], 15255 trimsAdded: [], 15256 paintsAdded: [], 15257 ePacksAdded: [], 15258 gradeIdsAdded: [], 15259 vehiclesData: {} 15260 }, 15261 vehicle: { 15262 carmodel: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.carmodel) ? scope.cv.data.vehicle.carmodel : null, 15263 engineVariant: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.engineVariant) ? scope.cv.data.vehicle.engineVariant : null, 15264 grade: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.grade) ? scope.cv.data.vehicle.grade : null, 15265 postcode: '', 15266 enhancementPack: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.enhancementPack) ? scope.cv.data.vehicle.enhancementPack : null, 15267 colour: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.colour) ? scope.cv.data.vehicle.colour : null, 15268 trim: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.trim) ? scope.cv.data.vehicle.trim : null, 15269 colourId: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.colourId) ? scope.cv.data.vehicle.colourId : null, 15270 bodyType: (scope.cv && scope.cv.data && scope.cv.data.vehicle && scope.cv.data.vehicle.bodyType) ? scope.cv.data.vehicle.bodyType : null, 15271 }, 15272 vehicleImage: '', 15273 postcodes: [] 15274 }; 15275 scope.init(); 15276 } 15277 }; 15278 15279 function rangeCompareVehiclesController($scope, $rootScope, $timeout, $location, $http, $filter, UserPreferencesService, BuildPriceService, $anchorScroll, BuildPriceAPIService, HttpPendingRequestsService, ngDialog, AddressSuggestService) { 15280 var cv = this; 15281 15282 15283 $scope.UserPreferencesService = UserPreferencesService; 15284 $scope.BuildPriceService = BuildPriceService; 15285 15286 $scope.init = function () { 15287 var visitor = $scope.UserPreferencesService.getLexusVisitor(); 15288 $scope.tagsLoading = false; 15289 if (visitor && visitor.postCode && visitor.suburb && visitor.state) { 15290 var postcodeSelection = UserPreferencesService.getAutocompleteTagFromVisitor(visitor); 15291 $scope.cv.data.postcodes.push(postcodeSelection); 15292 $scope.cv.data.vehicle.postcode = visitor.postCode; 15293 } 15294 }; 15295 15296 function getBodyTypeByModel(carmodel, vehicleData) { 15297 var bodyType = ""; 15298 if (!carmodel) return bodyType; 15299 15300 for (var i = 0; i < vehicleData.length; i++) { 15301 15302 var modelMap = vehicleData[i].models.map(function (model) { 15303 return model.uriName == carmodel; 15304 }) 15305 15306 if (modelMap.length > 0 && modelMap.indexOf(true) > -1) { 15307 return vehicleData[i].uriName; 15308 } 15309 } 15310 return bodyType; 15311 } 15312 15313 $scope.loadUserPreferences = function (vehicledata) { 15314 var sbdv = $scope.cv.data.vehicle; 15315 15316 //TODO: If carmodel is preselected then add that car as default model to compare. 15317 var vCookie = $scope.UserPreferencesService.getLexusVehicle(); 15318 var params = (vCookie.model) ? { model: vCookie.model } : null;
15319 var vCompareVehicleCookie = $scope.UserPreferencesService.getCompareVehiclesState(params); 15320 15321 if (vCompareVehicleCookie) { 15322 sbdv.carmodel = sbdv.carmodel ? sbdv.carmodel : vCompareVehicleCookie.model; 15323 } 15324 if (!sbdv.bodyType) { 15325 sbdv.bodyType = getBodyTypeByModel(sbdv.carmodel, vehicledata); 15326 } 15327 $scope.cv.data.compareVehicles.modelsBrowsed.push(sbdv.carmodel + ":" + sbdv.bodyType); 15328 } 15329 15330 $scope.loadTags = function (query) { 15331 $scope.tagsLoading = true; 15332 AddressSuggestService.setParam('term', query); 15333 return AddressSuggestService.GetResults($scope.tagsLoaded); 15334 }; 15335 15336 $scope.tagsLoaded = function () { 15337 $scope.tagsLoading = false; 15338 } 15339 15340 $scope.autocompleteLoading = function () { 15341 return $scope.tagsLoading; 15342 }; 15343 15344 $scope.updatePostcode = function ($tag) { 15345 $scope.cv.data.postcodes = [$tag]; 15346 $scope.cv.data.vehicle.postcode = $tag.data.postcode; 15347 $scope.$emit('visitor-details-cookie-change', { 15348 postCode: $tag.data.postcode, 15349 suburb: $tag.data.suburb, 15350 state: $tag.data.state 15351 }); 15352 //close after update 15353 $timeout(function () { ngDialog.close(); }, 300); 15354 }; 15355 15356 $scope.clearPostcode = function () { 15357 $scope.cv.data.postcodes = []; 15358 $scope.cv.data.vehicle.postcode = ''; 15359 }; 15360 15361 15362 $scope.clearDownstream = function (level, data) { 15363 15364 if(data.userInitiated) 15365 HttpPendingRequestsService.cancelAll(); 15366 15367 //Model = 5 15368 if (level >= 5) $scope.cv.data.vehicle.engineVariant = null; 15369 //Variant = 4 15370 if (level >= 4) $scope.cv.data.vehicle.grade = null; 15371 //Grade = 3 15372 if (level >= 3) $scope.cv.data.vehicle.enhancementPack = null; 15373 if (level >= 3) $scope.cv.data.vehicleImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsYAAAGRCAQAAADMAr3sAAAEOUlEQVR42u3UIQEAAAzDsM+/6SsYHkkkFDQHwFwkADBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjCQDMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAHMGAAzBjBjAMwYwIwBMGMAMwbAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwAzBsCMAcwYADMGMGMAzBjAjAEwYwDMGMCMATBjADMGwIwBzBgAMwYwYwDMGMCMATBjADMGoHq/RgGSYZc9owAAAABJRU5ErkJggg=='; 15374 15375 //Enhancement pack = 2 15376 if (level >= 2) $scope.cv.data.vehicle.colour = null; 15377 if (level >= 2) $scope.cv.data.vehicle.trim = null; 15378 if (level >= 2) $scope.cv.data.vehicleImageLoading = true; 15379 15380 //Trim = 1 15381 if (level >= 1) $scope.cv.data.vehicle.colourId = null; 15382 15383 }; 15384 15385 15386 //#region EVENTS 15387 15388 $scope.$on(BuildPriceService.events.userInteraction, function () { 15389 $scope.cv.data.userInteraction = true; 15390 }); 15391 15392 $scope.$on(BuildPriceService.events.overviewDataReceived, function (event, vehicledata) { 15393 $scope.loadUserPreferences(vehicledata); 15394 }); 15395 15396 15397 $scope.$on(BuildPriceService.events.onOfferText, function (event, data) { 15398 $scope.cv.data.onOfferText = data; 15399 }); 15400 15401 $scope.$on(BuildPriceService.events.openPostcodeDialog, function () { 15402 $scope.ngDialog = ngDialog; 15403 ngDialog.open({ 15404 template: 'cvPostcodeDialogTemplate', 15405 controller: '', 15406 className: 'ngdialog-theme-default', 15407 scope: $scope, // this line wasn't here before
15408 plain: false, 15409 showClose: true, 15410 closeByDocument: true, 15411 closeByEscape: true, 15412 appendTo: false, 15413 preCloseCallback: function (value) { 15414 15415 } 15416 }); 15417 }); 15418 15419 15420 $scope.setPageVisited = function () { 15421 $scope.cv.settings.firstVisit = false; 15422 return true; 15423 } 15424 15425 $scope.setUserInteraction = function (data) { 15426 if (data.userInitiated) { 15427 $scope.cv.data.userInteraction = true; 15428 } 15429 } 15430 //#region vehicle selection listeners 15431 function SetModelsBrowsedState(data) { 15432 if (!data.selection) { 15433 var index = $scope.cv.data.compareVehicles.modelsBrowsed.indexOf(data.modelTouched + ":" + data.bodyType); 15434 if (index > -1) { 15435 $scope.cv.data.compareVehicles.modelsBrowsed.splice(index, 1); 15436 } 15437 } 15438 else { 15439 if ($scope.cv.data.compareVehicles.modelsBrowsed.indexOf(data.modelTouched + ":" + data.bodyType) < 0) { 15440 var match = []; 15441 angular.forEach($scope.cv.data.compareVehicles.modelsBrowsed, function (model) { 15442 var existingBodyType = model.split(":")[1]; 15443 15444 if (existingBodyType == data.bodyType) { 15445 match.push(model); 15446 } 15447 }); 15448 angular.forEach(match, function (model) { 15449 var index = $scope.cv.data.compareVehicles.modelsBrowsed.indexOf(model); 15450 if (index > -1) { 15451 $scope.cv.data.compareVehicles.modelsBrowsed.splice(index, 1); 15452 } 15453 }); 15454 $scope.cv.data.compareVehicles.modelsBrowsed.push(data.modelTouched + ":" + data.bodyType); 15455 } 15456 else { 15457 var index = $scope.cv.data.compareVehicles.modelsBrowsed.indexOf(data.modelTouched + ":" + data.bodyType); 15458 if (index > -1) { 15459 $scope.cv.data.compareVehicles.modelsBrowsed.splice(index, 1); 15460 } 15461 } 15462 } 15463 } 15464 function SetCompareVariantsState(data) { 15465 if ($scope.cv.data.compareVehicles.selectedCount >= 2) { 15466 $scope.cv.data.compareVehicles.variantsAdded.splice(1, 1); 15467 $scope.cv.data.compareVehicles.modelsAdded.splice(1, 1); 15468 $scope.cv.data.compareVehicles.selectedCount--; 15469 } 15470 else { 15471 $scope.cv.data.compareVehicles.variantsAdded.splice($scope.cv.data.activeIndex, 1, data.selection); 15472 $scope.cv.data.compareVehicles.modelsAdded.splice($scope.cv.data.activeIndex, 1, data.carModel.name); 15473 $scope.cv.data.activeIndex++; 15474 $scope.cv.data.compareVehicles.vehiclesData[data.selection] = data.carModel; 15475 $scope.cv.data.compareVehicles.selectedCount++; 15476 } 15477 } 15478 15479 function SetCompareGradesState(data) { 15480 $scope.cv.data.compareVehicles.modelsAdded.splice(+data.vehicleIndex, 1, data.carmodel); 15481 $scope.cv.data.compareVehicles.variantsAdded.splice(+data.vehicleIndex, 1, data.engineVariant); 15482 $scope.cv.data.compareVehicles.gradesAdded.splice(+data.vehicleIndex, 1, data.grade); 15483 $scope.cv.data.compareVehicles.paintsAdded.splice(+data.vehicleIndex, 1, data.colour); 15484 $scope.cv.data.compareVehicles.trimsAdded.splice(+data.vehicleIndex, 1, data.trim); 15485 $scope.cv.data.compareVehicles.gradeIdsAdded.splice(+data.vehicleIndex, 1, data.gradeId); 15486 } 15487 //each listener sets the selected value, then sets null on all downstream vehicle selections 15488 $scope.$on(BuildPriceService.events.modelSelected, function (event, data) { 15489 if (data.clearDownstream) $scope.clearDownstream(5, data); 15490 15491 $scope.setUserInteraction(data); 15492 $scope.cv.data.vehicle.carmodel = data.selection; 15493 $scope.cv.data.vehicle.bodyType = data.bodyType; 15494 15495 SetModelsBrowsedState(data);
15496 $scope.saveCurrentState(); 15497 }); 15498 15499 $scope.$on(BuildPriceService.events.engineVariantSelected, function (event, data) { 15500 if (data.clearDownstream) $scope.clearDownstream(4, data); 15501 $scope.setUserInteraction(data); 15502 $scope.cv.data.vehicle.engineVariant = data.selection; 15503 15504 SetCompareVariantsState(data); 15505 $scope.saveCurrentState(); 15506 }); 15507 15508 $scope.$on(BuildPriceService.events.gradeSelected, function (event, data) { 15509 if (data.clearDownstream) $scope.clearDownstream(3, data); 15510 15511 $scope.setUserInteraction(data); 15512 $scope.cv.data.vehicle.grade = data.grade; 15513 SetCompareGradesState(data); 15514 $scope.saveCurrentState(); 15515 }); 15516 15517 $scope.$on(BuildPriceService.events.enhancementPackSelected, function (event, data) { 15518 $scope.cv.data.vehicle.enhancementPack = data.grade; 15519 $scope.cv.data.compareVehicles.ePacksAdded.splice(+data.vehicleIndex, 1, data.enhancementPack); 15520 $scope.saveCurrentState(); 15521 }); 15522 15523 //#endregion 15524 15525 $scope.$on(BuildPriceService.events.onCompareVehicles, function () { 15526 $scope.cv.data.compareVehiclesTriggered = true; 15527 }); 15528 15529 $scope.$on(BuildPriceService.events.compareVehicleActiveSelection, function (evenet, index) { 15530 $scope.cv.data.activeVehicleIndex = index; 15531 }); 15532 15533 $scope.$watch('cv.data.vehicle', function (newValue, oldValue) { 15534 console.log("%c cv.data.vehicle changed:", "color: blue;", newValue); 15535 }); 15536 15537 $scope.saveCurrentState = function () { 15538 //$scope.pushURI($scope.cv.data.vehicle); 15539 $scope.$emit('compare-vehicle-change', { 15540 model: $scope.cv.data.vehicle.carmodel, 15541 bodyType:$scope.cv.data.vehicle.bodyType, 15542 modelsBrowsed: $scope.cv.data.compareVehicles.modelsBrowsed.join("|"), 15543 variantsSelected: $scope.cv.data.compareVehicles.variantsAdded.join("|") 15544 }); 15545 15546 } 15547 //#endregion 15548 function SetActiveIndex(index) { 15549 //Check if needs to reset 15550 if ($scope.cv.data.compareVehicles.variantsAdded.join("") == "") { 15551 $scope.cv.data.activeIndex = 0; 15552 return; 15553 } 15554 $scope.cv.data.activeIndex = index; 15555 } 15556 15557 $scope.removeSelectedVariant = function (index) { 15558 if (index < 0) return; 15559 $scope.cv.data.compareVehicles.variantsAdded.splice(index, 1, ""); 15560 $scope.cv.data.compareVehicles.modelsAdded.splice(index, 1, ""); 15561 $scope.cv.data.compareVehicles.selectedCount--; 15562 SetActiveIndex(index); 15563 $scope.saveCurrentState(); 15564 } 15565 15566 $scope.onVehicleSelected = function (vehicleIndex) { 15567 $scope.$emit('vehicle-preference-change', { 15568 model: $scope.cv.data.compareVehicles.modelsAdded[vehicleIndex], 15569 engineVariant: $scope.cv.data.compareVehicles.variantsAdded[vehicleIndex], 15570 grade: $scope.cv.data.compareVehicles.gradesAdded[vehicleIndex] 15571 }); 15572 } 15573 15574 } 15575 15576 }]) 15577}());; 15578"use strict"; 15579angular.module('Lexus.Directives') 15580 .directive('lxSaveBuildPrice', [function () { 15581 saveBuildPriceController.$inject = ['$scope', '$rootScope', '$filter', 'UserPreferencesService', 'API', 'BuildPriceService', 'BuildPriceAPIService']; 15582 return { 15583 scope: { 15584 model: '<carmodel', 15585 engineVariant: '<variant', 15586 enhancementPack: '<enhancement', 15587 grade: '<grade', 15588 colour: '<colour', 15589 trim: '<trim', 15590 vehicle: '<vehicle', 15591 buildPriceUri:'<baseUri', 15592 vehicleData: '<overviewData', 15593 vehicleImage: '<vehicleImage', 15594 openSbp: '<openSbp' 15595 }, 15596 restrict: 'A', 15597 controllerAs: 'sbp', 15598 bindToController: true, 15599 controller: saveBuildPriceController, 15600 transclude: true, 15601 link: function (scope, element, attrs, ctrl, transclude) { 15602 transclude(scope, function (clone) { 15603 element.append(clone); 15604 }); 15605 scope.sbp = scope.sbp || {}; 15606 scope.sbp.loggedIn = false; 15607 scope.sbp.status = "Retrieve Saved Vehicles"; 15608 scope.sbp.initState = false; 15609 scope.sbp.loadingVehicles = false; 15610 scope.sbp.imageTransitionInProgress = false; 15611 scope.sbp.showCurrentVehicle = true; 15612 scope.sbp.vehicleMaxSavedId = 0; 15613 scope.sbp.vehicleMaxLimitToSave = 3; 15614 scope.sbp.data = { 15615 vehicleToSave: { 15616 carmodel: null, 15617 engineVariant: null, 15618 grade: null, 15619 postcode: null, 15620 enhancementPack: null, 15621 colour: null, 15622 trim: null, 15623 colourId: null, 15624 carImageSource: null, 15625 id: null, 15626 timeStamp: null 15627 }, 15628 currentVehicle: { 15629 name: null, 15630 imgSrc: null 15631 }, 15632 savedVehicles: [], 15633 engineVariantObj: null, 15634 }; 15635 15636 scope.init(attrs); 15637 } 15638 } 15639 function saveBuildPriceController($scope, $rootScope, $filter, UserPreferencesService, API, BuildPriceService, BuildPriceAPIService) { 15640 var sbp = this; 15641 15642 function getDefaultVehicleState() { 15643 //TODO: Sitecore 15644 return { 15645 name: "Configure", 15646 imgSrc: "Assets/Lexus/MainSite/images/placeholders/save-build/placeholder.png", 15647 buildPriceLink: $scope.sbp.buildPriceUri, 15648 id: null 15649 }; 15650 } 15651 15652 function updateStatus(savedVehicles) { 15653 $scope.sbp.status = (!$scope.sbp.loggedIn) ? "Retrieve Saved Vehicles" : (savedVehicles && savedVehicles.length > 0) ? "Saved Vehicle(S)" : "No Saved Vehicle(S)"; 15654 } 15655 15656 function getSavedVehiclesRendering(vehicles) { 15657 var savedArr = []; 15658 if (!vehicles) 15659 return savedArr; 15660 15661 vehicles.map(function (vehicle) { 15662 savedArr.push(getSavedVehicleRendering(vehicle, vehicle.id)); 15663 }); 15664 15665 return savedArr; 15666 } 15667 15668 function getSavedVehicleRendering(vehicle, id) { 15669 try { 15670 $scope.sbp.data.engineVariantObj = BuildPriceAPIService.findEngineVariantInVehicleData(vehicle.engineVariant); 15671 return { 15672 name: vehicle.engineVariant, 15673 imgSrc: vehicle.carImageSource, 15674 buildPriceLink: $scope.sbp.buildPriceUri + "/" + BuildPriceService.getBuildPriceLink(vehicle, 5), 15675 id: id, 15676 } 15677 } 15678 catch (e) { 15679 return getDefaultVehicleState(); 15680 } 15681 return null; 15682 } 15683 15684 function paintsResolved(vehicleId) { 15685 console.info("%c 9. Exterior Images Resolved", "color: blue; ", "Complete"); 15686 //Mutate the DOM saved Vehicles section 15687 $scope.sbp.data.savedVehicles = getSavedVehiclesRendering($scope.virtualSavedStates); 15688 $scope.sbp.loadingVehicles = false; 15689 } 15690 15691 function callVehicleTree(vehicle, vehicleId) { 15692 //if (!vehicle) return; 15693 $scope.sbp.loadingVehicles = true; 15694 //save car image source , need not cal vehicle tree to dig the paint 15695 paintsResolved(); 15696 return; 15697 15698 //Deep Nesting is required if we do not save the Vehicle Image in xDB 15699 15700 console.info("%c 2. Loading Vehicles ", "color: blue; ", $scope.sbp.loadingVehicles); 15701 try { 15702 var grade = BuildPriceAPIService.getGradeByName(vehicle.engineVariant, vehicle.grade); 15703 console.info("%c 2.1.Grade ", "color: blue; ", vehicle.grade); 15704 var variant = BuildPriceAPIService.getVariantByName(vehicle.engineVariant, grade.id, vehicle.enhancementPack); 15705 console.info("%c 2.2.Variant ", "color: blue; ", grade.id); 15706 if (!variant) { 15707 var ep = function (variantsResp) { 15708 console.info("%c 4. Variants Resolved ", "color: blue; ", ""); 15709 variant = BuildPriceAPIService.getVariantByName(vehicle.engineVariant, grade.id, vehicle.enhancementPack); 15710 var trim = null; 15711 if (!trim) { 15712 var tr = function (trimsResp) { 15713 console.info("%c 5. Trims Resolved ", "color: blue; ", ""); 15714 trim = BuildPriceAPIService.getTr
15714imByName(vehicle.engineVariant, grade.id, variant.mdmid, vehicle.trim); 15715 var paint = null; 15716 if (!paint) { 15717 var pt = function (paintResponse) { 15718 console.info("%c 7. paints resolved ", "color: blue; ", ""); 15719 paint = BuildPriceAPIService.getPaintByName(vehicle.engineVariant, grade.id, variant.mdmid, trim.id, vehicle.colour); 15720 console.info("%c 8. Calling Exterior Images ", "color: blue; ", paint.materialCode); 15721 BuildPriceAPIService.getExteriorImages(vehicle.engineVariant, grade.id, variant.mdmid, trim.id, paint.materialCode, paintsResolved.bind(null, vehicleId)); 15722 }; 15723 console.info("%c 6. Calling paints ", "color: blue; ", trim.id); 15724 BuildPriceAPIService.getPaints(vehicle.engineVariant, grade.id, variant.mdmid, trim.id, pt); 15725 } 15726 }; 15727 console.info("%c 5. Calling Trims ", "color: blue; ", variant.mdmid); 15728 BuildPriceAPIService.getTrims(vehicle.engineVariant, grade.id, variant.mdmid, tr); 15729 } 15730 }; 15731 console.info("%c 3. Calling Variants ", "color: blue; ", vehicle.engineVariant); 15732 BuildPriceAPIService.getVariants(vehicle.engineVariant, grade.id, ep); 15733 } 15734 else { 15735 //Resolve Paints as the tree might have fetched 15736 paintsResolved(vehicleId); 15737 } 15738 15739 } 15740 catch (e) { 15741 return null; 15742 } 15743 finally { 15744 } 15745 return null; 15746 15747 } 15748 15749 $scope.init = function (attrs) { 15750 //Virtual DOM for saved states 15751 $scope.virtualSavedStates = []; 15752 15753 var analyticsCookie = UserPreferencesService.getAnalyticsCookie(); 15754 15755 if (analyticsCookie) { 15756 $scope.userEmail = analyticsCookie.identifier; 15757 $scope.sbp.loggedIn = analyticsCookie.identifier != null && analyticsCookie.identifier != ""; 15758 console.info("%c Logged in ", "color: green; ", $scope.userEmail); 15759 } 15760 if (attrs) { 15761 $scope.vehicleState = attrs.vehicleState; 15762 $scope.sbp.vehicleMaxLimitToSave = +attrs.vehicleMaxLimit || $scope.sbp.vehicleMaxLimitToSave; 15763 var vIds = (attrs.vehicleIds) ? attrs.vehicleIds.split("|") : null; 15764 var sArr = (attrs.vehicleState) ? attrs.vehicleState.split("|") : null; 15765 15766 if (sArr && sArr.length > 0) { 15767 for (var i = 0; i < sArr.length; i++) { 15768 if (sArr[i]) { 15769 $scope.virtualSavedStates.push(JSON.parse(sArr[i] ? sArr[i] : null)); 15770 $scope.virtualSavedStates[i].id = vIds[i]; 15771 } 15772 } 15773 } 15774 updateStatus($scope.virtualSavedStates); 15775 } 15776 15777 }; 15778 15779 $scope.$watch(function (scope) { return scope.sbp.vehicleData; }, function (newVal, oldVal) { 15780 if (newVal && $scope.sbp.loggedIn) { 15781 //call vehicleTree for saved Vehicles 15782 callVehicleTree(); 15783 } 15784 }); 15785 15786 $scope.$watch(function (scope) { return scope.sbp.vehicleImage; }, function (newVal, oldVal) { 15787 if (newVal) { 15788 15789 if (newVal.indexOf("data:image") > -1) 15790 return; 15791 15792 $scope.sbp.showCurrentVehicle = true; 15793 $scope.sbp.loadingVehicles = false; 15794 $scope.sbp.imageTransitionInProgress = false; 15795 $scope.sbp.data.currentVehicle = { name: $scope.sbp.vehicle.engineVariant, imgSrc: newVal.indexOf("data:image") > -1 ? null : newVal.replace(/jpg/g, 'png') }; 15796 setVehicle($scope.sbp.vehicle); 15797 } 15798 }) 15799 15800 $scope.$watch(function (scope) { return scope.sbp.model; }, function (newVal, oldVal) { 15801 if (newVal) { 15802 if (!$scope.sbp.vehicle.engineVariant) { 15803 $scope.sbp.showCurrentVehicle = false; 15804 $scope.sbp.data.currentVehicle = getDefaultVehicleState(); 15805 $scope.sbp.imageTransitionInProgress = true; 15806 } 15807 } 15808 else { 15809 $scope.sbp.showCurrentVehicle = false; 15810 $scope.sbp.data.currentVehicle = getDefaultVehicleState(); 15811 } 15812 }) 15813 15814 $scope.$watch(function (scope) { return scope.sbp.engineVariant; }, function (newVal, oldVal) { 15815 if (newVal) { 15816 $scope.sbp.imageTransitionInProgress = false; 15817 $scope.sbp.loadingVehicles = true; 15818 } 15819 else { 15820 setVehicle($scope.sbp.vehicle); 15821 $scope.sbp.showCurrentVehicle = false; 15822 } 15823 }) 15824 15825 $scope.$on(BuildPriceService.events.openSaveBuildPriceDialog, function (e, vehicle) { 15826 openNav(vehicle); 15827 }); 15828 15829 $scope.$watch(function (scope) { return scope.sbp.openSbp; }, function (newVal, oldVal) { 15830 if (newVal === false) { 15831 $scope.closeNav(); 15832 } 15833 }); 15834 15835 $scope.$on(BuildPriceService.events.closeSaveBuildPriceDialog, function (e, vehicle) { 15836 $scope.closeNav(); 15837 }); 15838
15839 $scope.saveBuildAndPrice = function (email, close) { 15840 15841 if (!email || $scope.sbp.data.currentVehicle.name == "Configure") { 15842 return; 15843 } 15844 //disable Add vehicle until current request processed . 15845 $scope.sbp.showCurrentVehicle = false; 15846 15847 UserPreferencesService.setAnalyticsCookie({ identifier: email }); 15848 15849 var postData = { VehicleId: updateAndRetrieveVehicleId(), EmailId: email, DeepLink: getData() }; 15850 var postAnalytics = API.post(Lexus.API.Analytics.PostSavedVehicles, 15851 postData); 15852 15853 postAnalytics 15854 .then(function (data) { 15855 if (data.Data) { 15856 console.log('save B&P' + data.Data); 15857 15858 $scope.sbp.loggedIn = true; 15859 $scope.userEmail = email; 15860 mutateSavedVehicles(getSavedVehicleRendering(JSON.parse(data.Data.DeepLink), data.Data.VehicleId), data.Data.VehicleId); 15861 updateStatus($scope.sbp.data.savedVehicles); 15862 updateAndRetrieveVehicleId(); 15863 if (close) { 15864 $scope.closeNav(); 15865 } 15866 } 15867 15868 }, function (error) { 15869 $log.error(error); 15870 }).finally(function () { 15871 $scope.sbp.showCurrentVehicle = true; 15872 }); 15873 }; 15874 15875 $scope.deleteSaveBuildEntry = function (id) { 15876 15877 var postData = { VehicleId: id, EmailId: $scope.userEmail, DeepLink: null }; 15878 var postAnalytics = API.del($filter('formatArgs')(Lexus.API.Analytics.DeleteSavedVehicle, [id, $scope.userEmail])); 15879 $scope.sbp.showCurrentVehicle = false; 15880 15881 postAnalytics 15882 .then(function (data) { 15883 mutateSavedVehicles(null, postData.VehicleId); 15884 updateStatus($scope.sbp.data.savedVehicles); 15885 $scope.sbp.activeModel = null; 15886 }, function (error) { 15887 $log.error(error); 15888 }).finally(function () { 15889 $scope.sbp.showCurrentVehicle = true; 15890 }); 15891 }; 15892 15893 function getData() { 15894 //Set the ID and Time Stamp before Save/Update 15895 $scope.sbp.data.vehicleToSave.id = getVehicleId(); 15896 $scope.sbp.data.vehicleToSave.timeStamp = (new Date()).getTime(); 15897 15898 if ($scope.sbp.data.vehicleToSave) 15899 { 15900 return JSON.stringify($scope.sbp.data.vehicleToSave); 15901 } 15902 15903 var vCookie = UserPreferencesService.getLexusVehicle() || { model: '' }; 15904 var seperator = "~"; 15905 var vts = $scope.sbp.data.vehicleToSave; 15906 15907 if (vCookie) { 15908 if (vCookie.model) 15909 vts.carmodel = vCookie.model; 15910 if (vCookie.engineVariant) 15911 vts.engineVariant = vCookie.engineVariant; 15912 if (vCookie.grade) 15913 vts.grade = vCookie.grade; 15914 if (vCookie.enhancementPack) 15915 vts.enhancementPack = vCookie.enhancementPack; 15916 if (vCookie.trim) 15917 vts.trim = vCookie.trim; 15918 if (vCookie.colour) 15919 vts.colour = vCookie.colour; 15920 } 15921 15922 return JSON.stringify(vts); 15923 } 15924 15925 function getVehicleId() { 15926 return ($scope.sbp.activeModel) ? $scope.sbp.activeModel : null; 15927 } 15928 15929 //do not call this outside of AJAX calls 15930 function updateAndRetrieveVehicleId() { 15931 //active selection 15932 if ($scope.sbp.activeModel) 15933 return $scope.sbp.activeModel; 15934 15935 if ($scope.sbp.data.savedVehicles.length >= $scope.sbp.vehicleMaxLimitToSave) { 15936 //Set to first vehicle if max limit reached 15937 $scope.sbp.activeModel = $scope.sbp.data.savedVehicles[0].id; 15938 return $scope.sbp.activeModel; 15939 } 15940 15941 return null; 15942 } 15943 15944 function mutateSavedVehicles(vehicle, vehicleId) { 15945 var isExisting = false; 15946 var changedIdx = 0; 15947 15948 //mutation 15949 $scope.sbp.data.savedVehicles.map(function (savedVehicle, index) { 15950 if (savedVehicle.id == vehicleId) { 15951 isExisting = true; 15952 savedVehicle = vehicle; 15953 changedIdx = index; 15954 } 15955 }); 15956 //insert at last 15957 if (!isExisting) { 15958 var index = $scope.sbp.data.savedVehicles.length; 15959 (vehicle) ? $scope.sbp.data.savedVehicles.splice(index, 1, vehicle) : $scope.sbp.data.savedVehicles.splice(index, 1); 15960 }//update 15961 else { 15962 (vehicle) ? $scope.sbp.data.savedVehicles.splice(changedIdx, 1, vehicle) : $scope.sbp.data.savedVehicles.splice(changedIdx, 1); 15963 } 15964 } 15965 15966 function onGetVehicleInfoResponse(response) { 15967 $scope.sbp.changeEmail = false; 15968 15969 if (response && response.Data && response.Data.Vehicles.length == 0) { 15970 $scope.virtualSavedStates = []; 15971 $scope.sbp.data.savedVehicles = []; 15972 $scope.sbp.activeModel = null; 15973 updateStatus($scope.sbp.data.savedVehicles); 15974 return; 15975 } 15976 15977 $scope.vehicleState = response.Data.Vehicles[0].DeepLink; 15978 $scope.virtualSavedStates = []; 15979 var vehicleCount = response.Data.Vehicles.length; 15980 15981 for (var i = 0; i < vehicleCount; i++) {
15982 //To support old data n/a in live 15983 var _v = JSON.parse(response.Data.Vehicles[i].DeepLink); 15984 15985 if (_v && !_v.id) { 15986 _v.id = response.Data.Vehicles[i].VehicleId; 15987 } 15988 $scope.virtualSavedStates.push(_v); 15989 } 15990 15991 $scope.sbp.activeModel = (vehicleCount >= $scope.sbp.vehicleMaxLimitToSave) ? $scope.virtualSavedStates[0].id : null; 15992 callVehicleTree(JSON.parse(response.Data.Vehicles[0].DeepLink), response.Data.Vehicles[0].VehicleId); 15993 updateStatus($scope.sbp.data.savedVehicles); 15994 } 15995 15996 $scope.getVehicleInfo = function (email) { 15997 if (!email) { 15998 return; 15999 } 16000 16001 $scope.sbp.showCurrentVehicle = false; 16002 var getAnalytics = API.get($filter('formatArgs')(Lexus.API.Analytics.GetSavedVehicles, ["1", email])); 16003 16004 getAnalytics 16005 .then(function (response) { 16006 $scope.sbp.loggedIn = true; 16007 $scope.userEmail = email; 16008 UserPreferencesService.setAnalyticsCookie({ identifier: email }); 16009 onGetVehicleInfoResponse(response); 16010 }, function (error) { 16011 $scope.sbp.loggedIn = false; 16012 updateStatus($scope.sbp.data.savedVehicles); 16013 $log.error(error); 16014 }).finally(function () { 16015 $scope.sbp.showCurrentVehicle = true; 16016 }); 16017 }; 16018 16019 function openNav(vehicle) { 16020 $("#slide-out-tray").addClass("show"); 16021 $('body').removeClass("save-modal-open").addClass("save-modal-open"); 16022 onNavOpened(vehicle); 16023 } 16024 16025 function onNavOpened(vehicle) { 16026 setVehicle(vehicle); 16027 } 16028 16029 function setVehicle(vehicle) { 16030 if (!vehicle) { 16031 return; 16032 } 16033 16034 var vts = $scope.sbp.data.vehicleToSave; 16035 vts.carmodel = vehicle.carmodel; 16036 vts.engineVariant = vehicle.engineVariant; 16037 vts.grade = vehicle.grade; 16038 vts.enhancementPack = vehicle.enhancementPack; 16039 vts.trim = vehicle.trim; 16040 vts.colour = vehicle.colour; 16041 vts.id = $scope.sbp.activeModel; 16042 vts.carImageSource = $scope.sbp.data.currentVehicle.imgSrc; 16043 16044 $scope.sbp.data.currentVehicle = (vehicle.carmodel && vehicle.engineVariant) ? getSavedVehicleRendering(vts) : getDefaultVehicleState(); 16045 $scope.sbp.imageTransitionInProgress = false; 16046 16047 if (!$scope.sbp.initState && !$scope.sbp.loadingVehicles) { 16048 $scope.sbp.data.savedVehicles = getSavedVehiclesRendering($scope.virtualSavedStates); 16049 updateAndRetrieveVehicleId(); 16050 $scope.sbp.initState = true; 16051 } 16052 } 16053 16054 /* Set the width of the side navigation to 0 */ 16055 $scope.closeNav = function () { 16056 $scope.$emit(BuildPriceService.events.triggerCloseSaveBuildPriceDialog, {}); 16057 $("#slide-out-tray").removeClass("show"); 16058 $('body').removeClass("save-modal-open"); 16059 } 16060 } 16061 }]); 16062; 16063"use strict"; 16064angular.module('Lexus.Directives') 16065 .directive('lxTranslate', function () { 16066 lxTranslateToastController.$inject = ['$scope', '$attrs', '$window', '$rootScope', '$cookies', '$timeout', 'UserPreferencesService', 'TranslationService']; 16067 return { 16068 scope: true, 16069 restrict: 'C', 16070 controller: lxTranslateToastController, 16071 controllerAs: 'ltt', 16072 bindToController: true 16073 } 16074 16075 function lxTranslateToastController($scope, $attrs, $window, $rootScope, $cookies, $timeout, UserPreferencesService, TranslationService) { 16076 var translateUrl = $attrs.translateUrl; 16077 var pageGuid = $attrs.pageGuid; 16078 var window = angular.element($window); 16079 var throttlescroll; 16080 16081 $scope.showToast = false; 16082 16083 var languagePref = UserPreferencesService.getLanguagePref(pageGuid); 16084 if (languagePref == null || languagePref.translate == null) { 16085 $scope.showToast = true; 16086 } 16087 16088 $scope.translate = function (translate) { 16089 $scope.showToast = false; 16090 16091 if (translate) { 16092 UserPreferencesService.setLanguagePref({ translate: true }, pageGuid); 16093 $window.location.href = translateUrl + "?translate=true"; 16094 } 16095 else { 16096 UserPreferencesService.setLanguagePref({ translate: false }, pageGuid); 16097 $rootScope.$broadcast('show-confirmation'); 16098 } 16099 } 16100 16101 window.bind("scroll", function () { 16102 clearTimeout(throttlescroll); 16103 if ($scope.showToast == true) { 16104 throttlescroll = $timeout(checkAmountScrolled, 100); 16105 } 16106 }); 16107 16108 function checkAmountScrolled() { 16109 var pageYOffset = $window.pageYOffset; 16110 if ($attrs.scrollOffset < pageYOffset) { 16111 UserPreferencesService.setLanguagePref({ translate: false }, pageGuid); 16112 $scope.showToast = false; 16113 } 16114 } 16115 } 16116 });; 16117"use strict"; 16118 16119angular.module('Lexus.Services') 16120.service('TranslationService', [ 16121 function () { 16122 var self = this; 16123 self.isBrowserLanguageSupported = function (browserLanguages, supportedLanguagesStr) { 16124 var supportedLanguages = supportedLanguagesStr.split(","); 16125 if (browserLanguages && browserLanguages.length > 0) { 16126 for (var i = 0; i < browserLanguages.length; i++) { 16127 var browserLanguage = browserLanguages[i]; 16128 var langArray = browserLanguage.split(';'); 16129 if (langArray && supportedLanguages.indexOf(langArray[0].toLowerCase()) >= 0) { 16130 return true; 16131 } 16132 } 16133 } 16134 return false; 16135 } 16136 16137 return self; 16138}]); 16139 16140; 16141"use strict"; 16142angular.module('Lexus.Directives') 16143 .directive('lxLanguageCheck', ['TranslationService', function (TranslationService) { 16144 return { 16145 scope: true, 16146 restrict: 'A', 16147 link: function (scope, element, attrs) { 16148 var browserLanguageSupported = true; 16149 var supportedLanguages = attrs.lxLanguageCheck; 16150 if (supportedLanguages.length > 0) { 16151 var browserLanguages = angular.fromJson(attrs.browserLanguages); 16152 browserLanguageSupported = TranslationService.isBrowserLanguageSupported(browserLanguages, supportedLanguages); 16153 } 16154 if (browserLanguageSupported) { 16155 element.addClass("visible"); 16156 } 16157 } 16158 } 16159 }]);; 16160"use strict"; 16161angular.module('Lexus.Directives') 16162 .directive('lxTranslateConfirm', function () { 16163 lxTranslateConfirmController.$inject = ['$scope', '$attrs', '$rootScope', '$window', '$cookies', '$timeout', '$location', 'UserPreferencesService', 'TranslationService']; 16164 return { 16165 scope: true, 16166 restrict: 'C', 16167 controller: lxTranslateConfirmController, 16168 controllerAs: 'ltt', 16169 bindToController: true 16170 } 16171 16172 function lxTranslateConfirmController($scope, $attrs, $rootScope, $window, $cookies, $timeout, $location, UserPreferencesService, TranslationService) { 16173 $scope.showToast = false; 16174 var window = angular.element($window); 16175 var throttlescroll; 16176 var showTranslateConfirmation = $location.search().translate; 16177 if (showTranslateConfirmation == "true") { 16178 $scope.showToast = true; 16179 } 16180 16181 window.bind("scroll", function () { 16182 clearTimeout(throttlescroll); 16183 if ($scope.showToast == true) { 16184 throttlescroll = $timeout(checkAmountScrolled, 100); 16185 } 16186 }); 16187 16188 $rootScope.$on('show-confirmation', function (event, data) { 16189 $timeout(function () { 16190 $scope.showToast = true; 16191 }, 100); 16192 }); 16193 16194 function checkAmountScrolled() { 16195 var pageYOffset = $window.pageYOffset; 16196 if ($attrs.scrollOffset < pageYOffset) { 16197 $scope.showToast = false; 16198 } 16199 } 16200 } 16201 });; 16202"use strict"; 16203angular.module('Lexus.Directives') 16204 .directive('lxOpeningHours', ['$window', '$timeout', '$filter', '$http', function ($window, $timeout, $filter, $http) { 16205 openingHoursController.$inject = ['$scope', '$http', '$filter', '$timeout', '$window', '$interval', '$rootScope']; 16206 return { 16207 scope: true, 16208 restrict: 'A', 16209 controller: openingHoursController, 16210 controllerAs: 'oh', 16211 bindToController: true, 16212 link: function (scope, element, attrs, filter, http) { 16213 } 16214 }; 16215 16216 function openingHoursController($scope, $http, $filter, $timeout, $window, $interval, $rootScope) { 16217 var oh = this; 16218 $scope.init = function (openingHour, closingHour, isClosed) { 16219 oh.IsOpenNow = false; 16220 oh.OpenNowText = "Open now:"; 16221 var openingHourElements = openingHour.split(":"); 16222 var closingHourElements = closingHour.split(":"); 16223 if (!isClosed === true && openingHourElements.length === 2 && closingHourElements.length === 2) { 16224 var now = new Date(); 16225 var year = now.getFullYear();
16226 var month = now.getMonth(); 16227 var day = now.getDate(); 16228 16229 var dateOpeningHour = new Date(year, month, day, openingHourElements[0], openingHourElements[1]); 16230 var dateClosingHour = new Date(year, month, day, closingHourElements[0], closingHourElements[1]); 16231 16232 oh.IsOpenNow = dateOpeningHour.getTime() < now.getTime() && dateClosingHour.getTime() > now.getTime(); 16233 } 16234 oh.OpenNowText = oh.IsOpenNow ? "Open now:" : "Closed"; 16235 }; 16236 16237 oh.simplifyTime = function (time) { 16238 var result = time; 16239 var timeElements = time.split(":"); 16240 16241 if (timeElements.length === 2) { 16242 var hour = timeElements[0]; 16243 if (hour - 12 >= 0) { 16244 result = (hour - 12) + ':' + timeElements[1] + "pm"; 16245 } 16246 else { 16247 result = hour + ':' + timeElements[1] + "am"; 16248 } 16249 if (timeElements[1].indexOf("00") >= 0) { 16250 result = result.replace(':00', ''); 16251 } 16252 } 16253 16254 return result; 16255 }; 16256 16257 } 16258 }]); 16259 16260 16261; 16262'use strict'; 16263angular 16264 .module('Lexus.Components') 16265 .component('threeDotToggleButton', { 16266 bindings: { 16267 'isActive': '<', 16268 'screenReaderText': '@', 16269 'cssClass': '@' 16270 }, 16271 template: [ 16272 '<button class="lx-three-dot-toggle-button {{$ctrl.cssClass}}" ng-class="{\'is-active\' : $ctrl.isActive}">', 16273 '<span class="lx-three-dot-toggle-button__screen-reader-text">{{$ctrl.screenReaderText}}</span>', 16274 '<span class="lx-three-dot-toggle-button__dots"><span class="lx-three-dot-toggle-button__dot"></span></span>', 16275 '</button>' 16276 ].join('') 16277 }); 16278; 16279"use strict"; 16280angular 16281 .module('Lexus.Components') 16282 .component('welcomeMessage', { 16283 bindings: { 16284 hoursOfDay: '@hours', 16285 cssClass: '@cssClass' 16286 }, 16287 controller: ['API', '$filter', function (API, $filter) { 16288 var ctrl = this; 16289 this.$onInit = function () { 16290 16291 API.get($filter('formatArgs')(Lexus.API.Lookup.GetWelcomeMessage, [ 16292 Lexus.ID.Site, 16293 ctrl.hoursOfDay 16294 ])).then(function (data) { 16295 if (data && data.Data) { 16296 ctrl.message = data.Data.Message; 16297 } 16298 }, 16299 function (error) { 16300 ctrl.message = null; 16301 }); 16302 }; 16303 }], 16304 template: '<span class="{{$ctrl.cssClass}}">{{$ctrl.message}}</span>' 16305 });; 16306(function () { 16307 16308 "use strict"; 16309 16310 angular.module('Lexus') 16311 .config(['$locationProvider', function ($locationProvider) { 16312 $locationProvider.html5Mode( 16313 { 16314 enabled: true, 16315 rewriteLinks: 'data-route', 16316 requireBase: false 16317 }); 16318 }]) 16319 .config(['tagsInputConfigProvider', function (tagsInputConfigProvider) { 16320 tagsInputConfigProvider.setDefaults('tagsInput', { 16321 placeholder: '', 16322 addOnPaste: true, 16323 addOnBlur: true, 16324 maxTags: 1, 16325 replaceSpacesWithDashes: false, 16326 //enableEditingLastTag: true, 16327 selectOnBackspace: false, 16328 addFromAutocompleteOnly: true, 16329 allowLeftoverText: true, 16330 debounceDelay: 500 16331 }); 16332 tagsInputConfigProvider.setDefaults('autoComplete', { 16333 minLength: 2 16334 }); 16335 tagsInputConfigProvider.setActiveInterpolation('tagsInput', { placeholder: true }); 16336 }]) 16337}());; 16338(function () { 16339 16340 "use strict"; 16341 16342 angular.module('Lexus'); 16343 //UTM variables should not be persisted due to an incompatibility in how eloqua handles utm_campaigns 16344 /*.run([ 16345 "$location", "UserPreferencesService", 16346 function ($location, userPreferencesService) { 16347 var params = $location.search(); 16348 16349 var utmParameters = userPreferencesService.getUtmParameters(); 16350 16351 if (params.utm_source) { utmParameters.source = params.utm_source; } 16352 16353 if (params.utm_medium) { utmParameters.medium = params.utm_medium; } 16354 16355 if (params.utm_campaign) { utmParameters.campaign = params.utm_campaign; } 16356
16357 if (params.utm_content) { utmParameters.content = params.utm_content; } 16358 16359 userPreferencesService.setUtmParameters(utmParameters); 16360 } 16361 ]);*/ 16362}());;
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.