From 0487616edb3addd1f77ebea6c3b7ef4957f3b131 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Thu, 9 Oct 2014 23:10:07 +0400 Subject: [PATCH 1/6] Named locks --- ractive-adaptors-backbone.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index 1743b6c..a5c267d 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -78,18 +78,20 @@ throw new Error( 'Could not find Ractive or Backbone! Check your paths config' ); } - function acquireLock( key ) { - key[lockProperty] = ( key[lockProperty] || 0 ) + 1; + function acquireLock( key, name ) { + var namedLockProperty = lockProperty + ( name || '' ); + key[ namedLockProperty ] = ( key[ namedLockProperty ] || 0 ) + 1; return function release() { - key[lockProperty] -= 1; - if ( !key[lockProperty] ) { - delete key[lockProperty]; + key[ namedLockProperty ] -= 1; + if ( !key[ namedLockProperty ] ) { + delete key[ namedLockProperty ]; } }; } - function isLocked( key ) { - return !!key[lockProperty]; + function isLocked( key, name ) { + var namedLockProperty = lockProperty + ( name || '' ); + return !!key[ namedLockProperty ]; } Ractive.adaptors.Backbone = { @@ -109,7 +111,7 @@ this.value = model; model.on( 'change', this.modelChangeHandler = function () { - var release = acquireLock( model ); + var release = acquireLock( model, 'set' ); ractive.set( prefix( model.changed ) ); release(); }); @@ -125,7 +127,7 @@ set: function ( keypath, value ) { // Only set if the model didn't originate the change itself, and // only if it's an immediate child property - if ( !isLocked( this.value ) && keypath.indexOf( '.' ) === -1 ) { + if ( !isLocked( this.value, 'set' ) && keypath.indexOf( '.' ) === -1 ) { this.value.set( keypath, value ); } }, @@ -148,7 +150,7 @@ collection.on( 'add remove reset sort', this.changeHandler = function () { // TODO smart merge. It should be possible, if awkward, to trigger smart // updates instead of a blunderbuss .set() approach - var release = acquireLock( collection ); + var release = acquireLock( collection, 'set' ); ractive.set( keypath, collection.models ); release(); }); @@ -162,7 +164,7 @@ return this.value.models; }, reset: function ( models ) { - if ( isLocked( this.value ) ) { + if ( isLocked( this.value, 'set' ) ) { return; } From 9ebefcdbbc8ee8ac3d2d419889f7820679e7ee71 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Fri, 10 Oct 2014 12:29:48 +0400 Subject: [PATCH 2/6] Patch and unpatch collection.sync method --- ractive-adaptors-backbone.js | 41 +++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index a5c267d..d29e374 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -72,7 +72,9 @@ 'use strict'; - var BackboneModelWrapper, BackboneCollectionWrapper, lockProperty = '_ractiveAdaptorsBackboneLock'; + var BackboneModelWrapper, BackboneCollectionWrapper; + var lockProperty = '_ractiveAdaptorsBackboneLock'; + var originalSyncProperty = '_ractiveAdaptorsBackboneOriginalSync'; if ( !Ractive || !Backbone ) { throw new Error( 'Could not find Ractive or Backbone! Check your paths config' ); @@ -154,10 +156,47 @@ ractive.set( keypath, collection.models ); release(); }); + + if ( !collection.hasOwnProperty( originalSyncProperty ) ) { + // Patch sync method if not patched + var originalSync = collection.sync; + collection[ originalSyncProperty ] = collection.hasOwnProperty('sync') ? originalSync : null; + collection.sync = function ractivePatchedSync( method, model, options ) { + options = options || {}; + + var originalSuccess = options.success; + if ( originalSuccess ) { + options.success = function ( resp ) { + var release = acquireLock( collection, 'syncSuccess' ); + var result = originalSuccess.apply( this, arguments ); + release(); + return result; + }; + } + + return originalSync.apply( this, arguments ); + }; + } + this.releaseSyncPatch = acquireLock( collection, 'syncPatch' ); // Count patch users }; BackboneCollectionWrapper.prototype = { teardown: function () { + var collection = this.value; + + this.releaseSyncPatch(); + if ( !isLocked( collection, 'syncPatch' ) ) { + // Cleanup, return original sync + if ( collection[ originalSyncProperty ] ) { + // We had object-owned method + collection.sync = collection[ originalSyncProperty ]; + delete collection[ originalSyncProperty ]; + } else { + // Use prototype method + delete collection.sync; + } + } + this.value.off( 'add remove reset sort', this.changeHandler ); }, get: function () { From c71583d50dd285b969199befd9b47c2470a85d52 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Fri, 10 Oct 2014 13:20:12 +0400 Subject: [PATCH 3/6] Use `syncSuccess` lock in event handler --- ractive-adaptors-backbone.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index d29e374..3a68448 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -75,6 +75,7 @@ var BackboneModelWrapper, BackboneCollectionWrapper; var lockProperty = '_ractiveAdaptorsBackboneLock'; var originalSyncProperty = '_ractiveAdaptorsBackboneOriginalSync'; + var BackboneCollectionWrapperChangeEvent = 'BackboneCollectionWrapper:change'; if ( !Ractive || !Backbone ) { throw new Error( 'Could not find Ractive or Backbone! Check your paths config' ); @@ -149,13 +150,18 @@ BackboneCollectionWrapper = function ( ractive, collection, keypath ) { this.value = collection; - collection.on( 'add remove reset sort', this.changeHandler = function () { + var changeHandler = this.changeHandler = function () { + if ( isLocked( collection, 'syncSuccess' ) ) { + return; + } + // TODO smart merge. It should be possible, if awkward, to trigger smart // updates instead of a blunderbuss .set() approach var release = acquireLock( collection, 'set' ); ractive.set( keypath, collection.models ); release(); - }); + }; + collection.on( 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, changeHandler); if ( !collection.hasOwnProperty( originalSyncProperty ) ) { // Patch sync method if not patched @@ -170,6 +176,8 @@ var release = acquireLock( collection, 'syncSuccess' ); var result = originalSuccess.apply( this, arguments ); release(); + // Notify all `BackboneCollectionWrapper`s about change + collection.trigger( BackboneCollectionWrapperChangeEvent ); return result; }; } From a2a9ee55e0913dd4f16d25e2bd39920aa48e0046 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Tue, 14 Oct 2014 23:53:55 +0400 Subject: [PATCH 4/6] Correctly `off` event listener --- ractive-adaptors-backbone.js | 2 +- ractive-adaptors-backbone.min.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index 3a68448..69521f9 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -205,7 +205,7 @@ } } - this.value.off( 'add remove reset sort', this.changeHandler ); + this.value.off( 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, this.changeHandler ); }, get: function () { return this.value.models; diff --git a/ractive-adaptors-backbone.min.js b/ractive-adaptors-backbone.min.js index 47b3735..fee9caf 100644 --- a/ractive-adaptors-backbone.min.js +++ b/ractive-adaptors-backbone.min.js @@ -1 +1 @@ -(function(e,t){"use strict";if(typeof module!=="undefined"&&module.exports&&typeof require==="function"){t(require("ractive"),require("backbone"))}else if(typeof define==="function"&&define.amd){define(["ractive","backbone"],t)}else if(e.Ractive&&e.Backbone){t(e.Ractive,e.Backbone)}else{throw new Error("Could not find Ractive or Backbone! Both must be loaded before the ractive-adaptors-backbone plugin")}})(typeof window!=="undefined"?window:this,function(e,t){"use strict";var n,o,i="_ractiveAdaptorsBackboneLock";if(!e||!t){throw new Error("Could not find Ractive or Backbone! Check your paths config")}function r(e){e[i]=(e[i]||0)+1;return function t(){e[i]-=1;if(!e[i]){delete e[i]}}}function a(e){return!!e[i]}e.adaptors.Backbone={filter:function(e){return e instanceof t.Model||e instanceof t.Collection},wrap:function(e,i,r,a){if(i instanceof t.Model){return new n(e,i,r,a)}return new o(e,i,r,a)}};n=function(e,t,n,o){this.value=t;t.on("change",this.modelChangeHandler=function(){var n=r(t);e.set(o(t.changed));n()})};n.prototype={teardown:function(){this.value.off("change",this.modelChangeHandler)},get:function(){return this.value.attributes},set:function(e,t){if(!a(this.value)&&e.indexOf(".")===-1){this.value.set(e,t)}},reset:function(e){if(e instanceof t.Model||!(e instanceof Object)){return false}this.value.set(e)}};o=function(e,t,n){this.value=t;t.on("add remove reset sort",this.changeHandler=function(){var o=r(t);e.set(n,t.models);o()})};o.prototype={teardown:function(){this.value.off("add remove reset sort",this.changeHandler)},get:function(){return this.value.models},reset:function(e){if(a(this.value)){return}if(e instanceof t.Collection||Object.prototype.toString.call(e)!=="[object Array]"){return false}this.value.reset(e)}}}); \ No newline at end of file +(function(e,t){"use strict";if(typeof module!=="undefined"&&module.exports&&typeof require==="function"){t(require("ractive"),require("backbone"))}else if(typeof define==="function"&&define.amd){define(["ractive","backbone"],t)}else if(e.Ractive&&e.Backbone){t(e.Ractive,e.Backbone)}else{throw new Error("Could not find Ractive or Backbone! Both must be loaded before the ractive-adaptors-backbone plugin")}})(typeof window!=="undefined"?window:this,function(e,t){"use strict";var n,r;var o="_ractiveAdaptorsBackboneLock";var i="_ractiveAdaptorsBackboneOriginalSync";var a="BackboneCollectionWrapper:change";if(!e||!t){throw new Error("Could not find Ractive or Backbone! Check your paths config")}function c(e,t){var n=o+(t||"");e[n]=(e[n]||0)+1;return function r(){e[n]-=1;if(!e[n]){delete e[n]}}}function s(e,t){var n=o+(t||"");return!!e[n]}e.adaptors.Backbone={filter:function(e){return e instanceof t.Model||e instanceof t.Collection},wrap:function(e,o,i,a){if(o instanceof t.Model){return new n(e,o,i,a)}return new r(e,o,i,a)}};n=function(e,t,n,r){this.value=t;t.on("change",this.modelChangeHandler=function(){var n=c(t,"set");e.set(r(t.changed));n()})};n.prototype={teardown:function(){this.value.off("change",this.modelChangeHandler)},get:function(){return this.value.attributes},set:function(e,t){if(!s(this.value,"set")&&e.indexOf(".")===-1){this.value.set(e,t)}},reset:function(e){if(e instanceof t.Model||!(e instanceof Object)){return false}this.value.set(e)}};r=function(e,t,n){this.value=t;var r=this.changeHandler=function(){if(s(t,"syncSuccess")){return}var r=c(t,"set");e.set(n,t.models);r()};t.on("add remove reset sort "+a,r);if(!t.hasOwnProperty(i)){var o=t.sync;t[i]=t.hasOwnProperty("sync")?o:null;t.sync=function u(e,n,r){r=r||{};var i=r.success;if(i){r.success=function(e){var n=c(t,"syncSuccess");var r=i.apply(this,arguments);n();t.trigger(a);return r}}return o.apply(this,arguments)}}this.releaseSyncPatch=c(t,"syncPatch")};r.prototype={teardown:function(){var e=this.value;this.releaseSyncPatch();if(!s(e,"syncPatch")){if(e[i]){e.sync=e[i];delete e[i]}else{delete e.sync}}this.value.off("add remove reset sort "+a,this.changeHandler)},get:function(){return this.value.models},reset:function(e){if(s(this.value,"set")){return}if(e instanceof t.Collection||Object.prototype.toString.call(e)!=="[object Array]"){return false}this.value.reset(e)}}}); \ No newline at end of file From 9e8e4de10efb4ffbf99ebdd113ca176991ca5e68 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Wed, 15 Oct 2014 00:07:26 +0400 Subject: [PATCH 5/6] Safer set and remove event listeners --- ractive-adaptors-backbone.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index 69521f9..7e78e62 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -81,7 +81,7 @@ throw new Error( 'Could not find Ractive or Backbone! Check your paths config' ); } - function acquireLock( key, name ) { + function acquireLock ( key, name ) { var namedLockProperty = lockProperty + ( name || '' ); key[ namedLockProperty ] = ( key[ namedLockProperty ] || 0 ) + 1; return function release() { @@ -92,11 +92,20 @@ }; } - function isLocked( key, name ) { + function isLocked ( key, name ) { var namedLockProperty = lockProperty + ( name || '' ); return !!key[ namedLockProperty ]; } + function onOff ( obj /* on/off() parameters */ ) { + var onOffArgs = Array.prototype.slice.call( arguments, 1 ); + + obj.on.apply( obj, onOffArgs ); + return function off () { + obj.off.apply( obj, onOffArgs ); + }; + } + Ractive.adaptors.Backbone = { filter: function ( object ) { return object instanceof Backbone.Model || object instanceof Backbone.Collection; @@ -113,16 +122,16 @@ BackboneModelWrapper = function ( ractive, model, keypath, prefix ) { this.value = model; - model.on( 'change', this.modelChangeHandler = function () { + this.off = onOff( model, 'change', function () { var release = acquireLock( model, 'set' ); ractive.set( prefix( model.changed ) ); release(); - }); + } ); }; BackboneModelWrapper.prototype = { teardown: function () { - this.value.off( 'change', this.modelChangeHandler ); + this.off(); }, get: function () { return this.value.attributes; @@ -150,7 +159,7 @@ BackboneCollectionWrapper = function ( ractive, collection, keypath ) { this.value = collection; - var changeHandler = this.changeHandler = function () { + function changeHandler () { if ( isLocked( collection, 'syncSuccess' ) ) { return; } @@ -160,8 +169,8 @@ var release = acquireLock( collection, 'set' ); ractive.set( keypath, collection.models ); release(); - }; - collection.on( 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, changeHandler); + } + this.off = onOff( collection, 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, changeHandler ); if ( !collection.hasOwnProperty( originalSyncProperty ) ) { // Patch sync method if not patched @@ -205,7 +214,7 @@ } } - this.value.off( 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, this.changeHandler ); + this.off(); }, get: function () { return this.value.models; From d03fc8fadf0939b1b9a30ad88aee53083eb57f37 Mon Sep 17 00:00:00 2001 From: Anton Ryzhov Date: Sun, 19 Oct 2014 18:16:28 +0400 Subject: [PATCH 6/6] Patch `set` instead of `sync` --- ractive-adaptors-backbone.js | 51 ++++++++++++++------------------ ractive-adaptors-backbone.min.js | 2 +- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/ractive-adaptors-backbone.js b/ractive-adaptors-backbone.js index 7e78e62..e497dfa 100644 --- a/ractive-adaptors-backbone.js +++ b/ractive-adaptors-backbone.js @@ -74,7 +74,7 @@ var BackboneModelWrapper, BackboneCollectionWrapper; var lockProperty = '_ractiveAdaptorsBackboneLock'; - var originalSyncProperty = '_ractiveAdaptorsBackboneOriginalSync'; + var originalSetProperty = '_ractiveAdaptorsBackboneOriginalSet'; var BackboneCollectionWrapperChangeEvent = 'BackboneCollectionWrapper:change'; if ( !Ractive || !Backbone ) { @@ -160,7 +160,7 @@ this.value = collection; function changeHandler () { - if ( isLocked( collection, 'syncSuccess' ) ) { + if ( isLocked( collection, 'setSuccess' ) ) { return; } @@ -172,45 +172,38 @@ } this.off = onOff( collection, 'add remove reset sort ' + BackboneCollectionWrapperChangeEvent, changeHandler ); - if ( !collection.hasOwnProperty( originalSyncProperty ) ) { - // Patch sync method if not patched - var originalSync = collection.sync; - collection[ originalSyncProperty ] = collection.hasOwnProperty('sync') ? originalSync : null; - collection.sync = function ractivePatchedSync( method, model, options ) { - options = options || {}; - - var originalSuccess = options.success; - if ( originalSuccess ) { - options.success = function ( resp ) { - var release = acquireLock( collection, 'syncSuccess' ); - var result = originalSuccess.apply( this, arguments ); - release(); - // Notify all `BackboneCollectionWrapper`s about change - collection.trigger( BackboneCollectionWrapperChangeEvent ); - return result; - }; - } + if ( !collection.hasOwnProperty( originalSetProperty ) ) { + // Patch set method if not patched + var originalSet = collection.set; + collection[ originalSetProperty ] = collection.hasOwnProperty('set') ? originalSet : null; + + collection.set = function ractivePatchedSet() { + var release = acquireLock( collection, 'setSuccess' ); + var result = originalSet.apply( this, arguments ); + release(); - return originalSync.apply( this, arguments ); + // Notify all `BackboneCollectionWrapper`s about change + collection.trigger( BackboneCollectionWrapperChangeEvent ); + return result; }; } - this.releaseSyncPatch = acquireLock( collection, 'syncPatch' ); // Count patch users + this.releaseSetPatch = acquireLock( collection, 'setPatch' ); // Count patch users }; BackboneCollectionWrapper.prototype = { teardown: function () { var collection = this.value; - this.releaseSyncPatch(); - if ( !isLocked( collection, 'syncPatch' ) ) { - // Cleanup, return original sync - if ( collection[ originalSyncProperty ] ) { + this.releaseSetPatch(); + if ( !isLocked( collection, 'setPatch' ) ) { + // Cleanup, return original set + if ( collection[ originalSetProperty ] ) { // We had object-owned method - collection.sync = collection[ originalSyncProperty ]; - delete collection[ originalSyncProperty ]; + collection.set = collection[ originalSetProperty ]; + delete collection[ originalSetProperty ]; } else { // Use prototype method - delete collection.sync; + delete collection.set; } } diff --git a/ractive-adaptors-backbone.min.js b/ractive-adaptors-backbone.min.js index fee9caf..48dbb35 100644 --- a/ractive-adaptors-backbone.min.js +++ b/ractive-adaptors-backbone.min.js @@ -1 +1 @@ -(function(e,t){"use strict";if(typeof module!=="undefined"&&module.exports&&typeof require==="function"){t(require("ractive"),require("backbone"))}else if(typeof define==="function"&&define.amd){define(["ractive","backbone"],t)}else if(e.Ractive&&e.Backbone){t(e.Ractive,e.Backbone)}else{throw new Error("Could not find Ractive or Backbone! Both must be loaded before the ractive-adaptors-backbone plugin")}})(typeof window!=="undefined"?window:this,function(e,t){"use strict";var n,r;var o="_ractiveAdaptorsBackboneLock";var i="_ractiveAdaptorsBackboneOriginalSync";var a="BackboneCollectionWrapper:change";if(!e||!t){throw new Error("Could not find Ractive or Backbone! Check your paths config")}function c(e,t){var n=o+(t||"");e[n]=(e[n]||0)+1;return function r(){e[n]-=1;if(!e[n]){delete e[n]}}}function s(e,t){var n=o+(t||"");return!!e[n]}e.adaptors.Backbone={filter:function(e){return e instanceof t.Model||e instanceof t.Collection},wrap:function(e,o,i,a){if(o instanceof t.Model){return new n(e,o,i,a)}return new r(e,o,i,a)}};n=function(e,t,n,r){this.value=t;t.on("change",this.modelChangeHandler=function(){var n=c(t,"set");e.set(r(t.changed));n()})};n.prototype={teardown:function(){this.value.off("change",this.modelChangeHandler)},get:function(){return this.value.attributes},set:function(e,t){if(!s(this.value,"set")&&e.indexOf(".")===-1){this.value.set(e,t)}},reset:function(e){if(e instanceof t.Model||!(e instanceof Object)){return false}this.value.set(e)}};r=function(e,t,n){this.value=t;var r=this.changeHandler=function(){if(s(t,"syncSuccess")){return}var r=c(t,"set");e.set(n,t.models);r()};t.on("add remove reset sort "+a,r);if(!t.hasOwnProperty(i)){var o=t.sync;t[i]=t.hasOwnProperty("sync")?o:null;t.sync=function u(e,n,r){r=r||{};var i=r.success;if(i){r.success=function(e){var n=c(t,"syncSuccess");var r=i.apply(this,arguments);n();t.trigger(a);return r}}return o.apply(this,arguments)}}this.releaseSyncPatch=c(t,"syncPatch")};r.prototype={teardown:function(){var e=this.value;this.releaseSyncPatch();if(!s(e,"syncPatch")){if(e[i]){e.sync=e[i];delete e[i]}else{delete e.sync}}this.value.off("add remove reset sort "+a,this.changeHandler)},get:function(){return this.value.models},reset:function(e){if(s(this.value,"set")){return}if(e instanceof t.Collection||Object.prototype.toString.call(e)!=="[object Array]"){return false}this.value.reset(e)}}}); \ No newline at end of file +(function(e,t){"use strict";if(typeof module!=="undefined"&&module.exports&&typeof require==="function"){t(require("ractive"),require("backbone"))}else if(typeof define==="function"&&define.amd){define(["ractive","backbone"],t)}else if(e.Ractive&&e.Backbone){t(e.Ractive,e.Backbone)}else{throw new Error("Could not find Ractive or Backbone! Both must be loaded before the ractive-adaptors-backbone plugin")}})(typeof window!=="undefined"?window:this,function(e,t){"use strict";var n,o;var r="_ractiveAdaptorsBackboneLock";var i="_ractiveAdaptorsBackboneOriginalSet";var a="BackboneCollectionWrapper:change";if(!e||!t){throw new Error("Could not find Ractive or Backbone! Check your paths config")}function s(e,t){var n=r+(t||"");e[n]=(e[n]||0)+1;return function o(){e[n]-=1;if(!e[n]){delete e[n]}}}function c(e,t){var n=r+(t||"");return!!e[n]}function f(e){var t=Array.prototype.slice.call(arguments,1);e.on.apply(e,t);return function n(){e.off.apply(e,t)}}e.adaptors.Backbone={filter:function(e){return e instanceof t.Model||e instanceof t.Collection},wrap:function(e,r,i,a){if(r instanceof t.Model){return new n(e,r,i,a)}return new o(e,r,i,a)}};n=function(e,t,n,o){this.value=t;this.off=f(t,"change",function(){var n=s(t,"set");e.set(o(t.changed));n()})};n.prototype={teardown:function(){this.off()},get:function(){return this.value.attributes},set:function(e,t){if(!c(this.value,"set")&&e.indexOf(".")===-1){this.value.set(e,t)}},reset:function(e){if(e instanceof t.Model||!(e instanceof Object)){return false}this.value.set(e)}};o=function(e,t,n){this.value=t;function o(){if(c(t,"setSuccess")){return}var o=s(t,"set");e.set(n,t.models);o()}this.off=f(t,"add remove reset sort "+a,o);if(!t.hasOwnProperty(i)){var r=t.set;t[i]=t.hasOwnProperty("set")?r:null;t.set=function u(e,n){var o=s(t,"setSuccess");var i=r.apply(this,arguments);o();t.trigger(a);return i}}this.releaseSetPatch=s(t,"setPatch")};o.prototype={teardown:function(){var e=this.value;this.releaseSetPatch();if(!c(e,"setPatch")){if(e[i]){e.set=e[i];delete e[i]}else{delete e.set}}this.off()},get:function(){return this.value.models},reset:function(e){if(c(this.value,"set")){return}if(e instanceof t.Collection||Object.prototype.toString.call(e)!=="[object Array]"){return false}this.value.reset(e)}}}); \ No newline at end of file