cdn/model-v0.2.4.js
function Model(defaults){

    // Make sure "new" is always used,
    // so we can use "instanceof" to check if something is a Model.
    if (!(this instanceof Model)) {
      return new Model(defaults);
    }

    // `model` is the public API object returned from invoking `new Model()`.
    var model = this,

        // The internal stored values for tracked properties. { property -> value }
        values = {},

        // The callback functions for each tracked property. { property -> [callback] }
        listeners = {},

        // The set of tracked properties. { property -> true }
        trackedProperties = {};

    // The functional reactive "when" operator.
    //
    //  * `properties` An array of property names (can also be a single property string).
    //  * `callback` A callback function that is called:
    //    * with property values as arguments, ordered corresponding to the properties array,
    //    * only if all specified properties have values,
    //    * once for initialization,
    //    * whenever one or more specified properties change,
    //    * on the next tick of the JavaScript event loop after properties change,
    //    * only once as a result of one or more synchronous changes to dependency properties.
    function when(properties, callback, thisArg){
      
      // Make sure the default `this` becomes 
      // the object you called `.on` on.
      thisArg = thisArg || this;

      // Handle either an array or a single string.
      properties = (properties instanceof Array) ? properties : [properties];

      // This function will trigger the callback to be invoked.
      var listener = debounce(function (){
        var args = properties.map(function(property){
          return values[property];
        });
        if(allAreDefined(args)){
          callback.apply(thisArg, args);
        }
      });

      // Trigger the callback once for initialization.
      listener();
      
      // Trigger the callback whenever specified properties change.
      properties.forEach(function(property){
        on(property, listener);
      });

      // Return this function so it can be removed later with `model.cancel(listener)`.
      return listener;
    }

    // Adds a change listener for a given property with Backbone-like behavior.
    // Similar to http://backbonejs.org/#Events-on
    function on(property, callback, thisArg){
      thisArg = thisArg || this;
      getListeners(property).push(callback);
      track(property, thisArg);
    }
    
    // Gets or creates the array of listener functions for a given property.
    function getListeners(property){
      return listeners[property] || (listeners[property] = []);
    }

    // Tracks a property if it is not already tracked.
    function track(property, thisArg){
      if(!(property in trackedProperties)){
        trackedProperties[property] = true;
        values[property] = model[property];
        Object.defineProperty(model, property, {
          get: function () { return values[property]; },
          set: function(newValue) {
            var oldValue = values[property];
            values[property] = newValue;
            getListeners(property).forEach(function(callback){
              callback.call(thisArg, newValue, oldValue);
            });
          }
        });
      }
    }

    // Cancels a listener returned by a call to `model.when(...)`.
    function cancel(listener){
      for(var property in listeners){
        off(property, listener);
      }
    }

    // Removes a change listener added using `on`.
    function off(property, callback){
      listeners[property] = listeners[property].filter(function (listener) {
        return listener !== callback;
      });
    }

    // Sets all of the given values on the model.
    // `newValues` is an object { property -> value }.
    function set(newValues){
      for(var property in newValues){
        model[property] = newValues[property];
      }
    }

    // Transfer defaults passed into the constructor to the model.
    set(defaults);

    // Public API.
    model.when = when;
    model.cancel = cancel;
    model.on = on;
    model.off = off;
    model.set = set;
  }
function Model(defaults){

    // Make sure "new" is always used,
    // so we can use "instanceof" to check if something is a Model.
    if (!(this instanceof Model)) {
      return new Model(defaults);
    }

    // `model` is the public API object returned from invoking `new Model()`.
    var model = this,

        // The internal stored values for tracked properties. { property -> value }
        values = {},

        // The callback functions for each tracked property. { property -> [callback] }
        listeners = {},

        // The set of tracked properties. { property -> true }
        trackedProperties = {};

    // The functional reactive "when" operator.
    //
    //  * `properties` An array of property names (can also be a single property string).
    //  * `callback` A callback function that is called:
    //    * with property values as arguments, ordered corresponding to the properties array,
    //    * only if all specified properties have values,
    //    * once for initialization,
    //    * whenever one or more specified properties change,
    //    * on the next tick of the JavaScript event loop after properties change,
    //    * only once as a result of one or more synchronous changes to dependency properties.
    function when(properties, callback, thisArg){
      
      // Make sure the default `this` becomes 
      // the object you called `.on` on.
      thisArg = thisArg || this;

      // Handle either an array or a single string.
      properties = (properties instanceof Array) ? properties : [properties];

      // This function will trigger the callback to be invoked.
      var listener = debounce(function (){
        var args = properties.map(function(property){
          return values[property];
        });
        if(allAreDefined(args)){
          callback.apply(thisArg, args);
        }
      });

      // Trigger the callback once for initialization.
      listener();
      
      // Trigger the callback whenever specified properties change.
      properties.forEach(function(property){
        on(property, listener);
      });

      // Return this function so it can be removed later with `model.cancel(listener)`.
      return listener;
    }

    // Adds a change listener for a given property with Backbone-like behavior.
    // Similar to http://backbonejs.org/#Events-on
    function on(property, callback, thisArg){
      thisArg = thisArg || this;
      getListeners(property).push(callback);
      track(property, thisArg);
    }
    
    // Gets or creates the array of listener functions for a given property.
    function getListeners(property){
      return listeners[property] || (listeners[property] = []);
    }

    // Tracks a property if it is not already tracked.
    function track(property, thisArg){
      if(!(property in trackedProperties)){
        trackedProperties[property] = true;
        values[property] = model[property];
        Object.defineProperty(model, property, {
          get: function () { return values[property]; },
          set: function(newValue) {
            var oldValue = values[property];
            values[property] = newValue;
            getListeners(property).forEach(function(callback){
              callback.call(thisArg, newValue, oldValue);
            });
          }
        });
      }
    }

    // Cancels a listener returned by a call to `model.when(...)`.
    function cancel(listener){
      for(var property in listeners){
        off(property, listener);
      }
    }

    // Removes a change listener added using `on`.
    function off(property, callback){
      listeners[property] = listeners[property].filter(function (listener) {
        return listener !== callback;
      });
    }

    // Sets all of the given values on the model.
    // `newValues` is an object { property -> value }.
    function set(newValues){
      for(var property in newValues){
        model[property] = newValues[property];
      }
    }

    // Transfer defaults passed into the constructor to the model.
    set(defaults);

    // Public API.
    model.when = when;
    model.cancel = cancel;
    model.on = on;
    model.off = off;
    model.set = set;
  }
function Model ( defaults ) { // Make sure "new" is always used, // so we can use "instanceof" to check if something is a Model. if ( ! ( this instanceof Model ) ) { return new Model ( defaults ) ; } // `model` is the public API object returned from invoking `new Model()`. var model = this , // The internal stored values for tracked properties. { property -> value } values = { } , // The callback functions for each tracked property. { property -> [callback] } listeners = { } , // The set of tracked properties. { property -> true } trackedProperties = { } ; // The functional reactive "when" operator. // //  * `properties` An array of property names (can also be a single property string). //  * `callback` A callback function that is called: //    * with property values as arguments, ordered corresponding to the properties array, //    * only if all specified properties have values, //    * once for initialization, //    * whenever one or more specified properties change, //    * on the next tick of the JavaScript event loop after properties change, //    * only once as a result of one or more synchronous changes to dependency properties. function when ( properties , callback , thisArg ) { // Make sure the default `this` becomes  // the object you called `.on` on. thisArg = thisArg || this ; // Handle either an array or a single string. properties = ( properties instanceof Array ) ? properties : [ properties ] ; // This function will trigger the callback to be invoked. var listener = debounce ( function ( ) { var args = properties . map ( function ( property ) { return values [ property ] ; } ) ; if ( allAreDefined ( args ) ) { callback . apply ( thisArg , args ) ; } } ) ; // Trigger the callback once for initialization. listener ( ) ; // Trigger the callback whenever specified properties change. properties . forEach ( function ( property ) { on ( property , listener ) ; } ) ; // Return this function so it can be removed later with `model.cancel(listener)`. return listener ; } // Adds a change listener for a given property with Backbone-like behavior. // Similar to http://backbonejs.org/#Events-on function on ( property , callback , thisArg ) { thisArg = thisArg || this ; getListeners ( property ) . push ( callback ) ; track ( property , thisArg ) ; } // Gets or creates the array of listener functions for a given property. function getListeners ( property ) { return listeners [ property ] || ( listeners [ property ] = [ ] ) ; } // Tracks a property if it is not already tracked. function track ( property , thisArg ) { if ( ! ( property in trackedProperties ) ) { trackedProperties [ property ] = true ; values [ property ] = model [ property ] ; Object . defineProperty ( model , property , { get : function ( ) { return values [ property ] ; } , set : function ( newValue ) { var oldValue = values [ property ] ; values [ property ] = newValue ; getListeners ( property ) . forEach ( function ( callback ) { callback . call ( thisArg , newValue , oldValue ) ; } ) ; } } ) ; } } // Cancels a listener returned by a call to `model.when(...)`. function cancel ( listener ) { for ( var property in listeners ) { off ( property , listener ) ; } } // Removes a change listener added using `on`. function off ( property , callback ) { listeners [ property ] = listeners [ property ] . filter ( function ( listener ) { return listener !== callback ; } ) ; } // Sets all of the given values on the model. // `newValues` is an object { property -> value }. function set ( newValues ) { for ( var property in newValues ) { model [ property ] = newValues [ property ] ; } } // Transfer defaults passed into the constructor to the model. set ( defaults ) ; // Public API. model . when = when ; model . cancel = cancel ; model . on = on ; model . off = off ; model . set = set ; }
The constructor function, accepting default values.
The constructor function accepting default values .