webfontloader 1.4.9 → 1.4.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG +6 -0
  2. data/CONTRIBUTING.md +47 -0
  3. data/README.md +0 -49
  4. data/lib/webfontloader.rb +1 -1
  5. data/spec/core/domhelper_spec.js +65 -28
  6. data/spec/core/fontwatchrunner_spec.js +1 -1
  7. data/spec/core/webfont_spec.js +47 -0
  8. data/spec/{core → fixtures}/external_script.js +0 -0
  9. data/spec/fixtures/external_stylesheet.css +7 -0
  10. data/spec/{fonts → fixtures/fonts}/LICENSE.txt +0 -0
  11. data/spec/{fonts → fixtures/fonts}/nullfont.css +0 -0
  12. data/spec/{fonts → fixtures/fonts}/nullfont1.css +0 -0
  13. data/spec/{fonts → fixtures/fonts}/nullfont2.css +0 -0
  14. data/spec/{fonts → fixtures/fonts}/nullfont3.css +0 -0
  15. data/spec/{fonts → fixtures/fonts}/sourcesans.eot +0 -0
  16. data/spec/{fonts → fixtures/fonts}/sourcesans.otf +0 -0
  17. data/spec/{fonts → fixtures/fonts}/sourcesans.svg +0 -0
  18. data/spec/{fonts → fixtures/fonts}/sourcesans.ttf +0 -0
  19. data/spec/{fonts → fixtures/fonts}/sourcesans.woff +0 -0
  20. data/spec/{fonts → fixtures/fonts}/sourcesansa.css +0 -0
  21. data/spec/{fonts → fixtures/fonts}/sourcesansb.css +0 -0
  22. data/spec/{fonts → fixtures/fonts}/sourcesansc.css +0 -0
  23. data/spec/{fonts → fixtures/fonts}/sourcesanscbold.css +0 -0
  24. data/spec/{fonts → fixtures/fonts}/sourcesanscbold.otf +0 -0
  25. data/spec/index.html +8 -8
  26. data/spec/modules/ascender_spec.js +2 -4
  27. data/spec/modules/custom_spec.js +4 -5
  28. data/spec/modules/fontdeck_spec.js +3 -4
  29. data/spec/modules/google/googlefontapi_spec.js +1 -8
  30. data/spec/modules/monotype_spec.js +6 -4
  31. data/spec/modules/typekit_spec.js +6 -8
  32. data/src/core/domhelper.js +68 -53
  33. data/src/core/webfont.js +6 -6
  34. data/src/modules/ascender.js +1 -1
  35. data/src/modules/custom.js +1 -3
  36. data/src/modules/fontdeck.js +6 -4
  37. data/src/modules/google/googlefontapi.js +1 -2
  38. data/src/modules/monotype.js +8 -15
  39. data/src/modules/typekit.js +6 -3
  40. data/webfontloader.gemspec +20 -18
  41. metadata +22 -20
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ v1.4.10 (July 31, 2013)
2
+ * Add loadStylesheet method with optional callback that replaces createCssLink
3
+ * Remove supportForStyle check because it breaks XHTML/SVG and is no longer necessary
4
+ * Fix inactive never called when script loading times out
5
+ * Move test assets into fixtures directory
6
+
1
7
  v1.4.9 (July 24, 2013)
2
8
  * Disable terminal spec report when not using PhantomJS
