PageSourceSearch

https://shop.johnsrunwalkshop.com/assets/scripts/models/wishlist.js?v=1.2.0

js johnsrunwalkshop.com collected 2026-09-30 09:33:08 UTC 13,610 bytes, 333 lines download raw bytes

1var wishlist = {
2    data: [],
3    isLoaded: false,
4    isShared: false,
5    ownerName: null,
6    shareUrl: null,
7    
8    init: function() {
9        // Check if viewing a shared wishlist
10        var urlParams = new URLSearchParams(window.location.search);
11        var sharedToken = urlParams.get('shared');
12        
13        if (sharedToken) {
14            // Load shared wishlist (no auth required)
15            wishlist.loadShared(sharedToken);
16        } else if (user && user.data && user.data.memberId) {
17            // Load user's own wishlist
18            wishlist.load();
19        }
20    },
21    
22    load: function(callback) {
23        service.call("wishlist", {}, function(response) {
24            if (response.error) {
25                wishlist.data = [];
26                wishlist.isLoaded = true;
27            } else {
28                wishlist.data = response.wishlist || [];
29                wishlist.isLoaded = true;
30                wishlist.isShared = false;
31            }
32            if (callback) callback(wishlist.data);
33            context.set("wishlist", wishlist.data);
34        });
35    },
36    
37    loadShared: function(token, callback) {
38        // Load someone else's wishlist via share token
39        $.ajax({
40            url: '/api/wishlist/shared?shared=' + encodeURIComponent(token),
41            type: 'GET',
42            success: function(response) {
43                if (response.error) {
44                    growler.error(response.error);
45                    wishlist.data = [];
46                    wishlist.isLoaded = true;
47                    wishlist.isShared = false;
48                } else {
49                    wishlist.data = response.wishlist || [];
50                    wishlist.isLoaded = true;
51                    wishlist.isShared = true;
52                    wishlist.ownerName = response.ownerName;
53                }
54                if (callback) callback(wishlist.data);
55            },
56            error: function() {
57                growler.error("Failed to load shared wishlist");
58                wishlist.data = [];
59                wishlist.isLoaded = true;
60                if (callback) callback([]);
61            }
62        });
63    },
64    
65    getShareUrl: function(callback) {
66        // Get share URL for current user's wishlist
67        $.ajax({
68            url: '/api/wishlist/share',
69            type: 'GET',
70            success: function(response) {
71                if (response.error) {
72                    growler.error(response.error);
73                    if (callback) callback(null);
74                } else {
75                    wishlist.shareUrl = response.shareUrl;
76                    if (callback) callback(response.shareUrl);
77                }
78            },
79            error: function() {
80                growler.error("Failed to generate share link");
81                if (callback) callback(null);
82            }
83        });
84    },
85    
86    toggle: function(productId, callback) {
87        service.call("wishlist/toggle", { productId: productId }, function(response) {
88            if (response.error) {
89                if (callback) callback({ error: response.error });
90            } else {
91                // Update local data based on server response
92                if (response.isAdded) {
93                    wishlist.addToLocal(productId);
94                    
95                    // Send Google Analytics event for add to wishlist
96                    wishlist.sendGtagEvent('add_to_wishlist', productId, response.product);
97                    
98                    // Send Facebook Pixel event for add to wishlist
99                    wishlist.sendFbqEvent('AddToWishlist', response.product);
100                    
101                    // Send Blueshift event for add to wishlist
102                    if (window.blueshift != null && response.product) {
103                        var imageUrl = '';
104                        if (response.product.url) {
105                            var imageParts = response.product.url.split('/');
106                            imageUrl = 'https://' + window.location.hostname + '/images/300/' + imageParts[imageParts.length - 1];
107                        }
108                        
109                        var blueshiftData = {
110                            product_id: response.product.sku || productId,
111                            sku: response.product.sku,
112                            title: response.product.name,
113                            price: response.product.cost,
114                            brand: response.product.brandName,
115                            image: imageUrl,
116                            category: response.product.categories,
117                            in_stock: response.product.inStock || false,
118                            stock_quantity: (response.product.stock || 0) + (response.product.relayCount || 0)
119                        };
120                        
121                        // Add color variant if available
122                        if (response.product.color) {
123                            blueshiftData.color = response.product.color;
124                        }
125                        
126                        // Add user email if available
127                        if (user && user.data && user.data.emailAddress) {
128                            blueshiftData.email = user.data.emailAddress;
129                        }
130                        
131                        blueshift.track("add_to_wishlist", blueshiftData);
132                    }
133                } else {
134                    wishlist.removeFromLocal(productId);
135                    
136                    // Send Google Analytics event for remove from wishlist
137                    wishlist.sendGtagEvent('remove_from_wishlist', productId, response.product);
138                    
139                    // Send Facebook Pixel event for remove from wishlist (custom event)
140                    wishlist.sendFbqEvent('RemoveFromWishlist', response.product);
141                    
142                    // Send Blueshift event for remove from wishlist
143                    if (window.blueshift != null && response.product) {
144                        var imageUrl = '';
145                        if (response.product.url) {
146                            var imageParts = response.product.url.split('/');
147                            imageUrl = 'https://' + window.location.hostname + '/images/300/' + imageParts[imageParts.length - 1];
148                        }
149                        
150                        var blueshiftData = {
151                            product_id: response.product.sku || productId,
152                            sku: response.product.sku,
153                            title: response.product.name,
154                            price: response.product.cost,
155                            brand: response.product.brandName,
156                            image: imageUrl,
157                            category: response.product.categories,
158                            in_stock: response.product.inStock || false,
159                            stock_quantity: (response.product.stock || 0) + (response.product.relayCount || 0)
160                        };
161                        
162                        // Add color variant if available
163                        if (response.product.color) {
164                            blueshiftData.color = response.product.color;
165                        }
166                        
167                        // Add user email if available
168                        if (user && user.data && user.data.emailAddress) {
169                            blueshiftData.email = user.data.emailAddress;
170                        }
171                        
172                        blueshift.track("remove_from_wishlist", blueshiftData);
173                    }
174                }
175                    
176                context.set("wishlist", wishlist.data);
177                if (callback) callback({ 
178                    success: true, 
179                    isAdded: response.isAdded,
180                    count: response.count 
181                });
182            }
183        });
184    },
185    
186    remove: function(productId, callback) {
187        service.call("wishlist/toggle", { productId: productId }, function(response) {
188            if (response.error) {
189                if (callback) callback({ error: response.error });
190            } else {
191                wishlist.data = wishlist.removeFromLocal(productId);
192                context.set("wishlist", wishlist.data);
193                if (callback) callback({ 
194                    success: true,
195                    count: response.count 
196                });
197            }
198        });
199    },
200    
201    has: function(productId) {
202        return wishlist.data.indexOf(parseInt(productId)) !== -1;
203    },
204    
205    count: function() {
206        return wishlist.data.length;
207    },
208    
209    addToLocal: function(productId) {
210        var id = parseInt(productId);
211        if (wishlist.data.indexOf(id) === -1) {
212            wishlist.data.push(id);
213        }
214        return wishlist.data;
215    },
216    
217    removeFromLocal: function(productId) {
218        var id = parseInt(productId);
219        var index = wishlist.data.indexOf(id);
220        if (index !== -1) {
221            wishlist.data.splice(index, 1);
222        }
223        return wishlist.data;
224    },
225    
226    sendGtagEvent: function(eventName, productId, product) {
227        // Only send if trackEvent is available
228        if (typeof trackEvent === 'undefined') {
229            return;
230        }
231        
232        // Try to get product details from current context if not provided
233        if (!product) {
234            // Check if we have product data in global scope
235            if (typeof page !== 'undefined' && page.product && page.product.productId == productId) {
236                product = page.product;
237            } 
238            // Check if we're on a product list page
239            else if (typeof products !== 'undefined' && products.data) {
240                for (var i = 0; i < products.data.length; i++) {
241                    if (products.data[i].productId == productId) {
242                        product = products.data[i];
243                        break;
244                    }
245                }
246            }
247        }
248        
249        // If we found product details, send enhanced event
250        if (product) {
251            var gtagItem = {
252                item_id: product.productId,
253                item_name: product.name,
254                item_brand: product.brandName || '',
255                item_category: product.categories && product.categories[0] ? product.categories[0].name : '',
256                price: product.price || product.cost || 0,
257                quantity: 1
258            };
259            
260            // Add variant if color is available
261            if (product.color) {
262                gtagItem.item_variant = product.color;
263            }
264            
265            // Add item list context if available (from page context)
266            if (typeof page !== 'undefined' && page.listName) {
267                gtagItem.item_list_name = page.listName;
268                gtagItem.item_list_id = page.listId || page.listName;
269            }
270            
271            var eventParams = {
272                currency: 'USD',
273                value: product.price || product.cost || 0,
274                items: [gtagItem]
275            };
276            
277            // Add user ID if available
278            if (user && user.data && user.data.memberId) {
279                eventParams.user_id = user.data.memberId.toString();
280            }
281            
282            trackEvent(eventName, eventParams);
283        } else {
284            // Send basic event without product details
285            trackEvent(eventName, {
286                item_id: productId
287            });
288        }
289    },
290    
291    sendFbqEvent: function(eventName, product) {
292        // Only send if fbq is available (Facebook Pixel is loaded)
293        if (typeof fbq === 'undefined') {
294            return;
295        }
296        
297        try {
298            if (product) {
299                var fbData = {
300                    content_name: product.name,
301                    content_category: product.categories && product.categories[0] ? product.categories[0].name || product.categories[0] : 'All Categories',
302                    content_ids: [product.sku || product.productId],
303                    content_type: 'product',
304                    value: product.cost || product.price || 0,
305                    currency: 'USD'
306                };
307                
308                // Add contents array with detailed product info
309                fbData.contents = [{
310                    id: product.sku || product.productId,
311                    quantity: 1,
312                    item_price: product.cost || product.price || 0
313                }];
314                
315                fbq('track', eventName, fbData);
316            } else {
317                // Send basic event without product details
318                fbq('track', eventName);
319            }
320        } catch (e) {
321            console.error('Facebook Pixel error:', e);
322        }
323    }
324};
325
326// Auto-initialize when user data is available
327if (typeof context !== 'undefined') {
328    context.addListener("user", function() {
329        if (user && user.data && user.data.memberId && !wishlist.isLoaded) {
330            wishlist.load();
331        }
332    });
333}

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.