PageSourceSearch

https://www.fellowes.com/_layouts/15/_Common/Responsive/Scripts/category.js?c75266fbdfc0628403a4f5327a63c879

js fellowes.com collected 2026-10-09 21:58:21 UTC 28,052 bytes, 689 lines download raw bytes

1/*
2Fellowes Category Request
3Whenever we need to make a Category related request - create this object and dispatch 
4The parameter "requestModel" passed in - the publisher is responsible to know and correctly create the model
5if the listeners require them This object matches parameters on Server side
6*/
7var FellowesCategoryRequest = function (requestModel) {
8    var self = this;
9
10    self.requestModel = requestModel;
11
12    /*
13    Build Ajax Request Post Data here so we can use it anywhere we need
14    Just remember the types 
15    EMPTY - Empty Request - Default
16    GET_CATEGORY - PropertiesToReturn if emtpy Array means all Properties
17    GET_CATEGORIES - PropertiesToReturn if emtpy Array means all Properties
18    GET_CATEGORY_PROPERTY_FILTERS 
19    */
20    self.buildAjaxData = function (type) {
21        var data = {};
22        switch (type) {
23            case "EMPTY":
24                data = "{'request':{}}";
25                break;
26            case "GET_CATEGORY":
27                data = "{'request':{},'catalogItemId':'" + self.requestModel.catalogItemId
28                    + "','level':" + (self.requestModel.level ? self.requestModel.level : 1)
29                    + ",'propertiesToReturn':" + (self.requestModel.propertiesToReturn ? ko.toJSON(self.requestModel.propertiesToReturn) : "null") + "}";
30                break;
31            case "GET_CATEGORIES":
32                data = "{'request':{},'catalogItemIds':" + ko.toJSON(self.requestModel.catalogItemIds)
33                    + "','level':" + (self.requestModel.level ? self.requestModel.level : 1)
34                    + ",'propertiesToReturn':" + (self.requestModel.propertiesToReturn ? ko.toJSON(self.requestModel.propertiesToReturn) : "null") + "}";
35                break;
36            default:
37                data = "{'request':{}}";
38        }
39        return data;
40    };
41};
42
43/*
44Fellowes Category View and Options Model
45Responsible to Bind data to different Web Controls
46*/
47var FellowesCategoryViewModel = function (ajaxCatalogItem, idx) {
48    var self = this;
49    self.idx = idx;
50    self.readyToShow = ko.observable(false);
51
52    self.catalogItemId = ko.observable(empty(ajaxCatalogItem) ? "N/A" : ajaxCatalogItem.CatalogItemId);
53    self.catalogName = "N/A";
54    self.displayName = ko.observable(empty(ajaxCatalogItem) ? "" : ajaxCatalogItem.DisplayName);
55    self.shortDescription = ko.observable();
56    self.definitionName = "N/A";
57    self.companyId = "N/A";
58
59    self.primaryParentCategoryName = "N/A";
60    self.ancestorCategoryNames = ko.observableArray([]);
61    self.parentCategoryNames = [];
62    self.productsAllowed = false;
63    self.categoriesAllowed = false;
64    self.hasChildCategories = false;
65    self.isHidden = false;
66    self.childCategories = [];
67    self.childProducts = [];
68    self.children = ko.observableArray([]);
69
70    if (typeof FellowesAssetViewModel === 'function')
71        self.heroShotCategory = ko.observable(new FellowesAssetViewModel());
72
73    //self.heroShotsCategory = ko.observableArray();
74    self.categoryList = ko.observableArray();
75    self.productList = ko.observableArray();
76    self.grandCategoryList = ko.observableArray();
77    self.grandProductList = ko.observableArray();
78
79    self.relatedItems = ko.observableArray([]);
80    self.featureOptions = ko.observableArray([]);
81
82    if (typeof FellowesVirtualModel === 'function')
83        self.virtualModel = new FellowesVirtualModel();
84
85    self.damClientModel = window.fellowesDamClient ?
86        window.fellowesDamClient.damClientModel :
87        {};
88
89    self.properties = [];
90
91    /*
92        Extended Description Extended
93        */
94    self.extendedDescription = ko.pureComputed(function () {
95        self.readyToShow();
96        var desc = self.getProperty('ExtendedDescription', fellowesCore.cultureCode, "");
97        return desc;
98    }, self);
99
100    /*
101    Short Description Extended
102    */
103    self.shortDescriptionExtended = ko.pureComputed(function () {
104        self.readyToShow();
105        var desc = self.getProperty('ShortDescriptionExtended', fellowesCore.cultureCode, "");
106        return desc;
107    }, self);
108
109    /*
110    Short Description Brief
111    */
112    self.shortDescriptionBrief = ko.pureComputed(function () {
113        self.readyToShow();
114        var desc = self.getProperty('ShortDescriptionBrief', fellowesCore.cultureCode, "");
115        return desc;
116    }, self);
117
118    /*
119    Is Featured Category
120    */
121    self.isFeatured = ko.pureComputed(function () {
122        self.readyToShow();
123        var flag = self.getProperty('FeaturedCategory', fellowesCore.cultureCode, 0);
124        return flag == 1;
125    }, self);
126
127    /*
128    Featured Children
129    */
130    self.featuredChildren = ko.pureComputed(function () {
131        return ko.utils.arrayFilter(self.children(), function (child) {
132            return child.isFeatured();
133        });
134    }, self);
135
136    /*
137    Category Url Computed
138    */
139    self.categoryUrl = ko.pureComputed(function () {
140        if (self.children().length > 0)
141            return window.str_format(FellowesAppSettings.Core.CategoryUrl, [self.catalogItemId()]);
142        else
143            return self.subCategoryUrl();
144    }, self);
145
146    /*
147    Sub Category Url Computed
148    */
149    self.subCategoryUrl = ko.pureComputed(function () {
150        switch (FellowesAppSettings.Core.CategoryLevels) {
151            case 1:
152            case 2:
153                return self.terCategoryUrl();
154                break;
155            case 3:
156            default:
157                if (self.productsAllowed) {
158                    // Possible Second Level Category Has Products
159                    return self.terCategoryUrl();
160                } else {
161                    var marketingUrl = self.marketingUrl();
162                    if (marketingUrl)
163                        return marketingUrl;
164                    // Possible Two Levels - Fill Up Missing
165                    var categoryIds = self.ancestorCategoryNames().concat([self.catalogItemId()]);
166                    if (categoryIds.length == 1) categoryIds = categoryIds.concat([""]);
167                    return window.str_format(FellowesAppSettings.Core.SubCategoryUrl, categoryIds);
168                }
169                break;
170        }
171    }, self);
172
173    /*
174    Ter Category Url Computed
175    */
176    self.terCategoryUrl = ko.pureComputed(function () {
177        var marketingUrl = self.marketingUrl();
178        if (marketingUrl)
179            return marketingUrl;
180        // Possible Three Levels - Fill Up Missing
181        var categoryIds = self.ancestorCategoryNames().concat([self.catalogItemId()]);
182        if (categoryIds.length == 2) categoryIds = categoryIds.concat([""]);
183        else if (categoryIds.length == 1) categoryIds = categoryIds.concat([""]).concat([""]);
184        return window.str_format(FellowesAppSettings.Core.TerCategoryUrl, categoryIds);
185    }, self);
186
187    /*
188    Hero Shot Computed
189    */
190    self.heroShotCategory = ko.pureComputed(function () {
191        self.readyToShow();
192        var assets = self.getProperty('HeroShotCategory', fellowesCore.cultureCode, null);
193        return new FellowesAssetViewModel(assets ? assets[0] : null, self.catalogItemId());
194    }, self);
195
196    /*
197    Featured Shot Computed
198    */
199    self.featuredShotCategory = ko.pureComputed(function () {
200        self.readyToShow();
201        var assets = self.getProperty('HeroShotCategory', fellowesCore.cultureCode, null);
202        return new FellowesAssetViewModel(assets ? assets[1] : null, self.catalogItemId());
203    }, self);
204
205    /*
206    Hero Shot Computed
207    */
208    self.bannerTemplate = ko.pureComputed(function () {
209        var categoryBanners = self.virtualModel.categoryBanners();
210        return categoryBanners && categoryBanners.length > 1 ? 'multiple' : 'single';
211    }, self);
212
213    /*
214    Calculate Marketing Url
215    */
216    self.marketingUrl = function () {
217        try {
218            var navMenuNode = fellowesNavigationMenu.lookupMenuNode(self.catalogItemId());
219            if (navMenuNode.hasMarketingUrl())
220                return navMenuNode.marketingUrl();
221        }
222        catch (ex) { }
223        return null;
224    };
225
226    /*
227    Calculate Sales Channels
228    */
229    self.salesChannels = ko.pureComputed(function () {
230        self.readyToShow();
231        return self.getProperty('SalesChannels', fellowesCore.cultureCode, []);
232    }, self);
233
234    /*
235    Category Campaigns
236    */
237    self.campaigns = ko.pureComputed(function () {
238        self.readyToShow();
239        return self.getProperty('Campaigns', null, []);
240    }, self);
241
242    /*
243    Calculate Show All Variants
244    */
245    self.showAllVariants = ko.pureComputed(function () {
246        self.readyToShow();
247        return self.getProperty('ShowAllVariants', fellowesCore.cultureCode, null);
248    }, self);
249
250    /*
251    Callback Method that updates our Category Model
252    */
253    self.hydrateCategory = function (ajaxCategory) {
254        self.catalogItemId(ajaxCategory.CatalogItemId);
255        self.catalogName = ajaxCategory.CatalogName;
256        self.displayName(ajaxCategory.DisplayName);
257        self.shortDescription(ajaxCategory.ShortDescription);
258        self.definitionName = ajaxCategory.DefinitionName;
259        self.companyId = ajaxCategory.CompanyId;
260
261        self.primaryParentCategoryName = ajaxCategory.PrimaryParentCategoryName;
262        self.ancestorCategoryNames(ajaxCategory.AncestorCategoryNames);
263        self.parentCategoryNames = ajaxCategory.ParentCategoryNames;
264        self.productsAllowed = ajaxCategory.ProductsAllowed;
265        self.categoriesAllowed = ajaxCategory.CategoriesAllowed;
266        self.hasChildCategories = ajaxCategory.HasChildCategories;
267        self.isHidden = !ajaxCategory.DisplayOnWebsite;
268        self.childCategories = ajaxCategory.ChildCategories;
269        self.childProducts = ajaxCategory.ChildProducts;
270        self.hydrateChildren(ajaxCategory.Children);
271
272        self.properties = ajaxCategory.Properties;
273
274        self.hydrateRelatedItems(ajaxCategory.RelatedItems);
275        self.hydrateFeatureOptions(ajaxCategory.FeatureOptions);
276
277        self.readyToShow(true);
278    };
279
280    /*
281    Callback Method that updates our Categories Model
282    */
283    //self.hydrateCategories = function (ajaxChildCategories) {
284    //    self.categoryList.removeAll();
285    //    $.each(ajaxChildCategories, function (index, ajaxChildCategory) {
286    //        self.categoryList.push(new FellowesCategoryViewModel(ajaxChildCategory));
287    //    });
288    //};
289
290    /*
291    Callback Method that updates our Products Model
292    */
293    //self.hydrateProducts = function (ajaxChildProducts) {
294    //    self.productList.removeAll();
295    //    $.each(ajaxChildProducts, function (index, ajaxChildProduct) {
296    //        self.productList.push(new FellowesProductViewModel(ajaxChildProduct));
297    //    });
298    //};
299
300    /*
301    Callback Method that updates Children Categories
302    */
303    self.hydrateChildren = function (ajaxChildren) {
304        if (!ajaxChildren || ajaxChildren.length == 0) return;
305        self.children.removeAll();
306        var children = [];
307        $.each(ajaxChildren, function (index, ajaxChild) {
308            children.push(new FellowesCategoryViewModel(ajaxChild, index));
309        });
310        self.children.push.apply(self.children, children);
311    };
312
313    /*
314    Callback Method that updates our Feature Options
315    */
316    self.hydrateFeatureOptions = function (ajaxFeatureOptions) {
317        if (!ajaxFeatureOptions) return;
318        self.featureOptions.removeAll();
319        var options = [];
320        $.each(ajaxFeatureOptions, function (index, ajaxFeatureOption) {
321            options.push(new FellowesChoiceOptionViewModel(ajaxFeatureOption, self.catalogItemId));
322        });
323        self.featureOptions.push.apply(self.featureOptions, options);
324    };
325
326    /*
327    Callback Method that updates our Related Items
328    */
329    self.hydrateRelatedItems = function (ajaxRelatedItems) {
330        if (!ajaxRelatedItems || ajaxRelatedItems.length == 0) return;
331        self.relatedItems.removeAll();
332        var catalogRelatedItems = [];
333        var virtualRelatedItems = [];
334        $.each(ajaxRelatedItems, function (index, ajaxRelatedItem) {
335            if (ajaxRelatedItem.DefinitionName == "VirtualProduct")
336                virtualRelatedItems.push(ajaxRelatedItem);
337            else
338                catalogRelatedItems.push(new FellowesProductViewModel(ajaxRelatedItem, self.catalogItemId));
339        });
340        self.relatedItems.push.apply(self.relatedItems, catalogRelatedItems);
341        self.virtualModel.parentId = self.catalogItemId;
342        self.virtualModel.hydrate(virtualRelatedItems);
343    };
344
345    /*
346    Callback Method that updates our Children Related Items
347    */
348    self.hydrateChildrenRelatedItems = function (ajaxChildrenRelatedItems) {
349        if (!ajaxChildrenRelatedItems) return;
350        $.each(ajaxChildrenRelatedItems, function (catalogItemId, childRelatedItems) {
351            var currentChildItem = ko.utils.arrayFirst(self.children(), function (childItem) {
352                return childItem.catalogItemId == catalogItemId;
353            });
354            if (!currentChildItem)
355                return true;
356            currentChildItem.hydrateRelatedItems(childRelatedItems);
357        });
358    };
359
360
361    /*
362    Utility Method to lookup properties
363    */
364    self.getProperty = function (propertyName, cultureCode, defaultValue) {
365        var propertyValue = null;
366        if (typeof defaultValue === "undefined") defaultValue = null;
367        if (!self.properties || !propertyName) return defaultValue;
368        $.each(self.properties, function (index, categoryProperty) {
369            if (categoryProperty.PropertyName == propertyName) {
370                if (Array.isArray(categoryProperty.Value)) {
371                    var translated = ko.utils.arrayMap(categoryProperty.Value, function (val) {
372                        var opt = fellowesCatalogProperties.lookupOption(propertyName, val);
373                        return opt && cultureCode ? opt.DisplayName : val;
374                    });
375                    propertyValue = translated;
376                    return false;
377                } else if (typeof categoryProperty.Value == "object") {
378                    propertyValue = categoryProperty.Value[cultureCode];
379                    return false;
380                } else {
381                    propertyValue = categoryProperty.Value;
382                    return false;
383                }
384            }
385        });
386        return (propertyValue === null || propertyValue === undefined) ? defaultValue : propertyValue;
387    };
388
389    // Hydrate Model if Initialized
390    if (ajaxCatalogItem)
391        self.hydrateCategory(ajaxCatalogItem);
392};
393
394/*
395Fellowes Category
396Responsible for getting data from Backend 
397and then broadcasting it to the listeners
398*/
399var FellowesCategory = function (catalogItemId, options) {
400    var self = this;
401
402    self.catalogItemId = catalogItemId;
403    self.categoryModel = new FellowesCategoryViewModel();
404    self.categoryHash = {};
405
406    self.settings = {
407        // Lookup Type - Default CategoryOnly
408        type: FellowesCatalog.RequestType.CategoryOnly,
409        // Self Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
410        selfProperties: null,
411        // Child Product Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
412        productProperties: null,
413        // Child Category Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
414        categoryProperties: null,
415        // Self Relationships ex. null for none, ["CategoryBanners"] for only defined
416        selfRelationships: null,
417        // Child Product Relationships ex. null for none, ["BuyNow"] for only defined
418        productRelationships: null,
419        // Child Category Relationships ex. null for none, ["CategoryBanners"] for only defined
420        categoryRelationships: null,
421        // Self Relationships Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
422        selfRelationshipsProperties: null,
423        // Child Product Relationships Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
424        productRelationshipsProperties: null,
425        // Child Category Relationships Properties ex. null for none, [] for all, ["SafteyFeatures"] for only defined
426        categoryRelationshipsProperties: null,
427        // Child Product Variant Properties ex. null for none, [] for all, ["Swatches"] for only defined
428        productVariantProperties: null,
429        // Proxy Url
430        proxyUrl: FellowesAppSettings.Core.CatalogProxy,
431        // Allow Root (Null) Category
432        allowRoot: false,
433        // Operation/Methods names that can be performed - matches proxy methods
434        operations: {
435            getCategory: "GetCategory",
436            getCategories: "GetCategories"
437        },
438        context: null
439    };
440
441    // Merge options into settings
442    $.extend(self.settings, options);
443
444    /*
445    Initialize - Start listening to these events from across the application
446    */
447    self.init = function (evt) {
448        Fellowes.PostBox.subscribe(self.getCategory, self, Fellowes.PostBoxMessages.Catalog.GetCategory);
449        Fellowes.PostBox.subscribe(self.getCategories, self, Fellowes.PostBoxMessages.Catalog.GetCategories);
450
451        if (typeof fellowesNavigationMenu !== "undefined" && fellowesCore.catalogSubSiteKey)
452            self.buildCategoryHash(fellowesNavigationMenu.lookupMenuNode(fellowesCore.catalogSubSiteKey));
453    };
454
455    /*
456    Load - Bootstrap our Category Models
457    */
458    self.load = function (cid, opt) {
459        self.catalogItemId = cid;
460
461        // Merge options into settings
462        $.extend(self.settings, opt);
463
464        var level = 0;
465
466        switch (self.settings.type) {
467            case FellowesCatalog.RequestType.CategoryOnly:
468                level = 1;
469                break;
470            case FellowesCatalog.RequestType.CategoryWithChildCategories:
471                level = 2;
472                break;
473            case FellowesCatalog.RequestType.CategoryWithProducts:
474                level = 1;
475                break;
476            case FellowesCatalog.RequestType.CategoryWithChildCategoriesAndProducts:
477                level = 2;
478                break;
479            case FellowesCatalog.RequestType.CategoryWithChildAndGrandCategories:
480                level = 3;
481                break;
482            case FellowesCatalog.RequestType.CategoryWithChildGrandAndGreatGrandCategories:
483                level = 4;
484                break;
485            case FellowesCatalog.RequestType.CategoryWithChildAndGrandCategoriesAndProducts:
486                level = 3;
487                break;
488            default:
489                level = 1;
490                break;
491        }
492
493        // Retrieve Current Category
494        if (self.catalogItemId || self.settings.allowRoot) {
495            var request1 = new FellowesCategoryRequest({
496                catalogItemId: self.catalogItemId,
497                level: level,
498                propertiesToReturn: self.settings.selfProperties
499            });
500            self.getCategory(request1);
501            // or send event
502            //Fellowes.PostBox.notifySubscribers(request1, Fellowes.PostBoxMessages.Catalog.GetCategory);
503        }
504
505        // Retrieve Current Category Relationships
506        if (self.catalogItemId && self.settings.selfRelationships && self.settings.selfRelationships.length > 0) {
507            var request2 = new FellowesRelationshipRequest({
508                categoryId: self.catalogItemId,
509                relationshipTypes: self.settings.selfRelationships,
510                maxItems: self.settings.selfMaxRelated,
511                propertiesToReturn: [],
512                callback: function (msg) {
513                    var json = msg;
514                    if (json && json.d) {
515                        var response = json.d;
516                        if (response.IsSuccess) {
517                            self.categoryModel.hydrateRelatedItems(response.Object);
518                            Fellowes.PostBox.notifySubscribers(response, Fellowes.PostBoxMessages.Relationship.GetCategoryRelatedItemsComplete);
519                        }
520                    }
521                }
522            });
523            Fellowes.PostBox.notifySubscribers(request2, Fellowes.PostBoxMessages.Relationship.GetCategoryRelatedItems);
524        }
525    };
526
527    /*
528    Bind the container to the Fellowes Category Model
529    Default Model is Cart
530    */
531    self.bindMe = function (container) {
532        if (window.empty(container))
533            return;
534        ko.applyBindings(self.categoryModel, container);
535    };
536
537    /*
538    Flatten & Load Catalog Categories
539    Refer to navMenu.js
540    */
541    self.buildCategoryHash = function (parentCategory) {
542        if (!parentCategory)
543            return;
544        $.each(parentCategory.childNodeIds, function (index, childNodeId) {
545            var childCategory = fellowesNavigationMenu.lookupMenuNode(childNodeId);
546            var cat = {};
547            cat.id = childCategory.id;
548            cat.url = childCategory.cleanUrl();
549            cat.name = childCategory.name;
550            self.categoryHash[cat.id] = cat;
551            self.buildCategoryHash(childCategory);
552        });
553    };
554
555    /*
556    Lookup Catalog Category basic information 
557    */
558    self.lookup = function (categoryId) {
559        if (!categoryId)
560            return null;
561        if (categoryId in self.categoryHash)
562            return self.categoryHash[categoryId];
563        return null;
564    };
565
566    /*
567    Callback Method that updates our Category(s) Model
568    */
569    self.categoryCallback = function (ajaxCategory) {
570        if (!ajaxCategory)
571            return;
572        self.categoryModel.hydrateCategory(ajaxCategory);
573        Fellowes.PostBox.notifySubscribers(self.categoryModel, Fellowes.PostBoxMessages.Catalog.CategoryModelReady);
574
575        switch (self.settings.type) {
576            case FellowesCatalog.RequestType.CategoryWithChildCategories:
577                // Retrieve Child Category Relationships
578                if (self.categoryModel.childCategories.length > 0 && self.settings.categoryRelationships && self.settings.categoryRelationships.length > 0) {
579                    var request = new FellowesRelationshipRequest({
580                        catalogItemIds: self.categoryModel.childCategories,
581                        relationshipTypes: self.settings.categoryRelationships,
582                        maxItems: self.settings.selfMaxRelated,
583                        propertiesToReturn: self.settings.categoryRelationshipsProperties,
584                        isCategoryRelated: 1,
585                        callback: function (msg) {
586                            var json = msg;
587                            if (json && json.d) {
588                                var response = json.d;
589                                if (response.IsSuccess) {
590                                    self.categoryModel.hydrateChildrenRelatedItems(response.Object);
591                                    Fellowes.PostBox.notifySubscribers(response, Fellowes.PostBoxMessages.Relationship.GetRelatedItemsComplete);
592                                }
593                            }
594                        }
595                    });
596                    Fellowes.PostBox.notifySubscribers(request, Fellowes.PostBoxMessages.Relationship.GetRelatedItems);
597                }
598                break;
599
600            case FellowesCatalog.RequestType.CategoryWithProducts:
601                if (!self.categoryModel.childProducts || self.categoryModel.childProducts.length == 0)
602                    Fellowes.PostBox.notifySubscribers({}, Fellowes.PostBoxMessages.Catalog.GetProductsFailed);
603                window.fellowesProduct.load(self.categoryModel.childProducts, {
604                    type: FellowesCatalog.RequestType.CategoryListing,
605                    parentId: self.categoryModel.catalogItemId(),
606                    selfProperties: self.settings.productProperties,
607                    selfFeaturedProperties: self.categoryModel.getProperty("CategoryFeaturedIconProperties", fellowesCore.cultureCode, []),
608                    selfRelationships: self.settings.productRelationships,
609                    selfRelationshipsProperties: self.settings.productRelationshipsProperties,
610                    variantProperties: self.settings.productVariantProperties,
611                    context: self.settings.context
612                });
613                break;
614
615            case FellowesCatalog.RequestType.CategoryWithChildCategoriesAndProducts:
616
617                break;
618
619            case FellowesCatalog.RequestType.CategoryOnly:
620            default:
621                // Do nothing - category already retrieved
622                break;
623        }
624    };
625
626    /*
627    Lookup Category
628    */
629    self.getCategory = function (fellowesCategoryRequest) {
630        var url = self.settings.proxyUrl + self.settings.operations.getCategory;
631        var data = fellowesCategoryRequest.buildAjaxData("GET_CATEGORY");
632        var successCallback = null;     // Use default - otherwise provide your own;     
633        var errorCallback = null;       // Use default - otherwise provide your own
634        self.sendRequest(url, data, Fellowes.PostBoxMessages.Catalog.GetCategoryComplete,
635            Fellowes.PostBoxMessages.Catalog.GetCategoryFailed, successCallback, errorCallback);
636    };
637
638    /*
639    Lookup Categories
640    */
641    self.getCategories = function (fellowesCategoryRequest) {
642        var url = self.settings.proxyUrl + self.settings.operations.getCategories;
643        var data = fellowesCategoryRequest.buildAjaxData("GET_CATEGORIES");
644        var successCallback = null;     // Use default - otherwise provide your own;     
645        var errorCallback = null;       // Use default - otherwise provide your own
646        self.sendRequest(url, data, Fellowes.PostBoxMessages.Catalog.getCategoriesComplete,
647            Fellowes.PostBoxMessages.Catalog.GetCategoriesFailed, successCallback, errorCallback);
648    };
649
650    /*
651    Send requests to proxy
652    */
653    self.sendRequest = function (url, data, successMessage, errorMessage, successCallback, errorCallback) {
654        $.ajax({
655            type: 'POST',
656            url: url,
657            data: data,
658            contentType: "application/json",
659            dataType: "json",
660            success: successCallback ? successCallback : function (msg) {
661                var json = msg;
662                if (json && json.d) {
663                    var response = json.d;
664                    if (response.IsSuccess && response.Object) {
665                        self.categoryCallback(response.Object);
666                        Fellowes.PostBox.notifySubscribers(response, successMessage);
667                    }
668                    else {
669                        // Got a mess
670                        Fellowes.PostBox.notifySubscribers(response, errorMessage);
671                    }
672                }
673            },
674            error: errorCallback ? errorCallback : function (qXHR, textStatus, errorThrown) {
675                // Error connecting to proxy
676                console.log(qXHR, textStatus, errorThrown);
677                var response = { "IsSuccess": false, "Message": qXHR + textStatus + errorThrown };
678                Fellowes.PostBox.notifySubscribers(response, errorMessage);
679            }
680        });
681    };
682
683    // Initialize on Instantiation
684    self.init();
685};
686
687// Override if needed in SiteHeader 
688var fellowesCategory = new FellowesCategory();
689

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.