Skip to content

Instantly share code, notes, and snippets.

@tracend
Last active January 24, 2019 00:06
Show Gist options
  • Save tracend/1824154 to your computer and use it in GitHub Desktop.
Save tracend/1824154 to your computer and use it in GitHub Desktop.
[DEPRECATED] Uniform session support for Backbone.js apps Project moved: http://github.com/makesites/backbone-session

##Backbone Session

A uniform approach to session control for backbone.js apps.

Install

Using Bower:

bower install backbone.session

Usage

To load a new session, simply instantiate APP.Session :

app.session = new APP.Session();

If a remote is defined it will immediately be requested with a fetch(). Results will be saved locally and used for subsequent requests to the server.

Get info from the session like in any other Backbone Model:

app.session.get("user");
...

Options

  • local: Boolean, defining if the session will be saved locally
  • remote: Boolean, defining if a remote service will be called
  • persist: Boolean, using localStorage instead of sessionStorage (where available)

Conventions

There are a few things the plugin takes for granted and is good to note:

  • In the examples we're assuming there is an app in the global namespace.
  • Prefered api URL is "/session" (on the same domain)
  • The session is stored preferably in sessionStorage unless the persist : true in which case localStorage is used.
  • If the remote has no session an attempt will be made for the local info to be passed to the remote service.

Credits

Created by Makis Tracend ( @tracend )

Originally released as gist:1824154 (still maintained to sustain bower support...)

Distributed through Makesites.org

Released under the MIT license

