feat: Allow removing promises from the idle monitor.
This will facilitate tile layers reporting that they are idle when all
tiles in the view are loaded even if tiles out of the view are still
loading.
MODIFY
src/object.js
src/object.js
var inherit = require('./inherit');
var timestamp = require('./timestamp');
+var lastInternalId = 0;
+
/**
* Create a new instance of class object.
*
@@ -18,6 +20,7 @@ var object = function () {
var util = require('./util');
var m_this = this,
+ m_internalId = ++lastInternalId,
m_eventHandlers = {},
m_idleHandlers = [],
m_promiseCount = 0;
@@ -77,7 +80,10 @@ var object = function () {
this.addPromise = function (promise) {
// called on any resolution of the promise
function onDone() {
+ if (promise._geojsTracked && promise._geojsTracked[m_internalId]) {
m_promiseCount -= 1;
+ delete promise._geojsTracked[m_internalId];
+ }
if (!m_promiseCount) {
m_idleHandlers.splice(0, m_idleHandlers.length)
.forEach(function (handler) {
@@ -85,7 +91,13 @@ var object = function () {
});
}
}
+ if (!promise._geojsTracked) {
+ promise._geojsTracked = {};
+ }
+ if (!promise._geojsTracked[m_internalId]) {
+ promise._geojsTracked[m_internalId] = true;
m_promiseCount += 1;
+ }
if (promise.always) {
promise.always(onDone);
} else {
@@ -94,6 +106,27 @@ var object = function () {
return m_this;
};
+ /**
+ * Mark a promise as no longer required to resolve before the idle state is
+ * reached.
+ *
+ * @param {Promise} promise A promise object.
+ * @returns {this}
+ */
+ this.removePromise = function (promise) {
+ if (promise._geojsTracked && promise._geojsTracked[m_internalId]) {
+ m_promiseCount -= 1;
+ delete promise._geojsTracked[m_internalId];
+ if (!m_promiseCount) {
+ m_idleHandlers.splice(0, m_idleHandlers.length)
+ .forEach(function (handler) {
+ handler();
+ });
+ }
+ }
+ return m_this;
+ };
+
/**
* Bind an event handler to this object.
*
@@ -217,6 +250,8 @@ var object = function () {
m_eventHandlers = {};
m_idleHandlers = [];
m_promiseCount = 0;
+ // assign a new id so that adding and removing promises behave properly
+ m_internalId = ++lastInternalId;
}
if (Array.isArray(event)) {
event.forEach(function (e) {

MODIFY
src/sceneObject.js
src/sceneObject.js
@@ -23,7 +23,8 @@ var sceneObject = function (arg) {
m_children = [],
s_exit = this._exit,
s_trigger = this.geoTrigger,
- s_addPromise = this.addPromise;
+ s_addPromise = this.addPromise,
+ s_removePromise = this.removePromise;
/**
* Add the promise here and also propagate up the scene tree.
@@ -39,6 +40,20 @@ var sceneObject = function (arg) {
return m_this;
};
+ /**
+ * Remove the promise here and also propagate up the scene tree.
+ *
+ * @param {Promise} promise A promise object.
+ * @returns {this}
+ */
+ this.removePromise = function (promise) {
+ if (m_parent) {
+ m_parent.removePromise(promise);
+ }
+ s_removePromise(promise);
+ return m_this;
+ };
+
/**
* Get/set parent of the object.
*

MODIFY
tests/cases/sceneObject.js
tests/cases/sceneObject.js
@@ -311,5 +311,32 @@ describe('geo.sceneObject', function () {
}, 50);
});
+ it('removePromise', function () {
+ var defer = $.Deferred(),
+ handlerRoot = new CallCounter(null),
+ handler1 = new CallCounter(null),
+ handler2 = new CallCounter(null),
+ handler3 = new CallCounter(null);
+
+ function checkCallCount(countr, count1, count2, count3) {
+ expect(handlerRoot.ncalls).toBe(countr);
+ expect(handler1.ncalls).toBe(count1);
+ expect(handler2.ncalls).toBe(count2);
+ expect(handler3.ncalls).toBe(count3);
+ }
+
+ child3.addPromise(defer);
+ root.onIdle(handlerRoot.call);
+ child1.onIdle(handler1.call);
+ child2.onIdle(handler2.call);
+ child3.onIdle(handler3.call);
+
+ checkCallCount(0, 1, 0, 0);
+
+ child3.removePromise(defer);
+ checkCallCount(1, 1, 1, 1);
+
+ defer.resolve();
+ });
});
});

feat: Allow removing promises from the idle monitor.

This will facilitate tile layers reporting that they are idle when all
tiles in the view are loaded even if tiles out of the view are still
loading.