var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; /// <reference path="Request.ts" /> /// <reference path="widget/renderer/FunctionRenderer.ts" /> /// <reference path="widget/renderer/TemplateRenderer.ts" /> /// <reference path="widget/renderer/WebsaleRenderer.ts" /> /// <reference path="widget/IWidgetConfigOptions.ts" /> /// <reference path="../util/StringUtils.ts" /> /// <reference path="../util/DomHelper.ts" /> /// <reference path="recengine.d.ts" /> /// <reference path="../condition/ConditionContainer.ts" /> /// <reference path="../util/ArrayUtils.ts" /> /// <reference path="./widget/FallbackConfig.ts" /> /// <reference path="./widget/FallbackHandler.ts" /> var econda; (function (econda) { var recengine; (function (recengine) { /** * Cross sell widget * * The following example shows a browser only implementation of a widget. If you are looking for a server side rendering, check #setRendererUri. * * * <h4>Render Template using an html template</h4> * <div id="ecRecommendationsContainer">Loading...</div> * <script type="text/javascript"> * * // Setup widget, load data and render using defined template * var widget = new econda.recengine.Widget({ * element: document.getElementById('ecRecommendationsContainer'), * renderer: { * type: 'template', * uri: '/path/to/my/template.html' * }, * accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1', * id: 6, * context: { * products: [{id: 'prodId1'}, {id:'prodId2'}], * categories: [{ * type: 'brand', * path: 'econda' * }] * } * }); * widget.render(); * * </script> * * <h4>Render Widget using a Rendering Function</h4> * var widget = new econda.recengine.Widget({ * element: document.getElementById('ecRecommendationsContainer'), * renderer: { * type: 'function', * rendererFn: function(data, element, esc) { return 'rendered html'; } * }, * accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1', * id: 6 * }); * widget.render(); * * @class econda.recengine.Widget * @extends econda.recengine.Request */ var Widget = (function (_super) { __extends(Widget, _super); function Widget(cfg) { _super.call(this); /** * HTML container element where we'll insert the widget HTML. Node reference, id or css selector (only if jQuery is present). * Existing content will be removed. * @cfg {String|HTMLElement} element */ this.element = null; /** * Remove target {@link #cfg-element} if we have not enough products in response. * @cfg {Boolean} removeIfEmpty */ this.removeIfEmpty = false; /** * Callback if there are less recommendations than requested in response. Example: chunkSize = 4 but only 3 products in * response => callback will be executed. * @cfg {Function} * @accessor */ this.empty = null; this.setEmpty = function (fn) { this.empty = fn; return this; }; /** * Any product list with less items than are defined as empty * @cfg {Number} emptyThreshold * @accessor */ this.emptyThreshold = null; /** * Renderer configuration * @cfg {String} renderer name or instance of a class that implements IRenderer interface * @accessor */ this.renderer = null; /** * Function to call after widget was rendered * @cfg {Function} afterRender * @accessor */ this.afterRender = null; /** * If these conditions are not true, we'll not send any request but continue to fallback * @cfg {econda.condition.ConditionContainer} * @accessor */ this._preConditions = new econda.condition.ConditionContainer(); this._fallback = null; if (cfg instanceof Widget) { return cfg; } this.initConfig(cfg); } /** * Alias for {@link #widgetId}. * @cfg {Number} id * @accessor */ Widget.prototype.getId = function () { return this.getWidgetId(); }; Widget.prototype.setId = function (id) { this.setWidgetId(id); return this; }; Widget.prototype.getElement = function () { return this.element; }; Widget.prototype.setElement = function (element) { this.element = element; return this; }; Widget.prototype.getRemoveIfEmpty = function () { return this.removeIfEmpty; }; Widget.prototype.setRemoveIfEmpty = function (removeIfEmpty) { this.removeIfEmpty = removeIfEmpty; return this; }; Widget.prototype.getEmpty = function () { return this.empty; }; Widget.prototype.getEmptyThreshold = function () { return (this.emptyThreshold != null) ? this.emptyThreshold : this.chunkSize; }; Widget.prototype.setEmptyThreshold = function (itemCount) { this.emptyThreshold = itemCount; return this; }; Widget.prototype.getRenderer = function () { return this.renderer; }; Widget.prototype.setRenderer = function (renderer) { if (typeof renderer == 'string') { this.renderer = this.createAndReturnRenderer(renderer); return this; } if (renderer && renderer.type) { this.renderer = this.createAndReturnRenderer(renderer.type, renderer); return this; } this.renderer = renderer; return this; }; Widget.prototype.setAfterRender = function (fn) { this.afterRender = fn; return this; }; Widget.prototype.getAfterRender = function () { return this.afterRender; }; Widget.prototype.setPreConditions = function (conditions) { this._preConditions.clear(); this.addPreConditions(conditions); return this; }; Widget.prototype.addPreConditions = function (conditions) { if (econda.util.ArrayUtils.isArray(conditions)) { for (var n = 0; n < conditions.length; n++) { this._preConditions.add(conditions[n]); } } else { this._preConditions.add(conditions); } return this; }; Widget.prototype.setFallback = function (config) { this._fallback = new econda.recengine.widget.FallbackConfig(config); return this; }; Widget.prototype.getFallback = function () { return this._fallback; }; /** * Helper to create renderer instance * @private */ Widget.prototype.createAndReturnRenderer = function (type, cfg) { if (cfg === void 0) { cfg = null; } var className = econda.util.StringUtils.ucFirst(type) + "Renderer"; if (typeof econda.recengine.widget.renderer[className] == 'undefined') { throw "Unknown renderer type: " + type; } if (typeof cfg.type != 'undefined') { delete cfg.type; } return new econda.recengine.widget.renderer[className](cfg); }; /** * Alias for {@link #render} function. */ Widget.prototype.send = function () { _super.prototype.send.call(this); }; /** * Request recommendations and render widget */ Widget.prototype.render = function () { return this.send(); }; Widget.prototype.handleResponse = function (response) { // request will do things like calling success/error callback ... _super.prototype.handleResponse.call(this, response); // check if request was successfull if (response.getIsError() === true) { this._onErrorResponse(response); return; } // check if we got enough products in result if (response.products.length < this.getEmptyThreshold()) { this._onEmptyResponse(response); return; } this._onSuccessfulResponse(response); }; // @private Widget.prototype._onSuccessfulResponse = function (response) { var _this = this; this.requestWasSuccessful = true; // render data with configured renderer if (this.renderer) { var html = null; this.renderer.setWidget(this); html = this.renderer.render(response, function (html) { if (html !== false) { econda.util.DomHelper.update(_this.element, html); } if (typeof _this.afterRender == 'function') { _this.afterRender.call(_this, _this.requestWasSuccessful); } }); } }; // @private Widget.prototype._onErrorResponse = function (response) { var cmp = this; this.requestWasSuccessful = false; var callbackAfterFallback = function () { if (typeof this.afterRender == 'function') { cmp.afterRender.call(cmp, cmp.requestWasSuccessful); } }; this._executeFallback(false, callbackAfterFallback); }; // @private Widget.prototype._onEmptyResponse = function (response) { var cmp = this; this.requestWasSuccessful = false; var callbackAfterFallback = function () { if (typeof cmp.afterRender == 'function') { cmp.afterRender.call(cmp, cmp.requestWasSuccessful); } if (typeof cmp.empty == 'function') { cmp.empty.call(cmp, response); } }; if (this.removeIfEmpty) { econda.util.DomHelper.remove(this.element); if (typeof this.empty == 'function') { this.empty.call(this, response); } } else { this._executeFallback(true, callbackAfterFallback); } }; /// @private Widget.prototype._executeFallback = function (allowCrossSellRequests, callback) { if (allowCrossSellRequests === void 0) { allowCrossSellRequests = true; } if (callback === void 0) { callback = null; } if (this._fallback !== null) { var fallbackHandler = new econda.recengine.widget.FallbackHandler({ config: this._fallback, element: this.element, allowCrossSellRequests: allowCrossSellRequests, callback: callback }); fallbackHandler.execute(); } else { if (typeof callback == 'function') { callback({ success: false }); } } }; Widget.renderWidgetsFromConfigArray = function (configs) { for (var i = 0; i < configs.length; i++) { var w = new Widget(configs[i]); w.render(); } }; return Widget; }(recengine.Request)); recengine.Widget = Widget; // end of class /// render widgets already defined in ecWidgets array var initEcWidgets = function () { if (typeof ecWidgets != 'undefined') { Widget.renderWidgetsFromConfigArray(ecWidgets); } }; econda.util.DomHelper.isDocumentReady() ? initEcWidgets() : econda.util.DomHelper.documentReady(initEcWidgets); })(recengine = econda.recengine || (econda.recengine = {})); })(econda || (econda = {})); // end of module