function CarSelector(opts) { var me = this; var defaults = {ctr:null, showSB:true, inPopup:false, isPgChgInSrch:false, prCarSrch:false, isPkgCfgMode:false, isGrpRslt:true, srchPrms:'', carSrchTout:30000, sbOpt:{ctr:null}, dtlOpt:{ctr:null}, pgSz:50, allowHistPushState:false}; this.opts = $jQ.extend(true, {}, defaults, opts || {}); this.curSort = {nm:'Price', fld:'prc', asc:true}; this.init = function() { me.ctrJ = $jQ(me.opts.ctr); me.srchCtr = $jQ(".carsSrchVwCtr", me.ctrJ); me.rsltCtr = $jQ(".cSrchRsltCtr", me.srchCtr); me.rsltMsgCtr = $jQ(".cSrchRsltMsgCtr", me.srchCtr); me.dtlCtr = $jQ(".carDtlVwCtr", me.ctrJ); if (!me.opts.sbOpt.ctr) { me.opts.sbOpt.ctr = $jQ('.cSrchBxCtr', me.srchCtr); } if (!me.opts.sbOpt.srchCallback) { me.opts.sbOpt.srchCallback = function(el) { me.fetchResults.call(me, me.cSrchBx.getQueryJSON()); } } me.cSrchBx = new CarSearchBox(me, me.opts.sbOpt); me.cRsltO = new CarResults(me, me.rsltCtr); if (me.opts.dtlOpt.ctr) { me.dtlCtr = $jQ(me.opts.dtlOpt.ctr); } me.opts.dtlOpt.prCarSrch = me.opts.prCarSrch; me.cDtlO = new CarDetail(me, me.dtlCtr, me.opts.dtlOpt); me.rsltCtr.on('click', '.carRsltItm .car-act-ctr a', function() { var cJ = $jQ(this).closest('.carRsltItm'); var cItm = me.cRsltO.carKeys[cJ.data('car')]; me.loadCarDetails(cItm.cO.key, {}); return false; }); if (me.opts.allowHistPushState) { HISTUTIL.bind(function(state) { if (!state || !state.srchO) return; me.cSrchBx.populateFields(state.srchO); if (me.opts.sbOpt.srchCallback){ me.opts.sbOpt.srchCallback(); } }); } } this.setOptions = function(opts) { if (opts) { if (opts.dtlOpt) { if (opts.dtlOpt.ctr) {me.dtlCtr = me.cDtlO.dtlCtr = $jQ(opts.dtlOpt.ctr);} } } me.opts = $jQ.extend(true, {}, me.opts, opts || {}); } this.showSearchView = function(srchO, opts) { opts = $jQ.extend({}, {srchD:null}, opts || {}); me.cSrchBx.show(me.opts.showSB); me.srchCtr.removeClass('hide'); me.dtlCtr.addClass('hide'); if (opts.srchD) me.cSrchBx.setPkgSearchData(opts.srchD); if (srchO) { me.cSrchBx.populateFields(srchO); me.cRsltO.srchO = srchO; } } this.clearResults = function() { me.cRsltO.clear(); me.rsltCtr.hide(); } this.fetchResults = function(srchO, opts) { opts = $jQ.extend({}, {waitHndlr:null, loadClbk:null, isFltr:false, isUpdHist:false}, opts || {}); if (!srchO) {srchO = me.cRsltO.srchO}; if (!srchO) srchO = me.cSrchBx.getQueryJSON(); if (!me.cSrchBx.isValid(srchO)) return false; var successFetch = function(a, m) { var rsltO = JS_UTIL.parseJSON(m); me.parseResults(rsltO, opts); me.showResults(opts); if (!me.opts.inPopup) {MODAL_PANEL.hide();} } AJAX_UTIL.abortAjaxRequest(this.carRequest); if (opts.isFltr) { opts.waitHndlr = function(isShw, isSuccess) { if (isShw) { me.cRsltO.rsltTlbrCtr.addClass('hide'); me.cRsltO.rsltTlbrSecCtr.addClass('hide'); me.cRsltO.rsltLstCtr.html($jQ('#carRsltSklTpl').clone().attr('id', '')).removeClass('hide'); } } } var prmO = me.cSrchBx.getQueryParams(srchO); if (opts.isFltr && me.cRsltO.cFltrs) prmO = {...prmO, ...me.cRsltO.cFltrs.getAppliedFiltersQueryParams()}; if (me.opts.isPkgCfgMode) prmO.isPkgCfgMode = true; me.ctrJ.addClass('carSrchWRslt'); this.carRequest = AJAX_UTIL.asyncCall('/car/search-x', {params: $jQ.param(prmO)+(me.opts.prCarSrch?'&prCar=true':'')+'&'+me.opts.srchPrms, timeout: 120000, scope: me, wait: {inDialog:false, msg:'Searching '+(srchO.liv?'Live':'')+'...', handler:opts.waitHndlr, divEl:(me.opts.showSB && !opts.isFltr ? $jQ('a.srchAct', me.cSrchBx.sbCtr):null)}, success: {handler:successFetch, parseMsg:true}, error:{inDialog:false, handler:function(a, m) {me.showSearchMessage(m, false, true);}} }); if (opts.isUpdHist) { me.updateInHistory(srchO, {isReplace:true}); opts.isUpdHist = false; } if (!opts.isFltr) me.showSearchMessage($jQ(`

Searching for rentals...

`), true, false); } this.parseResults = function(rsltO, opts) { opts = $jQ.extend({}, {loadClbk:null}, opts || {}); me.cRsltO.setResults(rsltO, opts); if (opts.loadClbk) opts.loadClbk(rsltO); } this.showResults = function(opts) { opts = $jQ.extend({}, {resetFltr:false}, opts || {}); if (me.cRsltO.srchO) { me.cSrchBx.populateFields(me.cRsltO.srchO); } if (!opts.isFltr && (!me.cRsltO.rsltO || !me.cRsltO.rsltO.rsltA || me.cRsltO.rsltO.rsltA.length == 0)) { me.showSearchMessage('No results found', false, true); } else { me.rsltCtr.show(); me.rsltMsgCtr.hide(); me.cRsltO.showResults(opts); } } this.showSearchMessage = function(msgJ, showWait, isErr) { me.rsltCtr.hide(); me.rsltMsgCtr.html(msgJ).show().toggleClass('cSrchRsltErrMsg', isErr); if (showWait) me.rsltMsgCtr.append('
 
'); } this.loadCarDetails = function(ckey, opts) { opts = $jQ.extend({}, {srchO:null, loadClbk:null, wait:null, error:null}, opts || {}); if (!ckey) return; var srchO = opts.srchO; if (!srchO) srchO = me.cRsltO.srchO; if (!srchO) srchO = me.cSrchBx.getQueryJSON(); var loadWaitHandler = function(isShw, isSuccess) { if (!me.opts.inPopup) { if (!isShw && isSuccess) MODAL_PANEL.hide(); return; } if (isShw) { me.srchCtr.addClass('hide'); me.dtlCtr.html($jQ('#carDtlVwSklTpl').clone().attr('id', '')).removeClass('hide'); } } var successLoad = function(a, m) { var rspO = JS_UTIL.parseJSON(m); me.opts.dtlOpt.srchPrms = me.opts.srchPrms; if (me.opts.inPopup) me.opts.dtlOpt.cls = 'carDtlVwVt'; if (me.cSrchBx.dpLocO && me.cSrchBx.dpLocO.dcky) me.opts.dtlOpt.dcky = me.cSrchBx.dpLocO.dcky; me.cDtlO.showDetail(ckey, rspO, me.opts.dtlOpt); if (opts.loadClbk) opts.loadClbk(rspO); } var errorLoad = function(a, m) { if (!me.opts.inPopup) return; me.cDtlO.showDetail(ckey, null, me.opts.dtlOpt); } if (!opts.wait) opts.wait = {inDialog:!me.opts.inPopup, msg:'Loading, please wait...', handler:loadWaitHandler}; if (!opts.error) opts.error = {inDialog:!me.opts.inPopup, handler:errorLoad}; var prmO = {carkey:ckey}; if (me.opts.isPkgCfgMode) prmO.isPkgCfgMode = true; if (srchO) prmO = {...prmO, ...me.cSrchBx.getQueryParams(srchO)}; if (me.opts.prCarSrch) { Object.assign(document.createElement('a'), {target:'_blank', href:JS_UTIL.insAllParams('/car/details', prmO)+(me.opts.prCarSrch?'&prCar=true':'')+'&'+me.opts.srchPrms}).click(); return; } AJAX_UTIL.asyncCall('/car/details', {params: $jQ.param(prmO)+(me.opts.prCarSrch?'&prCar=true':'')+'&'+me.opts.srchPrms, timeout: 120000, scope: me, wait:opts.wait, success: {handler:successLoad, parseMsg:true}, error:opts.error }); } this.backToResults = function(srchO, ckey) { if (me.cRsltO.hasResults()) { me.dtlCtr.addClass('hide'); me.srchCtr.removeClass('hide'); me.scrollToCarResult(ckey); return; } var prmO = me.hSrchBx.getQueryParams(srchO); window.location.href = '/hotels/explore?' + $jQ.param(prmO); } this.scrollToCarResult = function(ckey) { var cItm = me.cRsltO.carKeys[ckey]; if (cItm) { JS_UTIL.scrollTo($jQ(`.carRsltItm[data-car-key="${cItm.cO.key}"]`, me.rsltCtr), 200, {offset:-20}); } else { JS_UTIL.scrollTo(me.cRsltO.rsltCtr, 200, {offset:-25}); } } this.updateInHistory = function(srchO, opts) { if (!me.opts.allowHistPushState) return; opts = $jQ.extend({}, {isReplace:false}, opts || {}); if (srchO) { var urlPrms = me.cSrchBx.getQueryParams(srchO), url = JS_UTIL.insAllParams('/car/search', urlPrms); var state = {noOvr:false, srchO:srchO}; if (opts.isReplace) { window.history.replaceState(state, '', url); } else { HISTUTIL.push({url:url, state:{noOvr:false, srchO:srchO}}, true); } } } this.init(); } function CarDetail(cSel, dtlCtr, opts) { var me = this; me.cSel = cSel; me.dtlCtr = dtlCtr; this.init = function() { } this.showDetail = function(ckey, dtlO, opts) { me.ckey = ckey; me.dtlO = dtlO; me.cSel.srchCtr.addClass('hide'); me.dtlCtr.removeClass('hide'); if (!dtlO) { me.dtlCtr.html(`
Unable to load the car details
Back to all options
`); $jQ('.carDtlMsgCtr a', me.dtlCtr).click(function() { me.cSel.backToResults(null); return false; }); return; } if (dtlO.dtlH) { me.dtlCtr.html(dtlO.dtlH); CAR_DTL.init('#carDtlVwCtr', dtlO.carO, opts); } JS_UTIL.scrollTo(me.dtlCtr, 200, {offset:-20}); if (me.cSel.opts.isPkgCfgMode && !me.cSel.cRsltO.hasResults()) { $jQ('.carSrchBkActCtr', me.dtlCtr).remove(); } else { $jQ('.carSrchBkActCtr a', me.dtlCtr).click(function() { me.cSel.backToResults(me.dtlO.srchO); return false; }); } } this.init(); } function CarResults(cSel, rsltCtr) { var me = this; me.cSel = cSel; me.rsltCtr = rsltCtr; me.srchO = null; me.cars = []; me.carKeys = {}; me.fltdCars = []; this.init = function() { me.rsltLstCtr = $jQ(".cRsltLst", me.rsltCtr); me.rsltFltrCtr = $jQ(".carFltrsCtr", me.rsltCtr); me.rsltSortCtr = $jQ(".carSortCtr", me.rsltCtr); me.rsltFltrApplCtr = $jQ(".cFltrApplCtr", me.rsltCtr); me.rsltFltrOpnActCtr = $jQ(".cRsltTlbr .cFltrOpnActCtr", me.rsltCtr); me.rsltSdSctCtr = $jQ(".cRsltSdSct", me.rsltCtr); me.rsltOvlyCtr = $jQ(".cRsltSdSctOvly", me.rsltCtr); me.rsltTlbrSecCtr = $jQ(".cRsltTlbrSec", me.rsltCtr); me.rsltFltrOpnActCtr.click(function() { me.rsltCtr.addClass('cSrchRslt-fopen'); return false; }); me.rsltOvlyCtr.click(function() { me.rsltCtr.removeClass('cSrchRslt-fopen'); return false; }); } this.clear = function() { me.cars = []; me.carKeys = {}; me.fltdCars = []; me.rsltO = null; me.cFltrs = null; } this.hasResults = function() { return !!me.rsltO; } this.setResults = function(rsltO, opts) { me.cars = []; me.carKeys = {}; me.fltdCars = []; me.rsltO = rsltO; if (!me.cFltrs || !opts || !opts.isFltr) { me.cFltrs = new CarFilters(me.cSel, me); } if (!rsltO || !rsltO.rsltA) return; me.srchO = rsltO.srchO; $jQ.each(rsltO.rsltA, function(i, cO) { var cItm = new CarResultItem(me.cSel, me, i, cO); me.cars.push(cItm); me.carKeys[cO.key] = cItm; }); me.cFltrs.createFilterOpts(rsltO.fltrAvl, rsltO.fltrAppl); } this.showResults = function(opts) { opts = $jQ.extend({}, {resetFltr:false}, opts || {}); if (opts.resetFltr) { me.cFltrs.resetApplied(); } if (!opts.fltrClbk) { opts.fltrClbk = function(sltdO) { if (!sltdO.isFltr || !sltdO.fltr.isDyn) { if (sltdO.isFltr || sltdO.isSort) opts.isDsbFltrRender = true; me.showResults(opts); } else { opts.isFltr = true; me.cSel.fetchResults(null, opts); } } } if (!opts.isDsbFltrRender) { me.rsltOvlyCtr.click(); } me.filter(); me.sort(me.cSel.curSort.fld, me.cSel.curSort.asc); if (!opts.isDsbFltrRender) { me.renderResultsFilters(opts); } me.rsltLstCtr.html(''); addResultItems(me.fltdCars); if (me.fltdCars.length == 0) { me.rsltLstCtr.append('
No matching results
'); } JS_UTIL.scrollTo(me.rsltCtr, 200, {offset:-50}); } var addResultItems = function(fltdCars) { if (me.cSel.opts.isGrpRslt) { var carGrpKeys = [], carGrpsO = {}, nCarItms = 0; $jQ.each(fltdCars, function(i, cItm) { var cItmsA = carGrpsO[cItm.cO.gk]; if (!cItmsA) { cItmsA = []; carGrpsO[cItm.cO.gk] = cItmsA; carGrpKeys.push(cItm.cO.gk); } cItmsA.push(cItm); }); $jQ.each(carGrpKeys, function(i ,cGrpKey) { var cItmsA = carGrpsO[cGrpKey], isAddGrp = false, cCntInGrp = 0, cCtrJ = me.rsltLstCtr; $jQ.each(cItmsA, function(j, cItm) { if (j == 1) { isAddGrp = true; cCtrJ = $jQ('
').appendTo(me.rsltLstCtr); } if (isAddGrp) cCntInGrp++; cCtrJ.append(cItm.getNode().clone(true).attr('data-car-key', cItm.cO.key)); nCarItms++; }); if (isAddGrp) { var grpJ = $jQ(`
show ${cCntInGrp} more
`).appendTo(me.rsltLstCtr); $jQ('a', grpJ).click(function() { var grpCtrJ = $jQ(this).parent('.carItmGrpMrActCtr').prev('.carItmGrpMore'); grpCtrJ.toggleClass('hide'); $jQ(this).html(grpCtrJ.hasClass('hide') ? `show ${cCntInGrp} more`: `show less`); return false; }); } if (i == me.cSel.opts.pgSz) {return false;} }); if (carGrpKeys.length > me.cSel.opts.pgSz) {addShowMoreResults(fltdCars, nCarItms);} } else { $jQ.each(fltdCars, function(i, cItm) { if (i == me.cSel.opts.pgSz) {return false;} me.rsltLstCtr.append(cItm.getNode().clone(true).attr('data-car-key', cItm.cO.key)); }); if (fltdCars.length > me.cSel.opts.pgSz) {addShowMoreResults(fltdCars, me.cSel.opts.pgSz);} } } var addShowMoreResults = function(fltdCars, startIdx) { var mrJ = $jQ(`
Show more
`).appendTo(me.rsltLstCtr); $jQ('a', mrJ).click(function() { var idx = parseInt($jQ(this).attr('data-start-idx'), 10), fltdCars = me.fltdCars.slice(idx); mrJ.remove(); addResultItems(fltdCars); // if (me.fltdCars.length > (idx + me.cSel.opts.pgSz)) addShowMoreResults(idx + me.cSel.opts.pgSz); return false; }); } this.renderResultsFilters = function(opts) { me.cFltrs.renderFilters(me.rsltO, opts); if (me.rsltO.isShwCms) { var shwCmsActJ = $jQ(`Show Commission`).click(function() { me.rsltCtr.toggleClass('showCarInctv'); return false; }); me.rsltTlbrSecCtr.html(shwCmsActJ).removeClass('hide'); } else { me.rsltTlbrSecCtr.addClass('hide'); } } this.filter = function() { me.fltdCars = []; $jQ.each(me.cars, function(i, cItm) { // me.fltdCars.push(cItm); if (me.cFltrs.isCarValid(cItm)) { me.fltdCars.push(cItm); } }); } this.sort = function(srtKey, asc) { return me.fltdCars.sort(function(c1, c2) { return (c1.sorts[srtKey] - c2.sorts[srtKey]) * (asc ? 1: -1); }); } this.init(); } function CarResultItem(cSel, cRslt, idx, cO) { var me = this; this.cO = cO; this.cRslt = cRslt; this.cSel = cSel; this.init = function() { me.sorts = {rscr:idx, prc: me.cO.prc}; me.makeHTML(); me.cO._mtchTxt = (me.cO.dpLoc.loc + ' ' + me.cO.pkLoc.loc + ' ' + me.cO.vd.vtyp + ' ' + me.cO.vd.vnm + ' ' + (me.cO.vd.svnm ? me.cO.vd.svnm: '')).toLowerCase(); } this.makeHTML = function() { var vdO = me.cO.vd; me.node = $jQ('#carRsltItmTpl').clone().attr('id', '').data('car', me.cO.key); if (vdO.img) $jQ('.car-pic-ctr', me.node).html(``) $jQ('.car--nm', me.node).text(vdO.vnm); if (vdO.svnm) $jQ('.car--snm', me.node).text(vdO.svnm); else $jQ('.car--snm', me.node).hide(); var spTags = []; if (vdO.nst > 0) spTags.push(`${vdO.nst} seats`); if (vdO.ndr > 0) spTags.push(`${vdO.ndr} doors`); if (vdO.slg > 0 || vdO.mlg > 0 || vdO.llg > 0) spTags.push(`${(vdO.llg ? vdO.llg: 0) + (vdO.mlg ? vdO.mlg: 0) + (vdO.slg ? vdO.slg: 0)} bag`); spTags.push(vdO.isAutoTx ? 'Automatic': 'Manual'); if (vdO.isAWD) spTags.push(`All-wheel drive/4x4`); if (vdO.hasAC) spTags.push(`Air Conditioning`); if (spTags.length > 0) { $jQ('.car--spc', me.node).html(`${spTags.map((spTag) => `
${spTag}
`).join('')}`) } if (me.cO.optr) { $jQ('.car--optr', me.node).html(`${me.cO.optr.lg ? ``: `${me.cO.optr.nm}`}`); } else $jQ('.car--optr', me.node).hide(); var ftA = []; if (me.cO.fpl) {ftA.push(`Fuel: ${me.cO.fpT ? ``: ''}${me.cO.fpl}${me.cO.fpT ? '': ''}`);} if (me.cO.mpl) {ftA.push(`${me.cO.mpT ? ``: ''}${me.cO.mpl}${me.cO.mpT ? '': ''}`);} ftA.push(...vdO.ftA); if (ftA.length > 0) { $jQ('.car--hls', me.node).html(``); } else { $jQ('.car--hls', me.node).hide(); } if (me.cO.pkLoc) { $jQ('.car--loc-pk', me.node).html(`
Pick-up
${me.cO.pkLoc.loc}
${me.cO.pkLoc.instr ? `
${me.cO.pkLoc.instr}
`: ``} ${me.cO.pkLoc.locTm ? `
${me.cO.pkLoc.locTm}
`: ``}`); } else { $jQ('.car--loc-pk', me.node).hide(); } if (me.cO.dpLoc) { $jQ('.car--loc-dp', me.node).html(`
Drop-off
${me.cO.dpLoc.loc}
${me.cO.dpLoc.instr ? `
${me.cO.dpLoc.instr}
`: ``} ${me.cO.dpLoc.locTm ? `
${me.cO.dpLoc.locTm}
`: ``}`); } else { $jQ('.car--loc-dp', me.node).hide(); } if (me.cO.xpSmry) { $jQ('.car--xcl', me.node).html(`${me.cO.xpSmry}`).addClass(me.cO.isNR ? 'car--xcl-nr': ''); } else $jQ('.car--xcl', me.node).hide(); $jQ('.prcQ', me.node).html(me.cO.prQ); $jQ('.prcD', me.node).html(me.cO.prD); if (me.cO.cmsD) { $jQ('.cmsD', me.node).html(`${me.cO.cmsD}`).attr('title', 'Total commission'); } else $jQ('.cmsD', me.node).remove(); if (me.cO.sprD) $jQ('.sprcD', me.node).html(me.cO.sprD); else $jQ('.sprcD', me.node).hide(); if (me.cO.asts == 'ON_REQUEST') $jQ('.car-act-ctr', me.node).prepend('
On Request
'); } this.getNode = function() { return me.node; } this.init(); } function CarFilters(cSel, cRslt) { var me = this; this.cSel = cSel; this.cRslt = cRslt; me.fltrOpts = {"cname": {typ:"cname", nm:"Search", optA:[]}, "ctype": {typ:"ctype", nm:"Car Type", applA:[], optA:[], opts:{}}, "spec":{typ:"spec", "nm": "Specification", applA:[], optA:[], opts:{}}, "seat":{typ:"seat", nm:"Seats", applA:[], optA:[], opts:{}}, "optr":{typ:"optr", nm:"Supplier", applA:[], optA:[], opts:{}}, "pkup":{typ:"pkup", nm:"Pick-up Location", applA:[], optA:[], opts:{}}, "drpoff":{typ:"drpoff", nm:"Drop-off Location", applA:[], optA:[], opts:{}}}; me.filters = ['cname', 'ctype', 'spec', 'seat', 'optr', "pkup", "drpoff"]; this.createFilterOpts = function(fltrAvl, fltrAppl) { if (!me.cRslt.cars) return; $jQ.each(me.cRslt.cars, function(i, cItm) { var vdO = cItm.cO.vd; if (vdO.nst > 0) addFilterOpt('seat', {id:(vdO.nst > 5)?6:vdO.nst, nm:(vdO.nst > 5?'6+':vdO.nst)+' seats'}); if (vdO.vtyp) addFilterOpt('ctype', {id:vdO.vtyp, nm:vdO.vtyp}); addFilterOpt('spec', {id:vdO.isAutoTx?'Auto':'Manual', nm:vdO.isAutoTx?'Automatic Transmission':'Manual Transmission'}); if (vdO.isAWD) addFilterOpt('spec', {id:'AWD', nm:'All wheel-drive/4x4'}); if (vdO.hasAC) addFilterOpt('spec', {id:'AC', nm:'Air Conditioning'}); if (cItm.cO.optr) addFilterOpt('optr', {id:cItm.cO.optr.nm, nm:cItm.cO.optr.nm}); if (cItm.cO.pkLoc.loc) addFilterOpt('pkup', {id:cItm.cO.pkLoc.loc, nm:cItm.cO.pkLoc.loc}); if (cItm.cO.dpLoc.loc) addFilterOpt('drpoff', {id:cItm.cO.dpLoc.loc, nm:cItm.cO.dpLoc.loc}); }); if (fltrAvl) { $jQ.each(fltrAvl, function(typ, fAvlA) { var fO = me.fltrOpts[typ]; if (!fO || !fAvlA) return true; fO.optA = fAvlA; }); } if (fltrAppl) { $jQ.each(fltrAppl, function(typ, fAppA) { var fO = me.fltrOpts[typ]; if (!fO || !fAppA) return true; fO.applA = fAppA; }); } } var addFilterOpt = function(typ, optO) { var fltrItmOpts = me.fltrOpts[typ]; if (!fltrItmOpts) return; if (!fltrItmOpts.opts[optO.id]) { fltrItmOpts.optA.push(optO); fltrItmOpts.opts[optO.id] = true; } } this.resetApplied = function() { $jQ.each(me.fltrOpts, function(typ, fItm) { if (!fItm.applA || fItm.applA.length == 0) return true; fItm.applA = []; }); } this.isCarValid = function(cItm) { if (!cItm) return true; var isValid = true, vdO = cItm.cO.vd; $jQ.each(me.fltrOpts, function(typ, fItm) { if (fItm.isDyn || ((!fItm.applA || fItm.applA.length == 0) && typ != 'cname')) return true; switch (typ) { case 'cname': { var fOpt = fItm.optA.length > 0 ? fItm.optA[0]: null; if (fOpt && fOpt.nm && cItm.cO._mtchTxt.indexOf(fOpt.nm.toLowerCase()) < 0) { isValid = false; return false; } } break; case 'ctype': if (fItm.applA.indexOf(vdO.vtyp) < 0) { isValid = false; return false; } break; case 'seat': { var isFound = false; $jQ.each(fItm.applA, function(_, appl) { if (vdO.nst == appl || (appl >= 6 && vdO.nst >= 6)) { isFound = true; return false; } }); if (!isFound) { isValid = false; return false; } } break; case 'spec': { var isFound = false; $jQ.each(fItm.applA, function(_, appl) { if ((vdO.hasAC && appl == 'AC') || (vdO.isAWD && appl == 'AWD') || (vdO.isAutoTx && appl == 'Auto') || (!vdO.isAutoTx && appl == 'Manual')) { isFound = true; return false; } }); if (!isFound) { isValid = false; return false; } } break; case 'optr': { if (!cItm.cO.optr || fItm.applA.indexOf(cItm.cO.optr.nm) < 0) { isValid = false; return false; } } break; case 'pkup': { if (!cItm.cO.pkLoc.loc || fItm.applA.indexOf(cItm.cO.pkLoc.loc) < 0) { isValid = false; return false; } } break; case 'drpoff': { if (!cItm.cO.dpLoc.loc || fItm.applA.indexOf(cItm.cO.dpLoc.loc) < 0) { isValid = false; return false; } } break; } }); return isValid; } this.renderFilters = function(rsltO, opts) { var fltrsJ = $jQ('
'); $jQ.each(me.filters, function(i, typ) { var fltrItm = me.fltrOpts[typ]; if (!fltrItm) return true; var fJ = me.getFilterHTM(fltrItm, opts); fltrsJ.append(fJ); }); me.cRslt.rsltFltrCtr.html(fltrsJ); me.cRslt.rsltFltrApplCtr.html(''); me.cRslt.rsltSortCtr.html(me.getSortHTM(opts)).toggleClass('hide', !me.cRslt.fltdCars || me.cRslt.fltdCars.length <= 2); } this.getFilterHTM = function(fO, opts) { var fJ = null, fCtrJ = null; fJ = $jQ(`
`); fCtrJ = $jQ('
').appendTo(fJ); if (fO.optA.length > 8) {fCtrJ = $jQ('
').appendTo(fCtrJ);} if (fO.typ == 'cname') { var oJ = $jQ(`
`).appendTo(fCtrJ.addClass('ddMenuACCtr')); if (fO.optA && fO.optA.length > 0) { $jQ('input', oJ).val(fO.optA[0].nm); } $jQ('input', oJ).keyup(JS_UTIL.delayCallback(function(e) { fOpt = fO.optA.length > 0 ? fO.optA[0]: null; if (!fOpt) { fOpt = {nm:''}; fO.optA.push(fOpt); } fOpt.nm = $jQ.trim($jQ('input', oJ).val()); if (opts && opts.fltrClbk) opts.fltrClbk({isFltr:true, fltr:fO, opt:fOpt}); }, 200)); } else { $jQ.each(fO.optA, function(i, fOpt) { fOpt.appl = (fO.applA.indexOf(fOpt.id) >= 0); var oJ = $jQ(`
${getFacetDisplayHTM(fO, fOpt)}
`); oJ.click(function() { var isSltd = oJ.hasClass('btnSltd'); if (isSltd) { fO.applA.splice(fO.applA.indexOf(fOpt.id), 1); oJ.removeClass('btnSltd'); } else { fO.applA.push(fOpt.id); oJ.addClass('btnSltd'); } if (opts && opts.fltrClbk) opts.fltrClbk({isFltr:true, fltr:fO, opt:fOpt}); return false; }); fCtrJ.append(oJ); }); } return fJ; } var getFacetDisplayHTM = function(fO, fOpt) { return fOpt.nm; } this.getAppliedFiltersQueryParams = function() { var prmsO = {}; $jQ.each(me.filters, function(i, typ) { var fltrItm = me.fltrOpts[typ]; if (!fltrItm || !fltrItm.isDyn || !fltrItm.applA || fltrItm.applA.length == 0) return true; prmsO[typ+'Fltr'] = fltrItm.applA.join(','); }); return prmsO; } this.getSortHTM = function(opts) { var fSrtJ = $jQ('
').append(`
Sort: ${me.cSel.curSort.nm}
`); var fSrtCtrJ = $jQ('
').append('
').appendTo(fSrtJ); fSrtCtrJ.append(getSortOptionHTM({nm:'Price - Low to High', fld:'prc', asc:true}, opts)); fSrtCtrJ.append(getSortOptionHTM({nm:'Price - High to Low', fld:'prc', asc:false}, opts)); return fSrtJ; } var getSortOptionHTM = function(srtO, opts) { var oJ = $jQ(`
${srtO.nm}
`); oJ.click(function() { me.cSel.curSort = srtO; if (opts && opts.fltrClbk) opts.fltrClbk({isSort:true}); return false; }); return oJ; } } function CarSearchBox(cSel, opts) { var me = this; me.cSel = cSel; var defaults = {ctr:null, srchCallback:null, fxDt:false, ctyA:null, extSrchO:null}; this.opts = $jQ.extend(true, {}, defaults, opts || {}); this.prevSrchO = null; this.allowSearch = true; this.alSrchTimer = null; this.init = function() { me.sbCtr = $jQ(me.opts.ctr); me.sbJ = me.getSBHTML(); me.sbCtr.html(me.sbJ); $jQ('.carSrchCatLst .carSrchCatItm', me.sbJ).click(function() { var optJ = $jQ(this), cat = optJ.attr('data-ctype'); optJ.addClass('carSrchCatItmSltd').siblings().removeClass('carSrchCatItmSltd'); $jQ('input[name=carCat]', me.sbJ).val(cat).change(); return false; }); $jQ('input[name=carCat]', me.sbJ).change(function() { var cat = $jQ(this).val(); $jQ(`.carSrchCatLst .carSrchCatItm[data-ctype="${cat}"]`, me.sbJ).addClass('carSrchCatItmSltd').siblings().removeClass('carSrchCatItmSltd'); }); $jQ('a.srchAct', me.sbJ).click(function() { var srchO = me.getQueryJSON(); if (!me.isValid(srchO)) {alert('Please provide valid pickup and drop details'); return false;} if (!JS_UTIL.isEqualJSON(srchO, me.prevSrchO)){ me.allowSearch = true; } if (me.cSel.opts.isPgChgInSrch) { document.location.href = JS_UTIL.insAllParams('/car/search', me.getQueryParams(srchO)); return; } if (me.allowSearch && me.opts.srchCallback) { me.prevSrchO = srchO; if (me.alSrchTimer) clearTimeout(me.alSrchTimer); me.alSrchTimer = setTimeout(function(){ me.allowSearch = true; }, me.cSel.opts.carSrchTout); me.allowSearch = false; me.opts.srchCallback(this); me.cSel.updateInHistory(srchO, {isReplace:false}); } return false; }); } this.show = function(showSB) { me.sbCtr.toggle(showSB); } this.getSBHTML = function() { var sbJ = $jQ("#carSrchBxTpl").clone().attr("id", "").show(), isPkgCfgMode = me.cSel.opts.isPkgCfgMode; if (!isPkgCfgMode) { var ctySuggestPrms = {incArp:true}; if (me.opts.extSrchO) ctySuggestPrms = $jQ.extend(ctySuggestPrms, me.opts.extSrchO); var pkupAC = new TFAutocomplete({inpF:$jQ('input.pickupLoc', sbJ), wclass:'tt-minwidth', applyChromeACFix:false, acOpts:{highlight:false}, datasets:new TFACDataset({remote:{url:'/car/cities-suggest'}, extraParams:ctySuggestPrms, oOpts:{templates:{suggestion:function(item) { return `
${item.data.nm}
${item.data.pnm ? `
${item.data.pnm}
`: ``}
`; }}}}), events: {'select': function(e, item) { me.pkLocO = item.data.isApt ? {acd:item.data.id, nm:item.data.nm}: {cid:item.data.id, nm:item.data.nm}; }, 'noselect': function() { me.pkLocO = null; }}}); var drpAC = new TFAutocomplete({inpF:$jQ('input.dropLoc', sbJ), wclass:'tt-minwidth', applyChromeACFix:false, acOpts:{highlight:false}, datasets:new TFACDataset({remote:{url:'/car/cities-suggest'}, extraParams:ctySuggestPrms, oOpts:{templates:{suggestion:function(item) { return `
${item.data.nm}
${item.data.pnm ? `
${item.data.pnm}
`: ``}
`; }}}}), events: {'select': function(e, item) { me.dpLocO = item.data.isApt ? {acd:item.data.id, nm:item.nm}: {cid:item.data.id, nm:item.nm}; }, 'noselect': function() { me.dpLocO = null; }}}); var dtPicker = new DatePick({fromInp:$jQ('input.pickupDate', sbJ), toInp:$jQ('input.dropDate', sbJ), calO:{dateFormat:'dd M yyyy'}}); } else { $jQ('input.pickupLoc', sbJ).replaceWith($jQ('').change(function() {me.onPkgLocationChange(false);})); $jQ('input.pickupDate', sbJ).replaceWith($jQ('').change(function() {me.onPkgDateChange(false);})); } JS_UTIL.addTimeField($jQ('select.pickupTime', sbJ), 0, 23, 30, true, true); $jQ('select.pickupTime', sbJ).val('09:00'); JS_UTIL.addTimeField($jQ('select.dropTime', sbJ), 0, 23, 30, true, true); $jQ('select.dropTime', sbJ).val('09:00'); return sbJ; } this.setPkgSearchData = function(srchD) { if (!me.cSel.opts.isPkgCfgMode) return; me.srchD = srchD; var pkLcJ = $jQ('select.pickupLoc', me.sbJ).html(''); $jQ.each(srchD.pkLocA, function(i, pkLO) { $jQ(``).data('location', pkLO).appendTo(pkLcJ); }); var dpLcJ = $jQ('select.dropLoc', me.sbJ).html(''); $jQ.each(srchD.dpLocA, function(i, dpLO) { $jQ(``).data('location', dpLO).appendTo(dpLcJ); }); pkLcJ.change(); dpLcJ.change(); } this.onPkgLocationChange = function(isPkup) { if (!me.cSel.opts.isPkgCfgMode || !me.srchD) return; var srchLocO = $jQ(`select.${isPkup ? 'pickupLoc': 'dropLoc'} option:selected`, me.sbJ).data('location'); var pkDtJ = $jQ('select.pickupDate', me.sbJ), pkDt = pkDtJ.val(); var dpDtJ = $jQ('select.dropDate', me.sbJ); if (isPkup) { me.pkLocO = srchLocO.acd ? {acd:srchLocO.acd, nm:srchLocO.nm}: {cid:srchLocO.cid, nm:srchLocO.nm}; pkDtJ.html(`${srchLocO.dtA.map((dtO) => ``).join('')}`); } else { me.dpLocO = srchLocO.acd ? {acd:srchLocO.acd, nm:srchLocO.nm, dcky:srchLocO.dcky}: {cid:srchLocO.cid, nm:srchLocO.nm, dcky:srchLocO.dcky}; } pkDtJ.change(); if (!isPkup) dpDtJ.change(); } this.onPkgDateChange = function(isPkup) { if (!me.cSel.opts.isPkgCfgMode || !me.srchD) return; if (isPkup) { var srchLocO = $jQ('select.dropLoc option:selected', me.sbJ).data('location'); var pkDtJ = $jQ('select.pickupDate', me.sbJ), pkDt = pkDtJ.val(), pkDtD = moment(pkDt, 'DD MMM YYYY'); var dpDtJ = $jQ('select.dropDate', me.sbJ), dpDt = dpDtJ.val(), isDpDtSltd = false; dpDtJ.html(''); $jQ.each(srchLocO.dtA, function(i, dtO) { var dtD = moment(dtO.dt, 'DD MMM YYYY'); if (pkDtD.isValid() && dtD.isSameOrBefore(pkDtD, 'day')) return true; var isSltd = (dpDt == dtO.dt); isDpDtSltd = isDpDtSltd || isSltd; dpDtJ.append(``); }); if (!isDpDtSltd) {dpDtJ.val(srchLocO.dtA[srchLocO.dtA.length - 1].dt);} } me.updateTimeOptions(isPkup); } this.updateTimeOptions = function(isPkup) { if (!me.cSel.opts.isPkgCfgMode || !me.srchD) return; var srchLocO = $jQ(`select.${isPkup ? 'pickupLoc': 'dropLoc'} option:selected`, me.sbJ).data('location'); var dtJ = $jQ(`select.${isPkup ? 'pickupDate': 'dropDate'}`, me.sbJ), dtD = moment(dtJ.val(), 'DD MMM YYYY'); var tmJ = $jQ(`select.${isPkup ? 'pickupTime': 'dropTime'}`, me.sbJ), tmV = tmJ.val(); $jQ.each(srchLocO.dtA, function(i, dtO) { var dt = moment(dtO.dt, 'DD MMM YYYY'); if (!dt.isSame(dtD, 'day')) return true; if (dtO.mnTm) { var mnTmD = moment(dtO.mnTm, 'HH:mm'); tmJ.html(''); JS_UTIL.addTimeField(tmJ, mnTmD.hour(), 23, 30, true, true); tmJ.val(dtO.mnTm); } else if (dtO.mxTm) { var mxTmD = moment(dtO.mxTm, 'HH:mm'); tmJ.html(''); JS_UTIL.addTimeField(tmJ, 0, mxTmD.hour(), 30, true, true); tmJ.val(dtO.mxTm); } else { JS_UTIL.addTimeField(tmJ, 0, 23, 30, true, true); tmJ.val(tmV); } if (dtO.dcky && me.dpLocO) { me.dpLocO.dcky = dtO.dcky; } return false; }); } this.getQueryJSON = function() { var srchO = {}; if (me.opts.extSrchO) srchO = $jQ.extend({}, srchO, me.opts.extSrchO); srchO.cat = $jQ('input[name=carCat]', me.sbJ).val(); if (me.pkLocO) {srchO.pkLoc = {...me.pkLocO};} if (me.dpLocO) {srchO.dpLoc = {...me.dpLocO};} var pkDt = $jQ('.pickupDate', me.sbJ).val(), dpDt = $jQ('.dropDate', me.sbJ).val(); if (pkDt) srchO.pkTm = moment(pkDt, 'DD MMM YYYY').format('YYYY-MM-DD') + ' '+$jQ('select.pickupTime', me.sbJ).val()+':00'; if (dpDt) srchO.dpTm = moment(dpDt, 'DD MMM YYYY').format('YYYY-MM-DD') + ' '+$jQ('select.dropTime', me.sbJ).val()+':00'; var dvAge = $jQ('input.drvAge', me.sbJ).val(); if ($jQ.isNumeric(dvAge)) srchO.dvAge = parseInt(dvAge, 10); return srchO; } this.populateFields = function(srchO) { if (!srchO) return; if (srchO.cat) $jQ('input[name=carCat]', me.sbJ).val(srchO.cat).change(); var isPkgCfgMode = me.cSel.opts.isPkgCfgMode; if (srchO.pkLoc) { me.pkLocO = srchO.pkLoc; if (isPkgCfgMode) $jQ('select.pickupLoc', me.sbJ).val(srchO.pkLoc.acd ? srchO.pkLoc.acd: srchO.pkLoc.cid).change(); else $jQ('input.pickupLoc', me.sbJ).val(srchO.pkLoc.nm); } if (!srchO.dpLoc) srchO.dpLoc = srchO.pkLoc; if (srchO.dpLoc) { me.dpLocO = srchO.dpLoc; if (isPkgCfgMode) $jQ('select.dropLoc', me.sbJ).val(srchO.dpLoc.acd ? srchO.dpLoc.acd: srchO.dpLoc.cid).change(); else $jQ('input.dropLoc', me.sbJ).val(srchO.dpLoc.nm); } if (srchO.pkTm) { var pkTmD = moment(srchO.pkTm, 'YYYY-MM-DD HH:mm:ss'); $jQ('.pickupDate', me.sbJ).val(pkTmD.format('DD MMM YYYY')).change(); $jQ('select.pickupTime', me.sbJ).val(pkTmD.format('HH:mm')); } if (srchO.dpTm) { var dpTmD = moment(srchO.dpTm, 'YYYY-MM-DD HH:mm:ss'); $jQ('.dropDate', me.sbJ).val(dpTmD.format('DD MMM YYYY')).change(); $jQ('select.dropTime', me.sbJ).val(dpTmD.format('HH:mm')); } if (srchO.dvAge) { $jQ('input.drvAge', me.sbJ).val(srchO.dvAge); } } this.getQueryParams = function(srchO) { var prmO = {}; if (!srchO) return prmO; if (srchO.cat) prmO.carCat= srchO.cat; if (srchO.pkLoc) {prmO.pkupLoc = srchO.pkLoc.acd ? srchO.pkLoc.acd: srchO.pkLoc.cid;} if (srchO.dpLoc) {prmO.dropLoc = srchO.dpLoc.acd ? srchO.dpLoc.acd: srchO.dpLoc.cid;} if (srchO.pkTm) prmO.pkupDate = srchO.pkTm; if (srchO.dpTm) prmO.dropDate = srchO.dpTm; if (srchO.dvAge) prmO.driverAge = srchO.dvAge; if (me.opts.extSrchO) prmO = $jQ.extend(prmO, me.opts.extSrchO); return prmO; } this.isValid = function(srchO) { if (!srchO) {srchO = me.srchO;} if (!srchO) {return false;} if (!srchO.pkLoc || !srchO.pkTm || !srchO.dpTm) {return false;} return true; } this.init(); }