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(`
').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(`
`).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(`
`).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(`
${ftA.map((ft) => `- ${ft}
`).join('')}
`);
} 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(`