PageSourceSearch

https://blueoxrunning.com/assets/admin/scripts/models/products.js?v=1.2.0

js blueoxrunning.com collected 2026-09-25 02:56:28 UTC 17,953 bytes, 556 lines download raw bytes

1var products = {
2	id: -1,
3	searchId: "",
4	product: {},
5	popularItems: [], 
6	data: [],
7	results: [],
8	brand: -1, 
9	category: -1,
10	options: null,
11	total: 0,
12	order: ['xxs', 'xs', 's', 'm', 'l', 'xl', 'xxl'],
13	filter: {
14		brand: -1,
15		category: -1,
16		collection: -1,
17		search: "",
18		grouped: false,
19		size: 50, 
20		cost: -1,
21		page: 1,
22		stock: -1,
23		complete: -1, 
24		live: -1,
25		sort: "name",
26		sortType: "asc",
27		admin: false
28	},
29	all: function() {
30		products.filter.stock = 1;
31		products.filter.live = 1;
32		products.filter.size = 10000;
33		products.filter.status = "complete"
34
35		service.call("products", products.filter, products.allReturned);
36	},
37	allReturned: function(e) {
38		$(".loader").removeClass("open");
39		if (e.error) growler.error(e.error);
40		else {
41			products.data = e.data;
42			products.total = e.total;
43			context.set("allproducts", products.data);
44		}
45	},
46	alerts: function() {
47		products.filter.stock = 0;
48		products.filter.cost = 0;
49		products.filter.live = 1;
50		service.call("products", products.filter, products.getReturned);
51	},
52	getSizes: function() {
53		service.call("product/sizes", {}, function(e) {
54			context.set("sizes", e);
55		});
56	},
57	getWidths: function() {
58		service.call("product/widths", {}, function(e) {
59			context.set("widths", e);
60		});
61	},
62	popular: function(sort) {
63		service.call("popular", { sort: sort }, products.popularReturned);
64	},
65	popularReturned: function(e) {
66		if (e.error) growler.error(e.error);
67		else {
68			products.popularItems = e;
69			context.set("popular", products.popularItems);
70		}
71	},
72	get: function() {
73		if (products.filter.admin!=null&&products.filter.admin==true) {
74			service.call("products", products.filter, products.getReturned);
75		} else { 
76			service.call("products-search", products.filter, products.getReturned);
77		}
78	},
79	getReturned: function(e) {
80		$(".loader").removeClass("open");
81		if (e.error) {
82			growler.error(e.error);
83			products.data = [];
84			products.total = 0;
85			var contextId = "products"+products.searchId;
86			if (products.filter.admin!=null&&products.filter.admin==true) contextId = "admin"+contextId;
87			context.set(contextId, products.data);
88		} else {
89			products.data = e.data;
90			products.total = e.total;
91			var contextId = "products"+products.searchId;
92			if (products.filter.admin!=null&&products.filter.admin==true) contextId = "admin"+contextId;
93			context.set(contextId, products.data);
94		}
95	},
96	searchView: function(filter) {
97		if (filter.trim().length>0) {
98			service.call("product/view/search", {search:filter}, () => {});
99		}
100	},
101	productView: function(id) {
102		service.call("productView", {id:id}, () => {});
103	},
104	details: function(id) {
105		service.call("product", { id: id }, products.detailsReturned);
106	},
107	detailsReturned: function(e) {
108		if (e.error) growler.error(e.error);
109		else {
110			products.product = e; 
111			
112			if (page.productDetails) page.productDetails(products.product);
113			else context.set("product", products.product);
114		}
115	},
116	import: function(sku) {
117		service.call("import", { sku: sku }, products.detailsReturned);
118	},
119	add: function(sku, name, description, cost, brand, color, shipping, categories, inStorePurchase, inStorePickup, showOnSite, autoPrice, isFeatured, isOnSale, inventory, images) {
120		var params = products.filter;
121		params.sku = sku;
122		params.name = name;
123		params.description = description;
124		params.cost = cost;
125		params.brand = brand;
126		params.color = color;
127		params.shipping = shipping;
128		params.categories = categories;
129		params.inStorePurchase = inStorePurchase;
130		params.inStorePickup = inStorePickup;
131		params.showOnSite = showOnSite;
132		params.autoPrice = autoPrice;
133		params.isFeatured = isFeatured;
134		params.isOnSale = isOnSale;
135		params.inventory = inventory;
136		params.images = images;
137		service.call("product/add", params, products.getReturned);
138	},
139	save: function(id, name, description, blurb, cost, shipping, categories, collections, images, isInStoreOnly, isInStorePurchaseOnly, isLive, isAuto, isOnSale, isFeatured, isPrimary, color, brand, metaTitle, metaDescription, metaTags, metaAlt,relayStatus,dateReleased,adminUpdate) {
140		var params = {
141			name: name,
142			description: description,
143			blurb: blurb,
144			cost: cost, 
145			shipping: shipping,
146			brand: brand,
147			color: color,
148			id: id,
149			categories: categories,
150			collections: collections,
151			images: images,
152			isInStoreOnly: isInStoreOnly,
153			isInStorePurchaseOnly: isInStorePurchaseOnly,
154			isLive: isLive,
155			isAuto: isAuto,
156			isOnSale: isOnSale,
157			isFeatured: isFeatured,
158			isPrimary: isPrimary, 
159			metaTitle: metaTitle,
160			metaDescription: metaDescription,
161			metaTags: metaTags,
162			metaAlt: metaAlt,
163			relayStatus:relayStatus,
164			dateReleased:dateReleased,
165			adminUpdate: adminUpdate
166		};
167		service.call("productSave", params, products.saveComplete);
168	},
169	getSize: function(size,url) {
170		var items = url.split('/');
171		var multiplier = 1;
172		if (window.devicePixelRatio) {
173			multiplier = window.devicePixelRatio;
174		}
175		if (url.indexOf("http")==0) return url;
176		else {
177			if (cdnOn!=null && cdnOn) return products.getSized(size,url); 
178			else return "/images/"+(size*multiplier).toFixed(0)+"/"+items[items.length-1];
179		} 
180	},
181	getSized: function(size,url) {
182		var items = url.split('/');
183		var multiplier = 1;
184		if (window.devicePixelRatio) {
185			multiplier = window.devicePixelRatio;
186		}
187		if (url.indexOf("http")==0) return url;
188		else {
189			let cdnUrl = "https://cdn.runfree.run/images/products/"+products.getBucket(url)+"/"+(size*multiplier).toFixed(0)+"/"+items[items.length-1];
190			return cdnUrl; 
191		} 
192	},
193	getBucket: function(url) {
194		var items = url.split('/');
195		let fileName = items[items.length-1];
196		let bucket = "";
197		if (url.indexOf("/products/")>0) {
198			var items = fileName.split('_');
199			if (items.length>2) {
200				bucket = items[0];
201			} else {
202				bucket = "sync";
203			}
204		} else if (url.indexOf("/meta/")>0) {   
205			bucket = "meta";
206		}
207		return bucket;
208	},
209	saveComplete: function(e) {
210		$(".loader").removeClass("open");
211		growler.success("Product Information has been saved");
212		if (page && page.get) page.get();
213	},
214	saveMultiInStorePurchase: function(ids, inStorePurchase) {
215		var params = Object.assign({}, products.filter);
216		params.ids = ids;
217		params.inStorePurchase = inStorePurchase;
218		service.call("multiInStorePurchase", params, products.getReturned);
219	},
220	saveMultiInStorePickup: function(ids, inStorePickup) {
221		var params = Object.assign({}, products.filter);
222		params.ids = ids;
223		params.inStorePickup = inStorePickup;
224		service.call("multiInStorePickup", params, products.getReturned);
225	},
226	saveMultiSaleToggle: function(ids, onSale) {
227		var params = Object.assign({}, products.filter);
228		params.ids = ids;
229		params.onSale = onSale;
230		service.call("multiSaleToggle", params, products.getReturned);
231	},
232	addToCollection: function(ids, collectionId) {
233		var params = Object.assign({}, products.filter);
234		params.ids = ids;
235		params.collectionId = collectionId;
236		service.call("addToCollection", params, products.getReturned);
237	},
238	saveMultiSale: function(ids, onSale, auto, price) {
239		var params = Object.assign({}, products.filter);
240		params.ids = ids;
241		params.onSale = onSale;
242		params.auto = auto;
243		params.price = price;
244		service.call("multiSale", params, products.getReturned);
245	},
246	saveMultiAutoUpdate: function(ids, auto) {
247		var params = Object.assign({}, products.filter);
248		params.ids = ids;
249		params.auto = auto;
250		service.call("multiAutoUpdate", params, products.getReturned);
251	},
252	saveMultiSalePrice: function(ids, price) {
253		var params = Object.assign({}, products.filter);
254		params.ids = ids;
255		params.price = price;
256		service.call("multiSalePrice", params, products.getReturned);
257	},
258	saveMultiShipping: function(ids, templateId) {
259		var params = Object.assign({}, products.filter);
260		params.ids = ids;
261		params.shipping = templateId;
262		service.call("multiShipping", params, products.getReturned);
263	},
264	saveMultiSeo: function(ids, metaTitle, metaTags, metaDescription, metaAlt) {
265		var params = Object.assign({}, products.filter);
266		params.ids = ids;
267		params.metaTitle = metaTitle;
268		params.metaTags = metaTags;
269		params.metaDescription = metaDescription;
270		params.metaAlt = metaAlt;
271		service.call("multiSeo", params, products.getReturned);
272	},
273	saveSkus: function(ids, sku) { 
274		var params = Object.assign({}, products.filter);
275		params.ids = ids;
276		params.sku = sku;
277		service.call("sku", params, products.getReturned);
278	},
279	saveMultiDescs: function(ids, desc) {
280		var params = Object.assign({}, products.filter);
281		params.ids = ids;
282		params.desc = desc;
283		service.call("multiDescs", params, products.getReturned);
284	},
285	saveMultiOffline: function(ids) {
286		var params = Object.assign({}, products.filter);
287		params.ids = ids;
288		service.call("multiOffline", params, products.getReturned);
289	},
290	saveMultiOnline: function(ids) {
291		var params = Object.assign({}, products.filter);
292		params.ids = ids;
293		service.call("multiOnline", params, products.getReturned);
294	},
295	metaSync: function(ids) {
296		var params = Object.assign({}, products.filter);
297		params.ids = ids;
298		service.call("sync/meta", params, products.getReturned);
299	},
300	setBlurb: function(ids, value) {
301		var params = Object.assign({}, products.filter);
302		params.ids = ids;
303		params.blurb = value;
304		service.call("multiBlurbs", params, products.getReturned);
305	},
306	setCategories: function(ids, catsToAdd, catsToRemove) {
307		var params = Object.assign({}, products.filter);
308		params.ids = ids;
309		params.catsToAdd = catsToAdd;
310		params.catsToRemove = catsToRemove;
311		service.call("productCats", params, products.getReturned);
312	},
313	setNames: function(ids, name) {
314		var params = Object.assign({}, products.filter);
315		params.ids = ids;
316		params.name = name;
317		service.call("productNames", params, products.getReturned);
318	},
319	appendNames: function(ids, prependValue, appendValue) {
320		var params = Object.assign({}, products.filter);
321		params.ids = ids;
322		params.prependValue = prependValue;
323		params.appendValue = appendValue;
324		service.call("appendNames", params, products.getReturned);
325	},
326	setColors: function(ids, color) {
327		var params = Object.assign({}, products.filter);
328		params.ids = ids;
329		params.color = color;
330		service.call("productColors", params, products.getReturned);
331	},
332	setRelayStauses: function(ids, status) {
333		var params = Object.assign({}, products.filter);
334		params.ids = ids;
335		params.status = status;
336		service.call("productRelayStatuses", params, products.getReturned);
337	},
338	setFeatures: function(ids, featured) {
339		var params = Object.assign({}, products.filter);
340		params.ids = ids;
341		params.featured = featured;
342		service.call("productFeatures", params, products.getReturned);
343	},
344	undeleteMulti: function(ids) {
345		var params = Object.assign({}, products.filter);
346		params.ids = ids;
347		params.operation = "un";
348		service.call("products", params, products.deleteReturned, "DELETE");
349	},
350	deleteMulti: function(ids) {
351		var params = Object.assign({}, products.filter);
352		params.ids = ids;
353		params.operation = "delete";
354		service.call("products", params, products.deleteReturned, "DELETE");
355	},
356    getCleaned: function(value) {
357        var toClear = [",", "'"];
358        value = value.trim();
359        value = value.toLowerCase();
360        for (var i=0; i<toClear.length; i++) {
361            value = value.split(toClear[i]).join('');
362        }
363        value = value.replace(/\W/g, ' ');
364        while (value.indexOf("  ")>=0) { 
365            value = value.split('  ').join(' ');
366        } 
367        value = value.split(' ').join('-');
368        return value;
369    },
370    getCanonical: function(product) {
371        var url = "/product/"+product.productId;
372
373        if (product.brandName) {
374            url += "/"+products.getCleaned(product.brandName);
375        }
376
377        url += "/"+products.getCleaned(product.name);
378        return url;
379    },
380	delete: function(id) {
381		var params = Object.assign({}, products.filter);
382		params.id = id;
383		params.operation = "delete";
384		service.call("product", params, products.deleteReturned, "DELET
384E");
385	},
386	undelete: function(id) {
387		var params = Object.assign({}, products.filter);
388		params.id = id;
389		params.operation = "un";
390		service.call("product", params, products.deleteReturned, "DELETE");
391	},
392	deleteReturned: function(e) {
393		$(".loader").removeClass("open");
394		if (e.error) growler.error(e.error);
395		else {
396			products.data = e.data;
397			products.total = e.total;
398			context.set("adminproducts", products.data);
399		}
400	},
401	deleteImage: function(id) {
402		service.call("image", { id: id }, (e) => {}, "DELETE"); 
403	},
404	inventory: function(type, value) {
405		service.call("inventory", { type: type, value: value }, products.inventoryReturned);
406	},
407	inventoryReturned: function(e) {
408		$(".loader").removeClass("open");
409		if (e.error) growler.error(e.error);
410		else {
411			products.results = e;
412			context.set("ricsProduct", products.results);
413		}
414	}, 
415	getOptions: function(sku, id, relay) {
416		service.call("options", { sku: sku, id: id, relay: relay }, products.storeOptionsReturned);
417	},
418	getAllProductIds: function () {
419		return new Promise((resolve, reject) => {
420			const customFilter = JSON.parse(JSON.stringify(products.filter));
421			customFilter.size = 10000;
422			// Query all products and strip out the Ids
423			service.call("products", customFilter, function (response) {
424				if (response.error) {
425					reject(response.error);
426				} else {
427					const productIds = response.data.map(product => product.productId);
428					resolve(productIds);
429				}
430			});
431		});
432	},
433	storeOptionsReturned: function(e) {
434		if (e.error) growler.error(e.error);
435		else {
436			if (page.inventoryReturned) page.inventoryReturned(e);
437			else context.set("productinventory", e);
438		}
439	},
440	getAdminOptions: function(sku, id, relay) {
441		service.call("adminoptions", { sku: sku, id: id, relay: relay }, products.storeAdminOptionsReturned);
442	},
443	storeAdminOptionsReturned: function(e) {
444		if (e.error) growler.error(e.error);
445		else context.set("admininventory", e);
446	}, 
447	refreshFromSource: function(sku) {
448		service.call("sync", { sku: sku }, products.storeAdminOptionsReturned);
449	},
450	refreshDoc: function(id) {
451		service.call("sync/description", { id: id }, products.doRefresh);
452	},
453	refreshPhoto: function(id) {
454		service.call("sync/images", { id: id }, products.doRefresh);
455	},
456	doRefresh: function(e) {
457		location.reload();
458	},
459	sourceReturned: function(e) {
460		if (e.error) growler.error(e.error);
461		else context.set("source", e);
462	},
463	refreshOptions: function(id) {
464		service.call("synconhand", { id: id }, products.optionsReturned);
465	},
466	optionsReturned: function(e) {
467		if (e.error) growler.error(e.error); 
468		else {
469			products.options = e;
470			for (var i=0; i<products.options.length; i++) {
471				if (!isNaN(Number(products.options[i].size.trim()))) {
472					products.options[i].osize = products.options[i].size;
473					products.options[i].size = Number(products.options[i].size).toFixed(1);
474				}
475			}
476			if (products.options.length>0) {
477				if (isNaN(Number(products.options[0].size))) {
478					products.options.sort((a, b) => (products.order.indexOf(a.size.toLowerCase()) > products.order.indexOf(b.size.toLowerCase())) ? 1 : -1);
479				} else {
480					products.options.sort((a, b) => (Number(a.size) > Number(b.size)) ? 1 : (Number(a.size) === Number(b.size)) ? ((a.sizeAppend > b.sizeAppend) ? 1 : -1) : -1 );
481				}
482			}
483			context.set("options", products.options);
484		}
485	},
486	next: function() {
487		if (!isLast()) products.filter.page++;
488		else products.filter.page = 1;
489		products.get();
490	},
491	prev: function() {
492		if (products.filter.page>1) products.filter.page--;
493		else products.filter.page = Math.ceil(products.total/products.filter.size);
494		products.get();
495	},
496	isLast: function() {
497		return (products.total<=(products.filter.page*products.filter.size));
498	},
499	isFirst: function() {
500		return products.filter.page==1;
501	},
502	pageTotal: function() {
503		return Math.ceil(products.total/products.filter.size);
504	},
505	goto: function(page) {
506		//if (page<=products.pageTotal()&&page>=1) {
507			products.filter.page = page;
508			products.get();
509		//} 
510	},
511	setGoogleProductSchema(product) {
512		var images = [];
513		for (var i = 0; i < product.images.length; i++) {
514			var imageItem = product.images[i];
515			var img = `${window.location.origin + imageItem.url}`;
516			if (imageItem.url.indexOf("http")==0) img = imageItem.url;
517			images.push(img);
518		}
519		var description = product.description || "";
520		var priceValidUntil = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
521		var schema =
522			{
523			  "@context": "https://schema.org/",
524			  "@type": "Product",
525			  "name": product.name,
526			  "image": images,
527			  "description": description.replace(/<[^>]*>?/gm, ''),
528			  "sku": product.sku,
529			  //"mpn": "925872",
530			  "brand": {
531				"@type": "Brand",
532				"name": product.brandName
533			  },
534			  "offers": {
535				"@type": "Offer",
536				"priceCurrency": "USD",
537				"price": product.cost.toFixed(2) + '',
538				"priceValidUntil": priceValidUntil.toISOString(),
539				"itemCondition": "https://schema.org/NewCondition",
540				"availability": "https://schema.org/InStock"
541			  }
542			}
543
544		if (product.reviewCount && product.reviewCount > 0) {
545			  schema.aggregateRating = {
546					"@type": "AggregateRating",
547					"ratingValue": product.reviewAgg + '',
548					"reviewCount": product.reviewCount + ''
549			  }
550		}
551		var script = document.createElement('script');
552		script.type = 'application/ld+json';
553		script.text = JSON.stringify(schema, null, 2);
554		document.head.appendChild(script);
555	}
556}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.