Last active
December 12, 2015 06:08
-
-
Save simshanith/4727003 to your computer and use it in GitHub Desktop.
Example Backbone app JS skeleton
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>Example Backbone Skeleto</title> | |
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"> | |
<meta content="utf-8" http-equiv="encoding"> | |
<style> | |
.hidden{ | |
display: none !important; | |
} | |
.invisible { | |
visibility: hidden !important; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="blkblnkt"></div> | |
<div class="page hidden" id="exampleMixinView"></div> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.2/jquery.cookie.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/1.0.0-rc.2/lodash.underscore.min.js"></script> | |
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js "></script> | |
<script src="assets/js/init.js"></script> | |
<script src="assets/js/views.js"></script> | |
<script src="assets/js/main.js"></script> | |
</body> | |
</html> |
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
// select few global variables | |
window.app = _.extend({ | |
views: {}, | |
urls: {}, // normalized to no trailing slash; set below | |
queryStrings: {}, // params to detect as part of OAuth Flow | |
cache: {}, // set up an object for request caching | |
cookies: ['__my_cookie_key'], // list of cookie keys _.reduce'd into object from cookie values (using jQuery.cookie) | |
ajaxHistory: [], | |
}, Backbone.Events); | |
window.utils = {}; | |
window.views = {}; | |
window.api = {}; | |
app.cookies = _.reduce(app.cookies, function(memo, cookie){memo[cookie] = $.cookie(cookie); return memo;}, {}); | |
_.mixin({ // lo-dash / underscore mixins, available in _ passed into main | |
safeGet: function(obj, propName){ // Utility for safely retrieving values. Test cases: | |
if(obj && _.has(obj, propName)) // _.safeGet({foo: "bar"}, "foo") ==> "bar" | |
return obj[propName]; // _.safeGet({foo: "bar"}, "bar") ==> null | |
} // _.safeGet(undefined, "foo") ==> null | |
}); | |
// utility functions | |
utils.getAjaxHistory = function(){ | |
return _.reduce(app.ajaxHistory, | |
function(memo, item){ | |
memo += [ | |
item.url, | |
item.status, | |
item.responseHeaders, | |
'\n' | |
].join('\n'); | |
return memo; | |
}, ''); | |
}; | |
utils.fetchRootUrl = function(){ | |
var rootAnchor = document.createElement('a'); | |
rootAnchor.setAttribute('href', '/'); | |
var rootUrl = rootAnchor.href; | |
delete rootAnchor; | |
return rootUrl.slice(-1) == '/' ? rootUrl.slice(0, -1) : rootUrl; // remove trailing slash (if present) | |
} | |
utils.toProperCase = function (myString) { | |
return myString.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); | |
}; | |
utils.startRemoteDebugger = function(listenId){ | |
if(!(app.debug || listenId))return; | |
if(listenId) app.debug = listenId; | |
(function(d, s, id) { | |
var js, fjs = d.getElementsByTagName(s)[0]; | |
if (d.getElementById(id)) return; | |
js = d.createElement(s); js.id = id; | |
js.src = "http://jsconsole.com/remote.js?"+app.debug; | |
fjs.parentNode.insertBefore(js, fjs); | |
}(document, 'script', 'remoteDebugger')); | |
}; | |
utils.queryString = function(key) { | |
var re=new RegExp('(?:\\?|&)'+key+'=(.*?)(?=&|$)','gi'); | |
var r=[], m; | |
while ((m=re.exec(document.location.search)) != null) r.push(m[1]); | |
return r; | |
}; | |
// Function To Safely console.log | |
utils.safeLog = function(){ | |
var logs = arguments; | |
if(window.console&&window.console.log){ | |
for (var i=0; i<logs.length; i++) { | |
window.console.log(logs[i]); | |
} | |
} | |
}; | |
// ajax logging for remote debugging | |
$(document).ajaxSuccess(function(e, xhr, settings){ | |
utils.safeLog('ajax success', 'url: '+settings.url, xhr.getAllResponseHeaders()); | |
app.ajaxHistory.push({ | |
url: settings.url, | |
responseHeaders: xhr.getAllResponseHeaders(), | |
status: xhr.status+' '+xhr.statusText, | |
}); | |
}); | |
$(document).ajaxError(function(e, xhr, settings){ | |
utils.safeLog('ajax error', 'url: '+settings.url, xhr.getAllResponseHeaders()); | |
app.ajaxHistory.push({ | |
url: settings.url, | |
responseHeaders: xhr.getAllResponseHeaders(), | |
status: xhr.status+' '+xhr.statusText, | |
}); | |
}); | |
//*****=====~~~~- environment config | |
// find app root url based on page context | |
app.rootUrl = app.urls.appRoot = utils.fetchRootUrl(); | |
// detect environment based on root url | |
app.env = ~app.rootUrl.indexOf('local') ? 'local' : | |
~app.rootUrl.indexOf('vmldev') ? 'dev' : | |
~app.rootUrl.indexOf('vmlstage') ? 'stage' : | |
~app.rootUrl.indexOf('example.com') ? 'prod' : 'whoknows'; | |
// set urls based on environment | |
switch(app.env){ | |
case 'prod': | |
app.urls.api = 'http://example.com/api'; | |
//break; // commented out to only allow qa urls until prod is ready | |
case 'stage': | |
case 'dev': | |
case 'local' : | |
app.urls.api = 'http://dev.example.com/api'; | |
break; | |
default: | |
app.urls.api = ''; | |
} | |
//*****=====~~~~- api functions | |
app.cache.data = {}; | |
api.getData = function(term, callback){ | |
callback = _.isFunction(callback) ? callback : function(){}; | |
var results = app.cache.data[term]; | |
if(results){ | |
callback(results); | |
} else { | |
var url = app.urls.api+'/data/'+term; | |
$.ajax(url, { | |
type: 'get', | |
dataType: 'json', | |
success: function(resp){ | |
app.cache.data[term] = resp; | |
callback(resp); | |
} | |
}); | |
} | |
}; | |
/////////////////////////////////////////////////////***=~- | |
// powerful AppView Backbone.View extension class //*****=====~~~~- | |
///////////////////////////////////////////////////***=~- | |
AppView = Backbone.View.extend({ | |
isCurrentView: function(){return (views.currentView && this.cid == views.currentView.cid);}, | |
initialize: function(options){ | |
var view = this; // view setup | |
var combinedRender = options && options.render && // chained render functions | |
_.isFunction(options.render) && function(){ | |
AppView.prototype.render.apply(view, [].slice.call(arguments)); // call app level render | |
options.render.apply(view, [].slice.call(arguments)); // call view level render | |
return view; | |
} || AppView.prototype.render; // fallback to app level render | |
view.id = view.$el.prop('id'); // set id on view to view's element id | |
view.data = view.data || {}; // initialize view.data as empty object (if not already initialized) | |
// call passed initialize function, if available | |
options && _.isFunction(options.initialize) && | |
options.initialize.apply(view, [].slice.call(arguments)); | |
// wrap it all up and redefine self | |
view = _.extend(view, options, {render: combinedRender}); | |
}, | |
render: function(){ | |
// ALL VIEWS SHOULD DO THIS | |
var view = this; // local reference | |
// hide other views | |
$('div.page').not(view.el).addClass('hidden'); | |
// update reference | |
views.currentView = view; | |
// reset skeleton template | |
view.$el.html(view.template(view.data)); | |
// be sure to show this view | |
view.$el.removeClass('hidden'); | |
}, | |
}); | |
AppView.MyViewMixin = function(){ | |
return { | |
option: "defaultValue", | |
viewFunction: function(){ | |
var view = this; // mixin handles binding | |
alert("View ID:"+ view.id); | |
}, | |
events: { // you can pass in events object directly, tho it can be tricky to extend this with more events specific to the view | |
'click .mySelector': function(e){ | |
utils.safeLog(e); | |
alert('Clicked!'); | |
} | |
} | |
}; | |
}; |
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
(function($, _, Backbone, window, undefined){ | |
app.views.exampleMixinView = new AppView(_.extend(AppView.MyViewMixin(), { | |
el: $('#exampleMixinView'), | |
template: views.myTemplate, | |
render: function() { | |
var view = this; | |
view.viewFunction(); // available from mixin | |
} | |
})); | |
/* *****==~~~- | |
* APPLICATION ROUTER | |
* ******************* */ | |
AppRouter = Backbone.Router.extend({ | |
routes: { | |
'*path' : 'defaultRoute' | |
}, | |
defaultRoute: function(){ | |
app.views.exampleMixinView.data = {foo: '<button class="mySelector">Click Me</button>'}; | |
app.views.exampleMixinView.render(); | |
} | |
}); | |
$(function(){ // on ready | |
app.router = new AppRouter(); | |
Backbone.history.start(); | |
utils.safeLog('Application Initialized', app); | |
api.getData('manbearpig'); | |
}); | |
})(jQuery, _, Backbone, this) |
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
views.myTemplate = _.template('<div><%= foo %></div>'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment