diff options
| author | Igor Minar | 2011-05-28 01:48:14 -0700 | 
|---|---|---|
| committer | Igor Minar | 2011-07-18 14:14:19 -0700 | 
| commit | 2b2df4754d8ee212741a78c068ba320d962556ba (patch) | |
| tree | 0a11ccedacf00fa3f7b987185bb912960ca4bf78 | |
| parent | 120701b9d9ebdd9352c7fca2b8a381597a808362 (diff) | |
| download | angular.js-2b2df4754d8ee212741a78c068ba320d962556ba.tar.bz2 | |
feat($browser.$defer.cancel): support canceling defered tasks
| -rw-r--r-- | src/Browser.js | 42 | ||||
| -rw-r--r-- | src/angular-mocks.js | 19 | ||||
| -rw-r--r-- | test/BrowserSpecs.js | 36 | 
3 files changed, 86 insertions, 11 deletions
| diff --git a/src/Browser.js b/src/Browser.js index 55b65471..58ad22c8 100644 --- a/src/Browser.js +++ b/src/Browser.js @@ -40,6 +40,8 @@ function Browser(window, document, body, XHR, $log) {        rawDocument = document[0],        location = window.location,        setTimeout = window.setTimeout, +      clearTimeout = window.clearTimeout, +      pendingDeferIds = {},        lastLocationUrl;    self.isMock = false; @@ -163,15 +165,12 @@ function Browser(window, document, body, XHR, $log) {     * @returns {function()} the added function     */    self.addPollFn = function(fn) { -    if (!pollTimeout) startPoller(100, setTimeout); +    if (isUndefined(pollTimeout)) startPoller(100, setTimeout);      pollFns.push(fn);      return fn;    };    /** -   * @name angular.service.$browser#startPoller -   * @methodOf angular.service.$browser -   *     * @param {number} interval How often should browser call poll functions (ms)     * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.     * @@ -339,20 +338,49 @@ function Browser(window, document, body, XHR, $log) {     * @methodOf angular.service.$browser     * @param {function()} fn A function, who's execution should be defered.     * @param {number=} [delay=0] of milliseconds to defer the function execution. +   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.     *     * @description     * Executes a fn asynchroniously via `setTimeout(fn, delay)`.     *     * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using -   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed via -   * `$browser.defer.flush()`. +   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed +   * via `$browser.defer.flush()`.     *     */    self.defer = function(fn, delay) { +    var timeoutId;      outstandingRequestCount++; -    setTimeout(function() { completeOutstandingRequest(fn); }, delay || 0); +    timeoutId = setTimeout(function() { +      delete pendingDeferIds[timeoutId]; +      completeOutstandingRequest(fn); +    }, delay || 0); +    pendingDeferIds[timeoutId] = true; +    return timeoutId;    }; + +  /** +   * @workInProgress +   * @ngdoc method +   * @name angular.service.$browser.defer#cancel +   * @methodOf angular.service.$browser.defer +   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfuly canceled. +   * +   * @description +   * Cancels a defered task identified with `deferId`. +   */ + +  self.defer.cancel = function(deferId) { +    if (pendingDeferIds[deferId]) { +      delete pendingDeferIds[deferId]; +      clearTimeout(deferId); +      completeOutstandingRequest(noop); +      return true; +    } +  }; + +    //////////////////////////////////////////////////////////////    // Misc API    ////////////////////////////////////////////////////////////// diff --git a/src/angular-mocks.js b/src/angular-mocks.js index a4941288..20423f05 100644 --- a/src/angular-mocks.js +++ b/src/angular-mocks.js @@ -281,15 +281,32 @@ function MockBrowser() {    self.cookieHash = {};    self.lastCookieHash = {};    self.deferredFns = []; +  self.deferredNextId = 0;    self.defer = function(fn, delay) {      delay = delay || 0; -    self.deferredFns.push({time:(self.defer.now + delay), fn:fn}); +    self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});      self.deferredFns.sort(function(a,b){ return a.time - b.time;}); +    return self.deferredNextId++;    }; +    self.defer.now = 0; + +  self.defer.cancel = function(deferId) { +    var fnIndex; + +    forEach(self.deferredFns, function(fn, index) { +      if (fn.id === deferId) fnIndex = index; +    }); + +    if (fnIndex) { +      self.deferredFns.splice(fnIndex, 1); +    } +  } + +    self.defer.flush = function(delay) {      if (angular.isDefined(delay)) {        self.defer.now += delay; diff --git a/test/BrowserSpecs.js b/test/BrowserSpecs.js index b4ad688b..40e983da 100644 --- a/test/BrowserSpecs.js +++ b/test/BrowserSpecs.js @@ -5,8 +5,11 @@ describe('browser', function(){    var browser, fakeWindow, xhr, logs, scripts, removedScripts, setTimeoutQueue;    function fakeSetTimeout(fn) { -    setTimeoutQueue.push(fn); -    return Math.random(); +    return setTimeoutQueue.push(fn) - 1; //return position in the queue +  } + +  function fakeClearTimeout(deferId) { +    setTimeoutQueue[deferId] = noop; //replace fn with noop to preserve other deferId indexes    }    fakeSetTimeout.flush = function() { @@ -25,7 +28,8 @@ describe('browser', function(){      xhr = null;      fakeWindow = {        location: {href:"http://server"}, -      setTimeout: fakeSetTimeout +      setTimeout: fakeSetTimeout, +      clearTimeout: fakeClearTimeout      };      var fakeBody = [{appendChild: function(node){scripts.push(node);}, @@ -161,6 +165,32 @@ describe('browser', function(){        fakeSetTimeout.flush();        expect(callback).toHaveBeenCalled();      }); + + +    it('should return unique deferId', function() { +      var deferId1 = browser.defer(noop), +          deferId2 = browser.defer(noop); + +      expect(deferId1).toBeDefined(); +      expect(deferId2).toBeDefined(); +      expect(deferId1).not.toEqual(deferId2); +    }) + + +    describe('cancel', function() { +      it('should allow tasks to be canceled with returned deferId', function() { +        var log = [], +            deferId1 = browser.defer(function() { log.push('cancel me') }), +            deferId2 = browser.defer(function() { log.push('ok') }), +            deferId3 = browser.defer(function() { log.push('cancel me, now!') }); + +        expect(log).toEqual([]); +        browser.defer.cancel(deferId1); +        browser.defer.cancel(deferId3); +        fakeSetTimeout.flush(); +        expect(log).toEqual(['ok']); +      }); +    });    }); | 
