diff --git a/package-lock.json b/package-lock.json index ca799e74..821ed8ad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openseadragon", - "version": "3.1.0", + "version": "4.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openseadragon", - "version": "3.1.0", + "version": "4.0.0", "license": "BSD-3-Clause", "devDependencies": { "grunt": "^1.4.1", diff --git a/src/eventsource.js b/src/eventsource.js index 9bc29704..f92adb67 100644 --- a/src/eventsource.js +++ b/src/eventsource.js @@ -58,7 +58,7 @@ $.EventSource.prototype = { /** * Add an event handler to be triggered only once (or a given number of times) - * for a given event. + * for a given event. It is not removable with removeHandler(). * @function * @param {String} eventName - Name of event to register. * @param {OpenSeadragon.EventHandler} handler - Function to call when event @@ -67,8 +67,9 @@ $.EventSource.prototype = { * to the handler. * @param {Number} [times=1] - The number of times to handle the event * before removing it. + * @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority. */ - addOnceHandler: function(eventName, handler, userData, times) { + addOnceHandler: function(eventName, handler, userData, times, priority) { var self = this; times = times || 1; var count = 0; @@ -77,9 +78,9 @@ $.EventSource.prototype = { if (count === times) { self.removeHandler(eventName, onceHandler); } - handler(event); + return handler(event); }; - this.addHandler(eventName, onceHandler, userData); + this.addHandler(eventName, onceHandler, userData, priority); }, /** @@ -88,14 +89,22 @@ $.EventSource.prototype = { * @param {String} eventName - Name of event to register. * @param {OpenSeadragon.EventHandler} handler - Function to call when event is triggered. * @param {Object} [userData=null] - Arbitrary object to be passed unchanged to the handler. + * @param {Number} [priority=0] - Handler priority. By default, all priorities are 0. Higher number = priority. */ - addHandler: function ( eventName, handler, userData ) { + addHandler: function ( eventName, handler, userData, priority ) { var events = this.events[ eventName ]; if ( !events ) { this.events[ eventName ] = events = []; } if ( handler && $.isFunction( handler ) ) { - events[ events.length ] = { handler: handler, userData: userData || null }; + var index = events.length, + event = { handler: handler, userData: userData || null, priority: priority || 0 }; + events[ index ] = event; + while ( index > 0 && events[ index - 1 ].priority < events[ index ].priority ) { + events[ index ] = events[ index - 1 ]; + events[ index - 1 ] = event; + index--; + } } }, @@ -156,7 +165,7 @@ $.EventSource.prototype = { * @function * @param {String} eventName - Name of event to get handlers for. */ - getHandler: function ( eventName ) { + getHandler: function ( eventName) { var events = this.events[ eventName ]; if ( !events || !events.length ) { return null; @@ -186,15 +195,12 @@ $.EventSource.prototype = { raiseEvent: function( eventName, eventArgs ) { //uncomment if you want to get a log of all events //$.console.log( eventName ); + var handler = this.getHandler( eventName ); - if ( handler ) { - if ( !eventArgs ) { - eventArgs = {}; - } - - handler( this, eventArgs ); + return handler( this, eventArgs || {} ); } + return undefined; } }; diff --git a/src/openseadragon.js b/src/openseadragon.js index 45e4c8e7..cb111195 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -826,14 +826,16 @@ function OpenSeadragon( options ){ * @private */ var class2type = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', - '[object Function]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regexp', - '[object Object]': 'object' + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object AsyncFunction]': 'function', + '[object Promise]': 'promise', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object' }, // Save a reference to some core methods toString = Object.prototype.toString, @@ -849,7 +851,6 @@ function OpenSeadragon( options ){ return $.type(obj) === "function"; }; - /** * Taken from jQuery 1.6.1 * @function isArray diff --git a/test/coverage.html b/test/coverage.html index 6d392209..68756461 100644 --- a/test/coverage.html +++ b/test/coverage.html @@ -65,6 +65,7 @@ + diff --git a/test/modules/event-source.js b/test/modules/event-source.js new file mode 100644 index 00000000..2f61e5ee --- /dev/null +++ b/test/modules/event-source.js @@ -0,0 +1,85 @@ +/* global QUnit, $, TouchUtil, Util, testLog */ + +(function () { + var context, result=[], eName = "test", eventCounter = 0, finished = false; + + function evaluateTest(e) { + if (finished) return; + finished = true; + e.assert.strictEqual(JSON.stringify(result), JSON.stringify(e.expected), e.message); + e.done(); + } + + function executor(i, ms) { + if (ms === undefined) return function (e) { + eventCounter++; + result.push(i); + if (eventCounter === context.numberOfHandlers(eName)) { + evaluateTest(e); + } + }; + + return function (e) { + return new Promise(function (resolve) { + setTimeout(function () { + eventCounter++; + result.push(i); + if (eventCounter === context.numberOfHandlers(eName)) { + evaluateTest(e); + } + resolve(); + }, ms); + }); + } + } + + function runTest(e) { + context.raiseEvent(eName, e); + } + + QUnit.module( 'EventSource', { + beforeEach: function () { + context = new OpenSeadragon.EventSource(); + eventCounter = 0; + result = []; + finished = false; + } + } ); + + // ---------- + QUnit.test('EventSource: no events', function(assert) { + context.addHandler(eName, evaluateTest); + runTest({ + assert: assert, + done: assert.async(), + expected: [], + message: 'No handlers registered - arrays should be empty.' + }); + }); + + QUnit.test('EventSource: simple callbacks order', function(assert) { + context.addHandler(eName, executor(1)); + context.addHandler(eName, executor(2)); + context.addHandler(eName, executor(3)); + runTest({ + assert: assert, + done: assert.async(), + expected: [1, 2, 3], + message: 'Simple callback order should follow [1,2,3].' + }); + }); + + QUnit.test('EventSource: priority callbacks order', function(assert) { + context.addHandler(eName, executor(1), undefined, 20); + context.addHandler(eName, executor(2), undefined, 124); + context.addHandler(eName, executor(3), undefined, -5); + context.addHandler(eName, executor(4)); + context.addHandler(eName, executor(5), undefined, -2); + runTest({ + assert: assert, + done: assert.async(), + expected: [2, 1, 4, 5, 3], + message: 'Prioritized callback order should follow [2,1,4,5,3].' + }); + }); +} )(); diff --git a/test/test.html b/test/test.html index 8b85a123..761db1f2 100644 --- a/test/test.html +++ b/test/test.html @@ -22,6 +22,7 @@ +