[]
0 && dtnargs.limit > 0 && dtn !== undefined); var limit = 12; var xhr; var defaultHooks = []; var defaultView = widget.custom_defaultView !== undefined ? widget.custom_defaultView : “grid”; var t = JSON.parse($(“#translations_bd3e13e6-7c45-4781-9169-06c0de3262a1”).html()); if (widget.detail_type !== undefined) { defaultHooks.push({ name : “afterFind_custom_detail_type”, args : { detail_type : widget.detail_type } }); } if (widget.dtnlimit) { // if a limit is specified in the widget, override that passed in config dtnargs.limit = Number(widget.dtnlimit); } if (hasDtn) { // we want the smaller of the limit and dtnargs.limit dtnargs.limit = Math.min(dtnargs.limit, limit); } var allFilterTagItems = subcats.map(function(val) { return { site : site.site, subcatid : Number(val.value) } }); // the base filter is the minimum filter applied to all queries. This is *not* the same as a “default” query, or the initial query. // this is the base. Any filter components that can be done in the UI are added to this object var baseFilter = { $and : [] } if (hasPrimaryCat) { baseFilter.$and.push({ filter_tags : { $in : crmLib.getListingFilterTags({ items : allFilterTagItems }) } }); } else { baseFilter.$and.push({ filter_tags : { $in : [‘site_’ + site.site] } }); } if (regionsChosen) { baseFilter.regionid = { $in : regions.map(function(val) { return Number(val.value) }) } } if (specificListingsChosen) { baseFilter.recid = { $in : widget.custom_specific_listings_ids }; } if (initialAmenities && widget.amenityoptions === “none”) { initialAmenities.forEach(function(val) { baseFilter[“amenities.” + val + “.value_raw”] = true; }); } else if (initialAmenities && widget.amenityoptions === “custom”) { initialAmenities.forEach(function(val) { let selected = amenities.some(function(amenity) { return amenity.value === val; }); if (!selected) { baseFilter[“amenities.” + val + “.value_raw”] = true; } }); } var masterFlow = new asyncLib.Flow(); masterFlow.series({ init: function(cb) { var vue = layoutjs.getVue({ rootNode : $(“#layoutjs_bd3e13e6-7c45-4781-9169-06c0de3262a1”), type : “listings”, view : defaultView, limit : limit, sort : “qualityScore”, translations : t.leo, // if there is a defaultImageUrl defined in client config, use it. Else it will utilize the default declared in custom_layoutjs.js fallbackImageUrl : site.siteConfig.custom && site.siteConfig.custom[site.site] && site.siteConfig.custom[site.site].defaultImageUrl, showFilter : true, baseFilter : baseFilter, filters : [ { name : “keyword”, label : t.leo.keyword, placeholder : t.leo.search_placeholder, type : “keyword”, toFilter : function(value, filter, context) { filter.solrOptions = { keyword : value } return filter; } }, { name : “yesno”, label : “Test Yes/No”, type : “toggle”, show: false, toFilter : function(value, filter, context) { filter.$and.push({ “amenities.room_testyesno.value_raw” : true }); return filter; } }, { name : “regions”, label : t.leo.regions, // we implicitly filter on regions if they have been selected in the widget, so no reason to display a region option with 1 choice // if no regions were selected, then a region option with 1 choice is valid and therefore we pass the whole array show : regionsChosen ? regions.length > 1 : regions.length > 0, type : “checkbox”, typeExtra : { options : regions, countArgs : { watchFilters : [“subcats”, “amenities”], unsupportedFilters : [“keyword”], field : “regionid”, model : “plugins_listings_listings”, sort : true } }, toFilter : function(value, filter, context) { filter.$and.push({ regionid : { $in : value.map(function(val) { return Number(val) }) } }); return filter; } }, { name : “subcats”, label : t.leo.categories, show : subcats.length > 1, type : useGroupedCats ? “twostage” : “checkbox”, typeExtra : { options : useGroupedCats ? groupedCats : subcats, countArgs : { watchFilters : [“amenities”, “regions”], unsupportedFilters : [“keyword”], field : “categories.subcatid”, unwind : “categories”, model : “plugins_listings_listings”, sort : true } }, toFilter : function(value, filter, context) { filter.$and.push({ filter_tags : { $in : crmLib.getListingFilterTags({ items : this.custom_selectedSubcatItems }) } }); return filter; } }, { name : “amenities”, label : t.listings.amenities, // we do not implicitly filter on amenities so if there is only one available option we still want to show the checkbox show : amenities.length > 0, type : “checkbox”, initialValue : initialAmenities, typeExtra : { options : amenities, countArgs : { watchFilters : [“subcats”, “regions”, “amenities”], unsupportedFilters : [“keyword”], field : “amenities_array.uniquename”, unwind : “amenities_array”, model : “plugins_listings_listings”, sort : true } }, toFilter : function(value, filter) { value.forEach(function(val) { filter[“amenities.” + val + “.value_raw”] = true; }); return filter; } } ], sortOptions : [ { value : “qualityScore”, label : t.leo.recommended }, { value : “distance”, label : t.leo.near_me } ], maxRangeMiles : 100, latitude : 35.691544, longitude : -105.944183, data : { custom_catid : (widget.listingcats !== undefined) ? Number(widget.listingcats) : undefined, custom_dtnids : [] }, // computed allows the passing of computed and method properties, in cases where they may need to be unique to the template computed : { custom_selectedSubcatItems : function() { return this.filter_subcats_numberArray.map(function(val) { return { site : site.site, subcatid : val } }); }, custom_dtnFilterTagItems : function() { // if we have not chosen subcats in the widget, then we need to load via the category id // if we have chosen subcats then we utilize whatever the state of the if (this.custom_selectedSubcatItems.length > 0) { // if we have items selected in the UI, use them return this.custom_selectedSubcatItems; } else if (subcatsChosen) { // if we have items chosen in the widget, use those return allFilterTagItems; } else { // otherwise fall back to the chosen catid return [{ site : site.site, catid : this.custom_catid }]; } } }, methods : {}, watch : { docs: function() { // place logic in here that needs to happen after render of items this.$nextTick(function() { if (hasDtn) { gamClient.renderAds(); } }); lazyload.lazy($(this.$el).find(‘.content .item’)) } }, query : function(cb) { var self = this; var filter = self.getFilter(“query”); var options = { limit : self.args.limit, skip : self.skip, count : true, castDocs : false, fields : { accountudfs_object : 1, recid : 1, title : 1, address1 : 1, url : 1, isDTN : 1, latitude : 1, longitude : 1, primary_image_url : 1, qualityScore : 1, weburl : 1, “dtn.rank” : 1, “yelp.rating” : 1, “yelp.url” : 1, “yelp.review_count” : 1, “yelp.price” : 1 }, hooks : defaultHooks }; if (self.sort === “qualityScore”) { options.sort = { qualityScore : -1, sortcompany : 1 }; } else if (self.sort === “distance”) { filter.solrOptions = filter.solrOptions || {}; filter.solrOptions.sort = “distance”; filter.solrOptions.point = [self.georesult.latitude, self.georesult.longitude].join(“,”); filter.solrOptions.radius = self.args.maxRangeMiles.toString(); } if (options.skip === 0) { // whenever the skip is 0, we reset the custom_dtnids back to scratch self.custom_dtnids = []; } var flow = new asyncLib.Flow(); flow.series({ dtn : function(cb) { if (hasDtn === false || options.skip > 0 || self.sort === “distance” || self.custom_catid === undefined) { return cb(null, []); } var dtnFilter = self.getFilter(“query”); dtnFilter.$and.push({ filter_tags : { $in : crmLib.getListingFilterTags({ items : self.custom_dtnFilterTagItems, dtn : true }) } }); // using 0000 and 2359 for caching purposes, otherwise we could just use Date().toISOString() var today0000 = clientMoment().startOf(“day”); // send date as 00:00:00 in the client timezone in UTC var today2359 = clientMoment().endOf(“day”); // send date as 23:59:59 in the client timezone in UTC dtnFilter.$and.push( { $or : [ { “dtn.sdate” : { $lte : { $date : today0000.toISOString() } } }, { “dtn.sdate” : { $exists : false } } ] }, { $or : [ { “dtn.edate” : { $gte : { $date : today2359.toISOString() } } }, { “dtn.edate” : { $exists : false } } ] } ); var dtnOptions = $.extend({}, options, { // we allow DTN to oversell the first page by a factor of 2 // we will pull from this set a max of the limit limit : self.limit * 2, count : false, hooks : defaultHooks.concat(“afterFind_dtn”) }); if (xhr) { xhr.abort(); } xhr = $.get(“/includes/rest_v2/plugins_listings_listings/find/”, { json : JSON.stringify({ filter : dtnFilter, options : dtnOptions }), token : core.simpleToken }); xhr.done(function(res) { // randomize the result set, then trim it down to our desired limit res.docs = arrayLib.randomize(res.docs); res.docs = res.docs.splice(0, dtnargs.limit); res.docs.forEach(function(val) { self.custom_dtnids.push(val.recid); val.dtnAuid = dtnargs.auid; val.isDTN = true; }); return cb(null, res.docs); }).fail(function(err, type, message) { if (type === “abort”) { return flow.halt({ total : 0, docs : [] }); } // another request has aborted this one, so halt this flow return cb(new Error(message)); }); }, data : function(cb) { if (flow.data.dtn.length > 0) { // has DTN listings, need to adjust page 1 limit and store dtnids for exclusion from main query on all pages options.limit -= self.custom_dtnids.length; } else { options.skip = (options.skip – self.custom_dtnids.length); } if (self.custom_dtnids.length > 0) { filter.recid = { $nin : self.custom_dtnids } } if (xhr) { xhr.abort(); } if (self.custom_dtnids.length === self.limit) { options.limit = 1; } xhr = $.get(“/includes/rest_v2/plugins_listings_listings/find/”, { json : JSON.stringify({ filter : filter, options : options }), token : core.simpleToken }); xhr.done(function(res) { var returnData = { total : res.docs.count + self.custom_dtnids.length, docs : flow.data.dtn.concat(res.docs.docs).slice(0, self.limit) }; returnData.docs = returnData.docs.map(function(val) { return { accountudfs_object : val.accountudfs_object, recid : val.recid, title : val.title, image_url : val.primary_image_url, url : val.url, dtn : val.isDTN ? { auid : dtnargs.auid, rank : val.dtn.rank } : undefined, yelp : val.yelp, locations: [{ title : val.address1 }], // sets listing location latitude : val.latitude, longitude : val.longitude, qualityScore : val.qualityScore, button : { title : t.leo.read_more, url : val.url, weburl : val.weburl, weburl_title : t.leo.visit_website } // call to action button } }); return cb(null, returnData); }).fail(function(err, type, message) { if (type === “abort”) { return flow.halt({ total : 0, docs : [] }); } // another request has aborted this one, so halt this flow return cb(new Error(message)); }); } }, flow.cbLast(cb)); } }); /* register available UI events */ var watcher = new UIWatcher(vue, $, document); var uid = clientLib.uuid().toString(); var widgetEvents = [ “change-page”, “view-change”, “value-change”, “sort-change”, “toggle-show-more”, “scroll-into-view”, “item-click”, “title-click”, “map-pin-click”, “tripbuilder” ]; for (var i=0; i