Created
October 24, 2013 23:53
-
-
Save chiplay/7147176 to your computer and use it in GitHub Desktop.
RequireJS + Backbone + Marionette + Modules
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define([ | |
'config', | |
'underscore', | |
'backbone', | |
'marionette', | |
'vent' | |
], | |
function (config, _, Backbone, Marionette, vent) { | |
var app = new Marionette.Application(); | |
app.addRegions({ | |
header: '#header', | |
main: '#main', | |
footer: '#footer' | |
}); | |
app.addInitializer(function (options) { | |
app.config = {}; | |
_.extend(app.config, config); | |
app.namespaces = options.namespaces; | |
app.router = new options.Router({ | |
controller: options.controller | |
}); | |
}); | |
app.on('initialize:after', function () { | |
if (Backbone.history) { | |
Backbone.history.start({ pushState: true }); | |
} | |
}); | |
// Get global settings from config | |
vent.reqres.setHandler('config',function(optionName){ | |
if (!optionName){ return; } | |
var value; | |
if (app.config.settings && (app.config.settings[optionName] !== undefined)){ | |
value = app.config.settings[optionName]; | |
} | |
return value; | |
}); | |
return app; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define([ | |
'app', | |
'underscore', | |
'backbone', | |
'marionette', | |
'vent' | |
], function (app, _, Backbone, Marionette, vent) { | |
var AppController = Marionette.Controller.extend({ | |
index: function() { | |
if (app.config.settings.city) { | |
this.invokeSubRoute('home'); | |
} else { | |
Backbone.history.navigate('welcome', { trigger: true }); | |
} | |
}, | |
invokeSubRoute: function(route, subroute){ | |
if (!_.contains(app.namespaces,route)) { | |
var msg = 'Route is not a defined namespace '; | |
throw new Error(msg); | |
} | |
subroute = subroute || ''; | |
// follows a /modules/product/product.js naming convention | |
require(['modules/' + route + '/' + route], | |
function(){ | |
app[route].start(); | |
}); | |
} | |
}); | |
return new AppController(); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require.config({ | |
"paths": { | |
"jquery": "libs/jquery/jquery", | |
"underscore": "libs/underscore/underscore", | |
"Handlebars": "libs/handlebars/handlebars", | |
"backbone": "libs/backbone/backbone", | |
"marionette": "libs/marionette/lib/core/amd/backbone.marionette", | |
"marionette.subapprouter": "libs/marionette.subapprouter/Marionette.SubAppRouter", | |
"backbone.wreqr": "libs/backbone.wreqr/lib/amd/backbone.wreqr", | |
"backbone.babysitter": "libs/backbone.babysitter/lib/amd/backbone.babysitter", | |
"text": "libs/text/text", | |
"hbar": "libs/requirejs-handlebars/hbars" | |
}, | |
"shim": { | |
"underscore": { | |
"exports": "_" | |
}, | |
"backbone": { | |
"deps": [ | |
"jquery", | |
"underscore" | |
], | |
"exports": "Backbone" | |
}, | |
"Handlebars": { | |
"exports": "Handlebars" | |
} | |
} | |
}); | |
require(['app','router','controller'],function(app, router, controller){ | |
var options = { | |
'controller': controller, | |
'Router': router, | |
'namespaces': [ 'welcome', 'home', 'product' ] | |
}; | |
app.start(options); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from https://github.com/relayfoods/Marionette.SubAppRouter | |
;define([ | |
'underscore', | |
'backbone', | |
'marionette' | |
], | |
/** | |
* A module that defines and adds Marionette.SubAppRouter to the Marionette object | |
* @module marionette.subapprouter | |
* @requires module:backbone | |
* @requires module:marionette | |
* @param {Function} Backbone - Backbone.js | |
* @param {Function} Marionette - Marionette.js | |
* @exports marionette | |
*/ | |
function(_, Backbone, Marionette) { | |
/** | |
* Creates an AppRouter with a particular prefix at the beginning of each route. | |
* @class Marionette.SubAppRouter | |
* @alias module:marionette.subapprouter | |
* @classdesc A router that prepends a specified prefix (passed on instantiation) onto each specified `route` or | |
* `appRoute`. Directly extends from Backbone.SubRoute, but also uses the additional logic provided by | |
* Marionette.AppRouter to enable controller objects linked to the `appRoutes` hash. Useful for sub applications | |
* that live in sub-directories under root and want to handle all of their own routing. | |
*/ | |
Marionette.SubAppRouter = Marionette.AppRouter.extend({ | |
/** | |
* @constructs Marionette.SubAppRouter | |
* @param {string} [prefix] - The prefix string to prepend to all routes, making them act as if relative. If | |
* blank, then it just acts like a regular Backbone.Router. | |
* @param {Object} [options] - The options object expected by Marionette.AppRouter. | |
* @param {Object} [options.controller] - An object with function properties corresponding to the hash values | |
* from `routes` and `appRoutes`. | |
*/ | |
constructor: function(prefix, options) { | |
var controller, | |
appRoutes, | |
routes = {}; | |
// each subapproute instance should have its own appRoutes hash | |
this.appRoutes = _.clone(this.appRoutes); | |
// Prefix is optional, set to empty string if not passed | |
this.prefix = prefix = prefix || ""; | |
// SubRoute instances may be instantiated using a prefix with or without a trailing slash. | |
// If the prefix does *not* have a trailing slash, we need to insert a slash as a separator | |
// between the prefix and the sub-route path for each route that we register with Backbone. | |
this.separator = (prefix.slice(-1) === "/") ? "" : "/"; | |
// if you want to match "books" and "books/" without creating separate routes, set this | |
// option to "true" and the sub-router will automatically create those routes for you. | |
var createTrailingSlashRoutes = options && options.createTrailingSlashRoutes; | |
if (this.appRoutes) { | |
if (options && options.controller) { | |
this.controller = options.controller; | |
} | |
_.each(this.appRoutes, function(callback, path) { | |
if (path) { | |
// Strip off any leading slashes in the sub-route path, | |
// since we already handle inserting them when needed. | |
if (path.substr(0) === "/") { | |
path = path.substr(1, path.length); | |
} | |
routes[prefix + this.separator + path] = callback; | |
if (createTrailingSlashRoutes) { | |
routes[prefix + this.separator + path + "/"] = callback; | |
} | |
} else { | |
// Default routes (those with a path equal to the empty string) | |
// are simply registered using the prefix as the route path. | |
routes[prefix] = callback; | |
if (createTrailingSlashRoutes) { | |
routes[prefix + "/"] = callback; | |
} | |
} | |
}, this); | |
// Override the local sub-routes with the fully-qualified routes that we just set up. | |
this.appRoutes = routes; | |
} | |
// Required to have Marionette AppRouter set up routes | |
Marionette.AppRouter.prototype.constructor.call(this, options); | |
// grab the full URL | |
var hash; | |
if (Backbone.history.fragment) { | |
hash = Backbone.history.getFragment(); | |
} else { | |
hash = Backbone.history.getHash(); | |
} | |
// Trigger the subroute immediately. this supports the case where | |
// a user directly navigates to a URL with a subroute on the first page load. | |
// Check every element, if one matches, break. Prevent multiple matches | |
_.every(this.appRoutes, function(key, route) { | |
// Use the Backbone parser to turn route into regex for matching | |
if (hash.match(Backbone.Router.prototype._routeToRegExp(route))) { | |
Backbone.history.loadUrl(hash); | |
return false; | |
} | |
return true; | |
}, this); | |
if (this.postInitialize) { | |
this.postInitialize(options); | |
} | |
} | |
}); | |
return Marionette; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define([ | |
'app', | |
'vent', | |
'jquery', | |
'underscore', | |
'backbone', | |
'marionette.subapprouter', | |
'common/HeaderView', | |
'common/FooterView', | |
'modules/product/Layout' | |
], function(app, vent, $, _, Backbone, Marionette, HeaderView, FooterView, LayoutView) { | |
var namespace = 'product'; | |
// Using Marionette Modules (light) to allow for simple start and stop methods | |
// with built in initializers / finalizers / events for startup and breakdown | |
app.module(namespace, function(){ | |
var Router = Marionette.SubAppRouter.extend({ | |
appRoutes: { | |
'': 'index', | |
':id': 'showProduct' | |
} | |
}); | |
var controller = { | |
index: function () { | |
this._setupLayout(); | |
}, | |
showProduct: function(id, model) { | |
var params = {}; | |
params.Productid = id; | |
if (model) params.model = model; | |
this._setupLayout(params); | |
}, | |
// ensure the layout is in place, and set it up so | |
// that the layout is removed when the layout is closed | |
_setupLayout: function(params){ | |
if (this.layout){ return; } | |
params = params || {}; | |
var _this = this; | |
this.layout = new LayoutView(params); | |
this.layout.on('close', function(){ | |
delete that.layout; | |
}); | |
app.main.show(this.layout); | |
} | |
}; | |
this.addInitializer(function(options) { | |
this.router = | |
new Router(namespace, { | |
controller: controller, | |
createTrailingSlashRoutes: true | |
}); | |
app.header.show( new HeaderView() ); | |
app.footer.show( new FooterView() ); | |
}); | |
this.addFinalizer(function(options) { | |
// tear down, shut down and clean up the module, here | |
this.options = options || {}; | |
}); | |
this.on('before:start', function () { | |
vent.trigger(namespace+':starting', this); | |
}); | |
this.on('start', function () { | |
vent.trigger(namespace+':started', this); | |
}); | |
}); | |
// Since app.module is immediately invoked and attached | |
// to the Marionette App, there is no need to return anything | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define(['marionette'], function(Marionette) { | |
var AppRouter = Marionette.AppRouter.extend({ | |
appRoutes: { | |
'': 'index', | |
':namespace(/*subroute)': 'invokeSubRoute' | |
} | |
}); | |
return AppRouter; | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
define([ | |
'backbone.wreqr', | |
'underscore' | |
], | |
function(Wreqr, _) { | |
var Vent = {}; | |
Vent = Wreqr.EventAggregator.extend({ | |
constructor: function(debug){ | |
this.commands = new Wreqr.Commands(); | |
this.reqres = new Wreqr.RequestResponse(); | |
Wreqr.EventAggregator.prototype.constructor.apply(this, arguments); | |
} | |
}); | |
_.extend(Vent.prototype, { | |
// Command execution, facilitated by Backbone.Wreqr.Commands | |
execute: function(){ | |
var args = Array.prototype.slice.apply(arguments); | |
this.commands.execute.apply(this.commands, args); | |
}, | |
// Request/response, facilitated by Backbone.Wreqr.RequestResponse | |
request: function(){ | |
var args = Array.prototype.slice.apply(arguments); | |
return this.reqres.request.apply(this.reqres, args); | |
} | |
}); | |
return new Vent(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment