diff --git a/docs/marionette.configuration.md b/docs/marionette.configuration.md new file mode 100644 index 0000000000..ae2501db8b --- /dev/null +++ b/docs/marionette.configuration.md @@ -0,0 +1,37 @@ +# Marionette Configuration + +Marionette has a few globally configurable settings that will +change how the system works. While many of these subjects are covered +in other docs, this configuration doc should provide a list of the +most common items to change. + +## Documentation Index + +* [Marionette.Deferred](#deferred) + +## Marionette.Deferred + +By default, Marionette makes use of `Backbone.$.Deferred` to create +thenable objects. All that is needed is a Deferred that has the +following properties: + +1. `promise`: a Promises/A+ thenable, or a function that returns one +2. `resolve`: a function that resolves the provided promise with a value + +For example: + +```js +var deferred = Marionette.Deferred(); + +_.result(deferred, 'promise').then(function (target) { + console.log("Hello, " + target + "!"); +}); + +deferred.resolve("world"); // asynchronous "Hello, world!" +``` + +If you wish to use a specific promise library, you can override the default via: + +```js +Marionette.Deferred = myDeferredLib; +``` diff --git a/spec/javascripts/callbacks.spec.js b/spec/javascripts/callbacks.spec.js index c202c9a430..5750f49153 100644 --- a/spec/javascripts/callbacks.spec.js +++ b/spec/javascripts/callbacks.spec.js @@ -92,4 +92,31 @@ describe('callbacks', function() { expect(this.numCallbacks).to.equal(1); }); }); + + describe("when Marionette.Deferred().promise is an object", function(){ + beforeEach(function(){ + this.sandbox = sinon.sandbox.create(); + + this.sandbox.stub(Backbone.Marionette, "Deferred", function(){ + var deferred = Backbone.$.Deferred(); + deferred.promise = deferred.promise(); + return deferred; + }); + + var callbacks = new Backbone.Marionette.Callbacks(); + + this.spy = sinon.spy(); + callbacks.add(this.spy); + + callbacks.run(); + }); + + afterEach(function(){ + this.sandbox.restore(); + }); + + it("should execute the callbacks", function(){ + expect(this.spy).to.have.been.called; + }); + }); }); diff --git a/src/build/marionette.bundle.js b/src/build/marionette.bundle.js index 5be8f4a7b7..2ae80ffd0f 100644 --- a/src/build/marionette.bundle.js +++ b/src/build/marionette.bundle.js @@ -8,6 +8,9 @@ var Marionette = (function(global, Backbone, _){ var Marionette = {}; Backbone.Marionette = Marionette; + // Get the Deferred creator for later use + Marionette.Deferred = Backbone.$.Deferred; + // @include ../marionette.helpers.js // @include ../marionette.triggermethod.js // @include ../marionette.domRefresh.js diff --git a/src/build/marionette.bundled.js b/src/build/marionette.bundled.js index df7ce093ea..3742615b6c 100644 --- a/src/build/marionette.bundled.js +++ b/src/build/marionette.bundled.js @@ -31,6 +31,9 @@ Backbone.Marionette = Marionette; + // Get the Deferred creator for later use + Marionette.Deferred = Backbone.$.Deferred; + // @include ../marionette.helpers.js // @include ../marionette.triggermethod.js // @include ../marionette.domRefresh.js diff --git a/src/build/marionette.core.js b/src/build/marionette.core.js index 8267d50cfc..849c7b25bc 100644 --- a/src/build/marionette.core.js +++ b/src/build/marionette.core.js @@ -31,6 +31,9 @@ // Get the DOM manipulator for later use Marionette.$ = Backbone.$; + // Get the Deferred creator for later use + Marionette.Deferred = Backbone.$.Deferred; + // @include ../marionette.helpers.js // @include ../marionette.triggermethod.js // @include ../marionette.domRefresh.js diff --git a/src/marionette.callbacks.js b/src/marionette.callbacks.js index 7c1c26ad14..0bc34e45ef 100644 --- a/src/marionette.callbacks.js +++ b/src/marionette.callbacks.js @@ -5,7 +5,7 @@ // and executing them at a later point in time, using jQuery's // `Deferred` object. Marionette.Callbacks = function() { - this._deferred = Backbone.$.Deferred(); + this._deferred = Marionette.Deferred(); this._callbacks = []; }; @@ -15,11 +15,13 @@ _.extend(Marionette.Callbacks.prototype, { // guaranteed to execute, even if they are added after the // `run` method is called. add: function(callback, contextOverride) { + var promise = _.result(this._deferred, 'promise'); + this._callbacks.push({cb: callback, ctx: contextOverride}); - this._deferred.done(function(context, options) { - if (contextOverride) { context = contextOverride; } - callback.call(context, options); + promise.then(function(args) { + if (contextOverride){ args.context = contextOverride; } + callback.call(args.context, args.options); }); }, @@ -27,14 +29,17 @@ _.extend(Marionette.Callbacks.prototype, { // Additional callbacks can be added after this has been run // and they will still be executed. run: function(options, context) { - this._deferred.resolve(context, options); + this._deferred.resolve({ + options: options, + context: context + }); }, // Resets the list of callbacks to be run, allowing the same list // to be run multiple times - whenever the `run` method is called. reset: function() { var callbacks = this._callbacks; - this._deferred = Backbone.$.Deferred(); + this._deferred = Marionette.Deferred(); this._callbacks = []; _.each(callbacks, function(cb) {