diff --git a/spec/core/webfont_spec.js b/spec/core/webfont_spec.js index 8f48daa3..f22166c4 100644 --- a/spec/core/webfont_spec.js +++ b/spec/core/webfont_spec.js @@ -150,7 +150,7 @@ describe('WebFont', function () { expect(font.onModuleReady_).toHaveBeenCalled(); expect(font.onModuleReady_.calls[0].args[2]).toEqual([new Font('Elena')]); - expect(font.onModuleReady_.calls[0].args[3]).toEqual({ 'Elena': '1234567' }); + expect(font.onModuleReady_.calls[0].args[4]).toEqual({ 'Elena': '1234567' }); }); }); @@ -241,4 +241,95 @@ describe('WebFont', function () { }); }); }); + + describe('multiple active events', function () { + var webFont = null, + active = null, + inactive = null, + loading = null, + spyOnFontWatchRunnerAreFontsLoading = null, + spyOnNativeFontWatchRunnerWaitForFontToLoad = null; + + beforeEach(function () { + active = jasmine.createSpy('active'), + inactive = jasmine.createSpy('inactive'); + loading = jasmine.createSpy('loading'); + + spyOnFontWatchRunnerAreFontsLoading = spyOn(FontWatchRunner.prototype, "areFontsLoading_"); + spyOnNativeFontWatchRunnerWaitForFontToLoad = spyOn(NativeFontWatchRunner.prototype, "waitForFontToLoad_"); + + spyOnFontWatchRunnerAreFontsLoading.andCallFake(function () { + return false; + }); + + spyOnNativeFontWatchRunnerWaitForFontToLoad.andCallFake(function () { + return new Promise(function (resolve, reject) { + resolve(); + }); + }); + + webFont = new WebFont(window); + webFont.addModule('module1', function (conf, domHelper) { + var testModule = new function () { + this.conf = conf; + }; + + testModule.load = function (onReady) { + onReady([new Font(conf.id)]); + }; + + return testModule; + }); + + webFont.addModule('module2', function (conf, domHelper) { + var testModule = new function () { + this.conf = conf; + }; + + testModule.load = function (onReady) { + onReady([new Font(conf.id)]); + }; + + return testModule; + }); + }); + + afterEach(function () { + spyOnFontWatchRunnerAreFontsLoading.reset(); + spyOnNativeFontWatchRunnerWaitForFontToLoad.reset(); + }); + + it('should fire multiple active events for multiple consecutive font requests', function () { + runs(function () { + webFont.load({ + 'module1': { + id: 'Elena' + }, + 'module2': { + id: 'Playfair Display' + }, + inactive: inactive, + active: active, + loading: loading + }); + + webFont.load({ + 'module1': { + id: 'Playfair Display' + }, + inactive: inactive, + active: active, + loading: loading + }); + }); + + waitsFor(function () { + return active.callCount == 2; + }); + + runs(function () { + expect(inactive.callCount).toEqual(0); + }); + }); + }); }); diff --git a/spec/deps.js b/spec/deps.js index e57cfb02..b1397421 100644 --- a/spec/deps.js +++ b/spec/deps.js @@ -7,12 +7,13 @@ goog.addDependency("../../src/core/eventdispatcher.js", ["webfont.EventDispatche goog.addDependency("../../src/core/font.js", ["webfont.Font"], []); goog.addDependency("../../src/core/fontmodule.js", ["webfont.FontModule"], []); goog.addDependency("../../src/core/fontmoduleloader.js", ["webfont.FontModuleLoader","webfont.FontModuleFactory"], []); +goog.addDependency("../../src/core/fontmodulesloadcounter.js", ["webfont.FontModulesLoadCounter"], []); goog.addDependency("../../src/core/fontruler.js", ["webfont.FontRuler"], []); goog.addDependency("../../src/core/fontwatcher.js", ["webfont.FontWatcher"], ["webfont.FontWatchRunner","webfont.NativeFontWatchRunner"]); goog.addDependency("../../src/core/fontwatchrunner.js", ["webfont.FontWatchRunner"], ["webfont.Font","webfont.FontRuler"]); goog.addDependency("../../src/core/initialize.js", ["webfont"], ["webfont.WebFont","webfont.modules.Typekit","webfont.modules.Fontdeck","webfont.modules.Monotype","webfont.modules.Custom","webfont.modules.google.GoogleFontApi"]); goog.addDependency("../../src/core/nativefontwatchrunner.js", ["webfont.NativeFontWatchRunner"], ["webfont.Font"]); -goog.addDependency("../../src/core/webfont.js", ["webfont.WebFont"], ["webfont.DomHelper","webfont.EventDispatcher","webfont.FontWatcher","webfont.FontModuleLoader"]); +goog.addDependency("../../src/core/webfont.js", ["webfont.WebFont"], ["webfont.DomHelper","webfont.EventDispatcher","webfont.FontWatcher","webfont.FontModuleLoader", "webfont.FontModulesLoadCounter"]); goog.addDependency("../../src/modules/custom.js", ["webfont.modules.Custom"], ["webfont.Font", "webfont.StyleSheetWaiter"]); goog.addDependency("../../src/modules/fontdeck.js", ["webfont.modules.Fontdeck"], ["webfont.Font"]); goog.addDependency("../../src/modules/google/fontapiparser.js", ["webfont.modules.google.FontApiParser"], ["webfont.Font"]); diff --git a/src/core/fontmodulesloadcounter.js b/src/core/fontmodulesloadcounter.js new file mode 100644 index 00000000..14fedfb2 --- /dev/null +++ b/src/core/fontmodulesloadcounter.js @@ -0,0 +1,27 @@ +goog.provide('webfont.FontModulesLoadCounter'); + +/** + * This class is used to keep track of the number of Font Modules that are loading + * @param {number} numberOfModulesLoading The initial amount of modules that are loading + * @constructor + */ +webfont.FontModulesLoadCounter = function(numberOfModulesLoading) { + this.numberOfModulesLoading_ = numberOfModulesLoading; +}; + +goog.scope(function () { + var FontModulesLoadCounter = webfont.FontModulesLoadCounter; + + FontModulesLoadCounter.prototype.decrement = function() { + if (this.numberOfModulesLoading_ - 1 >= 0) { + this.numberOfModulesLoading_ --; + } + } + + /** + * @return {number} + */ + FontModulesLoadCounter.prototype.count = function() { + return this.numberOfModulesLoading_; + } +}); diff --git a/src/core/fontwatchrunner.js b/src/core/fontwatchrunner.js index 62e91e92..b9e2095c 100644 --- a/src/core/fontwatchrunner.js +++ b/src/core/fontwatchrunner.js @@ -193,6 +193,18 @@ goog.scope(function () { return this.metricCompatibleFonts_ === null || this.metricCompatibleFonts_.hasOwnProperty(this.font_.getName()); }; + /** + * Returns true if both fonts are in a state that resembles loading. + * + * @private + * @param {number} a + * @param {number} b + * @return {boolean} + */ + FontWatchRunner.prototype.areFontsLoading_ = function (a, b) { + return this.isFallbackFont_(a, b) || this.isLastResortFont_(a, b); + }; + /** * Checks the width of the two spans against their original widths during each * async loop. If the width of one of the spans is different than the original @@ -206,14 +218,14 @@ goog.scope(function () { var widthA = this.fontRulerA_.getWidth(); var widthB = this.fontRulerB_.getWidth(); - if (this.isFallbackFont_(widthA, widthB) || this.isLastResortFont_(widthA, widthB)) { + if (this.areFontsLoading_(widthA, widthB)) { if (this.hasTimedOut_()) { if (this.isLastResortFont_(widthA, widthB) && this.isMetricCompatibleFont_()) { this.finish_(this.activeCallback_); } else { this.finish_(this.inactiveCallback_); } - } else { + } else { this.asyncCheck_(); } } else { diff --git a/src/core/nativefontwatchrunner.js b/src/core/nativefontwatchrunner.js index d6f46365..3532db87 100644 --- a/src/core/nativefontwatchrunner.js +++ b/src/core/nativefontwatchrunner.js @@ -23,20 +23,18 @@ goog.scope(function () { var NativeFontWatchRunner = webfont.NativeFontWatchRunner; - NativeFontWatchRunner.prototype.start = function () { + NativeFontWatchRunner.prototype.waitForFontToLoad_ = function (font, fontTestString, timeout) { var doc = this.domHelper_.getLoadWindow().document, - that = this; - - var start = goog.now(); + start = goog.now(); - var loader = new Promise(function (resolve, reject) { + return new Promise(function (resolve, reject) { var check = function () { var now = goog.now(); - if (now - start >= that.timeout_) { + if (now - start >= timeout) { reject(); } else { - doc.fonts.load(that.font_.toCssString(), that.fontTestString_).then(function (fonts) { + doc.fonts.load(font.toCssString(), fontTestString).then(function (fonts) { if (fonts.length >= 1) { resolve(); } else { @@ -50,6 +48,11 @@ goog.scope(function () { check(); }); + }; + + NativeFontWatchRunner.prototype.start = function () { + var that = this, + loader = this.waitForFontToLoad_(this.font_, this.fontTestString_, this.timeout_); var timeoutId = null, timer = new Promise(function (resolve, reject) { diff --git a/src/core/webfont.js b/src/core/webfont.js index fd1d79ea..0df4f037 100644 --- a/src/core/webfont.js +++ b/src/core/webfont.js @@ -4,6 +4,7 @@ goog.require('webfont.DomHelper'); goog.require('webfont.EventDispatcher'); goog.require('webfont.FontWatcher'); goog.require('webfont.FontModuleLoader'); +goog.require('webfont.FontModulesLoadCounter'); /** * @param {Window} mainWindow The main application window containing @@ -13,7 +14,6 @@ goog.require('webfont.FontModuleLoader'); webfont.WebFont = function(mainWindow) { this.mainWindow_ = mainWindow; this.fontModuleLoader_ = new webfont.FontModuleLoader(); - this.moduleLoading_ = 0; this.events_ = true; this.classes_ = true; }; @@ -22,7 +22,8 @@ goog.scope(function () { var WebFont = webfont.WebFont, DomHelper = webfont.DomHelper, EventDispatcher = webfont.EventDispatcher, - FontWatcher = webfont.FontWatcher; + FontWatcher = webfont.FontWatcher, + FontModulesLoadCounter = webfont.FontModulesLoadCounter; /** * @param {string} name @@ -57,12 +58,10 @@ goog.scope(function () { * @param {webfont.FontTestStrings=} opt_fontTestStrings * @param {Object.=} opt_metricCompatibleFonts */ - WebFont.prototype.onModuleReady_ = function(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts) { - var allModulesLoaded = --this.moduleLoading_ == 0; - + WebFont.prototype.onModuleReady_ = function(eventDispatcher, fontWatcher, fonts, lastModule, opt_fontTestStrings, opt_metricCompatibleFonts) { if (this.classes_ || this.events_) { setTimeout(function () { - fontWatcher.watchFonts(fonts, opt_fontTestStrings || null, opt_metricCompatibleFonts || null, allModulesLoaded); + fontWatcher.watchFonts(fonts, opt_fontTestStrings || null, opt_metricCompatibleFonts || null, lastModule); }, 0); } }; @@ -82,15 +81,15 @@ goog.scope(function () { modules = this.fontModuleLoader_.getModules(configuration, this.domHelper_); - var fontWatcher = new webfont.FontWatcher(this.domHelper_, eventDispatcher, timeout); - - this.moduleLoading_ = modules.length; + var fontWatcher = new FontWatcher(this.domHelper_, eventDispatcher, timeout); + var fontModulesLoadCounter = new FontModulesLoadCounter(modules.length); for (var i = 0, len = modules.length; i < len; i++) { var module = modules[i]; - module.load(function (fonts, opt_fontTestStrings, opt_metricCompatibleFonts) { - self.onModuleReady_(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts); + fontModulesLoadCounter.decrement(); + var wasLastModule = fontModulesLoadCounter.count() == 0; + self.onModuleReady_(eventDispatcher, fontWatcher, fonts, wasLastModule, opt_fontTestStrings, opt_metricCompatibleFonts); }); } }; diff --git a/src/modules.yml b/src/modules.yml index 6186bc48..509b6e92 100644 --- a/src/modules.yml +++ b/src/modules.yml @@ -7,6 +7,7 @@ core: - core/eventdispatcher.js - core/fontmodule.js - core/fontmoduleloader.js + - core/fontmodulesloadcounter.js - core/fontruler.js - core/nativefontwatchrunner.js - core/fontwatchrunner.js