drupalbackbone.js | |
---|---|
A Child of Backbone.JS with Drupal Services defaults.
| (function($) { |
Attached to page via Drupal behaviors, for reasons of both perperness and so we can use Drupal JS setings. | Drupal.behaviors.backbone = {
attach: function() { |
Drupal.BackboneStarts with the Drupal.Backbone Constructor, currently a no-op | Drupal.Backbone = function() {}; |
Base objects for Drupal Backbone implementation. | |
Drupal.Backbone.ModelExtend the Model object with default Drupal Services settings and methods. These are defaults for interfacing with all Service module's providers. | Drupal.Backbone.Model = Backbone.Model.extend({ |
Use the Drupal Services REST format for nodes, /endpoint/{{nid}}.json. We don't include the collection stuff here, since Drupal collections are indpendent of their objects. | url: function() { |
Modified from Backbone.js to ignore collection and add ".format" extension. | var base = this.urlRoot || urlError();
if (this.isNew()) { return base; } |
Add .json for format here. | return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id) + ".json";
}
}); |
Drupal.Backbone.CollectionCurrently just sets the endpoint for all collections. TODO fix scoping issue that causes params to bleed between children of this object. e.g. if you have two NodeViewCollections, setting limit on one sets on both. | Drupal.Backbone.Collection = Backbone.Collection.extend({ |
Base endpoint, used to create full url for each collection. | restEndpoint: Drupal.settings.backbone.endpoint || "/backbone/rest", |
initialize()We bind the param functions to this on initialize, to avoid chain inheritance issues. NOTE if you subclass this and have an initialize function in your subclass, you need to execute Drupal.Backbone.Collection.initialize explicitly. | initialize: function() {
_.bindAll(this, 'setParam', 'setParams', 'getParams');
this.params = {};
}, |
paramsDrupal collections are stateful, we store params in the collection. | params: {}, |
setParam(string, string)Setter for individual params, called as setParam('name','value'). | setParam: function(paramName, paramValue) {
this.params[paramName] = paramValue;
}, |
setParams(object)Setter for multiple params, passed as object with key/value pairs. | setParams: function(params) {
if (typeof(this.params) !== 'object') {
this.params = object;
}
if (typeof(params) === 'object') {
_.extend(
this.params,
params
);
}
},
|
getParams()Getter. Currently just returns param object property. | getParams: function() {
return this.params;
}, |
fetch() implementationFetch method passes params as data in AJAX call. | fetch: function(options) {
if (options.data) { |
Allow options.data to override any params. | _.defaults(options.data, this.getParams());
}
else if (this.getParams()) {
options.data = this.getParams();
} |
Call Super fetch function with options array including any collection params. | Backbone.Collection.prototype.fetch.call(this, options);
}
}); |
Drupal.Backbone.ViewThe parent class for most rendered Drupal Backbone views, this object mainly contains functions for standardizing and abstracting calls to the template library and references to templates. It meant to be easily extended, so you can focus on logic and presentation of content types, view data etc., and minimize boilerplate code. At the same time the template engine specifics have been abstracted out, so that switching to a differen template library (such as Handlebars.js), should be as easy as overriding the compileTemplate and/or executeTemplate functions, with everything else remaining the same.
| Drupal.Backbone.View = Backbone.View.extend({
|
initializeInitialize our view by preparing the template for later rendering. This can work in either of two ways:
| initialize: function(opts) {
_.bindAll(this,
'getTemplate',
'compileTemplate',
'getTemplateSource',
'loadTemplate',
'setTemplateSource',
'getTemplate',
'executeTemplate',
'render',
'unrender'
);
if (typeof(opts) !== 'object') {
opts = {};
}
this.setTemplateSource(opts.templateSource || this.templateSource);
this.templateSelector = opts.templateSelector || this.templateSelector;
if (this.getTemplateSource()) {
this.compileTemplate();
}
}, |
compileTemplate()Compile our template code as a template object. This is using _.template(), but so long as template objects have an execute function all we should need to do is override this method to implement new template libraries. | compileTemplate: function(source) {
this.template = _.template(source || this.getTemplateSource());
}, |
executeTemplate()Wrapper around tempating library's render function. By default this is executing the template object itself, the _.template standard, this should also work for Handlebars. For other systems this may need to be overridden. | executeTemplate: function(variables) {
return this.template(variables);
}, |
getTemplateSource()Returns the source for the template. If the templateSource property is not set, it will check the templateSeclector and try to load the template from code. | getTemplateSource: function() {
if (!this.templateSource && this.templateSelector) {
this.loadTemplate(this.templateSelector);
}
return this.templateSource;
}, |
loadTemplate()Load template from jQuery object or selector. If no selector is passed, uses the templateSelector property of the view. | loadTemplate: function(selector) {
selector = selector || this.templateSelector;
if (typeof(selector) === 'object') {
this.setTemplateSource(selector.html());
}
else if (typeof(selector) === 'string') {
this.setTemplateSource($(selector).html());
}
}, |
setTemplateSource()Setter for the template source property. | setTemplateSource: function(source) {
this.templateSource = source;
},
|
getTemplate()Function to encapsulate the logic for getting the template, and loading as needed from selector or source. | getTemplate: function() {
if (!this.templateSource && this.templateObj) {
this.setTemplateSource(this.templateObj.html());
}
else if (this.templateSource) {
return this.compileTemplate(this.templateSource);
}
}, |
render()Default render function, passes entire model attributes object to template, renders using executeTemplate() method and then appends to this.el. | render: function(){
if (this.model) {
var variables = this.model.toJSON();
}
$(this.el).html(this.executeTemplate(variables)); |
return | return this;
}, |
unrender()Default unrender method, removes this.el from DOM. | unrender: function() {
$(this.el).remove();
return this;
}
}); |
Drupal.Backbone ModelsDrupal-specific models. Currently just nodes, but terms and files could follow. | |
Drupal.Backbone.NodeModelNode-specific settings for Drupal Services' node resource. | Drupal.Backbone.NodeModel = Drupal.Backbone.Model.extend({
urlRoot: "/backbone/rest/node",
idAttribute: "nid", |
Override toJSON function to nest all attributes in a { node: ... } key to make this work with the Services module implementation of node PUSH/PUT. | toJSON: function() {
var data = {
node: _.clone(this.attributes)
};
return data;
}
}); |
Drupal Backbone CollectionsSpecific collections for Drupal listing types. | |
Drupal.Backbone.NodeIndexCollectionCreate collection for Node resource's index interface. | Drupal.Backbone.NodeIndexCollection = Drupal.Backbone.Collection.extend({
model: Drupal.Backbone.NodeModel,
url: function() {
return this.restEndpoint + "/node.json";
}
}); |
Drupal.Backbone.NodeViewCollectionCreate collection for Views resource's index interface. Note that this is just for views that use the "Content" display for their nodes. Field views will need to be handled differently. May be worth considering if field views are really appropriate for backbone, since it deals with collections of model objects, and field views do not fit that mode. TODO allow view name at initialization or fetch. TODO create basic view collection, subclass node and field views. | Drupal.Backbone.NodeViewCollection = Drupal.Backbone.Collection.extend({
model: Drupal.Backbone.NodeModel, |
Name of Drupal view for this collection. | viewName: null,
url: function() {
return this.restEndpoint + "/views/" + this.viewName + ".json";
}
});
}
};
})(jQuery);
|