3
9
  * Remove obsolete namespace declaration
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,47 @@
1
+ # Contributing
2
+
3
+ Please open [an issue](https://github.com/typekit/webfontloader/issues) if you find or suspect any problems. Sample pages and test cases are greatly appreciated.
4
+
5
+ ## Development requirements
6
+
7
+ You'll need a few rubygems to run the tests, demo server, and other rake tasks, which should be installed with [Bundler](http://gembundler.com/).
8
+
9
+ $ gem install bundler
10
+ $ bundle install
11
+
12
+ To run the tests in a headless WebKit you will also need to have [PhantomJS](http://www.phantomjs.org) installed. You can install PhantomJS by downloading a binary of using HomeBrew.
13
+
14
+ $ brew install phantomjs
15
+
16
+ ## Building
17
+
18
+ To build a JS file from source, just run rake:
19
+
20
+ $ rake
21
+
22
+ ## Demos
23
+
24
+ A full suite of demo pages is included in this source. Here you can find some
25
+ live examples using the JS and CSS events. Run the demo server with:
26
+
27
+ $ rake demo
28
+
29
+ You can also run the demos with uncompressed, debuggable code to aid in
30
+ development. Just start the server in dev mode:
31
+
32
+ $ rake demodev
33
+
34
+ Browse the demos [source code](http://github.com/typekit/webfontloader/blob/master/lib/webfontloader/demo/public).
35
+
36
+ ## Testing
37
+
38
+ Web Font Loader has an extensive test suite that runs via Jasmine. The test suite
39
+ should be passing before submitting a pull request, and new tests should be added for any new functionality.
40
+
41
+ To run tests, open up `spec/index.html` in a browser and check the results. The
42
+ test suite will run automatically. Again, before submitting a pull request
43
+ please run the test suite in multiple browsers and list them in the pull request.
44
+
45
+ To run tests in a headless WebKit using [PhantomJS](http://www.phantomjs.org) run:
46
+
47
+ $ rake test
data/README.md CHANGED
@@ -19,7 +19,6 @@ Web Font Loader gives you added control when using linked fonts via `@font-face`
19
19
  * [Google](#google)
20
20
  * [Typekit](#typekit)
21
21
  * [Browser support](#browser-support)
22
- * [Contributing](#contributing)
23
22
  * [License](#license)
24
23
 
25
24
  ## Get Started
@@ -270,54 +269,6 @@ For example:
270
269
 
271
270
  If `providerA` can serve fonts to a browser, but `providerB` cannot, The `fontinactive` event will be triggered for `Family2`. The `fontactive` event will be triggered for `Family1` once it loads, as will the `active` event.
272
271
 
273
- ## Contributing
274
-
275
- Please open [an issue](https://github.com/typekit/webfontloader/issues) if you find or suspect any problems. Sample pages and test cases are greatly appreciated.
276
-
277
- ### Development requirements
278
-
279
- You'll need a few rubygems to run the tests, demo server, and other rake tasks, which should be installed with [Bundler](http://gembundler.com/).
280
-
281
- $ gem install bundler
282
- $ bundle install
283
-
284
- To run the tests in a headless WebKit you will also need to have [PhantomJS](http://www.phantomjs.org) installed. You can install PhantomJS by downloading a binary of using HomeBrew.
285
-
286
- $ brew install phantomjs
287
-
288
- ### Building
289
-
290
- To build a JS file from source, just run rake:
291
-
292
- $ rake
293
-
294
- ### Demos
295
-
296
- A full suite of demo pages is included in this source. Here you can find some
297
- live examples using the JS and CSS events. Run the demo server with:
298
-
299
- $ rake demo
300
-
301
- You can also run the demos with uncompressed, debuggable code to aid in
302
- development. Just start the server in dev mode:
303
-
304
- $ rake demodev
305
-
306
- Browse the demos [source code](http://github.com/typekit/webfontloader/blob/master/lib/webfontloader/demo/public).
307
-
308
- ### Testing
309
-
310
- Web Font Loader has an extensive test suite that runs via Jasmine. The test suite
311
- should be passing before submitting a pull request, and new tests should be added for any new functionality.
312
-
313
- To run tests, open up `spec/index.html` in a browser and check the results. The
314
- test suite will run automatically. Again, before submitting a pull request
315
- please run the test suite in multiple browsers and list them in the pull request.
316
-
317
- To run tests in a headless WebKit using [PhantomJS](http://www.phantomjs.org) run:
318
-
319
- $ rake test
320
-
321
272
  ## License
322
273
 
323
274
  Web Font Loader is released under the [Apache 2.0](http://github.com/typekit/webfontloader/blob/master/LICENSE) license.
data/lib/webfontloader.rb CHANGED
@@ -3,7 +3,7 @@ require 'yaml'
3
3
  require 'webfontloader/modules'
4
4
 
5
5
  module WebFontLoader
6
- VERSION = '1.4.9'
6
+ VERSION = '1.4.10'
7
7
 
8
8
  ProjectRoot = File.expand_path(File.dirname(__FILE__) + "/..")
9
9
 
@@ -44,31 +44,6 @@ describe('DomHelper', function () {
44
44
  });
45
45
  });
46
46
 
47
- describe('#createCssLink', function () {
48
- var link = domHelper.createCssLink('http://moo/somecss.css');
49
-
50
- it('should create a link', function () {
51
- expect(link).not.toBeNull();
52
- });
53
-
54
- it('should create a link with correct rel and href properties', function () {
55
- expect(link.rel).toEqual('stylesheet');
56
- expect(link.href).toEqual('http://moo/somecss.css');
57
- });
58
- });
59
-
60
- describe('#createScriptSrc', function () {
61
- var script = domHelper.createScriptSrc('http://moo/somescript.js');
62
-
63
- it('should create a script element', function () {
64
- expect(script).not.toBeNull();
65
- });
66
-
67
- it('should have a src property', function () {
68
- expect(script.src).toEqual('http://moo/somescript.js');
69
- });
70
- });
71
-
72
47
  describe('#appendClassName', function () {
73
48
  it('should have added a class name', function () {
74
49
  var div = domHelper.createElement('div');
@@ -178,10 +153,35 @@ describe('DomHelper', function () {
178
153
  });
179
154
  });
180
155
 
156
+ describe('#loadStylesheet', function () {
157
+ it('should load the stylesheet', function () {
158
+ var el = null,
159
+ width = null,
160
+ link = null;
161
+
162
+ runs(function () {
163
+ el = domHelper.createElement('div', { id: 'TEST_ELEMENT' });
164
+ domHelper.insertInto('body', el);
165
+ width = el.offsetWidth;
166
+ link = domHelper.loadStylesheet('fixtures/external_stylesheet.css');
167
+ });
168
+
169
+ waitsFor(function () {
170
+ return width !== el.offsetWidth;
171
+ });
172
+
173
+ runs(function () {
174
+ expect(link).not.toBeNull();
175
+ expect(link.rel).toEqual('stylesheet');
176
+ expect(el.offsetWidth).toEqual(300);
177
+ });
178
+ });
179
+ });
180
+
181
181
  describe('#loadScript', function () {
182
182
  it('should load the script', function () {
183
183
  runs(function () {
184
- domHelper.loadScript('core/external_script.js');
184
+ domHelper.loadScript('fixtures/external_script.js');
185
185
  });
186
186
 
187
187
  waitsFor(function () {
@@ -194,11 +194,13 @@ describe('DomHelper', function () {
194
194
  });
195
195
 
196
196
  it('should call the callback', function () {
197
- var called = false;
197
+ var called = false,
198
+ error = null;
198
199
 
199
200
  runs(function () {
200
- domHelper.loadScript('core/external_script.js', function () {
201
+ domHelper.loadScript('fixtures/external_script.js', function (err) {
201
202
  called = true;
203
+ error = err;
202
204
  });
203
205
  });
204
206
 
@@ -208,6 +210,41 @@ describe('DomHelper', function () {
208
210
 
209
211
  runs(function () {
210
212
  expect(called).toBe(true);
213
+ expect(error).toBeFalsy();
214
+ });
215
+ });
216
+
217
+ it('should return a script element', function () {
218
+ var script = domHelper.loadScript('fixtures/external_script.js');
219
+
220
+ expect(script).not.toBeNull();
221
+ expect(script.nodeName).toEqual('SCRIPT');
222
+ });
223
+
224
+ it('should timeout if the script does not load or is very slow', function () {
225
+ var called = false,
226
+ error = false;
227
+
228
+ // Spy on createElement so the all loadScript code is executed but
229
+ // the "script" won't actually load.
230
+ spyOn(domHelper, 'createElement').andCallFake(function (name) {
231
+ return document.createElement('div');
232
+ });
233
+
234
+ runs(function () {
235
+ domHelper.loadScript('fixtures/external_script.js', function (err) {
236
+ called = true;
237
+ error = err;
238
+ }, 100);
239
+ });
240
+
241
+ waitsFor(function () {
242
+ return called;
243
+ });
244
+
245
+ runs(function () {
246
+ expect(called).toBe(true);
247
+ expect(error).toBeTruthy();
211
248
  });
212
249
  });
213
250
  });
@@ -372,7 +372,7 @@ describe('FontWatchRunner', function () {
372
372
  var link = document.createElement('link');
373
373
 
374
374
  link.rel = "stylesheet";
375
- link.href= "fonts/sourcesansb.css";
375
+ link.href= "fixtures/fonts/sourcesansb.css";
376
376
 
377
377
  domHelper.insertInto('head', link);
378
378
  });
@@ -270,4 +270,51 @@ describe('WebFont', function () {
270
270
  expect(inactive).toHaveBeenCalled();
271
271
  });
272
272
  });
273
+
274
+ describe('module fails to load', function () {
275
+ var font = null,
276
+ testModule = null,
277
+ inactive = null,
278
+ active = null;
279
+
280
+ beforeEach(function () {
281
+ inactive = jasmine.createSpy('inactive'),
282
+ active = jasmine.createSpy('active');
283
+
284
+ font = new WebFont(window, fontModuleLoader, userAgent);
285
+
286
+ font.addModule('test', function (conf, domHelper) {
287
+ testModule = new function () {};
288
+ testModule.supportUserAgent = function (ua, support) {
289
+ window.setTimeout(function () {
290
+ support(false);
291
+ }, 100);
292
+ };
293
+ testModule.load = function (onReady) {
294
+ onReady();
295
+ };
296
+
297
+ return testModule;
298
+ });
299
+ });
300
+
301
+ it('times out and calls inactive', function () {
302
+ runs(function () {
303
+ font.load({
304
+ 'test': {},
305
+ inactive: inactive,
306
+ active: active
307
+ });
308
+ });
309
+
310
+ waitsFor(function () {
311
+ return active.wasCalled || inactive.wasCalled;
312
+ });
313
+
314
+ runs(function () {
315
+ expect(inactive).toHaveBeenCalled();
316
+ expect(active).not.toHaveBeenCalled();
317
+ });
318
+ });
319
+ });
273
320
  });
File without changes
@@ -0,0 +1,7 @@
1
+ #TEST_ELEMENT {
2
+ display: block;
3
+ position: absolute;
4
+ top: 0;
5
+ left: 0;
6
+ width: 300px;
7
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
data/spec/index.html CHANGED
@@ -4,14 +4,14 @@
4
4
  <title>Webfontloader tests</title>
5
5
  <link rel="stylesheet" href="../tools/jasmine/jasmine.css">
6
6
 
7
- <link rel="stylesheet" href="fonts/nullfont.css">
8
- <link rel="stylesheet" href="fonts/nullfont1.css">
9
- <link rel="stylesheet" href="fonts/nullfont2.css">
10
- <link rel="stylesheet" href="fonts/nullfont3.css">
11
- <link rel="stylesheet" href="fonts/sourcesansa.css">
12
- <link rel="stylesheet" href="fonts/sourcesansb.css">
13
- <link rel="stylesheet" href="fonts/sourcesansc.css">
14
- <link rel="stylesheet" href="fonts/sourcesanscbold.css">
7
+ <link rel="stylesheet" href="fixtures/fonts/nullfont.css">
8
+ <link rel="stylesheet" href="fixtures/fonts/nullfont1.css">
9
+ <link rel="stylesheet" href="fixtures/fonts/nullfont2.css">
10
+ <link rel="stylesheet" href="fixtures/fonts/nullfont3.css">
11
+ <link rel="stylesheet" href="fixtures/fonts/sourcesansa.css">
12
+ <link rel="stylesheet" href="fixtures/fonts/sourcesansb.css">
13
+ <link rel="stylesheet" href="fixtures/fonts/sourcesansc.css">
14
+ <link rel="stylesheet" href="fixtures/fonts/sourcesanscbold.css">
15
15
  </head>
16
16
  <body>
17
17
  <script>
@@ -14,8 +14,7 @@ describe('modules.Ascender', function () {
14
14
 
15
15
  beforeEach(function () {
16
16
  fakeDomHelper = {
17
- insertInto: jasmine.createSpy('insertInto'),
18
- createCssLink: jasmine.createSpy('createCssLink'),
17
+ loadStylesheet: jasmine.createSpy('createCssLink'),
19
18
  getProtocol: jasmine.createSpy('getProtocol').andReturn('http:')
20
19
  };
21
20
 
@@ -26,8 +25,7 @@ describe('modules.Ascender', function () {
26
25
  });
27
26
 
28
27
  it('should create the link correctly', function () {
29
- expect(fakeDomHelper.createCssLink).toHaveBeenCalledWith('http://webfonts.fontslive.com/css/ec2de397-11ae-4c10-937f-bf94283a70c1.css');
30
- expect(fakeDomHelper.insertInto.calls[0].args[0]).toEqual('head');
28
+ expect(fakeDomHelper.loadStylesheet).toHaveBeenCalledWith('http://webfonts.fontslive.com/css/ec2de397-11ae-4c10-937f-bf94283a70c1.css');
31
29
  });
32
30
 
33
31
  it('should pass the fonts correctly', function () {
@@ -8,8 +8,7 @@ describe('modules.Custom', function () {
8
8
 
9
9
  beforeEach(function () {
10
10
  fakeDomHelper = {
11
- createCssLink: jasmine.createSpy('createCssLink'),
12
- insertInto: jasmine.createSpy('insertInto')
11
+ loadStylesheet: jasmine.createSpy('createCssLink')
13
12
  };
14
13
 
15
14
  load = jasmine.createSpy('load');
@@ -23,9 +22,9 @@ describe('modules.Custom', function () {
23
22
  });
24
23
 
25
24
  it('should have inserted the links correctly', function () {
26
- expect(fakeDomHelper.createCssLink.callCount).toEqual(2);
27
- expect(fakeDomHelper.createCssLink).toHaveBeenCalledWith('http://moo');
28
- expect(fakeDomHelper.createCssLink).toHaveBeenCalledWith('http://meuh');
25
+ expect(fakeDomHelper.loadStylesheet.callCount).toEqual(2);
26
+ expect(fakeDomHelper.loadStylesheet).toHaveBeenCalledWith('http://moo');
27
+ expect(fakeDomHelper.loadStylesheet).toHaveBeenCalledWith('http://meuh');
29
28
  });
30
29
 
31
30
  it('should have loaded the families correctly', function () {
@@ -52,8 +52,7 @@ describe('modules.Fontdeck', function () {
52
52
  };
53
53
 
54
54
  fakeDomHelper = {
55
- insertInto: jasmine.createSpy('insertInto'),
56
- createScriptSrc: jasmine.createSpy('createScriptSrc'),
55
+ loadScript: jasmine.createSpy('loadScript'),
57
56
  getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global),
58
57
  getProtocol: jasmine.createSpy('getProtocol').andReturn('https:'),
59
58
  getHostName: function () { return 'test-host-name'; }
@@ -72,8 +71,8 @@ describe('modules.Fontdeck', function () {
72
71
  });
73
72
 
74
73
  it('should create the script correctly', function () {
75
- expect(fakeDomHelper.createScriptSrc).toHaveBeenCalledWith('https://f.fontdeck.com/s/css/js/test-host-name/2282.js');
76
- expect(fakeDomHelper.insertInto.calls[0].args[0]).toEqual('head');
74
+ expect(fakeDomHelper.loadScript).toHaveBeenCalled();
75
+ expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('https://f.fontdeck.com/s/css/js/test-host-name/2282.js');
77
76
  });
78
77
 
79
78
  it('should have created a global', function () {
@@ -6,10 +6,7 @@ describe('modules.google.GoogleFontApi', function () {
6
6
  link = '',
7
7
  insert = '',
8
8
  fakeDomHelper = {
9
- insertInto: function (tag, e) {
10
- insert = tag;
11
- },
12
- createCssLink: function (cssLink) {
9
+ loadStylesheet: function (cssLink) {
13
10
  link = cssLink;
14
11
  },
15
12
  getProtocol: function () {
@@ -36,7 +33,6 @@ describe('modules.google.GoogleFontApi', function () {
36
33
  });
37
34
 
38
35
  it('has inserted the link element correctly', function () {
39
- expect(insert).toEqual('head');
40
36
  expect(link).toEqual('http://fonts.googleapis.com/css?family=Font1%7CFont2');
41
37
  });
42
38
 
@@ -60,7 +56,6 @@ describe('modules.google.GoogleFontApi', function () {
60
56
  });
61
57
 
62
58
  it('has inserted the link element correctly', function () {
63
- expect(insert).toEqual('head');
64
59
  expect(link).toEqual('http://moo?family=Font1%7CFont2');
65
60
  });
66
61
  });
@@ -74,7 +69,6 @@ describe('modules.google.GoogleFontApi', function () {
74
69
  });
75
70
 
76
71
  it('has inserted the link element correctly', function () {
77
- expect(insert).toEqual('head');
78
72
  expect(link).toEqual('http://fonts.googleapis.com/css?family=Font1+WithSpace%7CFont2+WithSpaceToo');
79
73
  });
80
74
  });
@@ -88,7 +82,6 @@ describe('modules.google.GoogleFontApi', function () {
88
82
  });
89
83
 
90
84
  it('has inserted the link element correctly', function () {
91
- expect(insert).toEqual('head');
92
85
  expect(link).toEqual('http://fonts.googleapis.com/css?family=Font1+WithSpace:bi%7CFont2+WithSpaceToo:b,r');
93
86
  });
94
87
  });
@@ -22,8 +22,10 @@ describe('modules.Monotype', function () {
22
22
  global = {};
23
23
 
24
24
  fakeDomHelper = {
25
- createElement: jasmine.createSpy('createElement').andReturn(script),
26
- insertInto: jasmine.createSpy('insertInto'),
25
+ loadScript: jasmine.createSpy('loadScript').andCallFake(function (src, callback) {
26
+ script.onload = callback;
27
+ return script;
28
+ }),
27
29
  getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global),
28
30
  getProtocol: jasmine.createSpy('getProtocol').andReturn('http:')
29
31
  };
@@ -57,8 +59,8 @@ describe('modules.Monotype', function () {
57
59
 
58
60
  it('should create a script element', function () {
59
61
  expect(support).toHaveBeenCalled();
60
- expect(fakeDomHelper.createElement).toHaveBeenCalledWith('script');
61
- expect(script.src).toEqual('http://fast.fonts.com/jsapidev/01e2ff27-25bf-4801-a23e-73d328e6c7cc.js');
62
+ expect(fakeDomHelper.loadScript).toHaveBeenCalled();
63
+ expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('http://fast.fonts.com/jsapidev/01e2ff27-25bf-4801-a23e-73d328e6c7cc.js');
62
64
  expect(load).toHaveBeenCalledWith([new Font('aachen bold'), new Font('kid print regular')]);
63
65
  });
64
66
  });
@@ -19,8 +19,7 @@ describe('modules.Typekit', function () {
19
19
  load = jasmine.createSpy('load');
20
20
 
21
21
  fakeDomHelper = {
22
- insertInto: jasmine.createSpy('insertInto'),
23
- createScriptSrc: jasmine.createSpy('createScriptSrc'),
22
+ loadScript: jasmine.createSpy('loadScript'),
24
23
  getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global),
25
24
  getProtocol: jasmine.createSpy('getProtocol').andReturn('http:')
26
25
  };
@@ -31,8 +30,8 @@ describe('modules.Typekit', function () {
31
30
 
32
31
  typekit.supportUserAgent('useragent', support);
33
32
 
34
- expect(fakeDomHelper.insertInto.calls[0].args[0]).toEqual('head');
35
- expect(fakeDomHelper.createScriptSrc).toHaveBeenCalledWith('http://use.typekit.net/abc.js');
33
+ expect(fakeDomHelper.loadScript).toHaveBeenCalled();
34
+ expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('http://use.typekit.net/abc.js');
36
35
  expect(support).not.toHaveBeenCalled();
37
36
 
38
37
  expect(global.__webfonttypekitmodule__).not.toBeNull();
@@ -78,8 +77,8 @@ describe('modules.Typekit', function () {
78
77
  var typekit = new Typekit(fakeDomHelper, { id: 'abc', api: '/test' });
79
78
 
80
79
  typekit.supportUserAgent('useragent', support);
81
- expect(fakeDomHelper.insertInto.calls[0].args[0]).toEqual('head');
82
- expect(fakeDomHelper.createScriptSrc).toHaveBeenCalledWith('/test/abc.js');
80
+ expect(fakeDomHelper.loadScript).toHaveBeenCalled();
81
+ expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('/test/abc.js');
83
82
  });
84
83
 
85
84
  it('should not load without a kit id', function () {
@@ -87,8 +86,7 @@ describe('modules.Typekit', function () {
87
86
 
88
87
  typekit.supportUserAgent('useragent', support);
89
88
 
90
- expect(fakeDomHelper.insertInto).not.toHaveBeenCalled();
91
- expect(fakeDomHelper.createScriptSrc).not.toHaveBeenCalled();
89
+ expect(fakeDomHelper.loadScript).not.toHaveBeenCalled();
92
90
  expect(support).toHaveBeenCalled();
93
91
 
94
92
  typekit.load(load);
@@ -14,9 +14,6 @@ webfont.DomHelper = function(mainWindow, opt_loadWindow) {
14
14
 
15
15
  /** @type {Document} */
16
16
  this.document_ = this.loadWindow_.document;
17
-
18
- /** @type {boolean|undefined} */
19
- this.supportForStyle_ = undefined;
20
17
  };
21
18
 
22
19
  goog.scope(function () {
@@ -106,29 +103,6 @@ goog.scope(function () {
106
103
  return false;
107
104
  };
108
105
 
109
- /**
110
- * Creates a link to a CSS document.
111
- * @param {string} src The URL of the stylesheet.
112
- * @return {Element} a link element.
113
- */
114
- DomHelper.prototype.createCssLink = function(src) {
115
- return this.createElement('link', {
116
- 'rel': 'stylesheet',
117
- 'href': src
118
- });
119
- };
120
-
121
- /**
122
- * Creates a link to a javascript document.
123
- * @param {string} src The URL of the script.
124
- * @return {Element} a script element.
125
- */
126
- DomHelper.prototype.createScriptSrc = function(src) {
127
- return this.createElement('script', {
128
- 'src': src
129
- });
130
- };
131
-
132
106
  /**
133
107
  * Appends a name to an element's class attribute.
134
108
  * @param {Element} e The element.
@@ -187,27 +161,7 @@ goog.scope(function () {
187
161
  * @param {string} styleString The style string.
188
162
  */
189
163
  DomHelper.prototype.setStyle = function(e, styleString) {
190
- if (this.hasSupportForStyle_()) {
191
- e.setAttribute("style", styleString);
192
- } else {
193
- e.style.cssText = styleString;
194
- }
195
- };
196
-
197
- /**
198
- * Check if getting and setting the style attribute on an element with
199
- * getAttribute/setAttribute is supported. In old IE, you must use style.cssText
200
- * instead. Feature detection is only done the first time this is called.
201
- * @private
202
- * @return {boolean} Whether or not the feature is supported.
203
- */
204
- DomHelper.prototype.hasSupportForStyle_ = function() {
205
- if (this.supportForStyle_ === undefined) {
206
- var e = this.document_.createElement('p');
207
- e.innerHTML = '<a style="top:1px;">w</a>';
208
- this.supportForStyle_ = /top/.test(e.getElementsByTagName('a')[0].getAttribute('style'));
209
- }
210
- return this.supportForStyle_
164
+ e.style.cssText = styleString;
211
165
  };
212
166
 
213
167
  /**
@@ -258,7 +212,7 @@ goog.scope(function () {
258
212
  * @return {Element} a DOM element.
259
213
  */
260
214
  DomHelper.prototype.createStyle = function(css) {
261
- var e = this.document_.createElement('style');
215
+ var e = this.createElement('style');
262
216
 
263
217
  e.setAttribute('type', 'text/css');
264
218
  if (e.styleSheet) { // IE
@@ -269,23 +223,71 @@ goog.scope(function () {
269
223
  return e;
270
224
  };
271
225
 
226
+ /**
227
+ * Loads an external stylesheet.
228
+ *
229
+ * @param {string} href the URL of the stylesheet
230
+ * @param {function(Error)=} opt_callback Called when the stylesheet has loaded or failed to
231
+ * load. Note that the callback is *NOT* guaranteed to be called in all browsers. The first
232
+ * argument to the callback is an error object that is falsy when there are no errors and
233
+ * truthy when there are.
234
+ * @return {Element} The link element
235
+ */
236
+ DomHelper.prototype.loadStylesheet = function (href, opt_callback) {
237
+ var link = this.createElement('link', {
238
+ 'rel': 'stylesheet',
239
+ 'href': href
240
+ });
241
+
242
+ var done = false;
243
+
244
+ link.onload = function () {
245
+ if (!done) {
246
+ done = true;
247
+
248
+ if (opt_callback) {
249
+ opt_callback(null);
250
+ }
251
+ }
252
+ };
253
+
254
+ link.onerror = function () {
255
+ if (!done) {
256
+ done = true;
257
+
258
+ if (opt_callback) {
259
+ opt_callback(new Error('Stylesheet failed to load'));
260
+ }
261
+ }
262
+ };
263
+
264
+ this.insertInto('head', link);
265
+
266
+ return link;
267
+ };
268
+
272
269
  /**
273
270
  * Loads an external script file.
274
271
  * @param {string} src URL of the script.
275
- * @param {function()=} opt_callback callback when the script has loaded.
272
+ * @param {function(Error)=} opt_callback callback when the script has loaded. The first argument to
273
+ * the callback is an error object that is falsy when there are no errors and truthy when there are.
274
+ * @param {number=} opt_timeout The number of milliseconds after which the callback will be called
275
+ * with a timeout error. Defaults to 5 seconds.
276
+ * @return {Element} The script element
276
277
  */
277
- DomHelper.prototype.loadScript = function(src, opt_callback) {
278
+ DomHelper.prototype.loadScript = function(src, opt_callback, opt_timeout) {
278
279
  var head = this.document_.getElementsByTagName('head')[0];
279
280
 
280
281
  if (head) {
281
- var script = this.document_.createElement('script');
282
- script.src = src;
282
+ var script = this.createElement('script', {
283
+ 'src': src
284
+ });
283
285
  var done = false;
284
286
  script.onload = script.onreadystatechange = function() {
285
287
  if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
286
288
  done = true;
287
289
  if (opt_callback) {
288
- opt_callback();
290
+ opt_callback(null);
289
291
  }
290
292
  script.onload = script.onreadystatechange = null;
291
293
  // Avoid a bizarre issue with unclosed <base> tag in IE6 - http://blog.dotsmart.net/2008/04/
@@ -293,6 +295,19 @@ goog.scope(function () {
293
295
  }
294
296
  };
295
297
  head.appendChild(script);
298
+
299
+ window.setTimeout(function () {
300
+ if (!done) {
301
+ done = true;
302
+ if (opt_callback) {
303
+ opt_callback(new Error('Script load timeout'));
304
+ }
305
+ }
306
+ }, opt_timeout || 5000);
307
+
308
+ return script;
296
309
  }
310
+
311
+ return null;
297
312
  };
298
313
  });
data/src/core/webfont.js CHANGED
@@ -60,10 +60,15 @@ goog.scope(function () {
60
60
  fontWatcher, support) {
61
61
  var that = this;
62
62
 
63
- if (!support) {
63
+ if (support) {
64
+ module.load(function (fonts, opt_fontTestStrings, opt_metricCompatibleFonts) {
65
+ that.onModuleReady_(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts);
66
+ });
67
+ } else {
64
68
  var allModulesLoaded = --this.moduleLoading_ == 0;
65
69
 
66
70
  this.moduleFailedLoading_--;
71
+
67
72
  if (allModulesLoaded) {
68
73
  if (this.moduleFailedLoading_ == 0) {
69
74
  eventDispatcher.dispatchInactive();
@@ -72,12 +77,7 @@ goog.scope(function () {
72
77
  }
73
78
  }
74
79
  fontWatcher.watchFonts([], {}, null, allModulesLoaded);
75
- return;
76
80
  }
77
-
78
- module.load(function (fonts, opt_fontTestStrings, opt_metricCompatibleFonts) {
79
- that.onModuleReady_(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts);
80
- });
81
81
  };
82
82
 
83
83
  /**
@@ -44,7 +44,7 @@ goog.scope(function () {
44
44
  var key = this.configuration_['key'];
45
45
  var protocol = this.domHelper_.getProtocol();
46
46
  var url = protocol + '//webfonts.fontslive.com/css/' + key + '.css';
47
- this.domHelper_.insertInto('head', this.domHelper_.createCssLink(url));
47
+ this.domHelper_.loadStylesheet(url);
48
48
  var fv = this.parseFamiliesAndVariations(this.configuration_['families']);
49
49
  onReady(fv);
50
50
  };
@@ -30,9 +30,7 @@ goog.scope(function () {
30
30
  var familiesConfiguration = this.configuration_['families'] || [];
31
31
 
32
32
  for (i = 0, len = urls.length; i < len; i++) {
33
- var url = urls[i];
34
-
35
- this.domHelper_.insertInto('head', this.domHelper_.createCssLink(url));
33
+ this.domHelper_.loadStylesheet(urls[i]);
36
34
  }
37
35
 
38
36
  var fonts = [];
@@ -51,11 +51,13 @@ goog.scope(function () {
51
51
  };
52
52
 
53
53
  // Call the Fontdeck API.
54
- var script = this.domHelper_.createScriptSrc(this.getScriptSrc(projectId));
55
- this.domHelper_.insertInto('head', script);
56
-
54
+ this.domHelper_.loadScript(this.getScriptSrc(projectId), function (err) {
55
+ if (err) {
56
+ support(false);
57
+ }
58
+ });
57
59
  } else {
58
- support(true);
60
+ support(false);
59
61
  }
60
62
  };
61
63
 
@@ -54,8 +54,7 @@ goog.scope(function () {
54
54
  var fontApiParser = new FontApiParser(fontFamilies);
55
55
  fontApiParser.parse();
56
56
 
57
- domHelper.insertInto('head', domHelper.createCssLink(
58
- fontApiUrlBuilder.build()));
57
+ domHelper.loadStylesheet(fontApiUrlBuilder.build());
59
58
  onReady(fontApiParser.getFonts(), fontApiParser.getFontTestStrings(), GoogleFontApi.METRICS_COMPATIBLE_FONTS);
60
59
  };
61
60
  });
@@ -49,10 +49,7 @@ goog.scope(function () {
49
49
  var projectId = self.configuration_['projectId'];
50
50
  var version = self.configuration_['version'];
51
51
  if (projectId) {
52
- var loadWindow = self.domHelper_.getLoadWindow(),
53
- sc = self.domHelper_.createElement("script");
54
-
55
- sc["id"] = Monotype.SCRIPTID + projectId;
52
+ var loadWindow = self.domHelper_.getLoadWindow();
56
53
 
57
54
  function onload() {
58
55
  if (loadWindow[Monotype.HOOK + projectId]) {
@@ -66,21 +63,17 @@ goog.scope(function () {
66
63
  support(userAgent.getBrowserInfo().hasWebFontSupport());
67
64
  }
68
65
 
69
- var done = false;
70
-
71
- sc["onload"] = sc["onreadystatechange"] = function () {
72
- if (!done && (!this["readyState"] || this["readyState"] === "loaded" || this["readyState"] === "complete")) {
73
- done = true;
66
+ var script = this.domHelper_.loadScript(self.getScriptSrc(projectId, version), function (err) {
67
+ if (err) {
68
+ support(false);
69
+ } else {
74
70
  onload();
75
- sc["onload"] = sc["onreadystatechange"] = null;
76
71
  }
77
- };
78
-
79
- sc["src"] = self.getScriptSrc(projectId, version);
80
- this.domHelper_.insertInto('head', sc);
72
+ });
73
+ script["id"] = Monotype.SCRIPTID + projectId;
81
74
  }
82
75
  else {
83
- support(true);
76
+ support(false);
84
77
  }
85
78
  };
86
79
 
@@ -58,10 +58,13 @@ goog.scope(function () {
58
58
  };
59
59
 
60
60
  // Load the Typekit script.
61
- var script = this.domHelper_.createScriptSrc(this.getScriptSrc(kitId))
62
- this.domHelper_.insertInto('head', script);
61
+ this.domHelper_.loadScript(this.getScriptSrc(kitId), function (err) {
62
+ if (err) {
63
+ support(false);
64
+ }
65
+ }, 2000);
63
66
  } else {
64
- support(true);
67
+ support(false);
65
68
  }
66
69
  };
67
70
 
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'webfontloader'
16
- s.version = '1.4.9'
17
- s.date = '2013-07-24'
16
+ s.version = '1.4.10'
17
+ s.date = '2013-07-31'
18
18
 
19
19
  ## Make sure your summary is short. The description may be as long
20
20
  ## as you like.
@@ -68,6 +68,7 @@ DESC
68
68
  s.files = %w[
69
69
  AUTHORS
70
70
  CHANGELOG
71
+ CONTRIBUTING.md
71
72
  Gemfile
72
73
  LICENSE
73
74
  README.md
@@ -109,7 +110,6 @@ DESC
109
110
  spec/core/cssclassname_spec.js
110
111
  spec/core/domhelper_spec.js
111
112
  spec/core/eventdispatcher_spec.js
112
- spec/core/external_script.js
113
113
  spec/core/font_spec.js
114
114
  spec/core/fontmoduleloader_spec.js
115
115
  spec/core/fontruler_spec.js
@@ -120,21 +120,23 @@ DESC
120
120
  spec/core/version_spec.js
121
121
  spec/core/webfont_spec.js
122
122
  spec/deps.js
123
- spec/fonts/LICENSE.txt
124
- spec/fonts/nullfont.css
125
- spec/fonts/nullfont1.css
126
- spec/fonts/nullfont2.css
127
- spec/fonts/nullfont3.css
128
- spec/fonts/sourcesans.eot
129
- spec/fonts/sourcesans.otf
130
- spec/fonts/sourcesans.svg
131
- spec/fonts/sourcesans.ttf
132
- spec/fonts/sourcesans.woff
133
- spec/fonts/sourcesansa.css
134
- spec/fonts/sourcesansb.css
135
- spec/fonts/sourcesansc.css
136
- spec/fonts/sourcesanscbold.css
137
- spec/fonts/sourcesanscbold.otf
123
+ spec/fixtures/external_script.js
124
+ spec/fixtures/external_stylesheet.css
125
+ spec/fixtures/fonts/LICENSE.txt
126
+ spec/fixtures/fonts/nullfont.css
127
+ spec/fixtures/fonts/nullfont1.css
128
+ spec/fixtures/fonts/nullfont2.css
129
+ spec/fixtures/fonts/nullfont3.css
130
+ spec/fixtures/fonts/sourcesans.eot
131
+ spec/fixtures/fonts/sourcesans.otf
132
+ spec/fixtures/fonts/sourcesans.svg
133
+ spec/fixtures/fonts/sourcesans.ttf
134
+ spec/fixtures/fonts/sourcesans.woff
135
+ spec/fixtures/fonts/sourcesansa.css
136
+ spec/fixtures/fonts/sourcesansb.css
137
+ spec/fixtures/fonts/sourcesansc.css
138
+ spec/fixtures/fonts/sourcesanscbold.css
139
+ spec/fixtures/fonts/sourcesanscbold.otf
138
140
  spec/index.html
139
141
  spec/modules/ascender_spec.js
140
142
  spec/modules/custom_spec.js
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webfontloader
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 4
9
- - 9
10
- version: 1.4.9
9
+ - 10
10
+ version: 1.4.10
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Carver
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2013-07-24 00:00:00 Z
19
+ date: 2013-07-31 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  name: rake
@@ -96,6 +96,7 @@ extra_rdoc_files:
96
96
  files:
97
97
  - AUTHORS
98
98
  - CHANGELOG
99
+ - CONTRIBUTING.md
99
100
  - Gemfile
100
101
  - LICENSE
101
102
  - README.md
@@ -137,7 +138,6 @@ files:
137
138
  - spec/core/cssclassname_spec.js
138
139
  - spec/core/domhelper_spec.js
139
140
  - spec/core/eventdispatcher_spec.js
140
- - spec/core/external_script.js
141
141
  - spec/core/font_spec.js
142
142
  - spec/core/fontmoduleloader_spec.js
143
143
  - spec/core/fontruler_spec.js
@@ -148,21 +148,23 @@ files:
148
148
  - spec/core/version_spec.js
149
149
  - spec/core/webfont_spec.js
150
150
  - spec/deps.js
151
- - spec/fonts/LICENSE.txt
152
- - spec/fonts/nullfont.css
153
- - spec/fonts/nullfont1.css
154
- - spec/fonts/nullfont2.css
155
- - spec/fonts/nullfont3.css
156
- - spec/fonts/sourcesans.eot
157
- - spec/fonts/sourcesans.otf
158
- - spec/fonts/sourcesans.svg
159
- - spec/fonts/sourcesans.ttf
160
- - spec/fonts/sourcesans.woff
161
- - spec/fonts/sourcesansa.css
162
- - spec/fonts/sourcesansb.css
163
- - spec/fonts/sourcesansc.css
164
- - spec/fonts/sourcesanscbold.css
165
- - spec/fonts/sourcesanscbold.otf
151
+ - spec/fixtures/external_script.js
152
+ - spec/fixtures/external_stylesheet.css
153
+ - spec/fixtures/fonts/LICENSE.txt
154
+ - spec/fixtures/fonts/nullfont.css
155
+ - spec/fixtures/fonts/nullfont1.css
156
+ - spec/fixtures/fonts/nullfont2.css
157
+ - spec/fixtures/fonts/nullfont3.css
158
+ - spec/fixtures/fonts/sourcesans.eot
159
+ - spec/fixtures/fonts/sourcesans.otf
160
+ - spec/fixtures/fonts/sourcesans.svg
161
+ - spec/fixtures/fonts/sourcesans.ttf
162
+ - spec/fixtures/fonts/sourcesans.woff
163
+ - spec/fixtures/fonts/sourcesansa.css
164
+ - spec/fixtures/fonts/sourcesansb.css
165
+ - spec/fixtures/fonts/sourcesansc.css
166
+ - spec/fixtures/fonts/sourcesanscbold.css
167
+ - spec/fixtures/fonts/sourcesanscbold.otf
166
168
  - spec/index.html
167
169
  - spec/modules/ascender_spec.js
168
170
  - spec/modules/custom_spec.js