PageSourceSearch

https://intern.katholikentag.de/wilma/static/public/shop/js/productList.js

js katholikentag.de collected 2026-09-26 03:59:37 UTC 20,113 bytes, 541 lines download raw bytes

1/*
2 * FRED SHOP
3 * (C) Copyright 2016 eGenius oHG (http://www.egenius.de) and others.
4 */
5
6var app = app || {};
7var _paq = _paq || [];
8
9/*
10 *  Models 
11 */
12
13app.Catalog = Backbone.Model.extend({
14    initialize: function () {
15        this.productCategories = new app.ProductCategoryList();
16        this.products = new app.ProductList();
17        
18        // Assign the Deferred issued by fetch() as a property
19        this.deferred = this.fetch(); // calls overridden sync()        
20    },
21    sync: function (method, model, options) {
22        var catalog = this;        
23
24        var defer = $.Deferred();
25        
26        if (PebblesConfig.catalogSrc === "URL") {
27            return this.fetchFromURL(catalog, defer);
28        } else if (PebblesConfig.catalogSrc === "PebblesConfig") {
29            return this.fetchFromPebblesConfig(catalog, defer);
30        } else {
31            return this.fetchFromAPI(catalog, defer);
32        }
33    },
34    fetchFromURL: function(catalog, defer) {
35        console.log("fetching catalog from URL " + PebblesConfig.shopDataUrl);
36        $.getJSON(PebblesConfig.shopDataUrl, function( response ) {
37            PebblesConfig.storage.setItem("Pebbles.apiData", JSON.stringify(response));
38             catalog.productCategories.add(response.productCategoryListResult.productCategoryList);
39             catalog.products.add(response.productListResult.productList, {parse: true});
40
41             defer.resolve();
42        });
43        
44        return defer.promise();
45    },
46    fetchFromPebblesConfig: function(catalog, defer) {
47        console.log("using catalog from PebblesConfig");
48        catalog.productCategories.add(PebblesConfig.shopData.productCategoryListResult.productCategoryList);
49        catalog.products.add(PebblesConfig.shopData.productListResult.productList, {parse: true});
50
51        defer.resolve();
52        return defer.promise();
53    },
54    fetchFromAPI: function(catalog,defer) {
55        // try to get from cache
56        var apiCache = JSON.parse(PebblesConfig.storage.getItem("Pebbles.shopData"));
57        if (false) {
58            console.log("using catalog from cache");
59            catalog.productCategories.add(apiCache.productCategoryListResult.productCategoryList);
60            catalog.products.add(apiCache.productListResult.productList, {parse: true});
61
62            defer.resolve();
63            return defer.promise();
64        }
65        
66        // not in cache
67        console.log("fetching catalog from api");
68        $.ajax({
69            url: PebblesConfig.apiEndpoint + "/getShopData",
70            type: "POST",
71            contentType: "application/x-www-form-urlencoded",
72            dataType: "json",
73            data: {
74                eventId: PebblesConfig.eventId
75                , key: PebblesConfig.apiKey
76                , apiRequest: "{ header: {} }"
77            }
78        })
79        .done(function (response) {
80            PebblesConfig.storage.setItem("Pebbles.shopData", JSON.stringify(response));
81            catalog.productCategories.add(response.productCategoryListResult.productCategoryList);
82            catalog.products.add(response.productListResult.productList, {parse: true});
83            
84            defer.resolve();
85        });
86                
87        return defer.promise();
88    },
89    fetchProductData: function(productId) {
90        var apiRequest = {
91            header: {},
92            data: {
93                productIdFilter: productId
94            }
95        };
96
97        return $.ajax({
98            url: PebblesConfig.apiEndpoint + "/getProductList",
99            type: "POST",
100            contentType: "application/x-www-form-urlencoded",
101            dataType: "json",
102            data: {
103                eventId: PebblesConfig.eventId
104                , key: PebblesConfig.apiKey
105                , apiRequest: JSON.stringify(apiRequest)
106            }
107        })
108    }
109});
110
111app.Product = Backbone.Model.extend({
112    idAttribute: "productId",
113    initialize: function () {
114        this.updateDerivedAttributes();
115        this.on("change:priceGross", this.updateDerivedAttributes, this);
116        // because initialize is called after parse
117        _.defaults(this, {
118            productOptionList: new app.ProductOptionList
119        });
120    },
121    parse: function (response) {
122        if (_.has(response, "productOptionList")) {
123            var availableOptions = response.productOptionList.filter(function(option) {
124                return ( (!PebblesConfig.checkItemsOnStock) || (option.itemsOnStock > 0));
125            });
126            this.productOptionList = new app.ProductOptionList(availableOptions, {
127                parse: true
128            });
129            delete response.productOptionList;
130        }
131        if ( ( (!response.imageURLs) || (response.imageURLs.length<=0) ) && (PebblesConfig.isTestSystem) ) {
132            response.imageURLs = ["//placehold.it/1024x768/529223/FFFFFF.jpg?text=" + encodeURI(response.productName),
133                            "//placehold.it/1024x768/529223/FFFFFF.jpg?text=" + encodeURI(response.productName+" 2"),
134                            "//placehold.it/1024x768/529223/FFFFFF.jpg?text=" + encodeURI(response.productName+" 3"),
135                            "//placehold.it/1024x768/529223/FFFFFF.jpg?text=" + encodeURI(response.productName+" 4"),
136                            ];
137        }
138        return response;
139    },
140    toJSON: function () {
141        var json = _.clone(this.attributes);
142        json.productOptionList = this.productOptionList.toJSON();
143        json.optionObject = JSON.stringify({
144            optionId: json.productId,
145            optionAttribute: json.productOptionsAttribute,
146            optionValue: json.optionValue
147        });
148        return json;
149    },
150    get: function (attr) {
151        switch (attr) {
152            case "descriptionHtml":
153                var descriptionHtml = Backbone.Model.prototype.get.call(this, attr);                
154                if ( ( (!descriptionHtml) || (descriptionHtml.length<=0) ) && (PebblesConfig.isTestSystem) ) { 
155                    descriptionHtml = faker.lorem.paragraph() + "<br/><br/>" + faker.lorem.paragraph() + "<br/><br/>" + faker.lorem.paragraph();
156                }
157                return descriptionHtml;
158            case "teaserHtml":
159                return (PebblesConfig.isTestSystem && faker) ? faker.lorem.paragraph() : "";
160            case "recommendedProducts":
161                var products = [];
162                $(this.get("recommendedProductIds")).each(function (index, productId) {
163                    var product = app.catalog.products.get(productId);
164                    products.push(product);
165                });
166                return products;
167            default:
168                return Backbone.Model.prototype.get.call(this, attr);
169        }
170    },
171    updateDerivedAttributes: function () {
172        this.set({
173            previewImage: (this.get("imageURLs") && (this.get("imageURLs").length > 0)) ? this.get("imageURLs")[0] : null,
174            descriptionHtml: this.get("descriptionHtml"),
175            teaserHtml: this.get("teaserHtml")
176        }, {silent: true});
177    }
178});
179
180app.ProductCategory = Backbone.Model.extend({
181    idAttribute: "productCategoryId",
182    get: function (attr) {
183        switch (attr) {
184            case "products":
185                var products = [];
186                $(this.get("productIds")).each(function (index, productId) {
187                    var product = app.catalog.products.get(productId);
188                    products.push(product);
189                });
190                return products;
191            default:
192                return Backbone.Model.prototype.get.call(this, attr);
193        }
194    },
195});
196
197/*
198 *  Collections 
199 */
200
201app.ProductOptionList = Backbone.Collection.extend({
202    model: app.Product
203});
204
205app.ProductList = Backbone.PageableCollection.extend({
206    model: app.Product
207    , state: {
208        pageSize: 18
209    }
210});
211
212app.ProductCategoryList = Backbone.Collection.extend({
213    model: app.ProductCategory
214});
215
216/*
217 * Initializations
218 */
219
220// Initiate the app.catalog
221app.catalog = new app.Catalog();
222
223/*
224 *  Views 
225 */
226
227app.ProductListView = Backbone.View.extend({
228    el: $("#productListing"),   
229    gotoPage: 1,
230    navigation: "",
231    template: Handlebars.compile($("#productListTemplate").html()),
232    paginationTemplate: Handlebars.compile($("#productPaginationTemplate").html()), 
233    render: function () {
234        var view = this, rendered;
235        var state = this.collection.state;
236
237        var products = view.collection.getPage(view.gotoPage);
238        state.currentPage = view.gotoPage;
239
240        var pages = [];
241        for (var i = state.firstPage; i <= state.lastPage; i++) {
242            var page = { 
243                pageNumber: i, 
244                active: (i === state.currentPage),
245                navigation: view.navigation
246            };
247            pages.push(page);
248        }
249        
250        // 1: Product Lising
251        rendered = view.template({ 
252            products: products.toJSON()
253        });
254        $(view.el).append(rendered);
255        
256        // 2: Pagination
257        $(".product_pagination").remove();
258        if (state.lastPage > 1) {
259            rendered = view.paginationTemplate({
260                pages: pages
261            });       
262            $(view.el).after(rendered);
263        }
264
265        return view;
266    }
267});
268
269app.ProductDetailView = Backbone.View.extend({
270    el: $("#productListing"),
271    template: Handlebars.compile($("#productDetailTemplate").html()),
272    carouselTemplate: Handlebars.compile($("#recommendationCarouselTemplate").html()||""),
273    render: function () {
274        var view = this, rendered;
275        
276        app.catalog.deferred.then(function () {
277            var product = view.collection.get(view.id);
278
279            rendered = view.template(product.toJSON());
280            $(view.el).html(rendered);
281
282            if (PebblesConfig.disableCart) {
283                console.debug("shopping cart disabled - removing controls");
284                $(".item_quantity_wrap").addClass("hidden");
285                $(".product_detail_tocart").find(".btn").addClass("hidden");
286            }
287
288            var productList = new app.ProductList(product.get('recommendedProducts'), { mode: "client" });
289            const carousel = view.carouselTemplate({
290                caption: 'Empfehlungen',
291                products: productList.toJSON()
292            });
293             $(view.el).append(carousel);
294
295            PebblesConfig.setShopBackground(false);
296
297            app.breadcrumbs.levels.push({
298                name: product.get("productName")
299                , navigation: "/product/"+product.get("productId")
300            });             
301            app.breadcrumbs.render();
302
303            $(".product_pagination").remove();
304            scrollToShopHeader();
305            
306            $( "#item_option" ).selectmenu({
307                icons: { button: "countersink" }
308                , width: 250
309            });
310            
311            $( "#item_quantity" ).selectmenu({
312                icons: { button: "countersink" }
313                , width: 100
314            });
315            
316            if (PebblesConfig.trackingImplementation=="piwik") {
317                _paq.push(['setEcommerceView',
318                    product.get("productId"), // (required) SKU: Product unique identifier
319                    product.get("productName"), // (optional) Product name
320                    [], // (optional) Product category, or array of up to 5 categories
321                    product.get("priceGross") // (optional) Product Price as displayed on the page
322                ]);
323                _paq.push(["setDocumentTitle", "Shop-Artikel: "+product.get("productId")+" "+product.get("productName")]);  
324                _paq.push(['trackPageView']);
325            }
326        });
327
328        if ($("#cart_area").unstick) $("#cart_area").unstick();
329
330        return view;
331    }
332});
333
334app.ProductCategoryNavigationView = Backbone.View.extend({
335    el: $("#productCategoryNavigation"),
336    template: Handlebars.compile($("#productCategoryNavigationTemplate").html()),
337    render: function () {
338        var view = this;
339        
340        $(view.collection.models).each(function (index, category) {
341            var rendered = view.template(category.toJSON());
342            $(view.el).append(rendered);
343        });
344
345        $("#shop_nav_categories").fadeIn();
346
347        return view;
348    }
349});
350
351/*
352app.ProductCarouselView = Backbone.View.extend({
353    el: $("#productListing"),
354    template: Handlebars.compile($("#productCarouselTemplate").html()||""),
355    render: function () {
356        var view = this, rendered;
357
358        if ($("#productCarouselTemplate").length == 0) {
359            return view;
360        }
361
362        var rendered = view.template({});
363        $(view.el).append(rendered);
364
365        return view;
366    }
367});
368*/
369
370app.ProductCategoryListView = Backbone.View.extend({
371    el: $("#productListing"),
372    template: Handlebars.compile($("#productCategoryListTemplate").html()),
373    carouselTemplate: Handlebars.compile($("#highlightCarouselTemplate").html()||""), // 20220321/msc
373h: DEPRECATED
374    highlightCategoryDisplayMode: 'highlight',
375    render: function () {
376        var view = this, rendered;
377
378        $(view.el).html("");
379        PebblesConfig.setShopBackground(true);
380        $("#cart_area").show();
381
382        app.catalog.deferred.then(function () {
383            if (PebblesConfig.namespace === 'KAT') {  // 20220321/msch: DEPRECATED
384                // 1: render highlight category products in carousel
385                $(view.collection.models).each(function (index, category) {
386                    if (category.get('displayMode') !== view.highlightCategoryDisplayMode) return;
387
388                    var productList = new app.ProductList(category.get('products'), { mode: "client" });
389                    const carousel = view.carouselTemplate({
390                        products: productList.toJSON()
391                    });
392                    $(view.el).append(carousel);
393                });
394
395                // 2: append categories in overwiew
396                $(view.collection.models).each(function (index, category) {
397                    if (category.get('displayMode') === 'highlight') return;
398
399                    const rendered = view.template(category.toJSON());
400                    $(view.el).append(rendered);
401                });
402            } else {
403                const highlightCategory = view.collection.models.find(category => category.get('displayMode') === view.highlightCategoryDisplayMode);
404                const templateParam = {
405                    highlightCategory: (highlightCategory ? highlightCategory.toJSON() : null),
406                }
407
408                // load highlight products
409                if (templateParam.highlightCategory) {
410                    const productList = new app.ProductList(highlightCategory.get('products'), { mode: "client" });
411                    templateParam.highlightCategory.products = (productList ? productList.toJSON() : null);
412                }
413
414                const categoryList = view.collection.models.filter(category => category.get('displayMode') !== view.highlightCategoryDisplayMode);
415                templateParam.categoryList = (categoryList ? categoryList.flatMap(e => e.toJSON()) : null);
416
417                console.log(templateParam);
418                const rendered = view.template(templateParam);
419                $(view.el).append(rendered);
420            }
421            
422            // xmas2021 scrollToShopHeader();
423        });
424
425        $(".product_pagination").remove();
426        if ($("#cart_area").unstick) $("#cart_area").unstick();
427        
428        if (PebblesConfig.trackingImplementation=="piwik") {
429            // track page view
430            _paq.push(["setDocumentTitle", "Shop: Storefront"]);    
431            _paq.push(['trackPageView']);
432        }
433
434        return view;
435    }
436});
437
438app.ProductCategoryDetailView = Backbone.View.extend({
439    el: $("#productListing"),
440    template: Handlebars.compile($("#categoryHeaderTemplate").html()),
441    page: 1,
442    render: function () {
443        var view = this, rendered;
444        
445        $(view.el).html("");
446        PebblesConfig.setShopBackground(true);
447        $("#cart_area").show();
448
449        app.catalog.deferred.then(function () {
450            var category = view.collection.get(view.id);
451
452            rendered = view.template(category.toJSON());
453            $(view.el).append(rendered);
454
455            var products = category.get('products');
456            var productList = new app.ProductList(products, { mode: "client" });
457            var productView = new app.ProductListView({collection: productList});
458            productView.gotoPage = view.page;
459            productView.navigation = "/category/"+category.get("productCategoryId")+"/"+category.get("productCategoryNamePrettyUrl");
460            productView.render();
461            
462            app.breadcrumbs.levels = [{
463                name: category.get("productCategoryName")
464                , navigation: productView.navigation
465            }];             
466            app.breadcrumbs.render();
467            
468            // track category view
469            if (view.page===1) {
470                if (PebblesConfig.trackingImplementation=="piwik") {
471                    // on a category page, productSKU and productName are not applicable and are set to false
472                    _paq.push(['setEcommerceView',
473                        false, // productSku No product on Category page
474                        false, // productName No product on Category page
475                        category.get("productCategoryName") // category
476                    ]);
477                    _paq.push(["setDocumentTitle", "Shop-Kategorie: "+category.get("productCategoryName")]);
478                    _paq.push(['trackPageView']);
479                }
480            }
481        });
482
483        scrollToShopHeader();
484        // $("#cart_area").sticky({topSpacing: 0});
485
486        return view;
487    }
488});
489
490function scrollToShopHeader() {
491    var offset = $("#fred_shop").offset();
492    offset.left -= 20;
493    // offset.top -= 20;
494
495    window.scrollTo(offset.left, offset.top);
496}
497
498app.ProductSearch = {
499    searching: false,
500    searchString: "",
501    page: 1,
502    run: function (searchString, page) {
503        var ps = this;
504        if (ps.searching) return;
505
506        ps.searching = true;
507        ps.page = page;
508        ps.seachString = searchString;
509
510        app.catalog.deferred.then(function () {
511            var compareTo = ps.seachString.toUpperCase();
512            var findings = app.catalog.products.filter(function (model) {
513                return _.any(model.attributes, function (val, attr) {
514                    return (("" + val).toUpperCase().indexOf(compareTo) >= 0);
515                });
516            });
517            
518            app.breadcrumbs.levels = [{
519                    name: "Suche \""+ps.seachString+"\""
520                    , navigation: "/query/"+ps.seachString
521            }];
522            app.breadcrumbs.render();
523
524            scrollToShopHeader();
525
526            $("#productListing").html("");
527            PebblesConfig.setShopBackground(true);
528            $("#cart_area").show();
529
530            var productList = new app.ProductList(findings, { mode: "client" });
531            var productView = new app.ProductListView({collection: productList});
532            productView.gotoPage = ps.page;
533            productView.navigation = "/query/"+ps.seachString;
534            productView.render();
535            
536            app.router.navigate(productView.navigation);
537
538            ps.searching = false;
539        });
540    }
541};

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.