/*
* Backbone Session
* Source: https://github.com/makesites/backbone-session
* Copyright © Makesites.org
*
* Initiated by Makis Tracend (@tracend)
* Distributed through [Makesites.org](http://makesites.org)
* Released under the [MIT license](http://makesites.org/licenses/MIT)
*/
(function (lib) {
//"use strict";
// Support module loaders
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define('backbone.session', ['underscore', 'backbone'], lib);
} else if ( typeof module === "object" && module && typeof module.exports === "object" ){
// Expose as module.exports in loaders that implement CommonJS module pattern.
module.exports = lib;
} else {
// Browser globals
lib(window._, window.Backbone);
}
}(function (_, Backbone) {
var APP = window.APP;
// support for Backbone APP() view if available...
var isAPP = ( typeof APP !== "undefined" && typeof APP.View !== "undefined" );
var Session = Backbone.Model.extend({
url: function(){ return this.options.host + "/session" },
defaults : {
auth: 0,
updated: 0
},
state: false,
options: {
broadcast: true,
local: true,
remote: true,
persist: false,
host: ""
},
initialize: function( model, options ){
_.bindAll(this, "logout", "cache", "update");
// default vars
options = options || {};
// parse options
this.options = _.extend(this.options, options);
// replace the whole URL if supplied
if( !_.isUndefined(options.url) ) this.url = options.url;
// pick a persistance solution
if( !this.options.persist && typeof sessionStorage != "undefined" && sessionStorage !== null ){
// choose localStorage
this.store = this.sessionStorage;
} else if( this.options.persist && typeof localStorage != "undefined" && localStorage !== null ){
// choose localStorage
this.store = this.localStorage;
} else {
// otherwise we need to store data in a cookie
this.store = this.cookie;
}
// try loading the session
var localSession = this.store.get("session");
//
if( _.isNull(localSession) || !this.options.local ){
// - no valid local session, try the server
this.fetch();
} else {
this.set( JSON.parse( localSession ) );
// reset the updated flag
this.set({ updated : 0 });
// fetch if not authenticated (every time)
if( !this.get('auth') && this.options.remote ) this.fetch();
// sync with the server ( if broadcasting local info )
if( this.options.broadcast ) this.save();
}
// event binders
this.bind("change",this.update);
this.bind("error", this.error);
this.on("logout", this.logout);
},
parse: function( data ) {
// if there is no response, keep what we've got locally
if( _.isNull(data) ) return;
// add updated flag
if( typeof data.updated == "undefined" ){
data.updated = ( new Date() ).getTime();
}
// add an id if one is not supplied
if( !data.id) data.id = this.generateUid();
return data;
},
sync: function(method, model, options) {
// fallbacks
options = options || {};
//console.log("method", method);
// intercept local store actions
switch(method){
case "read":
break;
case "update":
//this.store.set("session", JSON.stringify( model.toJSON() ) );
break;
}
// exit if explicitly noted as not calling a remote
if( !this.options["remote"] || (!this.options["broadcast"] && method != "read") ) return this.update();
return Backbone.sync.call(this, method, model, options);
},
update: function(){
// set a trigger
if( !this.state ) {
this.state = true;
this.trigger("loaded");
};
// caching is triggered after every model update (fetch/set)
if( this.get("updated") || !this.options["remote"] ){
this.cache();
}
},
cache: function(){
// update the local session
this.store.set("session", JSON.stringify( this.toJSON() ) );
// check if the object has changed locally
//...
},
// Destroy session - Source: http://backbonetutorials.com/cross-domain-sessions/
logout: function( options ) {
// Do a DELETE to /session and clear the clientside data
var self = this;
options = options || {};
// delete local version
this.store.clear("session");
// notify remote
this.destroy({
wait: true,
success: function (model, resp) {
model.clear();
model.id = null;
// Set auth to false to trigger a change:auth event
// The server also returns a new csrf token so that
// the user can relogin without refreshing the page
self.set({auth: false});
if( resp && resp._csrf) self.set({_csrf: resp._csrf});
// reload the page if needed
if( options.reload ){
window.location.reload();
}
}
});
},
// if data request fails request offline mode.
error: function( model, req, options, error ){
// consider redirecting based on statusCode
console.log( req );
},
// Stores
sessionStorage : {
get : function( name ) {
return sessionStorage.getItem( name );
},
set : function( name, val ){
// validation first?
return sessionStorage.setItem( name, val );
},
check : function( name ){
return ( sessionStorage.getItem( name ) == null );
},
clear: function( name ){
// actually just removing the session...
return sessionStorage.removeItem( name );
}
},
localStorage : {
get : function( name ) {
return localStorage.getItem( name );
},
set : function( name, val ){
// validation first?
return localStorage.setItem( name, val );
},
check : function( name ){
return ( localStorage.getItem( name ) == null );
},
clear: function( name ){
// actually just removing the session...
return localStorage.removeItem( name );
}
},
cookie : {
get : function( name ) {
var i,key,value,cookies=document.cookie.split(";");
for (i=0;i<cookies.length;i++){
key=cookies[i].substr(0,cookies[i].indexOf("="));
value=cookies[i].substr(cookies[i].indexOf("=")+1);
key=key.replace(/^\s+|\s+$/g,"");
if (key==name){
return unescape(value);
}
}
},
set : function( name, val ){
// automatically expire session in a day
var expiry = 86400000;
var date = new Date( ( new Date() ).getTime() + parseInt(expiry) );
var value=escape(val) + ((expiry==null) ? "" : "; expires="+date.toUTCString());
document.cookie=name + "=" + value;
},
check : function( name ){
var cookie=this.get( name );
if (cookie!=null && cookie!=""){
return true;
} else {
return false;
}
},
clear: function( name ) {
document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
},
// Helpers
// - Creates a unique id for identification purposes
generateUid : function (separator) {
var delim = separator || "-";
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + delim + S4() + delim + S4() + delim + S4() + delim + S4() + S4() + S4());
}
});
// fallbacks
// reference in the Backbone namespace
if( _.isUndefined( Backbone.Session) ){
Backbone.Session = Session;
}
// If there is a window object, that at least has a document property
if ( typeof window === "object" && typeof window.document === "object" ) {
// update APP namespace
if( isAPP ){
APP.Session = Session;
// save namespace
window.APP = APP;
}
// save Backbone namespace either way
window.Backbone = Backbone;
}
// for module loaders:
return Session;
}));
{
"name": "backbone.session",
"version": "0.7.0",
"main": ["./backbone.session.js"],
"dependencies": [ "backbone", "underscore", "backbone.app" ]
}
<!doctype html>
<html><head>
<meta charset="UTF-8">
<title>Backbone Session - Example</title>
</head>
<body>
<h2>Session Output</h2>
<p>This example uses a static session feed found at example.session.json. In practice you'd use a remote service that serves dynamic authentication credentials.</p>
<p>The data returned from the service are stored in SessionStorage by default, and optionally can be more persisting using LocalStorage.</p>
<p>The role of APP.Session is to sync local data with the remote service on subsequent reloads, using a PUT request.</p>
<h3>Result:</h3>
<pre id="session-info">
</pre>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>
<script type="text/javascript" src="backbone.session.js"></script>
<script type="text/javascript">
// this is the container of the application
var app = {};
// load the session (with dummy data)
app.session = new APP.Session(null, {
url: "./example.session.json"
});
// Helper
// blueprint view for outputting session info
var Info = Backbone.View.extend({
el: "#session-info",
initialize: function(){
//
_.bindAll(this, "render");
// check if the data is available
if( !_.isEmpty( this.model.toJSON() ) ){
this.render();
}
// re-render when the data updates
this.model.on( "change", this.render);
this.model.on( "sync", this.render);
},
render: function(){
// crude output
var data = JSON.stringify( this.model.toJSON() );
$( this.el).html( data );
}
});
// load a view
var view = new Info({ model : app.session });
</script>
</body>
</html>
{
"auth": 1,
"name": "MyName",
"email": "myname@mydomain.com"
}
@tracend
Copy link
Author

tracend commented Mar 3, 2013

Note: this gist is now DEPRECATED.
Project moved: http://github.com/makesites/backbone-session

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment