diff --git a/bench/benchmarks/buffer.js b/bench/benchmarks/buffer.js index 2af74994ae6..dcf59268b41 100644 --- a/bench/benchmarks/buffer.js +++ b/bench/benchmarks/buffer.js @@ -90,7 +90,7 @@ function preloadAssets(stylesheet, callback) { var style = new Style(stylesheet); - style.on('load', function() { + style.on('style.load', function() { function getGlyphs(params, callback) { style['get glyphs'](0, params, function(err, glyphs) { assets.glyphs[JSON.stringify(params)] = glyphs; diff --git a/bench/benchmarks/style_load.js b/bench/benchmarks/style_load.js index 49c8ee5ae57..1d88a7b7fac 100644 --- a/bench/benchmarks/style_load.js +++ b/bench/benchmarks/style_load.js @@ -28,7 +28,7 @@ module.exports = function() { .on('error', function(err) { evented.fire('error', { error: err }); }) - .on('load', function() { + .on('style.load', function() { var time = performance.now() - timeStart; timeSum += time; timeCount++; diff --git a/js/source/geojson_source.js b/js/source/geojson_source.js index e56bdae38b4..189f5da436d 100644 --- a/js/source/geojson_source.js +++ b/js/source/geojson_source.js @@ -88,7 +88,7 @@ function GeoJSONSource(id, options, dispatcher) { this.fire('error', {error: err}); return; } - this.fire('load'); + this.fire('source.load'); }.bind(this)); } @@ -119,7 +119,7 @@ GeoJSONSource.prototype = util.inherit(Evented, /** @lends GeoJSONSource.prototy if (err) { return this.fire('error', { error: err }); } - this.fire('change'); + this.fire('source.change'); }.bind(this)); return this; diff --git a/js/source/image_source.js b/js/source/image_source.js index 2deedf57b35..9317ad22096 100644 --- a/js/source/image_source.js +++ b/js/source/image_source.js @@ -53,7 +53,7 @@ function ImageSource(id, options, dispatcher) { this.image = image; this._loaded = true; - this.fire('load'); + this.fire('source.load'); if (this.map) { this.setCoordinates(options.coordinates); @@ -106,7 +106,7 @@ ImageSource.prototype = util.inherit(Evented, /** @lends ImageSource.prototype * Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); }); - this.fire('change'); + this.fire('source.change'); return this; }, diff --git a/js/source/raster_tile_source.js b/js/source/raster_tile_source.js index 567b88d0aee..858d88cfe73 100644 --- a/js/source/raster_tile_source.js +++ b/js/source/raster_tile_source.js @@ -17,7 +17,7 @@ function RasterTileSource(id, options, dispatcher) { return this.fire('error', err); } util.extend(this, tileJSON); - this.fire('load'); + this.fire('source.load'); }.bind(this)); } diff --git a/js/source/source_cache.js b/js/source/source_cache.js index bd4afc7ce8c..dacaa258cc7 100644 --- a/js/source/source_cache.js +++ b/js/source/source_cache.js @@ -27,8 +27,10 @@ function SourceCache(id, options, dispatcher) { this.id = id; this.dispatcher = dispatcher; - var source = this._source = Source.create(id, options, dispatcher) - .on('load', function () { + var source = this._source = Source.create(id, options, dispatcher); + source.setEventedParent(this); + + this.on('source.load', function() { if (this.map && this._source.onAdd) { this._source.onAdd(this.map); } this._sourceLoaded = true; @@ -42,20 +44,18 @@ function SourceCache(id, options, dispatcher) { this.attribution = source.attribution; this.vectorLayerIds = source.vectorLayerIds; + }); - this.fire('load'); - }.bind(this)) - .on('error', function (e) { + this.on('error', function() { this._sourceErrored = true; - this.fire('error', e); - }.bind(this)) - .on('change', function () { + }); + + this.on('source.change', function() { this.reload(); if (this.transform) { this.update(this.transform, this.map && this.map.style.rasterFadeDuration); } - this.fire('change'); - }.bind(this)); + }); this._tiles = {}; this._cache = new Cache(0, this.unloadTile.bind(this)); @@ -160,14 +160,12 @@ SourceCache.prototype = util.inherit(Evented, { _tileLoaded: function (tile, err) { if (err) { tile.state = 'errored'; - this.fire('tile.error', {tile: tile, error: err}); - this._source.fire('tile.error', {tile: tile, error: err}); + this._source.fire('error', {tile: tile, error: err}); return; } tile.source = this; tile.timeAdded = new Date().getTime(); - this.fire('tile.load', {tile: tile}); this._source.fire('tile.load', {tile: tile}); // HACK this is nescessary to fix https://github.com/mapbox/mapbox-gl-js/issues/2986 @@ -409,7 +407,6 @@ SourceCache.prototype = util.inherit(Evented, { tile.uses++; this._tiles[coord.id] = tile; - this.fire('tile.add', {tile: tile}); this._source.fire('tile.add', {tile: tile}); return tile; @@ -428,7 +425,6 @@ SourceCache.prototype = util.inherit(Evented, { tile.uses--; delete this._tiles[id]; - this.fire('tile.remove', {tile: tile}); this._source.fire('tile.remove', {tile: tile}); if (tile.uses > 0) diff --git a/js/source/vector_tile_source.js b/js/source/vector_tile_source.js index 68e2537e862..3b58adf02c4 100644 --- a/js/source/vector_tile_source.js +++ b/js/source/vector_tile_source.js @@ -23,7 +23,7 @@ function VectorTileSource(id, options, dispatcher) { return; } util.extend(this, tileJSON); - this.fire('load'); + this.fire('source.load'); }.bind(this)); } diff --git a/js/source/video_source.js b/js/source/video_source.js index 6251d0fbb00..338819d4df3 100644 --- a/js/source/video_source.js +++ b/js/source/video_source.js @@ -73,7 +73,7 @@ function VideoSource(id, options) { this.setCoordinates(options.coordinates); } - this.fire('load'); + this.fire('source.load'); }.bind(this)); } @@ -135,7 +135,7 @@ VideoSource.prototype = util.inherit(Evented, /** @lends VideoSource.prototype * Math.round((zoomedCoord.row - centerCoord.row) * EXTENT)); }); - this.fire('change'); + this.fire('source.change'); return this; }, diff --git a/js/style/image_sprite.js b/js/style/image_sprite.js index 1d75cab23fa..28a4d1e2765 100644 --- a/js/style/image_sprite.js +++ b/js/style/image_sprite.js @@ -20,7 +20,7 @@ function ImageSprite(base) { } this.data = data; - if (this.img) this.fire('load'); + if (this.img) this.fire('style.change'); }.bind(this)); ajax.getImage(normalizeURL(base, format, '.png'), function(err, img) { @@ -41,7 +41,7 @@ function ImageSprite(base) { } this.img = img; - if (this.data) this.fire('load'); + if (this.data) this.fire('style.change'); }.bind(this)); } @@ -58,7 +58,7 @@ ImageSprite.prototype.loaded = function() { ImageSprite.prototype.resize = function(/*gl*/) { if (browser.devicePixelRatio > 1 !== this.retina) { var newSprite = new ImageSprite(this.base); - newSprite.on('load', function() { + newSprite.on('style.change', function() { this.img = newSprite.img; this.data = newSprite.data; this.retina = newSprite.retina; diff --git a/js/style/style.js b/js/style/style.js index 20d1999b53d..d38666169dc 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -34,12 +34,7 @@ function Style(stylesheet, animationLoop, options) { this.sources = {}; this.zoomHistory = {}; - util.bindAll([ - '_forwardSourceEvent', - '_forwardTileEvent', - '_forwardLayerEvent', - '_redoPlacement' - ], this); + util.bindAll(['_redoPlacement'], this); this._resetUpdates(); @@ -67,12 +62,12 @@ function Style(stylesheet, animationLoop, options) { if (stylesheet.sprite) { this.sprite = new ImageSprite(stylesheet.sprite); - this.sprite.on('load', this.fire.bind(this, 'change')); + this.sprite.setEventedParent(this); } this.glyphSource = new GlyphSource(stylesheet.glyphs); this._resolve(); - this.fire('load'); + this.fire('style.load'); }.bind(this); if (typeof stylesheet === 'string') { @@ -146,7 +141,7 @@ Style.prototype = util.inherit(Evented, { if (layerJSON.ref) continue; layer = StyleLayer.create(layerJSON); this._layers[layer.id] = layer; - layer.on('error', this._forwardLayerEvent); + layer.setEventedParent(this, {layer: {id: layer.id}}); } // resolve all layers WITH a ref @@ -156,7 +151,7 @@ Style.prototype = util.inherit(Evented, { var refLayer = this.getLayer(layerJSON.ref); layer = StyleLayer.create(layerJSON, refLayer); this._layers[layer.id] = layer; - layer.on('error', this._forwardLayerEvent); + layer.setEventedParent(this, {layer: {id: layer.id}}); } this._groupLayers(); @@ -305,7 +300,7 @@ Style.prototype = util.inherit(Evented, { this._applyClasses(classes, options); if (this._updates.changed) { - this.fire('change'); + this.fire('style.change'); } this._resetUpdates(); @@ -340,15 +335,7 @@ Style.prototype = util.inherit(Evented, { source = new SourceCache(id, source, this.dispatcher); this.sources[id] = source; source.style = this; - source - .on('load', this._forwardSourceEvent) - .on('error', this._forwardSourceEvent) - .on('change', this._forwardSourceEvent) - .on('tile.add', this._forwardTileEvent) - .on('tile.load', this._forwardTileEvent) - .on('tile.error', this._forwardTileEvent) - .on('tile.remove', this._forwardTileEvent) - .on('tile.stats', this._forwardTileEvent); + source.setEventedParent(this, {source: source}); this._updates.events.push(['source.add', {source: source}]); this._updates.changed = true; @@ -372,15 +359,7 @@ Style.prototype = util.inherit(Evented, { var source = this.sources[id]; delete this.sources[id]; delete this._updates.sources[id]; - source - .off('load', this._forwardSourceEvent) - .off('error', this._forwardSourceEvent) - .off('change', this._forwardSourceEvent) - .off('tile.add', this._forwardTileEvent) - .off('tile.load', this._forwardTileEvent) - .off('tile.error', this._forwardTileEvent) - .off('tile.remove', this._forwardTileEvent) - .off('tile.stats', this._forwardTileEvent); + source.setEventedParent(null); this._updates.events.push(['source.remove', {source: source}]); this._updates.changed = true; @@ -420,7 +399,7 @@ Style.prototype = util.inherit(Evented, { } this._validateLayer(layer); - layer.on('error', this._forwardLayerEvent); + layer.setEventedParent(this, {layer: {id: layer.id}}); this._layers[layer.id] = layer; this._order.splice(before ? this._order.indexOf(before) : Infinity, 0, layer.id); @@ -454,7 +433,7 @@ Style.prototype = util.inherit(Evented, { } } - layer.off('error', this._forwardLayerEvent); + layer.setEventedParent(null); delete this._layers[id]; delete this._updates.layers[id]; @@ -730,18 +709,6 @@ Style.prototype = util.inherit(Evented, { } }, - _forwardSourceEvent: function(e) { - this.fire('source.' + e.type, util.extend({source: e.target.getSource()}, e)); - }, - - _forwardTileEvent: function(e) { - this.fire(e.type, util.extend({source: e.target}, e)); - }, - - _forwardLayerEvent: function(e) { - this.fire('layer.' + e.type, util.extend({layer: {id: e.target.id}}, e)); - }, - // Callbacks from web workers 'get icons': function(mapId, params, callback) { @@ -751,7 +718,7 @@ Style.prototype = util.inherit(Evented, { spriteAtlas.setSprite(sprite); spriteAtlas.addIcons(params.icons, callback); } else { - sprite.on('load', function() { + sprite.on('style.change', function() { spriteAtlas.setSprite(sprite); spriteAtlas.addIcons(params.icons, callback); }); diff --git a/js/ui/map.js b/js/ui/map.js index a345322ae8a..1c3c316f784 100755 --- a/js/ui/map.js +++ b/js/ui/map.js @@ -146,15 +146,6 @@ var Map = module.exports = function(options) { } util.bindAll([ - '_forwardStyleEvent', - '_forwardSourceEvent', - '_forwardLayerEvent', - '_forwardTileEvent', - '_onStyleLoad', - '_onStyleChange', - '_onSourceAdd', - '_onSourceRemove', - '_onSourceUpdate', '_onWindowOnline', '_onWindowResize', '_contextLost', @@ -199,11 +190,30 @@ var Map = module.exports = function(options) { if (options.style) this.setStyle(options.style); if (options.attributionControl) this.addControl(new Attribution(options.attributionControl)); - var fireError = this.fire.bind(this, 'error'); - this.on('style.error', fireError); - this.on('source.error', fireError); - this.on('tile.error', fireError); - this.on('layer.error', fireError); + this.on('style.load', function() { + if (this.transform.unmodified) { + this.jumpTo(this.style.stylesheet); + } + this.style.update(this._classes, {transition: false}); + }); + + this.on('style.change', function() { + this._update(true); + }); + + this.on('source.add', function(event) { + var source = event.source; + if (source.onAdd) source.onAdd(this); + }); + + this.on('source.remove', function(event) { + var source = event.source; + if (source.onRemove) source.onRemove(this); + }); + + this.on('source.load', this._update); + this.on('source.change', this._update); + this.on('tile.load', this._update); }; util.extend(Map.prototype, Evented); @@ -605,24 +615,8 @@ util.extend(Map.prototype, /** @lends Map.prototype */{ */ setStyle: function(style) { if (this.style) { - this.style - .off('load', this._onStyleLoad) - .off('error', this._forwardStyleEvent) - .off('change', this._onStyleChange) - .off('source.add', this._onSourceAdd) - .off('source.remove', this._onSourceRemove) - .off('source.load', this._onSourceUpdate) - .off('source.error', this._forwardSourceEvent) - .off('source.change', this._onSourceUpdate) - .off('layer.add', this._forwardLayerEvent) - .off('layer.remove', this._forwardLayerEvent) - .off('layer.error', this._forwardLayerEvent) - .off('tile.add', this._forwardTileEvent) - .off('tile.remove', this._forwardTileEvent) - .off('tile.load', this._update) - .off('tile.error', this._forwardTileEvent) - .off('tile.stats', this._forwardTileEvent) - ._remove(); + this.style.setEventedParent(null); + this.style._remove(); this.off('rotate', this.style._redoPlacement); this.off('pitch', this.style._redoPlacement); @@ -637,23 +631,7 @@ util.extend(Map.prototype, /** @lends Map.prototype */{ this.style = new Style(style, this.animationLoop); } - this.style - .on('load', this._onStyleLoad) - .on('error', this._forwardStyleEvent) - .on('change', this._onStyleChange) - .on('source.add', this._onSourceAdd) - .on('source.remove', this._onSourceRemove) - .on('source.load', this._onSourceUpdate) - .on('source.error', this._forwardSourceEvent) - .on('source.change', this._onSourceUpdate) - .on('layer.add', this._forwardLayerEvent) - .on('layer.remove', this._forwardLayerEvent) - .on('layer.error', this._forwardLayerEvent) - .on('tile.add', this._forwardTileEvent) - .on('tile.remove', this._forwardTileEvent) - .on('tile.load', this._update) - .on('tile.error', this._forwardTileEvent) - .on('tile.stats', this._forwardTileEvent); + this.style.setEventedParent(this, {style: this.style}); this.on('rotate', this.style._redoPlacement); this.on('pitch', this.style._redoPlacement); @@ -1116,54 +1094,6 @@ util.extend(Map.prototype, /** @lends Map.prototype */{ } }, - _forwardStyleEvent: function(e) { - this.fire('style.' + e.type, util.extend({style: e.target}, e)); - }, - - _forwardSourceEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); - }, - - _forwardLayerEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); - }, - - _forwardTileEvent: function(e) { - this.fire(e.type, util.extend({style: e.target}, e)); - }, - - _onStyleLoad: function(e) { - if (this.transform.unmodified) { - this.jumpTo(this.style.stylesheet); - } - this.style.update(this._classes, {transition: false}); - this._forwardStyleEvent(e); - }, - - _onStyleChange: function(e) { - this._update(true); - this._forwardStyleEvent(e); - }, - - _onSourceAdd: function(e) { - var source = e.source; - if (source.onAdd) - source.onAdd(this); - this._forwardSourceEvent(e); - }, - - _onSourceRemove: function(e) { - var source = e.source; - if (source.onRemove) - source.onRemove(this); - this._forwardSourceEvent(e); - }, - - _onSourceUpdate: function(e) { - this._update(); - this._forwardSourceEvent(e); - }, - _onWindowOnline: function() { this._update(); }, diff --git a/js/util/evented.js b/js/util/evented.js index b347e6623dc..7eec82c04dd 100644 --- a/js/util/evented.js +++ b/js/util/evented.js @@ -19,9 +19,9 @@ var Evented = { * @returns {Object} `this` */ on: function(type, listener) { - this._events = this._events || {}; - this._events[type] = this._events[type] || []; - this._events[type].push(listener); + this._listeners = this._listeners || {}; + this._listeners[type] = this._listeners[type] || []; + this._listeners[type].push(listener); return this; }, @@ -29,31 +29,16 @@ var Evented = { /** * Removes a previously registered event listener. * - * @param {string} [type] The event type to remove listeners for. - * If none is specified, listeners will be removed for all event types. - * @param {Function} [listener] The listener function to remove. - * If none is specified, all listeners will be removed for the event type. + * @param {string} type The event type to remove listeners for. + * @param {Function} listener The listener function to remove. * @returns {Object} `this` */ off: function(type, listener) { - if (!type) { - // clear all listeners if no arguments specified - delete this._events; - return this; - } - - if (!this.listens(type)) return this; - - if (listener) { - var idx = this._events[type].indexOf(listener); - if (idx >= 0) { - this._events[type].splice(idx, 1); + if (this._listeners && this._listeners[type]) { + var index = this._listeners[type].indexOf(listener); + if (index !== -1) { + this._listeners[type].splice(index, 1); } - if (!this._events[type].length) { - delete this._events[type]; - } - } else { - delete this._events[type]; } return this; @@ -85,36 +70,56 @@ var Evented = { * @returns {Object} `this` */ fire: function(type, data) { - if (!this.listens(type)) { - // To ensure that no error events are dropped, print them to the - // console if they have no listeners. - if (util.endsWith(type, 'error')) { - console.error((data && data.error) || data || 'Empty error event'); - } - return this; - } + if (this.listens(type)) { + + data = util.extend({}, data, {type: type, target: this}); - data = util.extend({}, data); - util.extend(data, {type: type, target: this}); + // make sure adding or removing listeners inside other listeners won't cause an infinite loop + var listeners = this._listeners && this._listeners[type] ? this._listeners[type].slice() : []; + + for (var i = 0; i < listeners.length; i++) { + listeners[i].call(this, data); + } - // make sure adding/removing listeners inside other listeners won't cause infinite loop - var listeners = this._events[type].slice(); + if (this._eventedParent) { + this._eventedParent.fire(type, util.extend({}, data, this._eventedParentData)); + } - for (var i = 0; i < listeners.length; i++) { - listeners[i].call(this, data); + // To ensure that no error events are dropped, print them to the + // console if they have no listeners. + } else if (util.endsWith(type, 'error')) { + console.error((data && data.error) || data || 'Empty error event'); } return this; }, /** - * Returns a Boolean indicating whether any listeners are registered for a specified event type. + * Returns a true if this instance of Evented or any forwardeed instances of Evented have a listener for the specified type. * - * @param {string} type The event type to check. - * @returns {boolean} `true` if there is at least one registered listener for specified event type. + * @param {string} type The event type + * @returns {boolean} `true` if there is at least one registered listener for specified event type, `false` otherwise */ listens: function(type) { - return !!(this._events && this._events[type]); + return ( + (this._listeners && this._listeners[type]) || + (this._eventedParent && this._eventedParent.listens(type)) + ); + }, + + /** + * Bubble all events fired by this instance of Evented to this parent instance of Evented. + * + * @private + * @param {parent} + * @param {data} + * @returns {Object} `this` + */ + setEventedParent: function(parent, data) { + this._eventedParent = parent; + this._eventedParentData = data; + + return this; } }; diff --git a/test/js/source/geojson_source.test.js b/test/js/source/geojson_source.test.js index 08596980a07..84d1ccfd0b1 100644 --- a/test/js/source/geojson_source.test.js +++ b/test/js/source/geojson_source.test.js @@ -59,7 +59,7 @@ test('GeoJSONSource#setData', function(t) { } }; var source = new GeoJSONSource('id', {data: {}}, mockDispatcher); - source.on('change', function() { + source.on('source.change', function() { t.end(); }); source.setData({}); @@ -119,7 +119,7 @@ test('GeoJSONSource#update', function(t) { var source = new GeoJSONSource('id', {data: {}}, mockDispatcher); - source.on('load', function() { + source.on('source.load', function() { t.end(); }); }); @@ -148,11 +148,11 @@ test('GeoJSONSource#update', function(t) { var source = new GeoJSONSource('id', {data: {}}, mockDispatcher); - source.on('load', function() { + source.on('source.load', function() { // Note: we register this before calling setData because `change` // is fired synchronously within that method. It may be worth // considering dezalgoing there. - source.on('change', function () { + source.on('source.change', function () { t.end(); }); source.setData({}); @@ -175,7 +175,7 @@ test('GeoJSONSource#update', function(t) { transform: {} }; - source.on('load', function () { + source.on('source.load', function () { source.setData({}); source.loadTile(new Tile(new TileCoord(0, 0, 0), 512), function () {}); }); @@ -216,4 +216,3 @@ test('GeoJSONSource#serialize', function(t) { t.end(); }); - diff --git a/test/js/source/source_cache.test.js b/test/js/source/source_cache.test.js index 05499bae5d8..f3c988334a5 100644 --- a/test/js/source/source_cache.test.js +++ b/test/js/source/source_cache.test.js @@ -32,7 +32,7 @@ Source.setType('mock-source-type', function create (id, sourceOptions) { if (sourceOptions.error) { source.fire('error', { error: sourceOptions.error }); } else { - source.fire('load'); + source.fire('source.load'); } }, 0); return source; @@ -53,7 +53,7 @@ test('SourceCache#attribution is set', function(t) { var sourceCache = createSourceCache({ attribution: 'Mapbox Heavy Industries' }); - sourceCache.on('load', function() { + sourceCache.on('source.load', function() { t.equal(sourceCache.attribution, 'Mapbox Heavy Industries'); t.end(); }); @@ -205,18 +205,18 @@ test('SourceCache#removeTile', function(t) { test('SourceCache / Source lifecycle', function (t) { t.test('does not fire load or change before source load event', function (t) { createSourceCache({noLoad: true}) - .on('load', t.fail) - .on('change', t.fail); + .on('source.load', t.fail) + .on('source.change', t.fail); setTimeout(t.end, 1); }); t.test('forward load event', function (t) { - createSourceCache({}).on('load', t.end); + createSourceCache({}).on('source.load', t.end); }); t.test('forward change event', function (t) { - var sourceCache = createSourceCache().on('change', t.end); - sourceCache.getSource().fire('change'); + var sourceCache = createSourceCache().on('source.change', t.end); + sourceCache.getSource().fire('source.change'); }); t.test('forward error event', function (t) { @@ -251,9 +251,9 @@ test('SourceCache / Source lifecycle', function (t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); - sourceCache.getSource().fire('change'); + sourceCache.getSource().fire('source.change'); }); }); @@ -267,7 +267,7 @@ test('SourceCache#update', function(t) { transform.zoom = 0; var sourceCache = createSourceCache({}, false); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), []); @@ -281,7 +281,7 @@ test('SourceCache#update', function(t) { transform.zoom = 0; var sourceCache = createSourceCache({}); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), [new TileCoord(0, 0, 0).id]); t.end(); @@ -299,7 +299,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), [new TileCoord(0, 0, 0).id]); @@ -330,7 +330,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), [new TileCoord(0, 0, 0).id]); @@ -361,7 +361,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), [new TileCoord(0, 0, 0, 1).id]); @@ -392,7 +392,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform, 100); t.deepEqual(sourceCache.getIds(), [ new TileCoord(2, 1, 1).id, @@ -422,7 +422,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform, 100); transform.zoom = 2; @@ -452,7 +452,7 @@ test('SourceCache#update', function(t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { t.equal(sourceCache.maxzoom, 14); sourceCache.update(transform); @@ -531,7 +531,7 @@ test('SourceCache#tilesIn', function (t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { sourceCache.update(transform); t.deepEqual(sourceCache.getIds(), [ @@ -572,7 +572,7 @@ test('SourceCache#tilesIn', function (t) { tileSize: 512 }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { var transform = new Transform(); transform.resize(512, 512); transform.zoom = 2.0; @@ -616,7 +616,7 @@ test('SourceCache#tilesIn', function (t) { tileSize: 512 }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { var transform = new Transform(); transform.resize(512, 512); transform.zoom = 2.0; @@ -638,7 +638,7 @@ test('SourceCache#loaded (no errors)', function (t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { var coord = new TileCoord(0, 0, 0); sourceCache.addTile(coord); @@ -654,7 +654,7 @@ test('SourceCache#loaded (with errors)', function (t) { } }); - sourceCache.on('load', function () { + sourceCache.on('source.load', function () { var coord = new TileCoord(0, 0, 0); sourceCache.addTile(coord); diff --git a/test/js/source/vector_tile_source.test.js b/test/js/source/vector_tile_source.test.js index 47685547e07..0208a619eb2 100644 --- a/test/js/source/vector_tile_source.test.js +++ b/test/js/source/vector_tile_source.test.js @@ -38,7 +38,7 @@ test('VectorTileSource', function(t) { tiles: ["http://example.com/{z}/{x}/{y}.png"] }); - source.on('load', function() { + source.on('source.load', function() { t.deepEqual(source.tiles, ["http://example.com/{z}/{x}/{y}.png"]); t.deepEqual(source.minzoom, 1); t.deepEqual(source.maxzoom, 10); @@ -52,7 +52,7 @@ test('VectorTileSource', function(t) { var source = createSource({ url: "/source.json" }); - source.on('load', function() { + source.on('source.load', function() { t.deepEqual(source.tiles, ["http://example.com/{z}/{x}/{y}.png"]); t.deepEqual(source.minzoom, 1); t.deepEqual(source.maxzoom, 10); @@ -107,7 +107,7 @@ test('VectorTileSource', function(t) { t.end(); }; - source.on('load', function() { + source.on('source.load', function() { source.loadTile({coord: new TileCoord(10, 5, 5, 0)}, function () {}); }); }); @@ -127,7 +127,7 @@ test('VectorTileSource', function(t) { return 1; }; - source.on('load', function () { + source.on('source.load', function () { var tile = { coord: new TileCoord(10, 5, 5, 0), state: 'loading', diff --git a/test/js/style/style.test.js b/test/js/style/style.test.js index 3bc11f9baa4..8fd77a4e2c9 100644 --- a/test/js/style/style.test.js +++ b/test/js/style/style.test.js @@ -53,7 +53,7 @@ test('Style', function(t) { window.useFakeXMLHttpRequest(); window.server.respondWith('/style.json', JSON.stringify(require('../../fixtures/style'))); var style = new Style('/style.json'); - style.on('load', function() { + style.on('style.load', function() { window.restore(); t.end(); }); @@ -69,7 +69,7 @@ test('Style', function(t) { } } })); - style.on('load', function() { + style.on('style.load', function() { t.ok(style.sources['mapbox'] instanceof SourceCache); t.end(); }); @@ -105,7 +105,7 @@ test('Style', function(t) { .on('error', function() { t.fail(); }) - .on('load', function() { + .on('style.load', function() { window.restore(); t.end(); }); @@ -127,7 +127,7 @@ test('Style', function(t) { }] })); - style.on('load', function() { + style.on('style.load', function() { style.removeSource('-source-id-'); var source = createSource(); @@ -156,13 +156,13 @@ test('Style', function(t) { }] })); - style.on('layer.error', function(e) { + style.on('error', function(e) { t.deepEqual(e.layer, {id: 'background'}); t.ok(e.mapbox); t.end(); }); - style.on('load', function() { + style.on('style.load', function() { style._layers.background.fire('error', {mapbox: true}); }); }); @@ -188,7 +188,7 @@ test('Style#_updateWorkerLayers', function(t) { style.on('error', function(error) { t.error(error); }); - style.on('load', function() { + style.on('style.load', function() { style.addLayer({id: 'first', source: 'source', type: 'fill', 'source-layer': 'source-layer' }, 'second'); style.addLayer({id: 'third', source: 'source', type: 'fill', 'source-layer': 'source-layer' }); @@ -219,7 +219,7 @@ test('Style#_updateWorkerLayers with specific ids', function(t) { style.on('error', function(error) { t.error(error); }); - style.on('load', function() { + style.on('style.load', function() { style.dispatcher.broadcast = function(key, value) { t.equal(key, 'update layers'); t.deepEqual(value.map(function(layer) { return layer.id; }), ['second', 'third']); @@ -249,7 +249,7 @@ test('Style#_resolve', function(t) { style.on('error', function(error) { t.error(error); }); - style.on('load', function() { + style.on('style.load', function() { t.ok(style.getLayer('fill') instanceof StyleLayer); t.end(); }); @@ -277,7 +277,7 @@ test('Style#_resolve', function(t) { style.on('error', function(event) { t.error(event.error); }); - style.on('load', function() { + style.on('style.load', function() { var ref = style.getLayer('ref'), referent = style.getLayer('referent'); t.equal(ref.type, 'fill'); @@ -293,7 +293,7 @@ test('Style#addSource', function(t) { t.test('returns self', function(t) { var style = new Style(createStyleJSON()), source = createSource(); - style.on('load', function () { + style.on('style.load', function () { t.equal(style.addSource('source-id', source), style); t.end(); }); @@ -305,7 +305,7 @@ test('Style#addSource', function(t) { t.throws(function () { style.addSource('source-id', source); }, Error, /load/i); - style.on('load', function() { + style.on('style.load', function() { t.end(); }); }); @@ -316,7 +316,7 @@ test('Style#addSource', function(t) { delete source.type; - style.on('load', function() { + style.on('style.load', function() { t.throws(function () { style.addSource('source-id', source); }, Error, /type/i); @@ -331,7 +331,7 @@ test('Style#addSource', function(t) { t.same(e.source.serialize(), source); t.end(); }); - style.on('load', function () { + style.on('style.load', function () { style.addSource('source-id', source); style.update(); }); @@ -340,7 +340,7 @@ test('Style#addSource', function(t) { t.test('throws on duplicates', function(t) { var style = new Style(createStyleJSON()), source = createSource(); - style.on('load', function () { + style.on('style.load', function () { style.addSource('source-id', source); t.throws(function() { style.addSource('source-id', source); @@ -351,7 +351,7 @@ test('Style#addSource', function(t) { t.test('emits on invalid source', function(t) { var style = new Style(createStyleJSON()); - style.on('load', function() { + style.on('style.load', function() { style.on('error', function() { t.notOk(style.sources['source-id']); t.end(); @@ -375,30 +375,24 @@ test('Style#addSource', function(t) { })); var source = createSource(); - function sourceEvent(e) { + function checkEvent(e) { t.same(e.source.serialize(), source); } - function tileEvent(e) { - t.same(e.source.serialize(), source); - } - - style.on('source.load', sourceEvent); - style.on('source.error', sourceEvent); - style.on('source.change', sourceEvent); - style.on('tile.add', tileEvent); - style.on('tile.load', tileEvent); - style.on('tile.error', tileEvent); - style.on('tile.remove', tileEvent); + style.on('error', checkEvent); + style.on('source.load', checkEvent); + style.on('source.change', checkEvent); + style.on('tile.add', checkEvent); + style.on('tile.load', checkEvent); + style.on('tile.remove', checkEvent); - style.on('load', function () { - t.plan(7); + style.on('style.load', function () { + t.plan(6); style.addSource('source-id', source); // Fires load style.sources['source-id'].fire('error'); - style.sources['source-id'].fire('change'); + style.sources['source-id'].fire('source.change'); style.sources['source-id'].fire('tile.add'); style.sources['source-id'].fire('tile.load'); - style.sources['source-id'].fire('tile.error'); style.sources['source-id'].fire('tile.remove'); }); }); @@ -410,7 +404,7 @@ test('Style#removeSource', function(t) { t.test('returns self', function(t) { var style = new Style(createStyleJSON()), source = createSource(); - style.on('load', function () { + style.on('style.load', function () { style.addSource('source-id', source); t.equal(style.removeSource('source-id'), style); t.end(); @@ -429,7 +423,7 @@ test('Style#removeSource', function(t) { t.throws(function () { style.removeSource('source-id'); }, Error, /load/i); - style.on('load', function() { + style.on('style.load', function() { t.end(); }); }); @@ -441,7 +435,7 @@ test('Style#removeSource', function(t) { t.same(e.source.serialize(), source); t.end(); }); - style.on('load', function () { + style.on('style.load', function () { style.addSource('source-id', source); style.removeSource('source-id'); style.update(); @@ -460,7 +454,7 @@ test('Style#removeSource', function(t) { t.test('throws on non-existence', function(t) { var style = new Style(createStyleJSON()); - style.on('load', function () { + style.on('style.load', function () { t.throws(function() { style.removeSource('source-id'); }, /There is no source with this ID/); @@ -473,14 +467,14 @@ test('Style#removeSource', function(t) { source = createSource(); style.on('source.load', t.fail); - style.on('source.error', t.fail); + style.on('error', t.fail); style.on('source.change', t.fail); style.on('tile.add', t.fail); style.on('tile.load', t.fail); - style.on('tile.error', t.fail); + style.on('error', t.fail); style.on('tile.remove', t.fail); - style.on('load', function () { + style.on('style.load', function () { style.addSource('source-id', source); source = style.sources['source-id']; @@ -488,14 +482,14 @@ test('Style#removeSource', function(t) { // Bind a listener to prevent fallback Evented error reporting. source.on('error', function() {}); - source.on('tile.error', function() {}); + source.on('error', function() {}); - source.fire('load'); + source.fire('source.load'); source.fire('error'); - source.fire('change'); + source.fire('source.change'); source.fire('tile.add'); source.fire('tile.load'); - source.fire('tile.error'); + source.fire('error'); source.fire('tile.remove'); t.end(); }); @@ -509,7 +503,7 @@ test('Style#addLayer', function(t) { var style = new Style(createStyleJSON()), layer = {id: 'background', type: 'background'}; - style.on('load', function() { + style.on('style.load', function() { t.equal(style.addLayer(layer), style); t.end(); }); @@ -521,7 +515,7 @@ test('Style#addLayer', function(t) { t.throws(function () { style.addLayer(layer); }, Error, /load/i); - style.on('load', function() { + style.on('style.load', function() { t.end(); }); }); @@ -529,13 +523,13 @@ test('Style#addLayer', function(t) { t.test('sets up layer event forwarding', function(t) { var style = new Style(createStyleJSON()); - style.on('layer.error', function(e) { + style.on('error', function(e) { t.deepEqual(e.layer, {id: 'background'}); t.ok(e.mapbox); t.end(); }); - style.on('load', function() { + style.on('style.load', function() { style.addLayer({ id: 'background', type: 'background' @@ -552,7 +546,7 @@ test('Style#addLayer', function(t) { } })); - style.on('load', function() { + style.on('style.load', function() { var source = createSource(); source['vector_layers'] = [{id: 'green'}]; style.addSource('-source-id-', source); @@ -578,7 +572,7 @@ test('Style#addLayer', function(t) { t.test('emits error on invalid layer', function(t) { var style = new Style(createStyleJSON()); - style.on('load', function() { + style.on('style.load', function() { style.on('error', function() { t.notOk(style.getLayer('background')); t.end(); @@ -610,7 +604,7 @@ test('Style#addLayer', function(t) { "filter": ["==", "id", 0] }; - style.on('load', function() { + style.on('style.load', function() { style.sources['mapbox'].reload = t.end; style.addLayer(layer); @@ -627,7 +621,7 @@ test('Style#addLayer', function(t) { t.end(); }); - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer); style.update(); }); @@ -637,13 +631,13 @@ test('Style#addLayer', function(t) { var style = new Style(createStyleJSON()), layer = {id: 'background', type: 'background'}; - style.on('layer.error', function(e) { + style.on('error', function(e) { t.deepEqual(e.layer, {id: 'background'}); t.notOk(/duplicate/.match(e.error.message)); t.end(); }); - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer); style.addLayer(layer); t.end(); @@ -662,7 +656,7 @@ test('Style#addLayer', function(t) { })), layer = {id: 'c', type: 'background'}; - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer); t.deepEqual(style._order, ['a', 'b', 'c']); t.end(); @@ -681,7 +675,7 @@ test('Style#addLayer', function(t) { })), layer = {id: 'c', type: 'background'}; - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer, 'a'); t.deepEqual(style._order, ['c', 'a', 'b']); t.end(); @@ -696,7 +690,7 @@ test('Style#removeLayer', function(t) { var style = new Style(createStyleJSON()), layer = {id: 'background', type: 'background'}; - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer); t.equal(style.removeLayer('background'), style); t.end(); @@ -710,7 +704,7 @@ test('Style#removeLayer', function(t) { t.throws(function () { style.removeLayer('background'); }, Error, /load/i); - style.on('load', function() { + style.on('style.load', function() { t.end(); }); }); @@ -724,7 +718,7 @@ test('Style#removeLayer', function(t) { t.end(); }); - style.on('load', function() { + style.on('style.load', function() { style.addLayer(layer); style.removeLayer('background'); style.update(); @@ -739,11 +733,11 @@ test('Style#removeLayer', function(t) { }] })); - style.on('layer.error', function() { + style.on('error', function() { t.fail(); }); - style.on('load', function() { + style.on('style.load', function() { var layer = style._layers.background; style.removeLayer('background'); @@ -758,7 +752,7 @@ test('Style#removeLayer', function(t) { t.test('throws on non-existence', function(t) { var style = new Style(createStyleJSON()); - style.on('load', function() { + style.on('style.load', function() { t.throws(function () { style.removeLayer('background'); }, /There is no layer with this ID/); @@ -777,7 +771,7 @@ test('Style#removeLayer', function(t) { }] })); - style.on('load', function() { + style.on('style.load', function() { style.removeLayer('a'); t.deepEqual(style._order, ['b']); t.end(); @@ -795,7 +789,7 @@ test('Style#removeLayer', function(t) { }] })); - style.on('load', function() { + style.on('style.load', function() { style.removeLayer('a'); t.deepEqual(style.getLayer('a'), undefined); t.deepEqual(style.getLayer('b'), undefined); @@ -823,7 +817,7 @@ test('Style#setFilter', function(t) { t.test('sets filter', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { style.dispatcher.broadcast = function(key, value) { t.equal(key, 'update layers'); t.deepEqual(value[0].id, 'symbol'); @@ -840,7 +834,7 @@ test('Style#setFilter', function(t) { t.test('gets a clone of the filter', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { var filter1 = ['==', 'id', 1]; style.setFilter('symbol', filter1); var filter2 = style.getFilter('symbol'); @@ -857,7 +851,7 @@ test('Style#setFilter', function(t) { t.test('sets again mutated filter', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { var filter = ['==', 'id', 1]; style.setFilter('symbol', filter); style.update({}, {}); // flush pending operations @@ -877,7 +871,7 @@ test('Style#setFilter', function(t) { t.test('sets filter on parent', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { style.dispatcher.broadcast = function(key, value) { t.equal(key, 'update layers'); t.deepEqual(value.map(function(layer) { return layer.id; }), ['symbol']); @@ -902,7 +896,7 @@ test('Style#setFilter', function(t) { t.test('emits if invalid', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { style.on('error', function() { t.deepEqual(style.getLayer('symbol').serialize().filter, ['==', 'id', 0]); t.end(); @@ -935,7 +929,7 @@ test('Style#setLayerZoomRange', function(t) { t.test('sets zoom range', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { style.dispatcher.broadcast = function(key, value) { t.equal(key, 'update layers'); t.deepEqual(value.map(function(layer) { return layer.id; }), ['symbol']); @@ -951,7 +945,7 @@ test('Style#setLayerZoomRange', function(t) { t.test('sets zoom range on parent layer', function(t) { var style = createStyle(); - style.on('load', function() { + style.on('style.load', function() { style.dispatcher.broadcast = function(key, value) { t.equal(key, 'update layers'); t.deepEqual(value.map(function(layer) { return layer.id; }), ['symbol']); @@ -969,7 +963,7 @@ test('Style#setLayerZoomRange', function(t) { t.throws(function () { style.setLayerZoomRange('symbol', 5, 12); }, Error, /load/i); - style.on('load', function() { + style.on('style.load', function() { t.end(); }); }); @@ -1071,7 +1065,7 @@ test('Style#queryRenderedFeatures', function(t) { }] }); - style.on('load', function() { + style.on('style.load', function() { style._applyClasses([]); style._recalculate(0); @@ -1154,7 +1148,7 @@ test('Style defers expensive methods', function(t) { } })); - style.on('load', function() { + style.on('style.load', function() { style.update(); // spies to track defered methods @@ -1182,7 +1176,7 @@ test('Style defers expensive methods', function(t) { t.equal(style.fire.args[0][0], 'layer.add', 'fire was called with layer.add'); t.equal(style.fire.args[1][0], 'layer.add', 'fire was called with layer.add'); t.equal(style.fire.args[2][0], 'layer.add', 'fire was called with layer.add'); - t.equal(style.fire.args[3][0], 'change', 'fire was called with change'); + t.equal(style.fire.args[3][0], 'style.change', 'fire was called with style.change'); // called per source t.ok(style._reloadSource.calledTwice, '_reloadSource is called per source'); @@ -1224,7 +1218,7 @@ test('Style#query*Features', function(t) { onError = sinon.spy(); style.on('error', onError) - .on('load', function() { + .on('style.load', function() { callback(); }); }); diff --git a/test/js/ui/map.test.js b/test/js/ui/map.test.js index 7611110cee2..c9e4e42b0db 100755 --- a/test/js/ui/map.test.js +++ b/test/js/ui/map.test.js @@ -1,10 +1,9 @@ 'use strict'; var test = require('tap').test; -var extend = require('../../../js/util/util').extend; +var util = require('../../../js/util/util'); var window = require('../../../js/util/window'); var Map = require('../../../js/ui/map'); -var Style = require('../../../js/style/style'); var LngLat = require('../../../js/geo/lng_lat'); var sinon = require('sinon'); @@ -17,7 +16,7 @@ function createMap(options, callback) { container.offsetWidth = 200; container.offsetHeight = 200; - var map = new Map(extend({ + var map = new Map(util.extend({ container: container, interactive: false, attributionControl: false, @@ -128,43 +127,39 @@ test('Map', function(t) { }); t.test('sets up event forwarding', function(t) { - var map = createMap(), - style = new Style({ - version: 8, - sources: {}, - layers: [] - }); + createMap({}, function(error, map) { + t.error(error); - var events = []; + var events = []; + function recordEvent(event) { + events.push(event.type); + } - function checkEvent(e) { - t.equal(e.style, style); - events.push(e.type); - } + map.on('error', recordEvent); + map.on('style.change', recordEvent); + map.on('source.load', recordEvent); + map.on('source.change', recordEvent); + map.on('tile.add', recordEvent); + map.on('tile.remove', recordEvent); + + map.style.fire('error'); + map.style.fire('style.change'); + map.style.fire('source.load'); + map.style.fire('source.change'); + map.style.fire('tile.add'); + map.style.fire('tile.remove'); + + t.deepEqual(events, [ + 'error', + 'style.change', + 'source.load', + 'source.change', + 'tile.add', + 'tile.remove' + ]); - map.on('style.load', checkEvent); - map.on('style.error', checkEvent); - map.on('style.change', checkEvent); - map.on('source.load', checkEvent); - map.on('source.error', checkEvent); - map.on('source.change', checkEvent); - map.on('tile.add', checkEvent); - map.on('tile.error', checkEvent); - map.on('tile.remove', checkEvent); - - // Suppress error messages - map.on('error', function() {}); - - t.plan(10); - map.setStyle(style); // Fires load - style.fire('error'); - style.fire('change'); - style.fire('source.load'); - style.fire('source.error'); - style.fire('source.change'); - style.fire('tile.add'); - style.fire('tile.error'); - style.fire('tile.remove'); + t.end(); + }); }); t.test('can be called more than once', function(t) { @@ -271,7 +266,7 @@ test('Map', function(t) { map.on('load', function () { map.addSource('geojson', createStyleSource()); - t.deepEqual(map.getStyle(), extend(createStyle(), { + t.deepEqual(map.getStyle(), util.extend(createStyle(), { sources: {geojson: createStyleSource()} })); t.end(); @@ -284,7 +279,7 @@ test('Map', function(t) { map.on('load', function () { map.addLayer(createStyleLayer()); - t.deepEqual(map.getStyle(), extend(createStyle(), { + t.deepEqual(map.getStyle(), util.extend(createStyle(), { layers: [createStyleLayer()] })); t.end(); @@ -1026,37 +1021,34 @@ test('Map', function(t) { }); t.test('#removeLayer restores Map#loaded() to true', function (t) { - var style = createStyle(); - style.sources.mapbox = { - type: 'vector', - minzoom: 1, - maxzoom: 10, - tiles: ['http://example.com/{z}/{x}/{y}.png'] - }; - style.layers.push({ - id: 'layerId', - type: 'circle', - source: 'mapbox', - 'source-layer': 'sourceLayer' + var map = createMap({ + style: util.extend(createStyle(), { + sources: { + mapbox: { + type: 'vector', + minzoom: 1, + maxzoom: 10, + tiles: ['http://example.com/{z}/{x}/{y}.png'] + } + }, + layers: [{ + id: 'layerId', + type: 'circle', + source: 'mapbox', + 'source-layer': 'sourceLayer' + }] + }) }); - var timer; - var map = createMap({ style: style }); - map.on('render', function () { - if (timer) clearTimeout(timer); - timer = setTimeout(function () { - map.off('render'); - map.on('render', check); - map.removeLayer('layerId'); - }, 100); + map.once('render', function() { + map.removeLayer('layerId'); + map.on('render', function() { + if (map.loaded()) { + map.remove(); + t.end(); + } + }); }); - - function check () { - if (map.loaded()) { - map.remove(); - t.end(); - } - } }); t.end(); diff --git a/test/js/util/evented.test.js b/test/js/util/evented.test.js index 433d50dbe34..3299ac4c6e9 100644 --- a/test/js/util/evented.test.js +++ b/test/js/util/evented.test.js @@ -2,69 +2,156 @@ var test = require('tap').test; var Evented = require('../../../js/util/evented'); +var sinon = require('sinon'); -test('evented', function(t) { - var evented = Object.create(Evented); - var report = function(data) { - t.deepEqual(data, { a: 'a', type: 'a', target: evented }); - }; - t.equal(evented.on('a', report), evented); - t.equal(evented.listens('a'), true); - t.equal(evented.fire('a', { a: 'a' }), evented); - t.equal(evented.off('a', report), evented); - t.equal(evented.off('a', report), evented); - t.equal(evented.listens('a'), false); - t.end(); -}); +test('Evented', function(t) { -test('evented-all', function(t) { - var report = function() { - t.fail(); - }; - var evented = Object.create(Evented); - t.equal(evented.on('a', report), evented); - t.equal(evented.on('b', report), evented); - t.equal(evented.on('c', report), evented); - t.equal(evented.off(), evented); - ['a', 'b', 'c'].forEach(function(e) { - t.equal(evented.fire(e, { a: 'a' }), evented); + t.test('calls listeners added with "on"', function(t) { + var evented = Object.create(Evented); + var listener = sinon.spy(); + evented.on('a', listener); + evented.fire('a'); + evented.fire('a'); + t.ok(listener.calledTwice); + t.end(); }); - t.end(); -}); -test('evented-one', function(t) { - var report1 = function() { t.fail(); }; - var report2 = function() { t.fail(); }; - var report3 = function() { t.fail(); }; - var evented = Object.create(Evented); - t.equal(evented.on('a', report1), evented); - t.equal(evented.on('a', report2), evented); - t.equal(evented.on('a', report3), evented); - t.equal(evented.off('a'), evented); - t.equal(evented.fire('a', { a: 'a' }), evented); - t.end(); -}); + t.test('calls listeners added with "once" once', function(t) { + var evented = Object.create(Evented); + var listener = sinon.spy(); + evented.once('a', listener); + evented.fire('a'); + evented.fire('a'); + t.ok(listener.calledOnce); + t.end(); + }); -test('evented-once', function(t) { - var evented = Object.create(Evented); + t.test('passes data to listeners', function(t) { + var evented = Object.create(Evented); + evented.on('a', function(data) { + t.equal(data.foo, 'bar'); + }); + evented.fire('a', {foo: 'bar'}); + t.end(); + }); - function report(data) { - t.equal(data.type, 'a'); - t.equal(data.n, 1); + t.test('passes "target" to listeners', function(t) { + var evented = Object.create(Evented); + evented.on('a', function(data) { + t.equal(data.target, evented); + }); + evented.fire('a'); t.end(); - } + }); - t.equal(evented.once('a', report), evented); + t.test('passes "type" to listeners', function(t) { + var evented = Object.create(Evented); + evented.on('a', function(data) { + t.deepEqual(data.type, 'a'); + }); + evented.fire('a'); + t.end(); + }); - evented.fire('a', {n: 1}); - evented.fire('a', {n: 2}); -}); + t.test('removes listeners with "off"', function(t) { + var evented = Object.create(Evented); + var listener = sinon.spy(); + evented.on('a', listener); + evented.off('a', listener); + evented.fire('a'); + t.ok(listener.notCalled); + t.end(); + }); + + t.test('reports if an event has listeners with "listens"', function(t) { + var evented = Object.create(Evented); + evented.on('a', function() {}); + t.ok(evented.listens('a')); + t.notOk(evented.listens('b')); + t.end(); + }); + + t.test('does not immediately call listeners added within another listener', function(t) { + var evented = Object.create(Evented); + evented.on('a', function() { + evented.on('a', t.fail.bind(t)); + }); + evented.fire('a'); + t.end(); + }); + + t.test('evented parents', function(t) { + + t.test('adds parents with "setEventedParent"', function(t) { + var listener = sinon.spy(); + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSource.setEventedParent(eventedSink); + eventedSink.on('a', listener); + eventedSource.fire('a'); + eventedSource.fire('a'); + t.ok(listener.calledTwice); + t.end(); + }); + + t.test('passes original data to parent listeners', function(t) { + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSource.setEventedParent(eventedSink); + eventedSink.on('a', function(data) { + t.equal(data.foo, 'bar'); + }); + eventedSource.fire('a', {foo: 'bar'}); + t.end(); + }); + + t.test('attaches parent data to parent listeners', function(t) { + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSource.setEventedParent(eventedSink, {foz: 'baz'}); + eventedSink.on('a', function(data) { + t.equal(data.foz, 'baz'); + }); + eventedSource.fire('a', {foo: 'bar'}); + t.end(); + }); + + t.test('passes original "target" to parent listeners', function(t) { + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSource.setEventedParent(eventedSink); + eventedSource.setEventedParent(null); + eventedSink.on('a', function(data) { + t.equal(data.target, eventedSource); + }); + eventedSource.fire('a'); + t.end(); + }); + + t.test('removes parents with "setEventedParent(null)"', function(t) { + var listener = sinon.spy(); + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSink.on('a', listener); + eventedSource.setEventedParent(eventedSink); + eventedSource.setEventedParent(null); + eventedSource.fire('a'); + t.ok(listener.notCalled); + t.end(); + }); + + t.test('reports if an event has parent listeners with "listens"', function(t) { + var eventedSource = Object.create(Evented); + var eventedSink = Object.create(Evented); + eventedSink.on('a', function() {}); + eventedSource.setEventedParent(eventedSink); + t.ok(eventedSink.listens('a')); + t.end(); + }); + + t.end(); + + }); -test('evented-not-found', function(t) { - var report1 = function() { t.pass(); }; - var evented = Object.create(Evented); - t.equal(evented.on('a', report1), evented); - t.equal(evented.off('a', function() {}), evented); - t.equal(evented.fire('a', { a: 'a' }), evented); t.end(); });