rendr
Version:
Render your Backbone.js apps on the client and the server.
139 lines (118 loc) • 3.79 kB
JavaScript
/**
* Since we make rendr files AMD friendly on app setup stage
* we need to pretend that this code is pure commonjs
* means no AMD-style require calls.
*/
var BaseModel = require("./base/model"),
BaseCollection = require("./base/collection");
var typePath = {
model: "app/models/",
collection: "app/collections/"
};
module.exports = ModelUtils;
function ModelUtils(entryPath) {
this.entryPath = entryPath;
this._classMap = {};
}
ModelUtils.prototype.getModel = function(path, attrs, options, callback) {
var Model;
attrs = attrs || {};
options = options || {};
if (typeof callback == 'function') {
this.getModelConstructor(path, function(Model) {
callback(new Model(attrs, options));
});
} else {
Model = this.getModelConstructor(path);
return new Model(attrs, options);
}
};
ModelUtils.prototype.getCollection = function(path, models, options, callback) {
var Collection;
models = models || [];
options = options || {};
if (typeof callback == 'function') {
this.getCollectionConstructor(path, function(Collection) {
callback(new Collection(models, options));
});
} else {
Collection = this.getCollectionConstructor(path);
return new Collection(models, options);
}
};
ModelUtils.prototype.getModelConstructor = function(path, callback) {
return this.fetchConstructor('model', path, callback);
};
ModelUtils.prototype.getCollectionConstructor = function(path, callback) {
return this.fetchConstructor('collection', path, callback);
};
ModelUtils.prototype.getFullPath = function(type, path) {
return this.entryPath + typePath[type] + path;
};
ModelUtils.prototype.fetchConstructor = function(type, path, callback) {
path = this.underscorize(path);
var fullPath = this.getFullPath(type, path);
if (this._classMap[path]) {
return (typeof callback == 'function') ? callback(this._classMap[path]) : this._classMap[path];
} else if (typeof callback == 'function') {
// Only used in AMD environment
if (typeof define != 'undefined') {
this._requireAMD([fullPath], callback);
} else {
callback(this._require(fullPath));
}
return;
} else {
return this._require(fullPath);
}
};
ModelUtils.prototype._require = require;
ModelUtils.prototype._requireAMD = require;
ModelUtils.prototype.isModel = function(obj) {
return obj instanceof BaseModel;
};
ModelUtils.prototype.isCollection = function(obj) {
return obj instanceof BaseCollection;
};
ModelUtils.prototype.getModelNameForCollectionName = function(collectionName) {
var Collection;
Collection = this.getCollectionConstructor(collectionName);
return this.modelName(Collection.prototype.model);
};
ModelUtils.uppercaseRe = /([A-Z])/g;
ModelUtils.prototype.underscorize = function(name) {
if (name == null) {
return undefined;
}
name = name.replace(ModelUtils.uppercaseRe, function(c) {
return "_" + c.toLowerCase();
});
if (name[0] === "_") {
name = name.slice(1);
}
return name;
};
/**
* The 'name' property is added to the constructor when using a named function,
* and it cannot be changed. I.e.:
*
* function MyClass(){}
* MyClass.name
* -> "MyClass"
*
* We first look for the 'id' property of the constructor, which is compatible
* with standard Backbone-style class inheritance.
*
* var MyClass = Backbone.Model.extend({});
* MyClass.name
* -> ""
* MyClass.id = "MyClass"
*/
ModelUtils.prototype.modelName = function(modelOrCollectionClass) {
return this.underscorize(modelOrCollectionClass.id || modelOrCollectionClass.name);
};
ModelUtils.prototype.modelIdAttribute = function(modelName, callback) {
this.getModelConstructor(modelName, function(constructor) {
callback(constructor.prototype.idAttribute);
});
};