diff --git a/Gruntfile.js b/Gruntfile.js index 258660b..257c8bd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -20,23 +20,13 @@ grunt.initConfig({ uglify: { "backbone-fiber.min.js": [ "", "backbone-fiber.js" ] - }, - - jshint: { - options: { - jshintrc: ".jshintrc" - }, - files: { - src: [ "src/backbone-fiber.js" ] - } } }); -grunt.loadNpmTasks( "grunt-contrib-jshint" ); grunt.loadNpmTasks( "grunt-contrib-uglify" ); grunt.loadNpmTasks( "grunt-contrib-concat" ); -grunt.registerTask( "default", [ "jshint", "concat", "uglify" ] ); +grunt.registerTask( "default", [ "concat", "uglify" ] ); }; diff --git a/backbone-fiber.js b/backbone-fiber.js index 651ddc6..8055088 100644 --- a/backbone-fiber.js +++ b/backbone-fiber.js @@ -43,7 +43,8 @@ var Fiber, _view_defs = {}, _view_inst = {}, - _view_loading = {}; + _view_loading = {}, + _view_creating = {}; // Store the old jQuery.cleanData var oldClean = $.cleanData; @@ -106,9 +107,9 @@ * otherwise, returns nothing. */ getPromise: function( view ) { - - if ( _view_loading[view] ) - return _view_loading[view]; + var v; + if ( v = ( _view_creating[view] || _view_loading[view] ) ) + return v; }, @@ -137,6 +138,8 @@ var dfd = $.Deferred(); + dfd.then(function() { delete _view_loading[target]; }, function() { delete _view_loading[target]; } ); + if ( _view_defs[target] ) { dfd.resolve( _view_defs[target] ); @@ -146,19 +149,16 @@ _view_loading[target] = dfd; require( [Fiber.viewPath + target, 'text!' + Fiber.viewPath + target + '.html'], function( view, template ) { if ( view === void 0 || template === void 0 ) { - delete _view_loading[target]; dfd.reject(); } else { view.prototype.instanceOf = target; view.prototype.template = _.template( template ); _view_defs[target] = view; - delete _view_loading[target]; dfd.resolve( view ); } }, function( err ) { - delete _view_loading[target]; dfd.reject( err ); }); } @@ -170,32 +170,46 @@ * View factory method. Creates instance, sets up the parent/child * relationship and renders the view. */ - function create( view, $el, options ) { + function create( dataView, $el, options ) { + + var dfd = $.Deferred(); - var inst = new view(_.extend( options, { el: $el[0] } )), - parent, fizzle = false; + dfd.then(function() { delete _view_creating[dataView]; }, function() { delete _view_creating[dataView]; } ); - $el.attr( 'data-cid', inst.cid ); - _view_inst[inst.cid] = inst; + _view_creating[dataView] = dfd; - parent = $el.parents( '[data-view]' ).first(); + load( dataView ).then( function( view ) { - if ( parent.length > 0 ) { - parent = parent.attr( 'data-cid' ); - if ( _view_inst[parent] ) { - _view_inst[parent].addChild( inst ); - inst.setParent( _view_inst[parent] ); - } else { + var inst = new view(_.extend( options, { el: $el[0] } )), + parent, fizzle = false; + + $el.attr( 'data-cid', inst.cid ); + _view_inst[inst.cid] = inst; + + parent = $el.parents( '[data-view]' ).first(); + + if ( parent.length > 0 ) { + parent = parent.attr( 'data-cid' ); + if ( _view_inst[parent] ) { + _view_inst[parent].addChild( inst ); + inst.setParent( _view_inst[parent] ); + } else { + fizzle = true; + inst.remove(); + } + } else if ( $el.closest('body').length === 0 ) { fizzle = true; inst.remove(); } - } else if ( $el.closest('body').length === 0 ) { - fizzle = true; - inst.remove(); - } - if (!fizzle) { inst.render(); } - return inst; + if (!fizzle) { + inst.render(); + dfd.resolve( inst ); + } else { + dfd.reject(); + } + + }, function() { dfd.reject(); } ); } @@ -212,11 +226,8 @@ if ( dataView ) { - load( dataView ).done( function( view ) { + create( dataView, $el, options ); - create( view, $el, options ); - - }); } } @@ -226,13 +237,13 @@ Backbone.View.mix([{ - + /** * Flag used to track whether the view is still connected to the dom * Useful for deferred functions to know if it still needs to run */ _connected: true, - + /** * load() will attach the compiled template to the * prototype of the loaded view. No need to do anything @@ -334,14 +345,14 @@ * onError [ Function ] ( optional ) * * Function to call if one of the views fails to load. - + */ waitFor: function( children, onSuccess, onError ) { var self = this, sync = _.compact( _.map( children, function( v ) { return Fiber.getPromise( v ); } ) ); - $.when.apply( this, sync ).then( + $.when.apply( this, sync ).then( function() { onSuccess.apply( self, arguments ); }, @@ -662,7 +673,7 @@ isMyChild: function( view ) { return ( view.parent && _.find( this.children, function( cid ) { return view.cid == cid; } ) !== void 0 ) || ( !view.parent && this.isMyElement( view.$el.parent() ) ); }, - + /** * quick method for children to determine if it is loaded */ @@ -691,9 +702,9 @@ var $el = (el instanceof $ ? el : $(el)); return ( $el.closest('[data-view]').first().attr('data-cid') == this.cid ); - + }, - + /** * Determine if still connected */ diff --git a/backbone-fiber.min.js b/backbone-fiber.min.js index d569bd5..fe42c62 100644 --- a/backbone-fiber.min.js +++ b/backbone-fiber.min.js @@ -1 +1 @@ -(function(t,e){"function"==typeof define&&define.amd?define(["jquery","underscore","backbone","base"],e):t.Backbone.Fiber=e(t.$,t._,t.Backbone,Base)})(this,function(t,e,i,n){function r(i){var n=t.Deferred();return s[i]?n.resolve(s[i]):(l[i]=n,require([d.viewPath+i,"text!"+d.viewPath+i+".html"],function(t,r){void 0===t||void 0===r?(delete l[i],n.reject()):(t.prototype.instanceOf=i,t.prototype.template=e.template(r),s[i]=t,delete l[i],n.resolve(t))},function(t){delete l[i],n.reject(t)})),n.promise()}function o(t,i,n){var r,o=new t(e.extend(n,{el:i[0]})),a=!1;return i.attr("data-cid",o.cid),c[o.cid]=o,r=i.parents("[data-view]").first(),r.length>0?(r=r.attr("data-cid"),c[r]?(c[r].addChild(o),o.setParent(c[r])):(a=!0,o.remove())):0===i.closest("body").length&&(a=!0,o.remove()),a||o.render(),o}function a(e,i){var n=i||{},a=e instanceof t?e:t(e),d=a.attr("data-view");d&&r(d).done(function(t){o(t,a,n)})}i.View.extend=n.extend,i.View.mix=n.mix;var d,s={},c={},l={},h=t.cleanData;return t.cleanData=function(e){for(var i,n=0;void 0!==(i=e[n]);n++)t(i).triggerHandler("destroyed");h(e)},i.Fiber=d={viewPath:"views/",getViewFromEl:function(e){var i=t(e),n=i.attr("data-cid")||i.closest("[data-cid]").attr("data-cid");return n?c[n]:void 0},getViewFromCid:function(t){return c[t]},getElFromCid:function(t){return c[t]?c[t].$el:void 0},getPromise:function(t){return l[t]?l[t]:void 0},isLoaded:function(e){return e=e instanceof t?e.attr("data-view")||e.closest("[data-view]").attr("data-view"):e,l[e]?!1:s[e]?!0:null}},d.start=function(){a(document.body)},i.View.mix([{_connected:!0,template:null,parent:null,children:null,renderedOnce:!1,forceRender:!1,connect:function(e,i){var n,r,o=this,s=t.Deferred(),c=null;return n="string"==typeof e?this.factory(e,i):e instanceof t?e:t(e),a(n,i),(r=d.getPromise(n.attr("data-view")))?r.then(function(){(c=d.getViewFromEl(n))?s.resolveWith(o,[c]):s.rejectWith(o)},function(){s.rejectWith(o)}):(c=d.getViewFromEl(n))?s.resolveWith(this,[c]):s.rejectWith(this),s.promise()},waitFor:function(i,n,r){var o=this,a=e.compact(e.map(i,function(t){return d.getPromise(t)}));t.when.apply(this,a).then(function(){n.apply(o,arguments)},function(){r&&r.apply(o,arguments)})},factory:function(e){return t("
").attr("data-view",e).appendTo(this.$el)},initialize:function(t){this.$el.on("destroyed",e.bind(this.remove,this)),this.options=t||{},this.children=[],this.setup(t),this.bindData(),this.trigger("created")},unbindData:function(){var t=this.data();t.trigger&&this.stopListening(t)},bindData:function(){var i=this,n=this.data();n.trigger&&e.each(this.events,function(e,r){var o;(o=r.indexOf(".data"))>-1&&(e=t.isFunction(e)?e:i[e],i.listenTo(n,r.slice(0,o),e))})},setup:t.noop,render:function(){var e,i,n=this;this.beforeRender()!==!1&&(this.trigger("rendering"),this.template&&"function"==typeof this.template&&(e=this.dataSerialized(),i=e&&t.isArray(e),((this.forceRender||this.renderedOnce)&&e||!this.renderedOnce&&(i&&e.length>0||!i))&&(this.$el.empty().html(this.template(e)),this.renderedOnce=!0,this.$el.find("[data-view]").each(function(e,i){$el=t(i),n.connect($el).fail(function(){n.trigger("child-connect-error",{"data-view":$el.attr("data-view"),$el:$el})})}))),this.afterRender(),this.trigger("rendered"))},beforeRender:t.noop,afterRender:t.noop,data:function(){return this.model?this.model:this.collection?this.collection:{}},clearData:function(){var t=this.data();return this.unbindData(),this.model=null,this.collection=null,this.trigger("undata",t),this},setData:function(t){var e=null;return this.unbindData(),t.model?this.model=e=t.model:t.collection&&(this.collection=e=t.collection),this.bindData(),e&&e.trigger&&e.trigger("ready",e,this),this},dataSerialized:function(){var t=this.data();return t.toJSON?t.toJSON({computedFields:!0}):t},remove:function(){this.parent?c[this.parent].removeChild(this):(this._connected=!1,this.destroy(),this.trigger("removed"),this.stopListening(),this.$el.off("destroyed"),this.$el.remove(),delete c[this.cid]),this._superStop()},destroy:t.noop,trigger:function(t,e){this.$el.trigger(t,{view:this,data:e||{}})||this._superStop()},setParent:function(t){this.parent=null,t&&(this.parent=t.cid)},addChild:function(t){e.contains(t.cid,this.children)||this.children.push(t.cid)},removeChild:function(t){var i=e.indexOf(this.children,t.cid);i>-1&&(this.children.splice(i,1),t.setParent(null),t.remove())},allChildren:function(){return e.map(this.children,function(t){return d.getViewFromCid(t)})},findChildren:function(t){return e.compact(e.map(this.children,function(e){var i;return(i=d.getViewFromCid(e))&&i.instanceOf==t?i:void 0}))},findChild:function(e){var i=null;if(e instanceof t)this.isChildLoaded(e)&&(i=d.getViewFromEl(e));else if("string"==typeof e&&(i=d.getViewFromCid(e),!i))for(var n=0;this.children.length>n;n++){var r;(r=d.getViewFromCid(this.children[n]))&&r.instanceOf==e&&(i=r)}return i},isMyChild:function(t){return t.parent&&void 0!==e.find(this.children,function(e){return t.cid==e})||!t.parent&&this.isMyElement(t.$el.parent())},isChildLoaded:function(t){return d.isLoaded(t)},purgeChildEl:function(e){var i,n=e instanceof t?e:t(e);this.isChildLoaded(n)&&(i=this.findChild(n))?i.remove():n.remove()},isMyElement:function(e){var i=e instanceof t?e:t(e);return i.closest("[data-view]").first().attr("data-cid")==this.cid},isConnected:function(){return this._connected}}]),d}); \ No newline at end of file +(function(t,e){"function"==typeof define&&define.amd?define(["jquery","underscore","backbone","base"],e):t.Backbone.Fiber=e(t.$,t._,t.Backbone,Base)})(this,function(t,e,i,n){function r(i){var n=t.Deferred();return n.then(function(){delete h[i]},function(){delete h[i]}),s[i]?n.resolve(s[i]):(h[i]=n,require([d.viewPath+i,"text!"+d.viewPath+i+".html"],function(t,r){void 0===t||void 0===r?n.reject():(t.prototype.instanceOf=i,t.prototype.template=e.template(r),s[i]=t,n.resolve(t))},function(t){n.reject(t)})),n.promise()}function o(i,n,o){var a=t.Deferred();a.then(function(){delete l[i]},function(){delete l[i]}),l[i]=a,r(i).then(function(t){var i,r=new t(e.extend(o,{el:n[0]})),d=!1;n.attr("data-cid",r.cid),c[r.cid]=r,i=n.parents("[data-view]").first(),i.length>0?(i=i.attr("data-cid"),c[i]?(c[i].addChild(r),r.setParent(c[i])):(d=!0,r.remove())):0===n.closest("body").length&&(d=!0,r.remove()),d?a.reject():(r.render(),a.resolve(r))},function(){a.reject()})}function a(e,i){var n=i||{},r=e instanceof t?e:t(e),a=r.attr("data-view");a&&o(a,r,n)}i.View.extend=n.extend,i.View.mix=n.mix;var d,s={},c={},h={},l={},u=t.cleanData;return t.cleanData=function(e){for(var i,n=0;void 0!==(i=e[n]);n++)t(i).triggerHandler("destroyed");u(e)},i.Fiber=d={viewPath:"views/",getViewFromEl:function(e){var i=t(e),n=i.attr("data-cid")||i.closest("[data-cid]").attr("data-cid");return n?c[n]:void 0},getViewFromCid:function(t){return c[t]},getElFromCid:function(t){return c[t]?c[t].$el:void 0},getPromise:function(t){var e;return(e=l[t]||h[t])?e:void 0},isLoaded:function(e){return e=e instanceof t?e.attr("data-view")||e.closest("[data-view]").attr("data-view"):e,h[e]?!1:s[e]?!0:null}},d.start=function(){a(document.body)},i.View.mix([{_connected:!0,template:null,parent:null,children:null,renderedOnce:!1,forceRender:!1,connect:function(e,i){var n,r,o=this,s=t.Deferred(),c=null;return n="string"==typeof e?this.factory(e,i):e instanceof t?e:t(e),a(n,i),(r=d.getPromise(n.attr("data-view")))?r.then(function(){(c=d.getViewFromEl(n))?s.resolveWith(o,[c]):s.rejectWith(o)},function(){s.rejectWith(o)}):(c=d.getViewFromEl(n))?s.resolveWith(this,[c]):s.rejectWith(this),s.promise()},waitFor:function(i,n,r){var o=this,a=e.compact(e.map(i,function(t){return d.getPromise(t)}));t.when.apply(this,a).then(function(){n.apply(o,arguments)},function(){r&&r.apply(o,arguments)})},factory:function(e){return t("
").attr("data-view",e).appendTo(this.$el)},initialize:function(t){this.$el.on("destroyed",e.bind(this.remove,this)),this.options=t||{},this.children=[],this.setup(t),this.bindData(),this.trigger("created")},unbindData:function(){var t=this.data();t.trigger&&this.stopListening(t)},bindData:function(){var i=this,n=this.data();n.trigger&&e.each(this.events,function(e,r){var o;(o=r.indexOf(".data"))>-1&&(e=t.isFunction(e)?e:i[e],i.listenTo(n,r.slice(0,o),e))})},setup:t.noop,render:function(){var e,i,n=this;this.beforeRender()!==!1&&(this.trigger("rendering"),this.template&&"function"==typeof this.template&&(e=this.dataSerialized(),i=e&&t.isArray(e),((this.forceRender||this.renderedOnce)&&e||!this.renderedOnce&&(i&&e.length>0||!i))&&(this.$el.empty().html(this.template(e)),this.renderedOnce=!0,this.$el.find("[data-view]").each(function(e,i){$el=t(i),n.connect($el).fail(function(){n.trigger("child-connect-error",{"data-view":$el.attr("data-view"),$el:$el})})}))),this.afterRender(),this.trigger("rendered"))},beforeRender:t.noop,afterRender:t.noop,data:function(){return this.model?this.model:this.collection?this.collection:{}},clearData:function(){var t=this.data();return this.unbindData(),this.model=null,this.collection=null,this.trigger("undata",t),this},setData:function(t){var e=null;return this.unbindData(),t.model?this.model=e=t.model:t.collection&&(this.collection=e=t.collection),this.bindData(),e&&e.trigger&&e.trigger("ready",e,this),this},dataSerialized:function(){var t=this.data();return t.toJSON?t.toJSON({computedFields:!0}):t},remove:function(){this.parent?c[this.parent].removeChild(this):(this._connected=!1,this.destroy(),this.trigger("removed"),this.stopListening(),this.$el.off("destroyed"),this.$el.remove(),delete c[this.cid]),this._superStop()},destroy:t.noop,trigger:function(t,e){this.$el.trigger(t,{view:this,data:e||{}})||this._superStop()},setParent:function(t){this.parent=null,t&&(this.parent=t.cid)},addChild:function(t){e.contains(t.cid,this.children)||this.children.push(t.cid)},removeChild:function(t){var i=e.indexOf(this.children,t.cid);i>-1&&(this.children.splice(i,1),t.setParent(null),t.remove())},allChildren:function(){return e.map(this.children,function(t){return d.getViewFromCid(t)})},findChildren:function(t){return e.compact(e.map(this.children,function(e){var i;return(i=d.getViewFromCid(e))&&i.instanceOf==t?i:void 0}))},findChild:function(e){var i=null;if(e instanceof t)this.isChildLoaded(e)&&(i=d.getViewFromEl(e));else if("string"==typeof e&&(i=d.getViewFromCid(e),!i))for(var n=0;this.children.length>n;n++){var r;(r=d.getViewFromCid(this.children[n]))&&r.instanceOf==e&&(i=r)}return i},isMyChild:function(t){return t.parent&&void 0!==e.find(this.children,function(e){return t.cid==e})||!t.parent&&this.isMyElement(t.$el.parent())},isChildLoaded:function(t){return d.isLoaded(t)},purgeChildEl:function(e){var i,n=e instanceof t?e:t(e);this.isChildLoaded(n)&&(i=this.findChild(n))?i.remove():n.remove()},isMyElement:function(e){var i=e instanceof t?e:t(e);return i.closest("[data-view]").first().attr("data-cid")==this.cid},isConnected:function(){return this._connected}}]),d}); \ No newline at end of file diff --git a/bower.json b/bower.json index 4656a5d..59b91ca 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "backbone-fiber", - "version": "0.1.7", + "version": "0.1.8", "ignore": [ "bower_components", "node_modules", diff --git a/package.json b/package.json index 766bdfc..2e909d9 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "Backbone.Fiber", "title": "", "description": "", - "version": "0.1.7", + "version": "0.1.8", "author": { "name": "Ben Olson", "url": "http://bseth99.github.com/"