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="../util/StringUtils.ts" /> /// <reference path="response/Response.ts" /> /// <reference path="decorator/PerformanceTracking.ts" /> /// <reference path="decorator/ProductListRandomizer.ts" /> /// <reference path="../base/BaseClass.ts" /> /// <reference path="context/Context.ts" /> /// <reference path="proxy/AjaxProxy.ts" /> var econda; (function (econda) { var recengine; (function (recengine) { var Context = econda.recengine.context.Context; /** * Simple recommendation request to cross sell engine. * @class econda.recengine.Request * @extends econda.base.BaseClass * * <h2>Examples</h2> * * <h3> Send request to econda recommendation service: </h3> * var request = new econda.recengine.Request({ * accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1', * widgetId: 6, * context: { * products: [{id: 'prodId1'}, {id: 'prodId2'}], * categories: [{ * type: 'brand', * path: 'econda' * }] * } * }); * request.send(); * * <h3> Get econda recommendation service properties for shop server side processing: </h3> * var request = new econda.recengine.Request({ * accountId: '00000cec-d98025a8-912b-46a4-a57d-7a691ba7a376-1', * widgetId: 6, * context: { * products: [{id: 'prodId1'}, {id: 'prodId2'}], * categories: [{ * type: 'brand', * path: 'econda' * }] * } * }); * var econdaRecoParameters = request.getRecommendationServiceParameters(); * * // Send econdaRecoParameters to shop for server side processing. * // The parameters have to be passed on to econda recommendation services. * */ var Request = (function (_super) { __extends(Request, _super); function Request(cfg) { if (cfg === void 0) { cfg = null; } _super.call(this); /** * Widget id as defined in cross sell management interface * @cfg {Number} widgetId * @accessor */ this.widgetId = null; /** * Cross Sell account id. * @cfg {String} accountId */ this.accountId = null; /** * Index of first result item. Starts with 0 * @cfg {Number} startIndex [Number=0] * @accessor */ this.startIndex = 0; /** * Max. number of results * @cfg {Number} chunkSize * @accessor */ this.chunkSize = null; /** * Context of request. * If defaultContextEnabled is set to true, this function will return this default context on first call. * If set to false, it will return null. * * @cfg {econda.recengine.context.Context} context * @accessor */ this.context = null; /** * True to enable a default context for all requests. * @cfg {boolean} [defaultContextEnabled=true] * @accessor */ this.defaultContextEnabled = true; /** * True to use the last viewed products as request context. See VisitorProfile history for details. * @cfg {Boolean} autoContext * @accessor */ this.autoContext = false; /** * Request type * @cfg {String} [type=cs] */ this.type = Request.TYPE_CROSS_SELL; /** * List of response decorators * @cfg {Array} decorators must implement IResultDecorator interface */ this.decorators = []; /** * Proxy to use for request * @cfg {String} proxy name or instance of IProxy interface * @accessor */ this.proxy = null; /** * Callback handle after successful request. * @cfg {Function} success * @accessor */ this.success = null; /** * Function to call if there was an error during cross Sell ajax request. * @cfg {Function} error * @accessor */ this._error = null; /** * milliseconds till timeout and abort * @cfg {Number} timeoutMilliseconds [Number=0] * @accessor */ this.timeoutMilliseconds = 0; /** * Function to call after request has finished (successful or not) * @cfg {Function} callback * @accessor */ this._callback = null; /** * True if last request was successfull. * @property {Boolean} requestWasSuccessful */ this.requestWasSuccessful = null; if (cfg instanceof Request) { return cfg; } else { this.initConfig(cfg); } } Request.prototype.getWidgetId = function () { return this.widgetId; }; Request.prototype.setWidgetId = function (widgetId) { this.widgetId = widgetId; return this; }; /** * Returns account id or account id of global configuration (econdaConfig.crosssellAccountId) or null if not set. * @returns String */ Request.prototype.getAccountId = function () { return this.accountId || econdaConfig.crosssellAccountId; }; /** * Set account id for this request. Setting Cross Sell accountId on global config * (econdaConfig.crosssellAccountId) might be a better place. * @param {String} accountId * @chainable */ Request.prototype.setAccountId = function (accountId) { this.accountId = accountId; return this; }; Request.prototype.getStartIndex = function () { return this.startIndex; }; Request.prototype.setStartIndex = function (index) { this.startIndex = index; return this; }; Request.prototype.getChunkSize = function () { return this.chunkSize; }; Request.prototype.setChunkSize = function (count) { this.chunkSize = count; return this; }; Request.prototype.getContext = function () { return this.defaultContextEnabled ? this.context || new Context() : this.context; }; Request.prototype.setContext = function (context) { this.context = new Context(context); return this; }; Request.prototype.getDefaultContextEnabled = function () { return this.defaultContextEnabled; }; Request.prototype.setDefaultContextEnabled = function (enabled) { this.defaultContextEnabled = (enabled === true); }; Request.prototype.getAutoContext = function () { return this.autoContext; }; Request.prototype.setAutoContext = function (autoContext) { this.autoContext = autoContext; return this; }; Request.prototype.getType = function () { return this.type; }; Request.prototype.setType = function (requestType) { if (requestType !== Request.TYPE_CROSS_SELL && requestType !== Request.TYPE_AD_REQUEST) { econda.debug.error('Trying to set invalid cross sell request type: ' + requestType); } this.type = requestType; return this; }; Request.prototype.getDecorators = function () { return this.decorators; }; Request.prototype.setDecorators = function (decorators) { var cmp = this; return this.setArray('decorators', decorators, null, { callback: function (dec) { dec.setRequest(cmp); } }); }; Request.prototype.addDecorators = function (decorators) { var cmp = this; return this.addArray('decorators', decorators, null, { callback: function (dec) { dec.setRequest(cmp); } }); }; Request.prototype.getProxy = function () { return this.proxy; }; Request.prototype.setProxy = function (proxy) { if (typeof proxy === 'string') { var className = econda.util.StringUtils.ucFirst(proxy); if (typeof econda.recengine.proxy[className] !== 'undefined') { this.proxy = new econda.recengine.proxy[className](); } else { throw 'proxy not supported: ' + proxy; } } else { this.proxy = proxy; } if (this.proxy && typeof this.proxy.setRequest !== 'undefined') { this.proxy.setRequest(this); } return this; }; Request.prototype.getSuccess = function () { return this.success; }; Request.prototype.setSuccess = function (callback) { this.success = callback; return this; }; Request.prototype.getError = function () { return this._error; }; Request.prototype.setError = function (callback) { this._error = callback; return this; }; Request.prototype.getTimeoutMilliseconds = function () { return this.timeoutMilliseconds; }; Request.prototype.setTimeoutMilliseconds = function (seconds) { this.timeoutMilliseconds = seconds; return this; }; Request.prototype.getCallback = function () { return this._callback; }; Request.prototype.setCallback = function (callback) { this._callback = callback; return this; }; /** * Send request. Set callbacks to handle result. */ Request.prototype.send = function () { var proxy = this.proxy; if (!proxy) { proxy = new econda.recengine.proxy.AjaxProxy(); proxy.setRequest(this); } this._validateAndLogErrors(); proxy.send(); }; /** * Returns recommendation service parameters * @returns {Object} parameters as expected by econda recommendation services */ Request.prototype.getRecommendationServiceParameters = function () { var proxy = this.proxy; if (!proxy) { proxy = new econda.recengine.proxy.AjaxProxy(); proxy.setRequest(this); } return proxy.getRecommendationServiceFormFieldParametersFromRequest(); }; /** * Log errors to debug * @private */ Request.prototype._validateAndLogErrors = function () { if (!this.getAccountId()) { econda.debug.error('Missing crosssell account id in request.', this); } if (!this.getWidgetId()) { econda.debug.error('Missing widget id in request', this); } }; /** * Handles response from proxy, must be called from proxy class * @param {econda.recengine.response.Response} response */ Request.prototype.handleResponse = function (response) { if (response.getIsError()) { if (typeof this._error === 'function') { this._error(); } } else { this.processResponseDecorators(response); if (typeof this.success === 'function') { this.success(response); } } if (typeof this._callback === 'function') { this._callback(response); } }; /** * Process added decorators, add default decorators * @private */ Request.prototype.processResponseDecorators = function (response) { // auto add decorators based on response data var details = response.getWidgetDetails(); var tracking = details && details.getTracking(); if (tracking && tracking.getEmcs() === true) { var source = ''; var context = this.getContext(); if (context && context.getProducts().length > 0) { source = context.getProducts()[0].getId(); } this.addDecorators(new econda.recengine.decorator.PerformanceTracking({ position: tracking.getEmcs1(), source: source, widgetName: tracking.getEmcs0() })); } // each decorator must process each product... for (var i = 0; i < this.decorators.length; i++) { this.decorators[i].decorate(response); } }; Request.TYPE_CROSS_SELL = 'cs'; Request.TYPE_AD_REQUEST = 'ac'; return Request; }(econda.base.BaseClass)); recengine.Request = Request; // end of class })(recengine = econda.recengine || (econda.recengine = {})); })(econda || (econda = {})); // end of module