Using JQuery and Backbone as a simple application framework
This project is maintained by georgefrick
By extending Backbone.js Router to add, remove and manage an instance of JQuery UI Tabs; you can build a single page web application without the mess. Organize your code into "modules", and launch the modules within tabs.
Each module can be developed independently; giving the application a real 'windowed' feel on a single page. The application is focusing on kick starting applications and helping users learn backbone. From there you can use it as an application skeleton; or just a fun example to refer back to.
Backbone Routed Application Live Demo
Create a special Backbone.Router, that has the two templates needed for adding a tab to Jquery UI Tabs; the list element and the content.
Application.Router = Backbone.Router.extend({
initialize:function (options) {
this.el = options.el;
this.tabTemplate = Handlebars.loadTemplate("tab");
this.tabContentTemplate = Handlebars.loadTemplate("tabContent");
},
Create the routes; similar to struts, this will be "what urls go where"; then add a blank function so that the url never looks like my.com/my.html#thelastcommand
routes:{
"":"showHome",
"newBookList":"newBookList",
"newTodoList":"newTodoList",
"newCalculator":"newCalculator",
"closeAll":"closeAllTabs"
},
showHome:function () {
// do nothing
},
Create the addTab function. This function adds a new tab to the user interface, and returns a unique id identifying the div where the content goes.
The user can provide just a name, or everything (name, content, id)
addTab : function(tabInfo) {
var current = {
// Defaults
'name' : "New Tab",
'content' : "",
'show' : true,
'id' : Math.guid()
};
var attr, val;
var attrs = {};
// Just name passed in? or an object full of properties.
if (typeof tabInfo === 'object') {
attrs = tabInfo;
} else {
attrs.name = tabInfo;
}
// Look for passed in options that override defaults and set them.
for (attr in attrs) {
val = attrs[attr];
if (current[attr] !== undefined && !_.isEqual(current[attr], val)) {
current[attr] = val;
}
}
// Construct the new tab, consisting of the tab and the tab content.
this.el.find(".ui-tabs-nav:first").append(this.tabTemplate(current));
this.el.append(this.tabContentTemplate(current));
this.el.tabs("refresh");
// If the user opted not to show the tab, open in the background.
if (current.show) {
this.selectTabById(current.id);
}
return current.id;
},
Time to add that ability to select by id. Just look for the tab with that URL and get the parent index. This is the newer JQuery UI 1.9 way of doing it. There is also a check to make sure the tab is open.
selectTabById : function(tabId) {
var index = $('#tabs a[href="#' + tabId + '"]').parent().index();
return $("#" + tabId).length
&& $("#tabs").tabs( "option", "active",index);
},
Another example of tab manipulation; this will close everything but the 'home' tab. You could have it close that too of course.
closeAllTabs:function () {
var tabCount = $('#tabs >ul >li').size();
while (tabCount > 1) {
var tab = $( "#tabs" ).find( ".ui-tabs-nav li:eq(1)" ).remove();
var panelId = tab.attr( "aria-controls" );
$( "#" + panelId ).remove();
$( "tabs" ).tabs( "refresh" );
tabCount--;
}
Backbone.history.navigate(""); // for now.
},
Now, lets open a simple module. This calculator module can be opened as many times as the user wishes. They'll get a new calculator and can operate separately on all of them. Shown here, is the routing function that creates an instance and places it in a tab.
newCalculator:function () {
// For the calculator, we allow multiple tabs...
var tabId = "calculator-" + Math.guid();
var tabName = "Calculator";
var calc = new Calculator.CalculatorView();
var uniqueId = this.addTab({
'id' : tabId,
'name' : tabName
});
var tabContent = $("#" + uniqueId);
tabContent.empty();
tabContent.append(calc.render().el);
Backbone.history.navigate("#");
},
What about something more important; where the user can only have a single instance open? We can track the unique ID and check if it is still on the page. Other than that, creation of the tab is similar to the calculator example.
newBookList:function () {
if (!this.openBookShelf
|| ($("#" + this.openBookShelf).length == 0)) {
var tabId = "book-shelf" + Math.guid();
var tabName = "Book Shelf";
var shelf = new BookDatabase.Shelf();
this.openBookShelf = this.addTab({
'id' : tabId,
'name' : tabName
});
var tabContent = $("#" + this.openBookShelf);
tabContent.empty();
tabContent.append(shelf.render().el);
} else if (this.openBookShelf) {
this.selectTabById(this.openBookShelf);
}
Backbone.history.navigate(""); // for now.
},
});
You could very easily create a Backbone model/collection pair to track open tabs and even remember them; since the tab was opened by a URL. Also, because of this URL setup, a the user can be sent to the application with a specific tab open.
I encourage you to review the rest of the source code and even run the application. I would love any feedback.
Simply build the application with Maven and deploy to Tomcat 7.
You can contact the author (@georgefrick) through GitHub or via email at george.frick@gmail.com.