JSFiddle - React, Tailwind, and code Playground

by Jon Jaques

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.10/backbone-min.js"></script>
<a href="#list">Pages List</a>
<a href="#list/1">Page 1 Detail</a>
<a href="#create">Create Page</a>

<br>
<br>
    
    <div id="log"><strong>LOG</strong></div>

CSS

#log {
   font-family: Menlo, monospaced;
}
#log strong {
   font-weight: bold;
   border-bottom: 1px solid black;
}

JavaScript

var userPermissions = {
  'api/pages': {
    create: true,  read: true,   update: false,   destroy: false
  },
  'api/links': {
    create: true,   read: true,  update: true,  destroy: false
  }
};

var PermRouter = Backbone.Router.extend({
  authorize: function(namedRoute) {
    if (this.permissions && this.collections) {
      var perms = this.permissions[namedRoute];
      if (!perms) {
        perms = {};
        // if nothing is specified for a particular  route, we
        // assume read access required for all registered controllers.
        _.each(_.keys(this.collections), function(key) {
          return perms[key] = [];
        });
      }

      var authorized = _.chain(perms)
        .map(function(reqPerms, collKey) {
          var collection = this.collections[collKey],
              permKey = _.result(collection, 'url');

          // We implicitly check for 'read'
          if (!_.contains('read')) {
            reqPerms.push('read');
          }

          return _.every(reqPerms, function(ability) {
            return userPermissions[permKey][ability];
          });
        }, this)
        .every(function(auth){ return auth; })
        .value();
      return authorized;
    }
    return true;
  },
  route: function(route, name, callback) {
    if (!callback) { callback = this[name]; }
    var action = function() {
      // allow anonymous routes through auth check.
      if (!name || this.authorize(name)) {
        callback.apply(this, arguments);
      } else {
        this.trigger('denied');
      }
    }
    Backbone.Router.prototype.route.call(this, route, name, action);
    return this;
  }
});

var PagesCollection = Backbone.Collection.extend({
  url: 'api/pages'
});

var LinksCollection = Backbone.Collection.extend({
  url: 'api/links'
});

var PagesController = PermRouter.extend({
  // Setup
  routes: {
    'list'     : 'list',
    'list/:id' : 'detail',
    'create'   : 'create'
  },

  // Collection are registered so we can
  // keep...