diff --git a/js/source/source.js b/js/source/source.js index 7d98b4d7fad..00f65e76d5b 100644 --- a/js/source/source.js +++ b/js/source/source.js @@ -10,6 +10,8 @@ var sourceTypes = { 'image': require('../source/image_source') }; +var coreTypes = ['vector', 'raster', 'geojson', 'video', 'image']; + /* * Creates a tiled data source instance given an options object. * @@ -38,6 +40,16 @@ exports.setType = function (name, type) { sourceTypes[name] = type; }; +/** + * Returns the names of any registered non-core source types. + * @private + */ +exports.getCustomTypeNames = function () { + return Object.keys(sourceTypes).filter(function (type) { + return coreTypes.indexOf(type) < 0; + }); +}; + /** * The `Source` interface must be implemented by each source type, including "core" types (`vector`, `raster`, `video`, etc.) and all custom, third-party types. * diff --git a/js/style/style.js b/js/style/style.js index d16e1cbfd7d..8e821cbcbdb 100644 --- a/js/style/style.js +++ b/js/style/style.js @@ -1,5 +1,6 @@ 'use strict'; +var assert = require('assert'); var Evented = require('../util/evented'); var StyleLayer = require('./style_layer'); var ImageSprite = require('./image_sprite'); @@ -70,11 +71,32 @@ function Style(stylesheet, animationLoop, workerCount) { this.fire('load'); }.bind(this); - if (typeof stylesheet === 'string') { - ajax.getJSON(normalizeURL(stylesheet), stylesheetLoaded); - } else { - browser.frame(stylesheetLoaded.bind(this, null, stylesheet)); - } + // register any existing custom source types with the workers + util.asyncAll(Source.getCustomTypeNames(), function (type, done) { + var CustomSource = Source.getType(type); + assert(CustomSource); + + if (CustomSource.workerSourceURL) { + this.dispatcher.broadcast('load worker source', { + name: type, + url: CustomSource.workerSourceURL + }, done); + } else { + return done(); + } + }.bind(this), function (err) { + if (err) { + this.fire('error', {error: err}); + return; + } + + if (typeof stylesheet === 'string') { + ajax.getJSON(normalizeURL(stylesheet), stylesheetLoaded); + } else { + browser.frame(stylesheetLoaded.bind(this, null, stylesheet)); + } + }.bind(this)); + this.on('source.load', function(event) { var source = event.source; diff --git a/test/js/style/style.test.js b/test/js/style/style.test.js index 6e20250640d..d589bde5d76 100644 --- a/test/js/style/style.test.js +++ b/test/js/style/style.test.js @@ -131,6 +131,34 @@ test('Style', function(t) { }); }); + t.test('registers existing custom sources', function (t) { + function SourceType () {} + SourceType.workerSourceURL = 'worker-source.js'; + function Dispatcher () {} + Dispatcher.prototype = { + broadcast: function (type, params, callback) { + if (type === 'load worker source') { + t.equal(params.name, 'my-source-type'); + t.equal(params.url, 'worker-source.js'); + setTimeout(callback, 0); + } + } + }; + + t.plan(2); + + var Style = proxyquire('../../../js/style/style', { + '../source/source': { + getType: function () { return SourceType; }, + setType: function () {}, + getCustomTypeNames: function () { return ['my-source-type']; } + }, + '../util/dispatcher': Dispatcher + }); + + new Style(createStyleJSON()); + }); + t.end(); }); @@ -1184,11 +1212,12 @@ test('Style#addSourceType', function (t) { var Style = proxyquire('../../../js/style/style', { '../source/source': { getType: function (name) { return _types[name]; }, - setType: function (name, create) { _types[name] = create; } + setType: function (name, create) { _types[name] = create; }, + getTypeNames: function () { return []; } } }); - t.test('adds factory function', function (t) { + t.test('adds source type', function (t) { var style = new Style(createStyleJSON()); var SourceType = function () {};