kilbot
11/19/2016 - 4:57 PM

Multiple Class Inheritance In Backbone Collections

Multiple Class Inheritance In Backbone Collections

<!DOCTYPE html>
<html>
<head>
	<title>Multiple Class Inheritance In Backbone Collections</title>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
	<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
</head>
<body>

	<h1>
		Multiple Class Inheritance In Backbone Collections
	</h1>


	<script type="text/javascript">

		/**
		 *
		 */
		var idbDecorator = function(parent){
			var sync = parent.prototype.sync;

			var IDBCollection = parent.extend({
   				sync: function(){
   					console.log('IDB sync');
   					sync.call(this);
   				},

   				idb: function(){
   					console.log(this);
   				}
   			});

   			return IDBCollection;
		};

		/**
		 *
		 */
		var dualDecorator = function(parent){
			if(!_.includes(parent._extended, 'idb')){
				parent = parent.decorate('idb');
			}

			var sync = parent.prototype.sync;


   			var DualCollection = parent.extend({
   				sync: function(){
   					console.log('Dual sync');
   					sync.call(this);
   				}
   			});


   			return DualCollection;
		};


		/**
		 *
		 */
		var filteredDecorator = function(parent){
			return parent;
		};

		/**
		 *
		 */
		var decoratorHash = {
			dual  		: dualDecorator,
			idb 		: idbDecorator,
			filtered 	: filteredDecorator,
		};

		/**
		 *
		 */
		var Collection = Backbone.Collection.extend({
			
			constructor: function () {
      			Backbone.Collection.apply(this, arguments);
      			this.isNew(true);
      			this._parent = Object.getPrototypeOf( Object.getPrototypeOf(this) );
      		},

			isNew: function(reset) {
      			if(reset){
        			this._isNew = true;
        			this.once('sync', function() {
          				this._isNew = false;
        			});
      			}
      			return this._isNew;
   			},

   			sync: function(){
   				console.log('Original sync');
   			}

		});

		/**
		 *
		 */
		Collection.extend = function(protoProps, staticProps){
		    var parent = this;
		    var child;
		    var extend;

		    if (protoProps && _.has(protoProps, 'extends')) {
				var extend = _.isString(protoProps.extends) ? [protoProps.extends] : protoProps.extends;
		    }

		    // russian doll decorators
		    if(extend && _.isArray(extend)){
		    	_.each(extend, function(key){
		    		if(!_.includes(parent._extended, key)){
		    			parent = parent.decorate(key);
		    		}
		    	});
		    }

		    // The constructor function for the new subclass is either defined by you
		    // (the "constructor" property in your `extend` definition), or defaulted
		    // by us to simply call the parent constructor.
		    if (protoProps && _.has(protoProps, 'constructor')) {
		      child = protoProps.constructor;
		    } else {
		      child = function(){ return parent.apply(this, arguments); };
		    }


		    // Add static properties to the constructor function, if supplied.
		    _.extend(child, parent, staticProps);

		    // Set the prototype chain to inherit from `parent`, without calling
		    // `parent`'s constructor function and add the prototype properties.
		    child.prototype = _.create(parent.prototype, protoProps);
		    child.prototype.constructor = child;

		    // Set a convenience property in case the parent's prototype is needed
		    // later.
		    child.__super__ = parent.prototype;

		    return child;
		};

		/**
		 *
		 */
		 Collection.decorate = function(key, func){
		 	var parent;
		 	if(_.isFunction(func)){
		 		parent = func(this);
		 	} else {
				parent = _.has(decoratorHash, key) ? decoratorHash[key](this) : this;
		 	}
			_.isArray(parent._extended) ? parent._extended.push(key) : parent._extended = [key];
			return parent;
		 };

		/**
		 *
		 */
		var ExtendedCollection = Collection.extend({
			extends: ['dual', 'idb'],

			sync: function(){
				console.log('Custom sync');
				this._parent.sync.call(this);
			}
		});

		/**
		 *
		 */
		 var NormalCollection = Collection.extend({
			sync: function(){
				console.log('Custom sync');
				this._parent.sync.call(this);
			}
		});

		/**
		 *
		 */
		console.log('-- without extends --');
		var normal = new NormalCollection();
		normal.sync();

		console.log('-- with extends --');
		var extended = new ExtendedCollection();
		extended.sync();
		

	</script>

</body>
</html>