|  | /* Cranium MVC | 
        
          |  | * A minimalist MVC implementation written for | 
        
          |  | * demonstration purposes at my workshops | 
        
          |  | * http://addyosmani.com | 
        
          |  | * Copyright (c) 2012 Addy Osmani; Licensed MIT */ | 
        
          |  |  | 
        
          |  |  | 
        
          |  | var Cranium = Cranium || {}; | 
        
          |  |  | 
        
          |  | // Set DOM selection utility | 
        
          |  | var $ = document.querySelector.bind(document) || this.jQuery || this.Zepto; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Mix in to any object in order to provide it with custom events. | 
        
          |  | var Events = Cranium.Events = { | 
        
          |  | channels: {}, | 
        
          |  | eventNumber: 0, | 
        
          |  | trigger: function (events, data) { | 
        
          |  | for (var topic in Cranium.Events.channels){ | 
        
          |  | if (Cranium.Events.channels.hasOwnProperty(topic)) { | 
        
          |  | if (topic.split("-")[0] == events){ | 
        
          |  | Cranium.Events.channels[topic](data) !== false || delete Cranium.Events.channels[topic]; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } | 
        
          |  | }, | 
        
          |  | on: function (events, callback) { | 
        
          |  | Cranium.Events.channels[events + --Cranium.Events.eventNumber] = callback; | 
        
          |  | }, | 
        
          |  | off: function(topic) { | 
        
          |  | delete Cranium.Events.channels[topic]; | 
        
          |  | } | 
        
          |  | }; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Domain-related data model | 
        
          |  | var Model = Cranium.Model = function (attributes) { | 
        
          |  | this.id = _.uniqueId('model'); | 
        
          |  | this.attributes = attributes || {}; | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | Cranium.Model.prototype.get = function(attr) { | 
        
          |  | return this.attributes[attr]; | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | Cranium.Model.prototype.set = function(attrs){ | 
        
          |  | if (_.isObject(attrs)) { | 
        
          |  | _.extend(this.attributes, attrs); | 
        
          |  | this.change(attrs); | 
        
          |  | } | 
        
          |  | return this; | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | Cranium.Model.prototype.toJSON = function(options) { | 
        
          |  | return _.clone(this.attributes); | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | Cranium.Model.prototype.change = function(attrs){ | 
        
          |  | this.trigger(this.id + 'update', attrs); | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | _.extend(Cranium.Model.prototype, Cranium.Events); | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // DOM View | 
        
          |  | var View = Cranium.View = function (options) { | 
        
          |  | _.extend(this, options); | 
        
          |  | this.id = _.uniqueId('view'); | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | _.extend(Cranium.View.prototype, Cranium.Events); | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Controller tying together a model and view | 
        
          |  | var Controller = Cranium.Controller = function(options){ | 
        
          |  | _.extend(this, options); | 
        
          |  | this.id = _.uniqueId('controller'); | 
        
          |  | var parts, selector, eventType; | 
        
          |  | if(this.events){ | 
        
          |  | _.each(this.events, function(method, eventName){ | 
        
          |  | parts = eventName.split('.'); | 
        
          |  | selector = parts[0]; | 
        
          |  | eventType = parts[1]; | 
        
          |  | $(selector)['on' + eventType] = this[method]; | 
        
          |  | }.bind(this)); | 
        
          |  | } | 
        
          |  | }; |