/* Minification failed. Returning unminified contents. (1022,28): run-time error JS1004: Expected ';' (1022,38-39): run-time error JS1010: Expected identifier: ( (1035,28): run-time error JS1004: Expected ';' (1063,57-65): run-time error JS1006: Expected ')': function (1063,68): run-time error JS1004: Expected ';' (1078,29): run-time error JS1004: Expected ';' (1080,33): run-time error JS1004: Expected ';' (1093,6-7): run-time error JS1195: Expected expression: ) (2354,6): run-time error JS1004: Expected ';' (2356,46-48): run-time error JS1006: Expected ')': => (2356,45): run-time error JS1004: Expected ';' (2357,32): run-time error JS1004: Expected ';' (2391,10-11): run-time error JS1195: Expected expression: ) */ /* FDN Updates: - changed object names to reduce data x-fer size: value => v, group => g - adjusted width option to allow for % - accessability modifiers **/ /** * Ajax Autocomplete for jQuery, version %version% * (c) 2015 Tomas Kirda * * Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license. * For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete */ /*jslint browser: true, white: true, plusplus: true, vars: true */ /*global define, window, document, jQuery, exports, require */ // Expose plugin as an AMD module if AMD loader is present: (function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], factory); } else if (typeof exports === 'object' && typeof require === 'function') { // Browserify factory(require('jquery')); } else { // Browser globals factory(jQuery); } }(function ($) { 'use strict'; var utils = (function () { return { escapeRegExChars: function (value) { return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); }, createNode: function (containerClass) { var div = document.createElement('div'); div.className = containerClass; div.style.position = 'absolute'; div.style.display = 'none'; return div; } }; }()), keys = { ESC: 27, TAB: 9, RETURN: 13, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 }; function Autocomplete(el, options) { var noop = function () { }, that = this, defaults = { ajaxSettings: {}, autoSelectFirst: false, appendTo: document.body, serviceUrl: null, lookup: null, onSelect: null, width: 'auto', minChars: 1, maxHeight: 450, deferRequestBy: 0, params: {}, formatResult: Autocomplete.formatResult, delimiter: null, zIndex: 10001, type: 'GET', noCache: false, onSearchStart: noop, onSearchComplete: noop, onSearchError: noop, preserveInput: false, containerClass: 'autocomplete-suggestions', tabDisabled: false, dataType: 'text', currentRequest: null, triggerSelectOnValidInput: true, preventBadQueries: true, lookupFilter: function (suggestion, originalQuery, queryLowerCase) { return suggestion.v.toLowerCase().indexOf(queryLowerCase) !== -1; }, paramName: 'query', transformResult: function (response) { return typeof response === 'string' ? $.parseJSON(response) : response; }, showNoSuggestionNotice: false, noSuggestionNotice: 'No results', orientation: 'bottom', forceFixPosition: false }; // Shared variables: that.element = el; that.el = $(el); that.suggestions = []; that.badQueries = []; that.selectedIndex = -1; that.currentValue = that.element.v; that.intervalId = 0; that.cachedResponse = {}; that.onChangeInterval = null; that.onChange = null; that.isLocal = false; that.suggestionsContainer = null; that.noSuggestionsContainer = null; that.options = $.extend({}, defaults, options); that.classes = { selected: 'autocomplete-selected', suggestion: 'autocomplete-suggestion' }; that.hint = null; that.hintValue = ''; that.selection = null; // Initialize and set options: that.initialize(); that.setOptions(options); } Autocomplete.utils = utils; $.Autocomplete = Autocomplete; Autocomplete.formatResult = function (suggestion, currentValue) { var pattern = '(' + utils.escapeRegExChars(currentValue) + ')'; return suggestion.v .replace(new RegExp(pattern, 'gi'), '$1<\/strong>') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/<(\/?strong)>/g, '<$1>'); }; Autocomplete.prototype = { killerFn: null, initialize: function () { var that = this, suggestionSelector = '.' + that.classes.suggestion, selected = that.classes.selected, options = that.options, container; // Remove autocomplete attribute to prevent native suggestions: that.element.setAttribute('autocomplete', 'off'); that.killerFn = function (e) { if ($(e.target).closest('.' + that.options.containerClass).length === 0) { that.killSuggestions(); that.disableKillerFn(); } }; // html() deals with many types: htmlString or Element or Array or jQuery that.noSuggestionsContainer = $('
') .html(this.options.noSuggestionNotice).get(0); that.suggestionsContainer = Autocomplete.utils.createNode(options.containerClass); container = $(that.suggestionsContainer); container.attr('aria-live', 'polite') .attr('role', 'listbox') .attr('aria-labeledby', 'search-input') .attr('aria-relevant', 'additions text'); container.appendTo(options.appendTo); // Only set width if it was provided: if (options.width !== 'auto') { container.width(options.width); } // Listen for mouse over event on suggestions list: container.on('mouseover.autocomplete', suggestionSelector, function () { that.activate($(this).data('index')); }); // Deselect active element when mouse leaves suggestions container: container.on('mouseout.autocomplete', function () { that.selectedIndex = -1; container.children('.' + selected).removeClass(selected); }); // Listen for click event on suggestions list: container.on('click.autocomplete', suggestionSelector, function () { that.select($(this).data('index')); }); that.fixPositionCapture = function () { if (that.visible) { that.fixPosition(); } }; $(window).on('resize.autocomplete', that.fixPositionCapture); that.el.on('keydown.autocomplete', function (e) { that.onKeyPress(e); }); that.el.on('keyup.autocomplete', function (e) { that.onKeyUp(e); }); that.el.on('blur.autocomplete', function () { that.onBlur(); }); that.el.on('focus.autocomplete', function () { that.onFocus(); }); that.el.on('change.autocomplete', function (e) { that.onKeyUp(e); }); that.el.on('input.autocomplete', function (e) { that.onKeyUp(e); }); }, onFocus: function () { var that = this; that.fixPosition(); if (that.options.minChars === 0 && that.el.val().length === 0) { that.onValueChange(); } }, onBlur: function () { this.enableKillerFn(); }, abortAjax: function () { var that = this; if (that.currentRequest) { that.currentRequest.abort(); that.currentRequest = null; } }, setOptions: function (suppliedOptions) { var that = this, options = that.options; $.extend(options, suppliedOptions); that.isLocal = $.isArray(options.lookup); if (that.isLocal) { options.lookup = that.verifySuggestionsFormat(options.lookup); } options.orientation = that.validateOrientation(options.orientation, 'bottom'); // Adjust height, width and z-index: $(that.suggestionsContainer).css({ 'max-height': options.maxHeight + 'px', 'width': options.width, 'z-index': options.zIndex }); }, clearCache: function () { this.cachedResponse = {}; this.badQueries = []; }, clear: function () { this.clearCache(); this.currentValue = ''; this.suggestions = []; }, disable: function () { var that = this; that.disabled = true; clearInterval(that.onChangeInterval); that.abortAjax(); }, enable: function () { this.disabled = false; }, fixPosition: function () { // Use only when container has already its content var that = this, $container = $(that.suggestionsContainer), containerParent = $container.parent().get(0); // Fix position automatically when appended to body. // In other cases force parameter must be given. if (containerParent !== document.body && !that.options.forceFixPosition) { return; } // Choose orientation var orientation = that.options.orientation, containerHeight = $container.outerHeight(), height = that.el.outerHeight(), offset = that.el.offset(), styles = { 'top': offset.top, 'left': offset.left }; if (orientation === 'auto') { var viewPortHeight = $(window).height(), scrollTop = $(window).scrollTop(), topOverflow = -scrollTop + offset.top - containerHeight, bottomOverflow = scrollTop + viewPortHeight - (offset.top + height + containerHeight); orientation = (Math.max(topOverflow, bottomOverflow) === topOverflow) ? 'top' : 'bottom'; } if (orientation === 'top') { styles.top += -containerHeight; } else { styles.top += height; } // If container is not positioned to body, // correct its position using offset parent offset if (containerParent !== document.body) { var opacity = $container.css('opacity'), parentOffsetDiff; if (!that.visible) { $container.css('opacity', 0).show(); } parentOffsetDiff = $container.offsetParent().offset(); styles.top -= parentOffsetDiff.top; styles.left -= parentOffsetDiff.left; if (!that.visible) { $container.css('opacity', opacity).hide(); } } // -2px to account for suggestions border. if (that.options.width === 'auto') { styles.width = (that.el.outerWidth() - 2) + 'px'; } $container.css(styles); }, enableKillerFn: function () { var that = this; $(document).on('click.autocomplete', that.killerFn); }, disableKillerFn: function () { var that = this; $(document).off('click.autocomplete', that.killerFn); }, killSuggestions: function () { var that = this; that.stopKillSuggestions(); that.intervalId = window.setInterval(function () { if (that.visible) { that.el.val(that.currentValue); that.hide(); } that.stopKillSuggestions(); }, 50); }, stopKillSuggestions: function () { window.clearInterval(this.intervalId); }, isCursorAtEnd: function () { var that = this, valLength = that.el.val().length, selectionStart = that.element.selectionStart, range; if (typeof selectionStart === 'number') { return selectionStart === valLength; } if (document.selection) { range = document.selection.createRange(); range.moveStart('character', -valLength); return valLength === range.text.length; } return true; }, onKeyPress: function (e) { var that = this; // If suggestions are hidden and user presses arrow down, display suggestions: if (!that.disabled && !that.visible && e.which === keys.DOWN && that.currentValue) { that.suggest(); return; } if (that.disabled || !that.visible) { return; } switch (e.which) { case keys.ESC: that.el.val(that.currentValue); that.hide(); break; case keys.RIGHT: if (that.hint && that.options.onHint && that.isCursorAtEnd()) { that.selectHint(); break; } return; case keys.TAB: if (that.hint && that.options.onHint) { that.selectHint(); return; } if (that.selectedIndex === -1) { that.hide(); return; } that.select(that.selectedIndex); if (that.options.tabDisabled === false) { return; } break; case keys.RETURN: if (that.selectedIndex === -1) { that.hide(); return; } that.select(that.selectedIndex); break; case keys.UP: that.moveUp(); break; case keys.DOWN: that.moveDown(); break; default: return; } // Cancel event if function did not return: e.stopImmediatePropagation(); e.preventDefault(); }, onKeyUp: function (e) { var that = this; if (that.disabled) { return; } switch (e.which) { case keys.UP: case keys.DOWN: return; } clearInterval(that.onChangeInterval); if (that.currentValue !== that.el.val()) { that.findBestHint(); if (that.options.deferRequestBy > 0) { // Defer lookup in case when value changes very quickly: that.onChangeInterval = setInterval(function () { that.onValueChange(); }, that.options.deferRequestBy); } else { that.onValueChange(); } } }, onValueChange: function () { var that = this, options = that.options, value = that.el.val(), query = that.getQuery(value); if (that.selection && that.currentValue !== query) { that.selection = null; (options.onInvalidateSelection || $.noop).call(that.element); } clearInterval(that.onChangeInterval); that.currentValue = value; that.selectedIndex = -1; // Check existing suggestion for the match before proceeding: if (options.triggerSelectOnValidInput && that.isExactMatch(query)) { that.select(0); return; } if (query.length < options.minChars) { that.hide(); } else { that.getSuggestions(query); } }, isExactMatch: function (query) { var suggestions = this.suggestions; return (suggestions.length === 1 && suggestions[0].v.toLowerCase() === query.toLowerCase()); }, getQuery: function (value) { var delimiter = this.options.delimiter, parts; if (!delimiter) { return value; } parts = value.split(delimiter); return $.trim(parts[parts.length - 1]); }, getSuggestionsLocal: function (query) { var that = this, options = that.options, queryLowerCase = query.toLowerCase(), filter = options.lookupFilter, limit = parseInt(options.lookupLimit, 10), data; data = { suggestions: $.grep(options.lookup, function (suggestion) { return filter(suggestion, query, queryLowerCase); }) }; if (limit && data.suggestions.length > limit) { data.suggestions = data.suggestions.slice(0, limit); } return data; }, getSuggestions: function (q) { var response, that = this, options = that.options, serviceUrl = options.serviceUrl, params, cacheKey, ajaxSettings; options.params[options.paramName] = q; params = options.ignoreParams ? null : options.params; if (options.onSearchStart.call(that.element, options.params) === false) { return; } if ($.isFunction(options.lookup)) { options.lookup(q, function (data) { that.suggestions = data.suggestions; that.suggest(); options.onSearchComplete.call(that.element, q, data.suggestions); }); return; } if (that.isLocal) { response = that.getSuggestionsLocal(q); } else { if ($.isFunction(serviceUrl)) { serviceUrl = serviceUrl.call(that.element, q); } cacheKey = serviceUrl + '?' + $.param(params || {}); response = that.cachedResponse[cacheKey]; } if (response && $.isArray(response.suggestions)) { that.suggestions = response.suggestions; that.suggest(); options.onSearchComplete.call(that.element, q, response.suggestions); } else if (!that.isBadQuery(q)) { that.abortAjax(); ajaxSettings = { url: serviceUrl, data: params, type: options.type, dataType: options.dataType }; $.extend(ajaxSettings, options.ajaxSettings); that.currentRequest = $.ajax(ajaxSettings).done(function (data) { var result; that.currentRequest = null; result = options.transformResult(data, q); that.processResponse(result, q, cacheKey); options.onSearchComplete.call(that.element, q, result.suggestions); }).fail(function (jqXHR, textStatus, errorThrown) { options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown); }); } else { options.onSearchComplete.call(that.element, q, []); } }, isBadQuery: function (q) { if (!this.options.preventBadQueries) { return false; } var badQueries = this.badQueries, i = badQueries.length; while (i--) { if (q.indexOf(badQueries[i]) === 0) { return true; } } return false; }, hide: function () { var that = this, container = $(that.suggestionsContainer); if ($.isFunction(that.options.onHide) && that.visible) { that.options.onHide.call(that.element, container); } that.visible = false; that.selectedIndex = -1; clearInterval(that.onChangeInterval); $(that.suggestionsContainer).hide(); that.signalHint(null); }, suggest: function () { if (this.suggestions.length === 0) { if (this.options.showNoSuggestionNotice) { this.noSuggestions(); } else { this.hide(); } return; } var that = this, options = that.options, groupBy = options.groupBy, formatResult = options.formatResult, value = that.getQuery(that.currentValue), className = that.classes.suggestion, classSelected = that.classes.selected, container = $(that.suggestionsContainer), noSuggestionsContainer = $(that.noSuggestionsContainer), beforeRender = options.beforeRender, html = '', category, formatGroup = function (suggestion, index) { var currentCategory = suggestion.data[groupBy]; if (category === currentCategory) { return ''; } category = currentCategory; return '
' + category + '
'; }; if (options.triggerSelectOnValidInput && that.isExactMatch(value)) { that.select(0); return; } // Build suggestions inner HTML: $.each(that.suggestions, function (i, suggestion) { if (groupBy) { html += formatGroup(suggestion, value, i); } html += '
' + formatResult(suggestion, value) + '
'; }); this.adjustContainerWidth(); noSuggestionsContainer.detach(); container.html(html); if ($.isFunction(beforeRender)) { beforeRender.call(that.element, container); } that.fixPosition(); container.show(); // Select first value by default: if (options.autoSelectFirst) { that.selectedIndex = 0; container.scrollTop(0); container.children('.' + className).first().addClass(classSelected); } that.visible = true; that.findBestHint(); }, noSuggestions: function () { var that = this, container = $(that.suggestionsContainer), noSuggestionsContainer = $(that.noSuggestionsContainer); this.adjustContainerWidth(); // Some explicit steps. Be careful here as it easy to get // noSuggestionsContainer removed from DOM if not detached properly. noSuggestionsContainer.detach(); container.empty(); // clean suggestions if any container.append(noSuggestionsContainer); that.fixPosition(); container.show(); that.visible = true; }, adjustContainerWidth: function () { var that = this, options = that.options, width, container = $(that.suggestionsContainer); // If width is auto, adjust width before displaying suggestions, // because if instance was created before input had width, it will be zero. // Also it adjusts if input width has changed. // -2px to account for suggestions border. if (options.width === 'auto') { width = that.el.outerWidth() - 2; container.width(width > 0 ? width : 300); } }, findBestHint: function () { var that = this, value = that.el.val().toLowerCase(), bestMatch = null; if (!value) { return; } $.each(that.suggestions, function (i, suggestion) { var foundMatch = suggestion.v.toLowerCase().indexOf(value) === 0; if (foundMatch) { bestMatch = suggestion; } return !foundMatch; }); that.signalHint(bestMatch); }, signalHint: function (suggestion) { var hintValue = '', that = this; if (suggestion) { hintValue = that.currentValue + suggestion.v.substr(that.currentValue.length); } if (that.hintValue !== hintValue) { that.hintValue = hintValue; that.hint = suggestion; (this.options.onHint || $.noop)(hintValue); } }, verifySuggestionsFormat: function (suggestions) { // If suggestions is string array, convert them to supported format: if (suggestions.length && typeof suggestions[0] === 'string') { return $.map(suggestions, function (value) { return { value: value, data: null }; }); } return suggestions; }, validateOrientation: function (orientation, fallback) { orientation = $.trim(orientation || '').toLowerCase(); if ($.inArray(orientation, ['auto', 'bottom', 'top']) === -1) { orientation = fallback; } return orientation; }, processResponse: function (result, originalQuery, cacheKey) { var that = this, options = that.options; result.suggestions = that.verifySuggestionsFormat(result.suggestions); // Cache results if cache is not disabled: if (!options.noCache) { that.cachedResponse[cacheKey] = result; if (options.preventBadQueries && result.suggestions.length === 0) { that.badQueries.push(originalQuery); } } // Return if originalQuery is not matching current query: if (originalQuery !== that.getQuery(that.currentValue)) { return; } that.suggestions = result.suggestions; that.suggest(); }, activate: function (index) { var that = this, activeItem, selected = that.classes.selected, container = $(that.suggestionsContainer), children = container.find('.' + that.classes.suggestion); container.find('.' + selected).removeClass(selected); that.selectedIndex = index; if (that.selectedIndex !== -1 && children.length > that.selectedIndex) { activeItem = children.get(that.selectedIndex); $(activeItem).addClass(selected); return activeItem; } return null; }, selectHint: function () { var that = this, i = $.inArray(that.hint, that.suggestions); that.select(i); }, select: function (i) { var that = this; that.hide(); that.onSelect(i); }, moveUp: function () { var that = this; if (that.selectedIndex === -1) { return; } if (that.selectedIndex === 0) { $(that.suggestionsContainer).children().first().removeClass(that.classes.selected); that.selectedIndex = -1; that.el.val(that.currentValue); that.findBestHint(); return; } that.adjustScroll(that.selectedIndex - 1); }, moveDown: function () { var that = this; if (that.selectedIndex === (that.suggestions.length - 1)) { return; } that.adjustScroll(that.selectedIndex + 1); }, adjustScroll: function (index) { var that = this, activeItem = that.activate(index); if (!activeItem) { return; } var offsetTop, upperBound, lowerBound, heightDelta = $(activeItem).outerHeight(); offsetTop = activeItem.offsetTop; upperBound = $(that.suggestionsContainer).scrollTop(); lowerBound = upperBound + that.options.maxHeight - heightDelta; if (offsetTop < upperBound) { $(that.suggestionsContainer).scrollTop(offsetTop); } else if (offsetTop > lowerBound) { $(that.suggestionsContainer).scrollTop(offsetTop - that.options.maxHeight + heightDelta); } if (!that.options.preserveInput) { that.el.val(that.getValue(that.suggestions[index].v)); } that.signalHint(null); }, onSelect: function (index) { var that = this, onSelectCallback = that.options.onSelect, suggestion = that.suggestions[index]; that.currentValue = that.getValue(suggestion.v); if (that.currentValue !== that.el.val() && !that.options.preserveInput) { that.el.val(that.currentValue); } that.signalHint(null); that.suggestions = []; that.selection = suggestion; if ($.isFunction(onSelectCallback)) { onSelectCallback.call(that.element, suggestion); } }, getValue: function (value) { var that = this, delimiter = that.options.delimiter, currentValue, parts; if (!delimiter) { return value; } currentValue = that.currentValue; parts = currentValue.split(delimiter); if (parts.length === 1) { return value; } return currentValue.substr(0, currentValue.length - parts[parts.length - 1].length) + value; }, dispose: function () { var that = this; that.el.off('.autocomplete').removeData('autocomplete'); that.disableKillerFn(); $(window).off('resize.autocomplete', that.fixPositionCapture); $(that.suggestionsContainer).remove(); } }; // Create chainable jQuery plugin: $.fn.autocomplete = $.fn.devbridgeAutocomplete = function (options, args) { var dataKey = 'autocomplete'; // If function invoked without argument return // instance of the first matched element: if (arguments.length === 0) { return this.first().data(dataKey); } return this.each(function () { var inputElement = $(this), instance = inputElement.data(dataKey); if (typeof options === 'string') { if (instance && typeof instance[options] === 'function') { instance[options](args); } } else { // If instance already exists, destroy it: if (instance && instance.dispose) { instance.dispose(); } instance = new Autocomplete(this, options); inputElement.data(dataKey, instance); } }); }; })); ; (function () { //var loadPartial = function (action, controller, routeData) { // var path = controller + '/' + action; // if (typeof routeData === 'object' && routeData !== null && 'area' in routeData) // path = routeData.area + '/' + path; // var req = { // url: Utils.BaseURL + path, // dataType: 'html' // }; // if (typeof routeData === 'object' && routeData !== null) // req.data = routeData; // return $.ajax(req); //}; var loadPartial = async function (action, controller, routeData) { var path = controller + '/' + action; var queryString = ""; if (typeof routeData === 'object' && routeData !== null && 'area' in routeData) path = routeData.area + '/' + path; if (typeof routeData === 'object' && routeData !== null) queryString = "?" + new URLSearchParams(routeData).toString(); //console.log("loadPartial: " + Utils.BaseURL + path + queryString); return resp = await fetch(Utils.BaseURL + path + queryString, { method:"GET", }) }; var executeCallback = function (callback) { if (callback !== null && callback.length > 0) { var fn = window[callback]; if (typeof fn === 'function') { try { fn(); } catch (e) { console.log('error executing callback'); console.log(e); } } else { console.log('callback is not a function'); } } }; //on document ready scan for ajaxpartials to execute //note: this could be further optimized to trigger the partials sooner than wait for the full document. although that would invalidate priority queueing document.addEventListener('DOMContentLoaded', async function () { //sort partials by their priority score. const sortedPartials = Array.from(document.querySelectorAll('.js-ajax-partial')).sort((a, b) => $(b).data('requestpriority') - $(a).data('requestpriority')); for(const ajaxPartial of sortedPartials) { var priority = $(ajaxPartial).data('requestpriority'); //console.log('request sort value: ' + priority); var self = $(ajaxPartial); var action = self.data('action'); var controller = self.data('controller'); var routeData = self.data('routeValues'); var callback = self.data('callback'); //await each partial - they get queued by IIS/.net in a synchronous fashion on server side anyway. this allows //us to have more control over the order here. var resp = await loadPartial(action, controller, routeData) if (resp.ok) { var data = await resp.text(); self.replaceWith(data) executeCallback(callback); } else { var errorMessage = { "Url": window.location.href, "Message": "error loading partial", "Error": JSON.stringify({ error: 'there was an error', action: action, controller: controller, routeData: routeData }) } log.Error(errorMessage); } }; }); //$(function () { // $('.js-ajax-partial').sort((a, b) => $(b).data('requestpriority') - $(a).data('requestpriority')).each(function () { // console.log('request sort value: ' + $(this).data('requestpriority')) // var self = $(this); // var action = self.data('action'); // var controller = self.data('controller'); // var routeData = self.data('routeValues'); // var callback = self.data('callback'); // loadPartial(action, controller, routeData) // .then(function (html) { // self.replaceWith(html); // executeCallback(callback); // }).fail(function (err) { // var errorMessage = { // "Url": window.location.href, // "Message":"error loading partial", // "Error":JSON.stringify({error:error,action:action,controller:controller,routeData:routeData }) // } // log.Error(errorMessage); // }); // }); //}); })(); ; (function () { if (!window.performance) return; var sampleRate = 1 / 25; var isInSample = (Math.random() < sampleRate); if (Math.random() > sampleRate) return; window.addEventListener("load", function () { var nav = window.performance.getEntriesByType('navigation'); if (!nav.length) return; var timings = nav[0]; var data = { dealerId: CurrentDealer.Id, pageType: typeof PageData.pageType === 'undefined' ? "Other" : PageData.pageType, serverResponse: Math.round(timings.responseEnd - timings.requestStart), contentDownload: Math.round(timings.responseEnd - timings.responseStart), domContentLoaded: Math.round(timings.domContentLoadedEventEnd), domInteractive: Math.round(timings.domInteractive), load: Math.round(timings.loadEventStart) }; fetch(Utils.BaseURL + 'monitoring/pagetiming', { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }); }); })();; /* * jQuery Mobile v1.4.5 * http://jquerymobile.com * * Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors * Released under the MIT license. * http://jquery.org/license * */ (function ( root, doc, factory ) { if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. define( [ "jquery" ], function ( $ ) { factory( $, root, doc ); return $.mobile; }); } else { // Browser globals factory( root.jQuery, root, doc ); } }( this, document, function ( jQuery, window, document, undefined ) {// This plugin is an experiment for abstracting away the touch and mouse // events so that developers don't have to worry about which method of input // the device their document is loaded on supports. // // The idea here is to allow the developer to register listeners for the // basic mouse events, such as mousedown, mousemove, mouseup, and click, // and the plugin will take care of registering the correct listeners // behind the scenes to invoke the listener at the fastest possible time // for that device, while still retaining the order of event firing in // the traditional mouse environment, should multiple handlers be registered // on the same element for different events. // // The current version exposes the following virtual events to jQuery bind methods: // "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel" (function( $, window, document, undefined ) { var dataPropertyName = "virtualMouseBindings", touchTargetPropertyName = "virtualTouchID", virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ), touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ), mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [], mouseEventProps = $.event.props.concat( mouseHookProps ), activeDocHandlers = {}, resetTimerID = 0, startX = 0, startY = 0, didScroll = false, clickBlockList = [], blockMouseTriggers = false, blockTouchTriggers = false, eventCaptureSupported = "addEventListener" in document, $document = $( document ), nextTouchID = 1, lastTouchID = 0, threshold, i; $.vmouse = { moveDistanceThreshold: 10, clickDistanceThreshold: 10, resetTimerDuration: 1500 }; function getNativeEvent( event ) { while ( event && typeof event.originalEvent !== "undefined" ) { event = event.originalEvent; } return event; } function createVirtualEvent( event, eventType ) { var t = event.type, oe, props, ne, prop, ct, touch, i, j, len; event = $.Event( event ); event.type = eventType; oe = event.originalEvent; props = $.event.props; // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280 // https://github.com/jquery/jquery-mobile/issues/3280 if ( t.search( /^(mouse|click)/ ) > -1 ) { props = mouseEventProps; } // copy original event properties over to the new event // this would happen if we could call $.event.fix instead of $.Event // but we don't have a way to force an event to be fixed multiple times if ( oe ) { for ( i = props.length, prop; i; ) { prop = props[ --i ]; event[ prop ] = oe[ prop ]; } } // make sure that if the mouse and click virtual events are generated // without a .which one is defined if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) { event.which = 1; } if ( t.search(/^touch/) !== -1 ) { ne = getNativeEvent( oe ); t = ne.touches; ct = ne.changedTouches; touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined ); if ( touch ) { for ( j = 0, len = touchEventProps.length; j < len; j++) { prop = touchEventProps[ j ]; event[ prop ] = touch[ prop ]; } } } return event; } function getVirtualBindingFlags( element ) { var flags = {}, b, k; while ( element ) { b = $.data( element, dataPropertyName ); for ( k in b ) { if ( b[ k ] ) { flags[ k ] = flags.hasVirtualBinding = true; } } element = element.parentNode; } return flags; } function getClosestElementWithVirtualBinding( element, eventType ) { var b; while ( element ) { b = $.data( element, dataPropertyName ); if ( b && ( !eventType || b[ eventType ] ) ) { return element; } element = element.parentNode; } return null; } function enableTouchBindings() { blockTouchTriggers = false; } function disableTouchBindings() { blockTouchTriggers = true; } function enableMouseBindings() { lastTouchID = 0; clickBlockList.length = 0; blockMouseTriggers = false; // When mouse bindings are enabled, our // touch bindings are disabled. disableTouchBindings(); } function disableMouseBindings() { // When mouse bindings are disabled, our // touch bindings are enabled. enableTouchBindings(); } function startResetTimer() { clearResetTimer(); resetTimerID = setTimeout( function() { resetTimerID = 0; enableMouseBindings(); }, $.vmouse.resetTimerDuration ); } function clearResetTimer() { if ( resetTimerID ) { clearTimeout( resetTimerID ); resetTimerID = 0; } } function triggerVirtualEvent( eventType, event, flags ) { var ve; if ( ( flags && flags[ eventType ] ) || ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) { ve = createVirtualEvent( event, eventType ); $( event.target).trigger( ve ); } return ve; } function mouseEventCallback( event ) { var touchID = $.data( event.target, touchTargetPropertyName ), ve; if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) { ve = triggerVirtualEvent( "v" + event.type, event ); if ( ve ) { if ( ve.isDefaultPrevented() ) { event.preventDefault(); } if ( ve.isPropagationStopped() ) { event.stopPropagation(); } if ( ve.isImmediatePropagationStopped() ) { event.stopImmediatePropagation(); } } } } function handleTouchStart( event ) { var touches = getNativeEvent( event ).touches, target, flags, t; if ( touches && touches.length === 1 ) { target = event.target; flags = getVirtualBindingFlags( target ); if ( flags.hasVirtualBinding ) { lastTouchID = nextTouchID++; $.data( target, touchTargetPropertyName, lastTouchID ); clearResetTimer(); disableMouseBindings(); didScroll = false; t = getNativeEvent( event ).touches[ 0 ]; startX = t.pageX; startY = t.pageY; triggerVirtualEvent( "vmouseover", event, flags ); triggerVirtualEvent( "vmousedown", event, flags ); } } } function handleScroll( event ) { if ( blockTouchTriggers ) { return; } if ( !didScroll ) { triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) ); } didScroll = true; startResetTimer(); } function handleTouchMove( event ) { if ( blockTouchTriggers ) { return; } var t = getNativeEvent( event ).touches[ 0 ], didCancel = didScroll, moveThreshold = $.vmouse.moveDistanceThreshold, flags = getVirtualBindingFlags( event.target ); didScroll = didScroll || ( Math.abs( t.pageX - startX ) > moveThreshold || Math.abs( t.pageY - startY ) > moveThreshold ); if ( didScroll && !didCancel ) { triggerVirtualEvent( "vmousecancel", event, flags ); } triggerVirtualEvent( "vmousemove", event, flags ); startResetTimer(); } function handleTouchEnd( event ) { if ( blockTouchTriggers ) { return; } disableTouchBindings(); var flags = getVirtualBindingFlags( event.target ), ve, t; triggerVirtualEvent( "vmouseup", event, flags ); if ( !didScroll ) { ve = triggerVirtualEvent( "vclick", event, flags ); if ( ve && ve.isDefaultPrevented() ) { // The target of the mouse events that follow the touchend // event don't necessarily match the target used during the // touch. This means we need to rely on coordinates for blocking // any click that is generated. t = getNativeEvent( event ).changedTouches[ 0 ]; clickBlockList.push({ touchID: lastTouchID, x: t.clientX, y: t.clientY }); // Prevent any mouse events that follow from triggering // virtual event notifications. blockMouseTriggers = true; } } triggerVirtualEvent( "vmouseout", event, flags); didScroll = false; startResetTimer(); } function hasVirtualBindings( ele ) { var bindings = $.data( ele, dataPropertyName ), k; if ( bindings ) { for ( k in bindings ) { if ( bindings[ k ] ) { return true; } } } return false; } function dummyMouseHandler() {} function getSpecialEventObject( eventType ) { var realType = eventType.substr( 1 ); return { setup: function(/* data, namespace */) { // If this is the first virtual mouse binding for this element, // add a bindings object to its data. if ( !hasVirtualBindings( this ) ) { $.data( this, dataPropertyName, {} ); } // If setup is called, we know it is the first binding for this // eventType, so initialize the count for the eventType to zero. var bindings = $.data( this, dataPropertyName ); bindings[ eventType ] = true; // If this is the first virtual mouse event for this type, // register a global handler on the document. activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1; if ( activeDocHandlers[ eventType ] === 1 ) { $document.bind( realType, mouseEventCallback ); } // Some browsers, like Opera Mini, won't dispatch mouse/click events // for elements unless they actually have handlers registered on them. // To get around this, we register dummy handlers on the elements. $( this ).bind( realType, dummyMouseHandler ); // For now, if event capture is not supported, we rely on mouse handlers. if ( eventCaptureSupported ) { // If this is the first virtual mouse binding for the document, // register our touchstart handler on the document. activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1; if ( activeDocHandlers[ "touchstart" ] === 1 ) { $document.bind( "touchstart", handleTouchStart ) .bind( "touchend", handleTouchEnd ) // On touch platforms, touching the screen and then dragging your finger // causes the window content to scroll after some distance threshold is // exceeded. On these platforms, a scroll prevents a click event from being // dispatched, and on some platforms, even the touchend is suppressed. To // mimic the suppression of the click event, we need to watch for a scroll // event. Unfortunately, some platforms like iOS don't dispatch scroll // events until *AFTER* the user lifts their finger (touchend). This means // we need to watch both scroll and touchmove events to figure out whether // or not a scroll happenens before the touchend event is fired. .bind( "touchmove", handleTouchMove ) .bind( "scroll", handleScroll ); } } }, teardown: function(/* data, namespace */) { // If this is the last virtual binding for this eventType, // remove its global handler from the document. --activeDocHandlers[ eventType ]; if ( !activeDocHandlers[ eventType ] ) { $document.unbind( realType, mouseEventCallback ); } if ( eventCaptureSupported ) { // If this is the last virtual mouse binding in existence, // remove our document touchstart listener. --activeDocHandlers[ "touchstart" ]; if ( !activeDocHandlers[ "touchstart" ] ) { $document.unbind( "touchstart", handleTouchStart ) .unbind( "touchmove", handleTouchMove ) .unbind( "touchend", handleTouchEnd ) .unbind( "scroll", handleScroll ); } } var $this = $( this ), bindings = $.data( this, dataPropertyName ); // teardown may be called when an element was // removed from the DOM. If this is the case, // jQuery core may have already stripped the element // of any data bindings so we need to check it before // using it. if ( bindings ) { bindings[ eventType ] = false; } // Unregister the dummy event handler. $this.unbind( realType, dummyMouseHandler ); // If this is the last virtual mouse binding on the // element, remove the binding data from the element. if ( !hasVirtualBindings( this ) ) { $this.removeData( dataPropertyName ); } } }; } // Expose our custom events to the jQuery bind/unbind mechanism. for ( i = 0; i < virtualEventNames.length; i++ ) { $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] ); } // Add a capture click handler to block clicks. // Note that we require event capture support for this so if the device // doesn't support it, we punt for now and rely solely on mouse events. if ( eventCaptureSupported ) { document.addEventListener( "click", function( e ) { var cnt = clickBlockList.length, target = e.target, x, y, ele, i, o, touchID; if ( cnt ) { x = e.clientX; y = e.clientY; threshold = $.vmouse.clickDistanceThreshold; // The idea here is to run through the clickBlockList to see if // the current click event is in the proximity of one of our // vclick events that had preventDefault() called on it. If we find // one, then we block the click. // // Why do we have to rely on proximity? // // Because the target of the touch event that triggered the vclick // can be different from the target of the click event synthesized // by the browser. The target of a mouse/click event that is synthesized // from a touch event seems to be implementation specific. For example, // some browsers will fire mouse/click events for a link that is near // a touch event, even though the target of the touchstart/touchend event // says the user touched outside the link. Also, it seems that with most // browsers, the target of the mouse/click event is not calculated until the // time it is dispatched, so if you replace an element that you touched // with another element, the target of the mouse/click will be the new // element underneath that point. // // Aside from proximity, we also check to see if the target and any // of its ancestors were the ones that blocked a click. This is necessary // because of the strange mouse/click target calculation done in the // Android 2.1 browser, where if you click on an element, and there is a // mouse/click handler on one of its ancestors, the target will be the // innermost child of the touched element, even if that child is no where // near the point of touch. ele = target; while ( ele ) { for ( i = 0; i < cnt; i++ ) { o = clickBlockList[ i ]; touchID = 0; if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) || $.data( ele, touchTargetPropertyName ) === o.touchID ) { // XXX: We may want to consider removing matches from the block list // instead of waiting for the reset timer to fire. e.preventDefault(); e.stopPropagation(); return; } } ele = ele.parentNode; } } }, true); } })( jQuery, window, document ); (function( $ ) { $.mobile = {}; }( jQuery )); (function( $, undefined ) { var support = { touch: "ontouchend" in document }; $.mobile.support = $.mobile.support || {}; $.extend( $.support, support ); $.extend( $.mobile.support, support ); }( jQuery )); (function( $, window, undefined ) { var $document = $( document ), supportTouch = $.mobile.support.touch, scrollEvent = "touchmove scroll", touchStartEvent = supportTouch ? "touchstart" : "mousedown", touchStopEvent = supportTouch ? "touchend" : "mouseup", touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; // setup new event shortcuts $.each( ( "touchstart touchmove touchend " + "tap taphold " + "swipe swipeleft swiperight " + "scrollstart scrollstop" ).split( " " ), function( i, name ) { $.fn[ name ] = function( fn ) { return fn ? this.bind( name, fn ) : this.trigger( name ); }; // jQuery < 1.8 //if ( $.attrFn ) { // $.attrFn[ name ] = true; //} }); function triggerCustomEvent( obj, eventType, event, bubble ) { var originalType = event.type; event.type = eventType; if ( bubble ) { $.event.trigger( event, undefined, obj ); } else { $.event.dispatch.call( obj, event ); } event.type = originalType; } // also handles scrollstop $.event.special.scrollstart = { enabled: true, setup: function() { var thisObject = this, $this = $( thisObject ), scrolling, timer; function trigger( event, state ) { scrolling = state; triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event ); } // iPhone triggers scroll after a small delay; use touchmove instead $this.bind( scrollEvent, function( event ) { if ( !$.event.special.scrollstart.enabled ) { return; } if ( !scrolling ) { trigger( event, true ); } clearTimeout( timer ); timer = setTimeout( function() { trigger( event, false ); }, 50 ); }); }, teardown: function() { $( this ).unbind( scrollEvent ); } }; // also handles taphold $.event.special.tap = { tapholdThreshold: 750, emitTapOnTaphold: true, setup: function() { var thisObject = this, $this = $( thisObject ), isTaphold = false; $this.bind( "vmousedown", function( event ) { isTaphold = false; if ( event.which && event.which !== 1 ) { return false; } var origTarget = event.target, timer; function clearTapTimer() { clearTimeout( timer ); } function clearTapHandlers() { clearTapTimer(); $this.unbind( "vclick", clickHandler ) .unbind( "vmouseup", clearTapTimer ); $document.unbind( "vmousecancel", clearTapHandlers ); } function clickHandler( event ) { clearTapHandlers(); // ONLY trigger a 'tap' event if the start target is // the same as the stop target. if ( !isTaphold && origTarget === event.target ) { triggerCustomEvent( thisObject, "tap", event ); } else if ( isTaphold ) { event.preventDefault(); } } $this.bind( "vmouseup", clearTapTimer ) .bind( "vclick", clickHandler ); $document.bind( "vmousecancel", clearTapHandlers ); timer = setTimeout( function() { if ( !$.event.special.tap.emitTapOnTaphold ) { isTaphold = true; } triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) ); }, $.event.special.tap.tapholdThreshold ); }); }, teardown: function() { $( this ).unbind( "vmousedown" ).unbind( "vclick" ).unbind( "vmouseup" ); $document.unbind( "vmousecancel" ); } }; // Also handles swipeleft, swiperight $.event.special.swipe = { // More than this horizontal displacement, and we will suppress scrolling. scrollSupressionThreshold: 30, // More time than this, and it isn't a swipe. durationThreshold: 1000, // Swipe horizontal displacement must be more than this. horizontalDistanceThreshold: 30, // Swipe vertical displacement must be less than this. verticalDistanceThreshold: 30, getLocation: function ( event ) { var winPageX = window.pageXOffset, winPageY = window.pageYOffset, x = event.clientX, y = event.clientY; if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) || event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) { // iOS4 clientX/clientY have the value that should have been // in pageX/pageY. While pageX/page/ have the value 0 x = x - winPageX; y = y - winPageY; } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) { // Some Android browsers have totally bogus values for clientX/Y // when scrolling/zooming a page. Detectable since clientX/clientY // should never be smaller than pageX/pageY minus page scroll x = event.pageX - winPageX; y = event.pageY - winPageY; } return { x: x, y: y }; }, start: function( event ) { var data = event.originalEvent.touches ? event.originalEvent.touches[ 0 ] : event, location = $.event.special.swipe.getLocation( data ); return { time: ( new Date() ).getTime(), coords: [ location.x, location.y ], origin: $( event.target ) }; }, stop: function( event ) { var data = event.originalEvent.touches ? event.originalEvent.touches[ 0 ] : event, location = $.event.special.swipe.getLocation( data ); return { time: ( new Date() ).getTime(), coords: [ location.x, location.y ] }; }, handleSwipe: function( start, stop, thisObject, origTarget ) { if ( stop.time - start.time < $.event.special.swipe.durationThreshold && Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold && Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) { var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight"; triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop }), true ); triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true ); return true; } return false; }, // This serves as a flag to ensure that at most one swipe event event is // in work at any given time eventInProgress: false, setup: function() { var events, thisObject = this, $this = $( thisObject ), context = {}; // Retrieve the events data for this element and add the swipe context events = $.data( this, "mobile-events" ); if ( !events ) { events = { length: 0 }; $.data( this, "mobile-events", events ); } events.length++; events.swipe = context; context.start = function( event ) { // Bail if we're already working on a swipe event if ( $.event.special.swipe.eventInProgress ) { return; } $.event.special.swipe.eventInProgress = true; var stop, start = $.event.special.swipe.start( event ), origTarget = event.target, emitted = false; context.move = function( event ) { if ( !start || event.isDefaultPrevented() ) { return; } stop = $.event.special.swipe.stop( event ); if ( !emitted ) { emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget ); if ( emitted ) { // Reset the context to make way for the next swipe event $.event.special.swipe.eventInProgress = false; } } // prevent scrolling if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) { event.preventDefault(); } }; context.stop = function() { emitted = true; // Reset the context to make way for the next swipe event $.event.special.swipe.eventInProgress = false; $document.off( touchMoveEvent, context.move ); context.move = null; }; $document.on( touchMoveEvent, context.move ) .one( touchStopEvent, context.stop ); }; $this.on( touchStartEvent, context.start ); }, teardown: function() { var events, context; events = $.data( this, "mobile-events" ); if ( events ) { context = events.swipe; delete events.swipe; events.length--; if ( events.length === 0 ) { $.removeData( this, "mobile-events" ); } } if ( context ) { if ( context.start ) { $( this ).off( touchStartEvent, context.start ); } if ( context.move ) { $document.off( touchMoveEvent, context.move ); } if ( context.stop ) { $document.off( touchStopEvent, context.stop ); } } } }; $.each({ scrollstop: "scrollstart", taphold: "tap", swipeleft: "swipe.left", swiperight: "swipe.right" }, function( event, sourceEvent ) { $.event.special[ event ] = { setup: function() { $( this ).bind( sourceEvent, $.noop ); }, teardown: function() { $( this ).unbind( sourceEvent ); } }; }); })( jQuery, this ); })); ; /** * * Responsive Utilities * **/ /*========================================= = Responsive Button = =========================================*/ (function () { "use strict"; function bindResponsiveButtons(responsiveButtons) { responsiveButtons.bind(clickEvent, function (event) { event.preventDefault(); if ($(this).next('.Responsive_ExpandableContainer').length) { $(this).toggleClass('isActiveButton').next('.Responsive_ExpandableContainer').slideToggle(); } else if ($(this).children('.Responsive_ExpandableContainer').length) { $(this).toggleClass('isActiveButton').children('.Responsive_ExpandableContainer').slideToggle(); } else { console.error('Responsive_ExpandableContainer could not be found--must be sibling or immediate child'); } }); } function unbindResponsiveButtons(responsiveButtons) { responsiveButtons.unbind(clickEvent); responsiveButtons.each(function () { if ($(this).next('.Responsive_ExpandableContainer').length) { $(this).removeClass('isActiveButton').next('.Responsive_ExpandableContainer').attr('style', '').slideDown(); } else if ($(this).children('.Responsive_ExpandableContainer').length) { $(this).removeClass('isActiveButton').children('.Responsive_ExpandableContainer').attr('style', '').slideDown(); } }); } enquire.register("only screen and (max-width: 47.9375em)", { match: function () { bindResponsiveButtons($('.Responsive_Button')); }, unmatch: function () { unbindResponsiveButtons($('.Responsive_Button')); } }); }()); /*----- End of Responsive Button ------*/; /**/ /* bet365在线平台ping Cart */ /**/ //better way to add an item to a cart //MPW 8.17.17: "good cart" -Paul function AddTobet365在线平台pingCart(gpid, quantity = 1, callback) { var data = '{"gpid":' + gpid + "," + '"quantity":' + quantity + '}'; $.ajax({ type: "POST", url: Utils.BaseURL + "AjaxItemService.asmx/AddTobet365在线平台pingCart", data: data, contentType: "application/json; charset=utf-8", dataType: "json", success: function (res) { var data = JSON.parse(res.d); var item = JSON.parse(data.item); //track in facebook window.fbPixel.done(function () { fbq('track', 'AddToCart', { content_type: 'product', content_ids: [gpid.toString()] }, { eventID: data.metaEventId }); }); // update CartStatus control count var cartItemCount = (parseInt($(".js-cart-count").first().text().replace(/\D/g, ""), 10) + 1); if ($(".cart-status-v4").length > 0) $(".js-cart-count").text(cartItemCount); else $(".js-cart-count").text("(" + cartItemCount + ")"); if (typeof (laurentideTracker) !== 'undefined') Laurentide_AddToCart(item, cartItemCount); callback(item); // returns item data Ga4AddToCart(item); //GaAddToCart(item); // TrackItemEvent('bet365在线平台ping Cart', 'Add', item.GPID, item); }, error: function (msg) { console.log(msg.responseText); } }); } // Updated scrollTo function $.fn.scrollTo = function (target, options, callback) { if (typeof options === 'function' && arguments.length === 2) { callback = options; options = target; } var settings = $.extend({ scrollTarget: target, offsetTop: 50, duration: 500, easing: 'swing' }, options); return this.each(function () { var scrollPane = $(this); var scrollTarget = (typeof settings.scrollTarget === "number") ? settings.scrollTarget : $(settings.scrollTarget); var scrollY = (typeof scrollTarget === "number") ? scrollTarget : scrollTarget.offset().top - parseInt(settings.offsetTop); scrollPane.animate({ scrollTop: scrollY }, parseInt(settings.duration), settings.easing, function () { if (typeof callback === 'function') { callback.call(this); } }); }); } $(function () { /* Enable tooltips on material icon */ if ($('.material-icons[data-toggle="tooltip"]').length > 0) { $('.material-icons[data-toggle="tooltip"]').tooltip(); } // initialize slider when the 1st image loads $(".shared-swiper .swiper-wrapper .content-slider:first-child img").one("load", function () { InitsharedSlider($(this)); }).each(function () { if (this.complete) { $(this).load(); } }); }); // Handles off canvas slideouts $(document).on('click keydown', '[data-toggle="offcanvas"]', function (event) { // Check if the event is a click or Enter key press if (event.type === 'click' || (event.type === 'keydown' && event.key === 'Enter')) { const target = $(this).data('target'); const context = $(this).data('context'); if (target) { if ($(target).hasClass('open')) { closeOffCanvas(target, context); } else { openOffCanvas(target, context); } } // Prevent default action when Enter key is pressed if (event.type === 'keydown') { event.preventDefault(); } } }); //handle modal mask click aways $('body').on('click', '.modal-backdrop--offcanvas', function (event) { closeOffCanvas(); }); function openOffCanvas(target,context,callback) { const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth; // Create the modal mask element const modalMask = document.createElement('div'); modalMask.className = 'modal-backdrop--offcanvas modal-backdrop fade'; modalMask.tabIndex = 0; // Attach event listener for keydown event modalMask.addEventListener('keydown', function (event) { if (event.key === 'Enter') { closeOffCanvas(target); } }); $(target).addClass('open'); $(target).attr('tabindex', 0); if ($('.modal-backdrop--offcanvas').length == 0) { $(modalMask).insertAfter(target); setTimeout(function () { $('.modal-backdrop--offcanvas').addClass('show'); }, 100); } document.body.classList.add('__offcanvas-open'); if (scrollbarWidth) { document.body.style.paddingRight = scrollbarWidth + "px"; } //trigger open event to window dispatchOffCanvasOpenContextEvent(target, context); //execute callback callback && callback(); } function closeOffCanvas(target, context, callback) { const mask = $('.modal-backdrop--offcanvas'); $(mask).removeClass('show'); setTimeout(function () { $(mask).remove(); }, 200); if (target) { $(target).removeClass('open'); $(target).attr('tabindex', -1); //trigger closed event to window dispatchOffCanvasCloseContextEvent(target, context); } else { $('.offcanvas-collapse').each(function () { $('.offcanvas-collapse').removeClass('open'); dispatchOffCanvasCloseContextEvent("#"+$(this).attr("id"), context); }); } document.body.classList.remove('__offcanvas-open'); document.body.style.paddingRight = 0; //execute callback callback && callback(); } function dispatchOffCanvasOpenContextEvent(target, context) { //console.log("dispatchOffCanvasOpenContextEvent hit"); //console.log("dispatchOffCanvasOpenContextEvent target " + target); //console.log("dispatchOffCanvasOpenContextEvent context " + context); // if a context was passed in, emit a custom event and pass along the context if (context) { event.target.dispatchEvent(new CustomEvent('open-context', { detail: { context: context }, bubbles: true })); } else { event.target.dispatchEvent(new CustomEvent('open-context', { detail: { context: "default" }, bubbles: true })); } } function dispatchOffCanvasCloseContextEvent(target, context) { //console.log("dispatchOffCanvasOpenContextEvent hit"); //console.log("dispatchOffCanvasOpenContextEvent target " + target); //console.log("dispatchOffCanvasOpenContextEvent context " + context); // if a context was passed in, emit a custom event and pass along the context if (context) { event.target.dispatchEvent(new CustomEvent('close-context', { detail: { context: context, targetOffCanvas: target }, bubbles: true })); } else { event.target.dispatchEvent(new CustomEvent('close-context', { detail: { context: "default", targetOffCanvas: target }, bubbles: true })); } } function InitsharedSlider(target) { var swiperWrapper = $(target).closest('.shared-swiper'); var slidesPerView = $(swiperWrapper).data('slidesperview') ? $(swiperWrapper).data('slidesperview') : 5; var spaceBetween = $(swiperWrapper).data('spacebetween') ? $(swiperWrapper).data('spacebetween') : 30; var mySwiper = new Swiper(swiperWrapper, { calculateHeight: true, preloadImages: false, scrollbar: { el: '.swiper-scrollbar', hide: false, dragSize: 50, draggable: true }, navigation: { nextEl: '.swiper-button-next', prevEl: '.swiper-button-prev', }, freeMode: true, slidesPerView: slidesPerView, spaceBetween: spaceBetween, slidesPerGroup: 3, watchOverflow: true, touchEventsTarget: 'wrapper', breakpoints: { 1024: { slidesPerView: 4.25, spaceBetween: spaceBetween }, 768: { slidesPerView: 3.25, spaceBetween: 4 }, 465: { slidesPerView: 1.5, spaceBetween: 4 } } }); // add class to set image width to 100% $(swiperWrapper).find('.content-slider__image').addClass('w-100'); // set scrollbar top var calculatedTop = calculatedTop = $(target).height() + 20; $(swiperWrapper).find('.swiper-scrollbar').css('top', calculatedTop); $(window).on('resize', function () { setTimeout(function () { calculatedTop = calculatedTop = $(target).height() + 20; $(swiperWrapper).find('.swiper-scrollbar').css('top', calculatedTop); }, 400); }); } //jb:not sure about location this here async function runRecaptchaAssessment(reCaptchaKey, actionName, actionId, successCallback, errorCallback) { return new Promise((resolve, reject) => { grecaptcha.enterprise.ready(async () => { const token = await grecaptcha.enterprise.execute(reCaptchaKey, { action: actionName }); var body = { "token": token, "recaptchaAction": actionName, "actionId" : actionId } $.ajax({ url: Utils.BaseURL + "Captcha/CreateCaptchaAssessment", type: 'POST', contentType: "application/json; charset=utf-8", dataType: 'json', data: JSON.stringify(body), success: function (data) { console.log(JSON.stringify(data)); if (successCallback) { //console.log('execute captcha success callback'); successCallback(data.score); } resolve(data.Score); }, error: function (data) { console.log(data.responseText); if (errorCallback) { //console.log('execute captcha error callback'); errorCallback(); } reject(); } }); }); }); } ; (function (registration, $, undefined) { registration.RegisterToken = function (regvm, success, error) { ///call api to login dataObj = {}; dataObj.username = regvm.Email; dataObj.password = regvm.Password; dataObj.dealerid = CurrentDealer.Id; reqData = JSON.stringify(dataObj); var apiURL = Utils.IsDev ? "http://helpfurniture.com/ws1/customersv1.svc/GetRegistrationToken/" : "https://api.furnituredealer.net/CustomersV1.svc/GetRegistrationToken/"; $.ajax({ url: apiURL + CurrentDealer.Id, type: 'POST', contentType: "application/json; charset=utf-8", dataType: 'json', data: reqData, success: function (data) { //get response do postback if good if (data.status == 1) { if (success) success(regvm, data.token); } else { if (error) error(data.status); } }, error: function (data) { console.log(data.responseText); error("There was an error creating your account."); } }); }; registration.SimpleRegister = function (regvm, callback) { // call api to do simple register var reqData = JSON.stringify(regvm); $.ajax({ url: Utils.BaseURL + "Registration/SimpleRegisterSubmit", type: 'POST', contentType: "application/json; charset=utf-8", dataType: 'json', data: reqData, success: function (data) { console.log(data); if (data.status === 1) { TrackEvent('Signup', 'Simple', '', true); if (callback) callback(); else window.location = data.redirectUrl; } else { FormButtonSpinnerRemove($('#SimpleRegisterSubmit')); $('#statusmessage').html(data.message); } }, error: function (data) { console.log(data.responseText); FormButtonSpinnerRemove(); } }); }; registration.EmailOnlyRegister = function (regvm, callback) { //call api to do email only register var reqData = JSON.stringify(regvm); $.ajax({ url: Utils.BaseURL + "Registration/EmailOnlyRegisterSubmit", type: 'POST', contentType: "application/json; charset=utf-8", dataType: 'json', data: reqData, success: function (data) { console.log(data); if (data.status === 1) { TrackEvent('Signup', 'Email Only', '', true); if (callback) callback(); else window.location = data.redirectUrl; } else { FormButtonSpinnerRemove($('#EmailOnlyRegisterSubmit')); setRegStatusMessage(data.message); } }, error: function (data) { console.log(data.responseText); } }); }; }(window.registration = window.registration || {}, jQuery));; // moved to login pages // google sign in api //window.googleSignInApi //if (!Utils.no3p && typeof (CurrentDealer.GoogleAuthClientId) !== 'undefined' && CurrentDealer.GoogleAuthClientId.length > 1) { // $.getScript("https://apis.google.com/js/api:client.js", function () { // gapi.load('auth2', function () { // auth2 = gapi.auth2.init({ // client_id: CurrentDealer.GoogleAuthClientId // }); // window.googleSignInApi.resolve(); // }); // }); //} //else { window.googleSignInApi.reject(); //} //no longer used // facebook api //window.fbLoaded //if (!Utils.no3p && typeof (CurrentDealer.FacebookAppId) !== 'undefined' && CurrentDealer.FacebookAppId !== '') { // $.getScript("https://connect.facebook.net/en_US/sdk.js", function () { // FB.init({ // appId: CurrentDealer.FacebookAppId, // version: 'v2.9', // open graph version // cookie: true, // creates cookie for session // xfbml: true // finds and initializes fb social plugins on page // }); // window.fbLoaded.resolve(); // // subscribe to the like event // FB.Event.subscribe('edge.create', function (response) { // TrackEvent('Social', 'Facebook Like', window.location.pathname + window.location.search, true); // }); // }); //} //else { // window.fbLoaded.reject(); //} window.fbLoaded.reject(); // fb events stuff if (!Utils.no3p && typeof CurrentDealer.FacebookPixelId !== 'undefined' && CurrentDealer.FacebookPixelId.length > 0) { !function (f, b, e, v, n, t, s) { if (f.fbq) return; n = f.fbq = function () { n.callMethod ? n.callMethod.apply(n, arguments) : n.queue.push(arguments) }; if (!f._fbq) f._fbq = n; n.push = n; n.loaded = !0; n.version = '2.0'; n.queue = []; t = b.createElement(e); t.async = !0; t.src = v; s = b.getElementsByTagName(e)[0]; s.parentNode.insertBefore(t, s) }(window, document, 'script', '//connect.facebook.net/en_US/fbevents.js'); fbq('init', CurrentDealer.FacebookPixelId); //fbq('track', "PageView"); window.fbPixel.resolve(); } else { window.fbPixel.reject(); }; (function () { /**/ /* bet365在线平台ping Cart */ /**/ $(".js-add-to-shopping-cart__collection-item").one("click", function () { var obj = $(this); AddTobet365在线平台pingCart($(this).data('gpid'),1, function (item) { obj.addClass('added'); obj.attr("data-tooltip", "Item added!"); obj.find('.RelatedItem__cart-text').text('Added!'); $('body').append(''); GaAddToCart(item); TrackItemEvent('bet365在线平台ping Cart', 'Add', item.GPID, item); }); }); $("body").on("click", ".js-add-to-shopping-cart", function () { var obj = $(this); if (!obj.hasClass('added')) { if (obj.data('cart-context') === 'browse3-btn') { obj.append('
'); } AddTobet365在线平台pingCart($(this).data('gpid'),1, function (item) { var context = obj.data('cart-context'); context = typeof (context) === 'undefined' ? 'default' : context; obj.addClass('added'); switch (context) { case 'browse-btn': obj.addClass('btn-green').removeClass('btn-blue').find('.fdnicon-cart').removeClass('fdnicon-cart').addClass('fdnicon-checkmark'); obj.find('.cart-status-text').text('Item Added!'); setTimeout(function () { obj.find('.cart-status-text').text('In Cart'); }, 3000); break; case 'browse3-btn': obj.html('shopping_cart'); obj.attr('title', 'Item in Cart'); obj.prepend('
Item Added!
'); setTimeout(function () { obj.find('.item__add-to-cart__status').fadeOut().removeClass('slideInUp').addClass('slideOutDown'); }, 2500); break; case 'default': default: break; } $('body').append(''); }); } }); // Add an item to a cart $(".AddItemToCartTrigger, .js-add-to-cart").one("click", function () { var obj = $(this); var popup = $('.item-cart-popup-mask'); var dots = '
'; if (obj.data('context') === 'itempage14') { obj.addClass('__loading'); obj.append(dots); } AddTobet365在线平台pingCart(obj.data('gpid'),1, function (item) { if (obj.data('context') === 'itempage14') { obj.removeClass('__loading').html(' Item Added to Cart'); $(popup).appendTo('body').show(); if ($('.shopping-cart-item__addon').length > 0) { $('.item-cart-popup__addons').show(); } $('.item-cart-popup.shopping-cart-parent-item').attr("data-cartitemid", item.CartItemId); $('.item-cart-popup__title').focus(); } else { obj.children(".addToCartText").html(' Item In Cart'); $(popup).appendTo('body').show(); if ($('.shopping-cart-item__addon').length > 0) { $('.item-cart-popup__addons').show(); } $('.item-cart-popup.shopping-cart-parent-item').attr("data-cartitemid", item.CartItemId); $('.item-cart-popup__title').focus(); } $('body').append(''); }); return false; }); // Add an addon item to a cart $("body").on("click", ".shopping-cart-item__addon-btn", function () { var btn = $(this); var data = jQuery.parseJSON(btn.attr("rel")); data.ParentCartItemId = btn.closest('.shopping-cart-parent-item').attr('data-cartitemid'); //LoadingModal(true, btn); btn.html(""); $.ajax({ type: "POST", url: Utils.BaseURL + "AjaxItemService.asmx/AddItemToCartAddOns", data: JSON.stringify(data), contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { //LoadingModal(false); btn.html(" Added!"); if (window.location.href.indexOf("viewcart.aspx") > -1) { UpdateCartItem(data.ParentCartItemId, 1); } else if ($(".view-cart-v4").length) { bet365在线平台pingCartV4.LoadViewCartItems(); bet365在线平台pingCartV4.LoadViewCartTotals(); } // GA ecommerce tracking try { var item = eval("(" + $('#itemData-main').attr("rel") + ")"); GaAddToCart(item); TrackItemEvent('bet365在线平台ping Cart', 'Add', item.GPID, item); } catch (e) { console.log(e); } //track in laurentide try { var item2 = eval("(" + $('#itemData-main').attr("rel") + ")"); if (typeof (laurentideTracker) !== 'undefined') Laurentide_AddToCart(item2); } catch (e) { console.log(e); } }, error: function (msg) { //LoadingModal(false); btn.html("Add to Cart"); alert(msg.responseText); } }); return false; }); $('body').on('click', '.item-cart-popup__close--trigger', function () { $('.item-cart-popup-mask').remove(); return false; }); // Show cart items on hover of cart status $('body').on('mouseenter', '.cart-status-container', function () { var url = $(this).data("url"); if (parseInt($(".js-cart-count").text().replace(/\D/g, ""), 10) > 0 && window.location.href.indexOf("viewcart.aspx") === -1 && Modernizr.mq('only screen and (min-width: 67.500em)')) { if ($('.cart-status-popup__items').children().length === 0) { $.ajax({ url: url, type: 'GET', contentType: false, processData: false, success: function (d) { $(".cart-status-popup").html(d); }, error: function () { } }); } $(this).addClass('__active'); } }); var hoverIntentTimer; $('body').on('mouseleave', '.cart-status-container, .cart-status-container-v4', function () { var self = $(this); // Clear any existing timer to avoid triggering the mouseenter function clearTimeout(hoverIntentTimer); hoverIntentTimer = setTimeout(function () { self.removeClass('__active'); if (self.attr('aria-expanded')) self.attr('aria-expanded', false); document.dispatchEvent(new Event('cart-status-mouseleave')); }, 500); }); $('body').on('mouseenter', '.cart-status-container-v4', function () { var trigger = $(this); // Clear any existing timer to avoid triggering the mouseleave function clearTimeout(hoverIntentTimer); hoverIntentTimer = setTimeout(function () { if (parseInt($(".js-cart-count").text().replace(/\D/g, ""), 10) > 0 && window.location.href.toLowerCase().indexOf("shoppingcart") === -1 && Modernizr.mq('only screen and (min-width: 67.500em)')) { var event = new Event('cart-status-mouseenter'); if ($('.cart-status-popup__items-v4').children().length === 0) { return $.ajax({ "type": "GET", "url": Utils.BaseURL + 'bet365在线平台pingCart/bet365在线平台pingCart/CartStatusPopupV4', cache: false }).then(function (d) { $(".cart-status-popup-v4").html(d); $(trigger).addClass('__active'); trigger.attr('aria-expanded', true); document.dispatchEvent(event); }); } else { $(trigger).addClass('__active'); document.dispatchEvent(event); } } }, 100); }); $('body').on('focus', '.cart-status-container-v4', function () { if (parseInt($(".js-cart-count").text().replace(/\D/g, ""), 10) > 0 && window.location.href.toLowerCase().indexOf("shoppingcart") === -1 && Modernizr.mq('only screen and (min-width: 67.500em)')) { if ($('.cart-status-popup__items-v4').children().length === 0) { return $.ajax({ "type": "GET", "url": Utils.BaseURL + 'bet365在线平台pingCart/bet365在线平台pingCart/CartStatusPopupV4', cache: false }).then(function (d) { $(".cart-status-popup-v4").html(d); }); } } }); //tooltip $('.tooltip-trigger').tooltip({ position: 'bottom center', relative: true, tip: '.tooltip-text' }); // // //overlays // $(".OverlayTrigger").overlay({ // color: '#ccc', // start: { // top: 300 // }, // expose: { // color: '#333', // opacity: 0.7, // closeSpeed: 300 // } // }); /**/ /* Item Preview */ /**/ var ItemPreviewOverlayApi = ""; if ($(".AjaxItemPreviewTrigger").length && !$("#ItemPreviewContentPlaceHolder").length) { $(".SectionMenu").append("
"); // Create and overlay for the item to go into ItemPreviewOverlayApi = $("#AjaxItemPreviewOverlay").overlay({ top: 'center', api: true, absolute: true, expose: { color: '#5b5b5b', loadSpeed: 1, opacity: 0.7 } }); } // AJAX request to get the item preview $(".AjaxItemPreviewTrigger").on("click", function () { var link = $("",{ rel: "stylesheet", type: "text/css", href: Utils.BaseURL + 'StyleSheets/modules/ajax-item-preview.css' }) $('head').append(link); var self = $(this), itemData = eval('(' + $(this).attr("rel") + ')'), data = self.data('preview'), requestUrl; var gpid = typeof (data) !== 'undefined' ? data.GPID : itemData.GPID; if (gpid) requestUrl = Utils.BaseURL + "AjaxItemService.asmx/GetItemPreviewHtmlFromGPID"; else requestUrl = Utils.BaseURL + "AjaxItemService.asmx/GetItemPreviewHtmlFromNum"; ItemPreviewOverlayApi.load(); $.ajax({ type: "POST", url: requestUrl, data: $(this).attr("rel"), contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { $("#ItemPreviewContentPlaceHolder").html(msg.d); }, error: function (msg) { // TO DO: handle the error alert(msg.responseText); } }); }); /**/ /* Delivery Lookup */ /**/ /* Delivery lookup on viewcart and item page -- can be used anywhere */ $('body').on('input', ".zipcodeLookupInput", function () { var zipInputVal = $('.zipcodeLookupInput').val(); console.log(zipInputVal); //If they have something entered it should be enabled. If not, it should be disabled. $('.delivery-lookup__submit').prop("disabled", zipInputVal.length < 3); }); $('body').on("keypress", ".delivery-lookup__input input", function (e) { if (e.keyCode === 13) { $(".delivery-lookup__submit").click(); } }); $("body").on("click", ".delivery-lookup__submit", function () { $(this).html(""); var zipcode = $(this).siblings("#ZipCode").val(); var gpid = $(this).data("gpid"); return $.ajax({ type: "POST", url: Utils.BaseURL + 'bet365在线平台pingCart/Delivery/ZipCodeLookup', contentType: "application/json; charset=utf-8", data: JSON.stringify({ "zipCode": zipcode, "gpid": gpid }) }).then(function (data) { $(".delivery-lookup").replaceWith(data); }); }); $("body").on("click", ".delivery-lookup__change-zip", function () { $(".delivery-lookup__input").addClass("__active"); }); /**/ /* Zip Code Lookup that only returns whether the zip code is included in delivery rules */ /**/ // Disable up and down keys. $('body').on('keydown', '.zipcode-lookup input[type=number]', function (e) { if (e.which == 38 || e.which == 40) e.preventDefault(); }); $('body').on('input', ".checkZipcodeInput", function () { var zipInputVal = $('.checkZipcodeInput').val(); //If they have something entered it should be enabled. If not, it should be disabled. $('.zipcode-lookup__submit').prop("disabled", zipInputVal.length < 3); }); // Lookup zip code $('body').on("keypress", ".zipcode-lookup__input input", function (e) { if (e.keyCode === 13) { e.preventDefault(); $(".zipcode-lookup__submit").click(); } }); $("body").on("click", ".zipcode-lookup__submit", function () { $(this).html(""); var model = {}; model.zipcode = $(this).siblings(".zipcode-lookup__input").children("#ZipCode").val(); model.useContactUsLookup = $(this).siblings(".zipcode-lookup__contact-us-lookup").val(); model.useV2 = $(this).siblings(".zipcode-lookup__v2").val(); model.deliveryTitle = $(this).siblings(".zipcode-lookup__delivery-title").val(); model.disclaimerText = $(this).siblings(".zipcode-lookup__disclaimer-text").val(); model.buttonText = $(this).siblings(".zipcode-lookup__button-text").val(); return $.post(Utils.BaseURL + 'bet365在线平台pingCart/Delivery/CheckUserZipCode', model) .then(function (data) { $(".zipcode-lookup").replaceWith(data); }); }); }()); ; /*** data is returned in the following format: [ { "name":"Product Categories" ,"items":[ {"kw":"sofa","c":0} ] } ] kw = the keyword, c = total search count (I used short names to reduce the amount of data downloaded) ***/ $(function () { var apiUrl = Utils.BaseURL + 'AjaxItemService.asmx/GetAutoCompleteKeywords'; var maxResults = 10; var groupMax = 5; var lastQuery = ''; var includesSkus = false; var lastResult = []; var width = (window.innerWidth < 880) ? '97.2%' : '300px'; $(document).ready(function () { $('.js-search-auto-complete').each(function (i) { $(this).autocomplete({ lookup: GetKeywords, deferRequestBy: 100, groupBy: 'g', orientation: 'auto', triggerSelectOnValidInput: false, onSelect: function (suggestion) { $(this).siblings('.search-submit-btn').trigger('click'); }, containerClass: $(this).parent().data("autocompletecontainerclass") }); }); $(document).on("keypress", ".js-search-auto-complete", function (e) { if (e.which == 13) { $(this).closest(".keyword-search").find('.search-submit-btn').trigger("click"); return false; } }); }); $('body').on('click', '.search-submit-btn', function () { var searchString = $(this).closest(".keyword-search").find('[type="search"]').val(); if (searchString.trim().length > 0) { SubmitSearch(searchString); } }); function GetKeywords(query, callback) { var needsRefresh = includesSkus != ShouldIncludeSkus(query); var result = { "suggestions": [] }; // if the first character typed is a number, wait for another character before doing the search if (!needsRefresh && query.length === 1 && !isNaN(query.charAt(0))) { } // if the query is just refining the previous query, we can just use the same dataset and filter it else if (!needsRefresh && lastQuery !== '' && lastQuery.length < query.length && query.indexOf(lastQuery) !== -1) { var newItems = FilterResults(lastResult, query); result.suggestions = FormatResults(newItems).slice(0, maxResults); callback(result); } else { includesSkus = ShouldIncludeSkus(query); $.ajax({ method: "POST", url: apiUrl, dataType: "json", contentType: "application/json; charset=utf-8", data: JSON.stringify({ "query": query, "dealerId": CurrentDealer.Id }), success: function (res) { lastQuery = query; lastResult = res.d; result.suggestions = FormatResults( FilterResults(lastResult,query) ).slice(0, maxResults); callback(result); }, error: function (msg) { console.log(msg.responseText); } }); } } function FilterResults(arr, query) { var newItems = []; $.each(lastResult, function (i, group) { var name = group.name; // filter out keywords that no longer contain the query var items = group.items.filter(function (item, index, arr) { return (item.kw.toLowerCase().indexOf(query.toLowerCase()) !== -1); }); // re-sort by whether or not the items start with the query and then by length items = items.sort(function (a, b) { var aIndex = a.kw.indexOf(query); var bIndex = b.kw.indexOf(query); if (aIndex === 0 && bIndex != 0) { return -1; } else if (aIndex !== 0 && bIndex === 0) { return 1; } else { // now sort by search count if (a.c === b.c) { //if the count is the same, just sort by length if (a.kw.length < b.kw.length) { return -1; } else if (a.kw.length > b.kw.length) { return 1; } else { return 0; } } else if (a.c > b.c) { return -1; } else if (a.c < b.c) { return 1; } else { return 0; } } }); // only allow so many items per group items = items.filter(function (item, index, arr) { return index < groupMax; }); newItems = newItems.concat({ "name": name, "items": items }); }); return newItems; } // turns the results into the format that the autocomplete plugin uses function FormatResults(arr) { var result = []; $.each(arr, function (i, group) { if (group.items.length > 0) { result = result.concat( group.items.map(function (item, i, arr) { return { "v": item.kw , "data": { "g": group.name } } }) ); } }); return result; } // returns true if there are numbers in the query function ShouldIncludeSkus(query) { if (query.length > 1){ return query.split("").some(function(char){ return !isNaN(char); }); } else { return false; } } function SubmitSearch(searchString) { var escapedSearchString = searchString.replace(/\./g, "_pp_") .replace(/\//g, '_sl_') .replace(/#/g, "_h_") .replace(/\+/g, "_pl_") .replace(/\?/g, "_q_") .replace(/&/g, "_and_") .replace(/庐/g, "_r_") .replace(/:/g, "_c_") .replace(/%/g, "_pc_") .replace(/\*/g, "_a_") .replace(/\"/g, "_in_"); var url = Utils.BaseURL + "search/keyword/" + escapedSearchString.trim() + "?kwd=" + encodeURIComponent(searchString); window.location.href = url; } });; $(function () { // event handlers $('.room-planner--trigger').on('click', function () { if ($('.room-planner-main .canvas-container').length === 0 || !RoomPlannerV2) { console.log('init'); init(); } else { console.log('open'); RoomPlannerV2.open(); } }); $('body').on('click', '.js-add-to-room-plan', function () { var data = $(this).data("room-plan-item"); init(data); if (typeof laurentideTracker !== 'undefined') Laurentide_AddToRoomplan(data); }); var scriptsLoaded = false; var isCurrentlyLoading = false; var init = function (data) { if (!scriptsLoaded && !isCurrentlyLoading) { isCurrentlyLoading = true; var startTime = performance.now(); $.getScript(Utils.BaseURL + "bundles/roomplanner") .done(function (script, textStatus) { var endTime = performance.now(); console.log(`loaded rp scripts in ${endTime - startTime}ms`); RoomPlannerV2.init(data); isCurrentlyLoading = false; scriptsLoaded = true; }) .fail(function (err) { isCurrentlyLoading = false; console.error(err); }); } else if (!isCurrentlyLoading) { RoomPlannerV2.open(data); } }; }); // for backward compatibility function AddToRoomPlan(data) { RoomPlannerV2.AddToRoomPlan(data); }; "use strict"; var AddToListWidget = (function () { var settings = { gpid: "" }; var version = 1; var mobile = (Modernizr.mq("only screen and (max-width: 47.938em)")) ? true : false; var loading = '
Loading...
'; var initEventHandlers = function () { $("body").on("click", "#add-to-list-overlay", function () { fadeOutWidget(); }); $("body").on("click", ".add-to-list-widget-dropdown-toggle", function () { // load the quicklist js and css if needed loadQuickListJsAndCss(); }) // V1 handlers $("body").on("click", ".quicklist-view__add-to-list__close", function () { fadeOutWidget(); }); $("body").on("click", ".quicklist-view__add-to-list__list-items", function () { addItemToList($(this)); }); $("body").on("click", ".quicklist-view__add-to-list__create-new", function () { createNewToggle() }); $("#add-to-list-widget").on("click", ".quicklist-view__add-to-list__save-btn", function () { addNewTitle($(this)); }); $("#add-to-list-widget").on("keyup", "#quicklist-view__add-to-list__new-title", function (e) { if (e.keyCode == 13) { addNewTitle($(this)); } else { $('#quicklist-new_message').remove(); } }); // V2 handlers $("body").on("click", ".quicklist-view__add-to-list--v2__close", function () { fadeOutWidget(); }); $("body").on("click", ".quicklist-view__add-to-list--v2__list-item", function () { addItemToList($(this)); }); $("body").on("click", ".quicklist-view__add-to-list--v2__create-new", function () { createNewToggle() }); $("#add-to-list-widget").on("click", ".quicklist-view__add-to-list--v2__create-new__input-btn", function () { addNewTitle($(this)); }); $("#add-to-list-widget").on("keyup", ".quicklist-view__add-to-list--v2__create-new__input-text", function (e) { if (e.keyCode == 13) { addNewTitle($(this)); } else { $('#quicklist-new_message').remove(); } }); $('body').on('click', '.js-toggle-ql-item', function (e) { if ($(this).hasClass('js-toggle-ql-item--v2')) { version = 2; } LoadAddToListWidget($(this)); }); }; var LoadAddToListWidget = function (trigger) { var gpid = trigger.data("gpid"); settings.gpid = gpid; var ControllerAction = (version == 2) ? "Quicklist/AddToListWidgetV2" : "Quicklist/AddToListWidget"; var cssClasses = "animated fast"; if (mobile) { cssClasses += " slideInUp"; } else { cssClasses += " fadeIn"; } $("#add-to-list-widget").attr('class', cssClasses).append(loading); $("body").append('
'); openWidget(trigger); // load the partial view - contains all the relevant html $.ajax({ "type": "GET", "url": Utils.BaseURL + ControllerAction, cache: false, success: function (data) { $('.quicklist__loading').remove(); $("#add-to-list-widget").html(data); }, error: function () { } }); }; var openWidget = function (trigger) { $("#add-to-list-widget").addClass("__open"); $(trigger).closest('.ResultsLarge_Object').addClass("add-to-list__hover"); $(trigger).closest('.quicklist-item-layout').addClass("add-to-list__hover"); if ($(window).width() > 767) { // set position for triggers inside of a dropdown var positionItem = $(trigger); if ($(trigger).closest('.dropdown').length > 0) { positionItem = $(trigger).closest('.dropdown'); } $("#add-to-list-widget").position({ my: "center bottom-12", at: "center top", of: positionItem, collision: "flipfit" }); } else { $("#add-to-list-widget").addClass("__mobile"); } $(".quicklist-view__add-to-list--focus").focus(); }; var fadeOutWidget = function (callback) { if (mobile) { $("#add-to-list-widget").removeClass("slideInUp").addClass("slideOutDown"); } else { $("#add-to-list-widget").removeClass("fadeIn").addClass("fadeOut"); } $("#add-to-list-overlay").addClass("fadeOut"); $('.add-to-list__hover').removeClass("add-to-list__hover"); setTimeout(function () { destroyWidget(callback); }, 500); }; var destroyWidget = function (callback) { $("#add-to-list-widget").removeClass("__open fadeOut slideOutDown"); $(".quicklist-view__add-to-list").remove(); $('#add-to-list-overlay').remove(); if (callback) { callback(); } }; var addItemToList = function (trigger) { $(trigger).append(loading); $.ajax({ type: "POST", url: Utils.BaseURL + "Quicklist/AddItem", contentType: "application/json; charset=utf-8", data: JSON.stringify({ "GPID": settings.gpid, "listId": trigger.data('listid') }), success: function (response) { //$('.quicklist__loading').remove(); var item = $('.quicklist-view__add-to-list__list-items[data-listid=' + trigger.data("listid") + ']'); if (version == 2) { var item = $('.quicklist-view__add-to-list--v2__list-item[data-listid=' + trigger.data("listid") + ']'); } var resp = JSON.parse(response); if (resp.Status == 0) { addItemMessage(resp.Message, item); setTimeout(function () { fadeOutWidget(QuickListV2.LoadData); }, 500); // track in Laurentide if (typeof (laurentideTracker) !== 'undefined') Laurentide_AddToList(resp.QuickListItem, resp.QuickListItemCount); //get the trigger by gpid data var itemTrigger = $('.js-toggle-ql-item[data-gpid="' + settings.gpid + '"]') var method = itemTrigger.data("ga-method"); // track in Google Analytics fdEvents.publish("add_to_wishlist", resp.Event); //TrackQuicklist("Add", method, resp.QuickListItem); // Meta Pixel window.fbPixel.done(function () { fbq('track', 'AddToWishlist', { content_name:'product',content_ids: [settings.gpid]}, { eventID: resp.MetaEventId }); }); // Open QuickList menu if (version == 1) $('.quicklist--trigger').click(); } else { addItemMessage(resp.Message, item); }; }, error: function (msg) { console.log("FAILURE"); } }); }; var addItemMessage = function (message, item) { if ($("#quicklist_message").length > 0) { $("#quicklist_message").remove(); } $(item).append('
'); $('#quicklist_message').html(message); $(".quicklist-view__add-to-list__main").scrollTop($(".quicklist-view__add-to-list__main").scrollTop() + $("#quicklist_message").position().top - 50); }; var createNewToggle = function () { //console.log("createNewToggle"); //console.log("createNewToggle version " + version); if (version == 2) { $('.quicklist-view__add-to-list--v2__create-new__input').show(); $('.quicklist-view__add-to-list--v2__create-new__input-text').focus(); } else { if ($(".quicklist-view__add-to-list__new").hasClass("__open")) { $(".quicklist-view__add-to-list__new").removeClass("__open"); $(".quicklist-view__add-to-list__create-new").removeClass("__open"); } else { $(".quicklist-view__add-to-list__new").addClass("__open"); $(".quicklist-view__add-to-list__create-new").addClass("__open"); } } }; var addNewTitle = function (btn) { var input = (version == 2) ? ".quicklist-view__add-to-list--v2__create-new__input-text" : "#quicklist-view__add-to-list__new-title"; var responseElement = (version == 2) ? ".quicklist-view__add-to-list--v2__create-new__input" : ".quicklist-view__add-to-list__new"; var title = $(input).val().trim(); if (title.length > 0) { $(btn).addClass('__loading').append(loading); createListAndAddItem(title); } else { $(responseElement).append('
Please enter a title first.
'); $(responseElement).addClass("__message"); } }; var createListAndAddItem = function (listname) { var responseElement = (version == 2) ? ".quicklist-view__add-to-list--v2__create-new__input" : ".quicklist-view__add-to-list__new"; $.ajax({ type: "POST", url: Utils.BaseURL + "Quicklist/CreateNewQuicklistAndAddItem", contentType: "application/json; charset=utf-8", data: JSON.stringify({ "quickListName": listname, "setAsDefault": true, "GPID": settings.gpid }), success: function (response) { var resp = JSON.parse(response); if (resp.Status == 1) { $('.loading-spinner').remove(); $('.loading-spinner--dots').remove(); $('.__loading').removeClass('__loading'); if ($("#quicklist-new_message").length > 0) { $("#quicklist-new_message").remove(); } $(responseElement).append('
Saved!
'); $(responseElement).addClass("__message"); } setTimeout(function () { $(".quicklist").removeClass('__new __no-list'); fadeOutWidget(QuickListV2.LoadData); }, 500); // track in Laurentide if initialized if (typeof (laurentideTracker) !== 'undefined') Laurentide_AddToList(resp.QuickListItem, resp.QuickListItemCount); //get the trigger by gpid data var trigger = $('.js-toggle-ql-item[data-gpid="' + settings.gpid + '"]'); var method = trigger.data("ga-method"); // track in Google Analytics fdEvents.publish("add_to_wishlist", resp.Event); //TrackQuicklist("Add", method, resp.QuickListItem); // Open QuickList menu if (version == 1) $('.quicklist--trigger').click(); }, error: function (msg) { console.log("FAILURE"); } }); }; var loadQuickListJsAndCss = function () { if (typeof QuickListV2 != "object") { var css = document.createElement("link"); css.href = Utils.BaseURL + "bundles/stylesheets/quicklist"; css.type = "text/css"; css.rel = "stylesheet"; css.media = "screen,print"; document.getElementsByTagName("head")[0].appendChild(css); var js = document.createElement("script"); js.type = "text/javascript"; js.src = Utils.BaseURL + "bundles/quicklist"; document.getElementsByTagName("head")[0].appendChild(js); } } // hook up event handlers initEventHandlers(); return { LoadAddToListWidget: LoadAddToListWidget }; })(); ; /** * * Header Layout 3 * **/ (function () { "use strict"; /*======================================== = FDN Toggle Setup = ========================================*/ $(".hlv3-nav-btns__btn--open").on('vclick', function () { CloseSearchOnClick(); CloseLocationsOnClick(); }) $('body').on('vclick', '.hlv3-search--mask', function () { CloseSearchOnClick(); }) $(".hlv3-mobile-search").on('vclick', function () { if ($(".hlv3-mobile-search").hasClass("hlv3-search-trigger--active")) { $('.hlv3-search__text-box').blur(); $('.hlv3-search__text-box').closest('.hlv3-search').removeClass('__search-active'); RemoveSearchMask(); } else { CloseNavOnClick(); CloseLocationsOnClick(); $('.hlv3-search__text-box').focus(); $('.hlv3-search__text-box').closest('.hlv3-search').addClass('__search-active'); const searchMask = '
'; $('body').append(searchMask); } }) $(".hlv3-mobile-locations__btn").on('vclick', function () { if (!$(".hlv3-mobile-locations__btn").hasClass("hlv3-locations-trigger--active")) { CloseNavOnClick(); CloseSearchOnClick(); } }) function CloseSearchOnClick() { $(".hlv3-mobile-search.hlv3-search-trigger--active").trigger('vclick'); RemoveSearchMask(); } function CloseLocationsOnClick() { $(".hlv3-mobile-locations__btn.hlv3-locations-trigger--active").trigger('vclick'); } function CloseNavOnClick() { $(".hlv3-nav-btns__btn--close.hlv3-trigger--active").trigger('vclick'); } function RemoveSearchMask() { $('.hlv3-search--mask').removeClass('fadeIn').addClass('fadeOut'); setTimeout(function () { $('.hlv3-search--mask').remove(); }, 500); } $(".hlv3-nav-btns__btn--close, .hlv3-nav-overlay").on('vclick', function (event) { event.preventDefault(); //keeps from clicking items behind overlay $('.hlv3-primary-nav .nav-builder-trigger--active').removeClass('nav-builder-trigger--active'); // remove any active classes when closing navigation }) $(".hlv3-nav-btns__btn--open").fdnToggle({ triggers: ".hlv3-nav-btns__btn--close", targets: "body", persist: true, className: "hlv3", relatives: ".hlv3-primary-nav-container" }); $(".hlv3-mobile-search").fdnToggle({ targets: ".hlv3-search-container", className: "hlv3-search", closeOnClick: false }); $(".hlv3-mobile-locations__btn").fdnToggle({ targets: "body", className: "hlv3-locations", relatives: ".hlv3-locations__wrapper" }); /*----- End of FDN Toggle Setup ------*/ /*============================================ = Element Manipulation = ============================================*/ var container = $(".hlv3-container"), staticNav = $(".hlv3-static-nav"), search = $(".hlv3-search-container"), locations = $(".hlv3-locations__wrapper"), sectionOuter = $(".SectionOuter"), secondaryNav = $('.nav-builder-single-level.hlv3-secondary-nav__item'); SetHeaderHeight(); if (Utils.IsResponsivePage) { enquire.register("only screen and (max-width: 55em)", { match: function () { search.insertAfter(".hlv3-main__left"); locations.insertAfter(".hlv3-mobile-locations__btn"); $('.SectionMenu').removeClass('x-header'); SetHeaderHeight(); // there is a spacer that gets set to match the height of the header. then we show it, and set the header to position-fixed. // this is to allow for a fixed position header that still keeps the body content pushed down, and prevents CLS issues var headerHeight = $('.hlv3-primary-container').height(); $('#hlv3-spacer').css('height', headerHeight); $('#hlv3-spacer').removeClass('d-none'); $('.hlv3-container').addClass('position-fixed'); secondaryNav.insertAfter('.hlv3-primary-nav .nav-builder-sub-menu .nav-builder-1:last-child'); if ($(".hlv3-mobile-search").hasClass("hlv3-mobile-search__open")) { $(".hlv3-mobile-search").trigger('vclick'); } }, unmatch: function () { search.insertBefore(staticNav); locations.insertAfter(".hlv3-secondary-nav__item.hlv3-locations > a"); $('.SectionMenu').addClass('x-header'); SetHeaderHeight(); $('.SectionMenu').css('margin-top', 'auto'); secondaryNav.insertBefore('.hlv3-secondary-nav__item.hlv3-locations'); $('#hlv3-spacer').addClass('d-none'); $('.hlv3-container').removeClass('position-fixed'); } }); } function SetHeaderHeight() { var headerHeight = $('.hlv3-primary-container').height(); $('.hlv3-nav-overlay').css('top', headerHeight).show(); $('.hlv3-primary-nav-container').css('top', headerHeight); } /*----- End of Element Manipulation ------*/ /*============================================ = Primary Navigation = ============================================*/ //Only use hoverintent on desktop //enquire.register("only screen and (min-width: 55em)", { // match: function () { // $('.hlv3-primary-nav > .nav-builder-0').hoverIntent({ // over: function () { // $('body').addClass('hlv3-primary-nav__active'); // }, // out: function () { // $('body').removeClass('hlv3-primary-nav__active'); // }, // timeout: 100, // interval: 40 // }); // } //}); enquire.register("only screen and (min-width: 55em)", { match: function () { $('.hlv3-primary-nav > .nav-builder-0 > .nav-builder-trigger').on('click', function (event) { event.preventDefault(); //keeps from clicking items behind overlay if ($('body').hasClass('hlv3-primary-nav__active')) { $('body').removeClass('hlv3-primary-nav__active'); // remove --active class } else { $('body').addClass('hlv3-primary-nav__active'); // add --active class } }) } }); enquire.register("only screen and (min-width: 55em)", { match: function () { $('.hlv3-nav-overlay').on('click', function (event) { $('body').removeClass('hlv3-primary-nav__active'); }) } }); if (Utils.IsResponsivePage) { enquire.register("only screen and (max-width: 55em)", { match: function() { $('.hlv3-primary-nav .nav-builder-trigger').on('click', function(e) { e.preventDefault(); // prevent click if ($(this).hasClass('nav-builder-trigger--active')) { $(this).removeClass('nav-builder-trigger--active'); // remove --active class } else { $(this).addClass('nav-builder-trigger--active'); // add --active class } }); }, unmatch: function() { $('.hlv3-primary-nav .nav-builder-trigger').off(); } }); } //For menu accessiblity for keyboard users and screen readers using IE/Edge browsers //$(".hlv3-primary-nav a").on("focus", function () { // $(this).closest(".nav-builder-0").addClass("nav-builder-0--focus"); //}); //$(".hlv3-primary-nav a").on("focusout", function () { // $(".nav-builder-0").removeClass("nav-builder-0--focus"); //}); /*----- End of Primary Navigation ------*/ /*============================================ = Hide Header when Scrolling = ============================================*/ if (Utils.IsResponsivePage) { enquire.register("only screen and (max-width: 55em)", { match: function () { var didScroll; var lastScrollTop = 0; var delta = 20; var navbarHeight = $('.hlv3-container').height(); window.addEventListener('scroll', function () { didScroll = true; }, { passive: false }); setInterval(function () { if (didScroll) { hasScrolled(); didScroll = false; } }, 250); function hasScrolled() { var st = $(window).scrollTop(); // Make sure they scroll more than delta if (Math.abs(lastScrollTop - st) <= delta) return; if (!($('body.hlv3-target--active').length || $('body.hlv3-locations-target--active').length)) { // If they scrolled down and are past the navbar, add class .nav-up. // This is necessary so you never see what is "behind" the navbar. if (st > lastScrollTop) { // Scroll Down if (st > navbarHeight) { $('.hlv3-container').addClass('__scroll'); } } else { // Scroll Up if (st + $(window).height() < $(document).height()) { $('.hlv3-container').removeClass('__scroll'); } } } lastScrollTop = st; } } }); } /*----- End of Hide Header when Scrolling ------*/ document.addEventListener('keydown', function (event) { var code = event.keyCode || event.which; if (code === 9) { // the thing being tabbed on is not in the primary nav but the nav is still open, so close it // console.log(event.target.closest('.hlv3-primary-nav')); if (event.target.closest('.hlv3-primary-nav') == null && $('body').hasClass('hlv3-primary-nav__active')) { $('body').removeClass('hlv3-primary-nav__active'); } } }); }());; /*========================================= = Dealer JavaScript = =========================================*/ /*----- End of Dealer JavaScript ------*/; /*==================================================== = Dealer Responsive JavaScript = ====================================================*/ /*----- End of Dealer Responsive JavaScript ------*/;