UNPKG

lazo-next

Version:

A client-server web framework built on Node.js that allows front-end developers to easily create a 100% SEO compliant, component MVC structured web application with an optimized first page load.

273 lines (219 loc) 12.4 kB
define(['underscore', 'backbone', 'proxy', 'resolver/model', 'async', 'utils/dataschema-json'], function (_, Backbone, Proxy, helpers, async, SchemaJSON) { 'use strict'; /** * A base class for models * * @class LazoModel * @constructor * @param {Object} attributes A hash of name-value pairs that will be the model's state * @param {Object} options * @param {String} options.name The name of the model in the repo * @param {Object} options.params A hash of name-value pairs used in url substitution * @param {Context} options.ctx The current context for the request * @extends Backbone.Model */ var LazoModel = Backbone.Model.extend({ constructor: function (attributes, options) { this._initialize(attributes, options); Backbone.Model.apply(this, arguments); }, save: function (key, val, options) { var attrs; // Handle both `"key", value` and `{key: value}` -style arguments. if (key == null || typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } options || (options = {}); if (options.persist === false) { // no-op, just skip the saving. return; } if (options.syncDataFromChildren !== false && this.modelsSchema && this.modelsSchema.length > 0) { for (var i = 0, il = this.modelsSchema.length; i < il; i++) { var schema = this.modelsSchema[i], paths = SchemaJSON.getPath(schema.locator), parentData; if (paths && paths.length && this[schema.prop]) { (parentData = {})[paths[0]] = this.get(paths[0]); SchemaJSON.setLocationValue(schema.locator, parentData, this[schema.prop].toJSON()); } } } return Backbone.Model.prototype.save.apply(this, arguments); }, set: function (key, val, options) { var attr, attrs; if (Backbone.Model.prototype.set.apply(this, arguments) == false) return false; // Handle both `"key", value` and `{key: value}` -style arguments. if (typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } options || (options = {}); if (key === null || !this.modelsSchema || options.syncDataToChildren === false) return this; for (attr in attrs) { for (var i = 0, il = this.modelsSchema.length; i < il; i++) { var schema = this.modelsSchema[i], paths = SchemaJSON.getPath(schema.locator); // if an attribute being set is part of a schema definition, set the data into the child model if (attr == paths[0] && this[schema.prop]) { var submodeldata = SchemaJSON.apply({resultListLocator: schema.locator}, attrs); this[schema.prop].set(submodeldata.results); } } } return this; }, sync: function (method, model, options) { var self = this, success = options.success; options.success = function (resp) { self._resp = resp; if (success) { success(resp); } }; //ignoring model since this==model passed by backbone sync return Proxy.prototype.sync.call(this, method, options); }, call: function (fname, args, options) { Proxy.prototype.callSyncher.call(this, fname, args, options); }, _initialize: function (attributes, options) { if (options.name) { this.name = options.name; } this.params = options.params; this.ctx = options.ctx; }, _getGlobalId: function () { return LazoModel._getGlobalId(this.name, this.params); } }, { _serialize: function (models, serModelObj) { _.each(models, function (value, key, list) { serModelObj[key] = value._getGlobalId(); }); }, _deserialize: function (ctl, _rootCtx, options) { LAZO.require(['utils/modelLoader'], function (modelLoader) { var processModel = function (processFuncs, value, key, type, child) { var glMdlMeta = _rootCtx.modelList[value], modelInstances = _rootCtx.modelInstances; processFuncs[processFuncs.length] = function (asyncCb) { var gid = LazoModel._getGlobalId(glMdlMeta.name, glMdlMeta.params); function checkProcessing() { if (modelInstances[gid].processing) { setTimeout(checkProcessing, 50); } else { ctl.ctx[type + 's'][key] = modelInstances[gid]; asyncCb(null, modelInstances[gid]); } return; } if (modelInstances[gid]) { checkProcessing(); return; } else { modelInstances[gid] = {}; modelInstances[gid].processing = true; var _initModel = function (Model, _default) { var m = new Model(glMdlMeta.data, {name: glMdlMeta.name, ctx: ctl.ctx, params: glMdlMeta.params, parse: true}); modelInstances[gid] = m; m.cid = glMdlMeta.cid; m._default = _default; if (glMdlMeta.idMap) { _.each(glMdlMeta.idMap, function (elem) { var modelItem = m.get(elem.id); if (modelItem) { modelItem.cid = elem.cid; } }); } ctl.ctx[type + 's'][key] = m; if (child && child.parentModel) { m.lazoParent = child.parentModel; child.parentModel.lazoChildren = child.parentModel.lazoChildren || {}; child.parentModel.lazoChildren[glMdlMeta.name] = m; if (child.schema && child.schema.prop) { child.parentModel[child.schema.prop] = m; child.parentModel._childNames = child.parentModel._childNames || []; child.parentModel._childNames.push(child.schema.prop); } } if (m.modelsSchema) { var subtasks = []; _.each(m.modelsSchema, function (modelSchemaDef) { var subgid = LazoModel._getGlobalId(modelSchemaDef.name, glMdlMeta.params), submodeldata = _rootCtx.modelList[subgid].data, subtype = _.isArray(submodeldata) ? 'collection' : 'model'; processModel(subtasks, subgid, modelSchemaDef.name, subtype, { parentModel: m, data: submodeldata, schema: modelSchemaDef }); }); async.parallel(subtasks, function (err, results) { return asyncCb(null, m); }); } else { return asyncCb(null, m); } }; modelLoader(glMdlMeta.name, type, _initModel); } }; }; var mdlFuncs = []; // models _.each(ctl.ctx.models, function (value, key, list) { processModel(mdlFuncs, value, key, 'model'); }); // collections _.each(ctl.ctx.collections, function (value, key, list) { processModel(mdlFuncs, value, key, 'collection'); }); // load models and collections in parallel async.parallel( mdlFuncs, function (err, results) { if (err) { return options.error(err); } return options.success(); } ); }); }, _getGlobalId: function (modelName, params) { var globalModelId = 'GET:'+modelName; if (modelName.indexOf("u:") === 0 || modelName.indexOf("http") === 0) { if (params) { globalModelId = helpers.substitute(globalModelId, params); } } else { if (params) { var props = _.keys(params); props.sort(); _.each(props, function(element, index, list) { globalModelId = globalModelId + "|" + element + "=" + params[element]; }); } } return globalModelId; } } ); return LazoModel; });