govuk_template 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/LICENCE.txt +22 -0
  2. data/README.md +61 -0
  3. data/app/assets/images/apple-touch-icon-114x114.png +0 -0
  4. data/app/assets/images/apple-touch-icon-144x144.png +0 -0
  5. data/app/assets/images/apple-touch-icon-57x57.png +0 -0
  6. data/app/assets/images/apple-touch-icon-72x72.png +0 -0
  7. data/app/assets/images/favicon.ico +0 -0
  8. data/app/assets/images/gov.uk_logotype-2x.png +0 -0
  9. data/app/assets/images/gov.uk_logotype_crown.png +0 -0
  10. data/app/assets/images/gov.uk_logotype_crown_invert.png +0 -0
  11. data/app/assets/images/gov.uk_logotype_crown_invert_trans.png +0 -0
  12. data/app/assets/images/open-government-licence_2x.png +0 -0
  13. data/app/assets/images/opengraph-image.png +0 -0
  14. data/app/assets/javascripts/govuk-template.js +97 -0
  15. data/app/assets/javascripts/ie.js +512 -0
  16. data/app/assets/javascripts/vendor/goog/webfont-debug.js +2126 -0
  17. data/app/assets/stylesheets/external-link-24x24.png +0 -0
  18. data/app/assets/stylesheets/external-link-black-12x12.png +0 -0
  19. data/app/assets/stylesheets/external-link-black-24x24.png +0 -0
  20. data/app/assets/stylesheets/external-link.png +0 -0
  21. data/app/assets/stylesheets/fonts-ie8.css.erb +30 -0
  22. data/app/assets/stylesheets/fonts.css.erb +30 -0
  23. data/app/assets/stylesheets/fonts/NTA-Bold-20130221.eot +0 -0
  24. data/app/assets/stylesheets/fonts/NTA-Bold-20130221.woff +0 -0
  25. data/app/assets/stylesheets/fonts/NTA-Light-20130221.eot +0 -0
  26. data/app/assets/stylesheets/fonts/NTA-Light-20130221.woff +0 -0
  27. data/app/assets/stylesheets/fonts/NTATabularNumbers-Bold.eot +0 -0
  28. data/app/assets/stylesheets/fonts/NTATabularNumbers-Bold.woff +0 -0
  29. data/app/assets/stylesheets/fonts/NTATabularNumbers-Light.eot +0 -0
  30. data/app/assets/stylesheets/fonts/NTATabularNumbers-Light.woff +0 -0
  31. data/app/assets/stylesheets/govuk-template-ie6.css.erb +548 -0
  32. data/app/assets/stylesheets/govuk-template-ie7.css.erb +544 -0
  33. data/app/assets/stylesheets/govuk-template-ie8.css.erb +527 -0
  34. data/app/assets/stylesheets/govuk-template-print.css.erb +78 -0
  35. data/app/assets/stylesheets/govuk-template.css.erb +575 -0
  36. data/app/assets/stylesheets/images/close.png +0 -0
  37. data/app/assets/stylesheets/images/govuk-crest-2x.png +0 -0
  38. data/app/assets/stylesheets/images/govuk-crest-ie.png +0 -0
  39. data/app/assets/stylesheets/images/govuk-crest.png +0 -0
  40. data/app/assets/stylesheets/images/separator-2x.png +0 -0
  41. data/app/assets/stylesheets/images/separator.png +0 -0
  42. data/app/views/layouts/govuk_template.html.erb +127 -0
  43. data/lib/govuk_template.rb +5 -0
  44. data/lib/govuk_template/engine.rb +13 -0
  45. data/lib/govuk_template/version.rb +3 -0
  46. metadata +209 -0
@@ -0,0 +1,2126 @@
1
+ /*
2
+ * Copyright 2012 Small Batch, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5
+ * use this file except in compliance with the License. You may obtain a copy of
6
+ * the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+ * License for the specific language governing permissions and limitations under
14
+ * the License.
15
+ */
16
+
17
+ var webfont = {};
18
+
19
+ /**
20
+ * @param {Object} context
21
+ * @param {function(...)} func
22
+ * @param {...*} opt_args
23
+ */
24
+ webfont.bind = function(context, func, opt_args) {
25
+ var args = arguments.length > 2 ?
26
+ Array.prototype.slice.call(arguments, 2) : [];
27
+
28
+ return function() {
29
+ args.push.apply(args, arguments);
30
+ return func.apply(context, args);
31
+ };
32
+ };
33
+
34
+ webfont.extendsClass = function(baseClass, subClass) {
35
+
36
+ // Avoid polluting the baseClass prototype object with methods from the
37
+ // subClass
38
+ /** @constructor */
39
+ function baseExtendClass() {};
40
+ baseExtendClass.prototype = baseClass.prototype;
41
+ subClass.prototype = new baseExtendClass();
42
+
43
+ subClass.prototype.constructor = subClass;
44
+ subClass.superCtor_ = baseClass;
45
+ subClass.super_ = baseClass.prototype;
46
+ };
47
+
48
+ /**
49
+ * Handles common DOM manipulation tasks. The aim of this library is to cover
50
+ * the needs of typical font loading. Not more, not less.
51
+ * @param {HTMLDocument} doc The HTML document we'll manipulate.
52
+ * @param {webfont.UserAgent} userAgent The current user agent.
53
+ * @constructor
54
+ */
55
+ webfont.DomHelper = function(doc, userAgent) {
56
+ this.document_ = doc;
57
+ this.userAgent_ = userAgent;
58
+ };
59
+
60
+ /**
61
+ * Creates an element.
62
+ * @param {string} elem The element type.
63
+ * @param {Object=} opt_attr A hash of attribute key/value pairs.
64
+ * @param {string=} opt_innerHtml Contents of the element.
65
+ * @return {Element} the new element.
66
+ */
67
+ webfont.DomHelper.prototype.createElement = function(elem, opt_attr,
68
+ opt_innerHtml) {
69
+ var domElement = this.document_.createElement(elem);
70
+
71
+ if (opt_attr) {
72
+ for (var attr in opt_attr) {
73
+ // protect against native prototype augmentations
74
+ if (opt_attr.hasOwnProperty(attr)) {
75
+ if (attr == "style") {
76
+ this.setStyle(domElement, opt_attr[attr]);
77
+ } else {
78
+ domElement.setAttribute(attr, opt_attr[attr]);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ if (opt_innerHtml) {
84
+ domElement.appendChild(this.document_.createTextNode(opt_innerHtml));
85
+ }
86
+ return domElement;
87
+ };
88
+
89
+ /**
90
+ * Inserts an element into the document. This is intended for unambiguous
91
+ * elements such as html, body, head.
92
+ * @param {string} tagName The element name.
93
+ * @param {Element} e The element to append.
94
+ * @return {boolean} True if the element was inserted.
95
+ */
96
+ webfont.DomHelper.prototype.insertInto = function(tagName, e) {
97
+ var t = this.document_.getElementsByTagName(tagName)[0];
98
+
99
+ if (!t) { // opera allows documents without a head
100
+ t = document.documentElement;
101
+ }
102
+
103
+ if (t && t.lastChild) {
104
+ // This is safer than appendChild in IE. appendChild causes random
105
+ // JS errors in IE. Sometimes errors in other JS exectution, sometimes
106
+ // complete 'This page cannot be displayed' errors. For our purposes,
107
+ // it's equivalent because we don't need to insert at any specific
108
+ // location.
109
+ t.insertBefore(e, t.lastChild);
110
+ return true;
111
+ }
112
+ return false;
113
+ };
114
+
115
+ /**
116
+ * Calls a function when the body tag exists.
117
+ * @param {function()} callback The function to call.
118
+ */
119
+ webfont.DomHelper.prototype.whenBodyExists = function(callback) {
120
+ var check = function() {
121
+ if (document.body) {
122
+ callback();
123
+ } else {
124
+ setTimeout(check, 0);
125
+ }
126
+ }
127
+ check();
128
+ };
129
+
130
+ /**
131
+ * Removes an element from the DOM.
132
+ * @param {Element} node The element to remove.
133
+ * @return {boolean} True if the element was removed.
134
+ */
135
+ webfont.DomHelper.prototype.removeElement = function(node) {
136
+ if (node.parentNode) {
137
+ node.parentNode.removeChild(node);
138
+ return true;
139
+ }
140
+ return false;
141
+ };
142
+
143
+ /**
144
+ * Creates a link to a CSS document.
145
+ * @param {string} src The URL of the stylesheet.
146
+ * @return {Element} a link element.
147
+ */
148
+ webfont.DomHelper.prototype.createCssLink = function(src) {
149
+ return this.createElement('link', {
150
+ 'rel': 'stylesheet',
151
+ 'href': src
152
+ });
153
+ };
154
+
155
+ /**
156
+ * Creates a link to a javascript document.
157
+ * @param {string} src The URL of the script.
158
+ * @return {Element} a script element.
159
+ */
160
+ webfont.DomHelper.prototype.createScriptSrc = function(src) {
161
+ return this.createElement('script', {
162
+ 'src': src
163
+ });
164
+ };
165
+
166
+ /**
167
+ * Appends a name to an element's class attribute.
168
+ * @param {Element} e The element.
169
+ * @param {string} name The class name to add.
170
+ */
171
+ webfont.DomHelper.prototype.appendClassName = function(e, name) {
172
+ var classes = e.className.split(/\s+/);
173
+ for (var i = 0, len = classes.length; i < len; i++) {
174
+ if (classes[i] == name) {
175
+ return;
176
+ }
177
+ }
178
+ classes.push(name);
179
+ e.className = classes.join(' ').replace(/^\s+/, '');
180
+ };
181
+
182
+ /**
183
+ * Removes a name to an element's class attribute.
184
+ * @param {Element} e The element.
185
+ * @param {string} name The class name to remove.
186
+ */
187
+ webfont.DomHelper.prototype.removeClassName = function(e, name) {
188
+ var classes = e.className.split(/\s+/);
189
+ var remainingClasses = [];
190
+ for (var i = 0, len = classes.length; i < len; i++) {
191
+ if (classes[i] != name) {
192
+ remainingClasses.push(classes[i]);
193
+ }
194
+ }
195
+ e.className = remainingClasses.join(' ').replace(/^\s+/, '')
196
+ .replace(/\s+$/, '');
197
+ };
198
+
199
+ /**
200
+ * Returns true if an element has a given class name and false otherwise.
201
+ * @param {Element} e The element.
202
+ * @param {string} name The class name to check for.
203
+ * @return {boolean} Whether or not the element has this class name.
204
+ */
205
+ webfont.DomHelper.prototype.hasClassName = function(e, name) {
206
+ var classes = e.className.split(/\s+/);
207
+ for (var i = 0, len = classes.length; i < len; i++) {
208
+ if (classes[i] == name) {
209
+ return true;
210
+ }
211
+ }
212
+ return false;
213
+ };
214
+
215
+ /**
216
+ * Sets the style attribute on an element.
217
+ * @param {Element} e The element.
218
+ * @param {string} styleString The style string.
219
+ */
220
+ webfont.DomHelper.prototype.setStyle = function(e, styleString) {
221
+ if (this.userAgent_.getName() == "MSIE") {
222
+ e.style.cssText = styleString;
223
+ } else {
224
+ e.setAttribute("style", styleString);
225
+ }
226
+ };
227
+
228
+ /**
229
+ * @param {string} name
230
+ * @param {string} version
231
+ * @param {string} engine
232
+ * @param {string} engineVersion
233
+ * @param {string} platform
234
+ * @param {string} platformVersion
235
+ * @param {number|undefined} documentMode
236
+ * @param {boolean} webFontSupport
237
+ * @constructor
238
+ */
239
+ webfont.UserAgent = function(name, version, engine, engineVersion, platform,
240
+ platformVersion, documentMode, webFontSupport) {
241
+ this.name_ = name;
242
+ this.version_ = version;
243
+ this.engine_ = engine;
244
+ this.engineVersion_ = engineVersion;
245
+ this.platform_ = platform;
246
+ this.platformVersion_ = platformVersion;
247
+ this.documentMode_ = documentMode;
248
+ this.webFontSupport_ = webFontSupport;
249
+ };
250
+
251
+ /**
252
+ * @return {string}
253
+ */
254
+ webfont.UserAgent.prototype.getName = function() {
255
+ return this.name_;
256
+ };
257
+
258
+ /**
259
+ * @return {string}
260
+ */
261
+ webfont.UserAgent.prototype.getVersion = function() {
262
+ return this.version_;
263
+ };
264
+
265
+ /**
266
+ * @return {string}
267
+ */
268
+ webfont.UserAgent.prototype.getEngine = function() {
269
+ return this.engine_;
270
+ };
271
+
272
+ /**
273
+ * @return {string}
274
+ */
275
+ webfont.UserAgent.prototype.getEngineVersion = function() {
276
+ return this.engineVersion_;
277
+ };
278
+
279
+ /**
280
+ * @return {string}
281
+ */
282
+ webfont.UserAgent.prototype.getPlatform = function() {
283
+ return this.platform_;
284
+ };
285
+
286
+ /**
287
+ * @return {string}
288
+ */
289
+ webfont.UserAgent.prototype.getPlatformVersion = function() {
290
+ return this.platformVersion_;
291
+ };
292
+
293
+ /**
294
+ * @return {number|undefined}
295
+ */
296
+ webfont.UserAgent.prototype.getDocumentMode = function() {
297
+ return this.documentMode_;
298
+ };
299
+
300
+ /**
301
+ * @return {boolean}
302
+ */
303
+ webfont.UserAgent.prototype.isSupportingWebFont = function() {
304
+ return this.webFontSupport_;
305
+ };
306
+
307
+ /**
308
+ * @param {string} userAgent The browser userAgent string to parse.
309
+ * @constructor
310
+ */
311
+ webfont.UserAgentParser = function(userAgent, doc) {
312
+ this.userAgent_ = userAgent;
313
+ this.doc_ = doc;
314
+ };
315
+
316
+ /**
317
+ * @const
318
+ * @type {string}
319
+ */
320
+ webfont.UserAgentParser.UNKNOWN = "Unknown";
321
+
322
+ /**
323
+ * @const
324
+ * @type {webfont.UserAgent}
325
+ */
326
+ webfont.UserAgentParser.UNKNOWN_USER_AGENT = new webfont.UserAgent(
327
+ webfont.UserAgentParser.UNKNOWN,
328
+ webfont.UserAgentParser.UNKNOWN,
329
+ webfont.UserAgentParser.UNKNOWN,
330
+ webfont.UserAgentParser.UNKNOWN,
331
+ webfont.UserAgentParser.UNKNOWN,
332
+ webfont.UserAgentParser.UNKNOWN,
333
+ undefined,
334
+ false);
335
+
336
+ /**
337
+ * Parses the user agent string and returns an object.
338
+ * @return {webfont.UserAgent}
339
+ */
340
+ webfont.UserAgentParser.prototype.parse = function() {
341
+ if (this.isIe_()) {
342
+ return this.parseIeUserAgentString_();
343
+ } else if (this.isOpera_()) {
344
+ return this.parseOperaUserAgentString_();
345
+ } else if (this.isWebKit_()) {
346
+ return this.parseWebKitUserAgentString_();
347
+ } else if (this.isGecko_()) {
348
+ return this.parseGeckoUserAgentString_();
349
+ } else {
350
+ return webfont.UserAgentParser.UNKNOWN_USER_AGENT;
351
+ }
352
+ };
353
+
354
+ /**
355
+ * @private
356
+ */
357
+ webfont.UserAgentParser.prototype.getPlatform_ = function() {
358
+ var mobileOs = this.getMatchingGroup_(this.userAgent_,
359
+ /(iPod|iPad|iPhone|Android)/, 1);
360
+
361
+ if (mobileOs != "") {
362
+ return mobileOs;
363
+ }
364
+ var os = this.getMatchingGroup_(this.userAgent_,
365
+ /(Linux|Mac_PowerPC|Macintosh|Windows)/, 1);
366
+
367
+ if (os != "") {
368
+ if (os == "Mac_PowerPC") {
369
+ os = "Macintosh";
370
+ }
371
+ return os;
372
+ }
373
+ return webfont.UserAgentParser.UNKNOWN;
374
+ };
375
+
376
+ /**
377
+ * @private
378
+ */
379
+ webfont.UserAgentParser.prototype.getPlatformVersion_ = function() {
380
+ var macVersion = this.getMatchingGroup_(this.userAgent_,
381
+ /(OS X|Windows NT|Android) ([^;)]+)/, 2);
382
+ if (macVersion) {
383
+ return macVersion;
384
+ }
385
+ var iVersion = this.getMatchingGroup_(this.userAgent_,
386
+ /(iPhone )?OS ([\d_]+)/, 2);
387
+ if (iVersion) {
388
+ return iVersion;
389
+ }
390
+ var linuxVersion = this.getMatchingGroup_(this.userAgent_,
391
+ /Linux ([i\d]+)/, 1);
392
+ if (linuxVersion) {
393
+ return linuxVersion;
394
+ }
395
+
396
+ return webfont.UserAgentParser.UNKNOWN;
397
+ };
398
+
399
+ /**
400
+ * @private
401
+ */
402
+ webfont.UserAgentParser.prototype.isIe_ = function() {
403
+ return this.userAgent_.indexOf("MSIE") != -1;
404
+ };
405
+
406
+ /**
407
+ * @private
408
+ */
409
+ webfont.UserAgentParser.prototype.parseIeUserAgentString_ = function() {
410
+ var browser = this.getMatchingGroup_(this.userAgent_, /(MSIE [\d\w\.]+)/, 1);
411
+ var engineName = webfont.UserAgentParser.UNKNOWN;
412
+ var engineVersion = webfont.UserAgentParser.UNKNOWN;
413
+
414
+ if (browser != "") {
415
+ var pair = browser.split(' ');
416
+ var name = pair[0];
417
+ var version = pair[1];
418
+
419
+ // For IE we give MSIE as the engine name and the version of IE
420
+ // instead of the specific Trident engine name and version
421
+ return new webfont.UserAgent(name, version, name, version,
422
+ this.getPlatform_(), this.getPlatformVersion_(),
423
+ this.getDocumentMode_(this.doc_), this.getMajorVersion_(version) >= 6);
424
+ }
425
+ return new webfont.UserAgent("MSIE", webfont.UserAgentParser.UNKNOWN,
426
+ "MSIE", webfont.UserAgentParser.UNKNOWN,
427
+ this.getPlatform_(), this.getPlatformVersion_(),
428
+ this.getDocumentMode_(this.doc_), false);
429
+ };
430
+
431
+ /**
432
+ * @private
433
+ */
434
+ webfont.UserAgentParser.prototype.isOpera_ = function() {
435
+ return this.userAgent_.indexOf("Opera") != -1;
436
+ };
437
+
438
+ /**
439
+ * @private
440
+ */
441
+ webfont.UserAgentParser.prototype.parseOperaUserAgentString_ = function() {
442
+ var engineName = webfont.UserAgentParser.UNKNOWN;
443
+ var engineVersion = webfont.UserAgentParser.UNKNOWN;
444
+ var enginePair = this.getMatchingGroup_(this.userAgent_,
445
+ /(Presto\/[\d\w\.]+)/, 1);
446
+
447
+ if (enginePair != "") {
448
+ var splittedEnginePair = enginePair.split('/');
449
+
450
+ engineName = splittedEnginePair[0];
451
+ engineVersion = splittedEnginePair[1];
452
+ } else {
453
+ if (this.userAgent_.indexOf("Gecko") != -1) {
454
+ engineName = "Gecko";
455
+ }
456
+ var geckoVersion = this.getMatchingGroup_(this.userAgent_, /rv:([^\)]+)/, 1);
457
+
458
+ if (geckoVersion != "") {
459
+ engineVersion = geckoVersion;
460
+ }
461
+ }
462
+ if (this.userAgent_.indexOf("Version/") != -1) {
463
+ var version = this.getMatchingGroup_(this.userAgent_, /Version\/([\d\.]+)/, 1);
464
+
465
+ if (version != "") {
466
+ return new webfont.UserAgent("Opera", version, engineName, engineVersion,
467
+ this.getPlatform_(), this.getPlatformVersion_(),
468
+ this.getDocumentMode_(this.doc_), this.getMajorVersion_(version) >= 10);
469
+ }
470
+ }
471
+ var version = this.getMatchingGroup_(this.userAgent_, /Opera[\/ ]([\d\.]+)/, 1);
472
+
473
+ if (version != "") {
474
+ return new webfont.UserAgent("Opera", version, engineName, engineVersion,
475
+ this.getPlatform_(), this.getPlatformVersion_(),
476
+ this.getDocumentMode_(this.doc_), this.getMajorVersion_(version) >= 10);
477
+ }
478
+ return new webfont.UserAgent("Opera", webfont.UserAgentParser.UNKNOWN,
479
+ engineName, engineVersion, this.getPlatform_(),
480
+ this.getPlatformVersion_(), this.getDocumentMode_(this.doc_), false);
481
+ };
482
+
483
+ /**
484
+ * @private
485
+ */
486
+ webfont.UserAgentParser.prototype.isWebKit_ = function() {
487
+ return this.userAgent_.indexOf("AppleWebKit") != -1;
488
+ };
489
+
490
+ /**
491
+ * @private
492
+ */
493
+ webfont.UserAgentParser.prototype.parseWebKitUserAgentString_ = function() {
494
+ var platform = this.getPlatform_();
495
+ var platformVersion = this.getPlatformVersion_();
496
+ var webKitVersion = this.getMatchingGroup_(this.userAgent_,
497
+ /AppleWebKit\/([\d\.\+]+)/, 1);
498
+
499
+ if (webKitVersion == "") {
500
+ webKitVersion = webfont.UserAgentParser.UNKNOWN;
501
+ }
502
+ var name = webfont.UserAgentParser.UNKNOWN;
503
+
504
+ if (this.userAgent_.indexOf("Chrome") != -1) {
505
+ name = "Chrome";
506
+ } else if (this.userAgent_.indexOf("Safari") != -1) {
507
+ name = "Safari";
508
+ } else if (this.userAgent_.indexOf("AdobeAIR") != -1) {
509
+ name = "AdobeAIR";
510
+ }
511
+ var version = webfont.UserAgentParser.UNKNOWN;
512
+
513
+ if (this.userAgent_.indexOf("Version/") != -1) {
514
+ version = this.getMatchingGroup_(this.userAgent_,
515
+ /Version\/([\d\.\w]+)/, 1);
516
+ } else if (name == "Chrome") {
517
+ version = this.getMatchingGroup_(this.userAgent_,
518
+ /Chrome\/([\d\.]+)/, 1);
519
+ } else if (name == "AdobeAIR") {
520
+ version = this.getMatchingGroup_(this.userAgent_,
521
+ /AdobeAIR\/([\d\.]+)/, 1);
522
+ }
523
+ var supportWebFont = false;
524
+ if (name == "AdobeAIR") {
525
+ var minor = this.getMatchingGroup_(version, /\d+\.(\d+)/, 1);
526
+ supportWebFont = this.getMajorVersion_(version) > 2 ||
527
+ this.getMajorVersion_(version) == 2 && parseInt(minor, 10) >= 5;
528
+ } else {
529
+ var minor = this.getMatchingGroup_(webKitVersion, /\d+\.(\d+)/, 1);
530
+ supportWebFont = this.getMajorVersion_(webKitVersion) >= 526 ||
531
+ this.getMajorVersion_(webKitVersion) >= 525 && parseInt(minor, 10) >= 13;
532
+ }
533
+
534
+ return new webfont.UserAgent(name, version, "AppleWebKit", webKitVersion,
535
+ platform, platformVersion, this.getDocumentMode_(this.doc_), supportWebFont);
536
+ };
537
+
538
+ /**
539
+ * @private
540
+ */
541
+ webfont.UserAgentParser.prototype.isGecko_ = function() {
542
+ return this.userAgent_.indexOf("Gecko") != -1;
543
+ };
544
+
545
+ /**
546
+ * @private
547
+ */
548
+ webfont.UserAgentParser.prototype.parseGeckoUserAgentString_ = function() {
549
+ var name = webfont.UserAgentParser.UNKNOWN;
550
+ var version = webfont.UserAgentParser.UNKNOWN;
551
+ var supportWebFont = false;
552
+
553
+ if (this.userAgent_.indexOf("Firefox") != -1) {
554
+ name = "Firefox";
555
+ var versionNum = this.getMatchingGroup_(this.userAgent_,
556
+ /Firefox\/([\d\w\.]+)/, 1);
557
+
558
+ if (versionNum != "") {
559
+ var minor = this.getMatchingGroup_(versionNum, /\d+\.(\d+)/, 1);
560
+
561
+ version = versionNum;
562
+ supportWebFont = versionNum != "" && this.getMajorVersion_(versionNum) >= 3 &&
563
+ parseInt(minor, 10) >= 5;
564
+ }
565
+ } else if (this.userAgent_.indexOf("Mozilla") != -1) {
566
+ name = "Mozilla";
567
+ }
568
+ var geckoVersion = this.getMatchingGroup_(this.userAgent_, /rv:([^\)]+)/, 1);
569
+
570
+ if (geckoVersion == "") {
571
+ geckoVersion = webfont.UserAgentParser.UNKNOWN;
572
+ } else {
573
+ if (!supportWebFont) {
574
+ var majorVersion = this.getMajorVersion_(geckoVersion);
575
+ var intMinorVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.(\d+)/, 1), 10);
576
+ var subVersion = parseInt(this.getMatchingGroup_(geckoVersion, /\d+\.\d+\.(\d+)/, 1), 10);
577
+
578
+ supportWebFont = majorVersion > 1 ||
579
+ majorVersion == 1 && intMinorVersion > 9 ||
580
+ majorVersion == 1 && intMinorVersion == 9 && subVersion >= 2 ||
581
+ geckoVersion.match(/1\.9\.1b[123]/) != null ||
582
+ geckoVersion.match(/1\.9\.1\.[\d\.]+/) != null;
583
+ }
584
+ }
585
+ return new webfont.UserAgent(name, version, "Gecko", geckoVersion,
586
+ this.getPlatform_(), this.getPlatformVersion_(), this.getDocumentMode_(this.doc_),
587
+ supportWebFont);
588
+ };
589
+
590
+ /**
591
+ * @private
592
+ */
593
+ webfont.UserAgentParser.prototype.getMajorVersion_ = function(version) {
594
+ var majorVersion = this.getMatchingGroup_(version, /(\d+)/, 1);
595
+
596
+ if (majorVersion != "") {
597
+ return parseInt(majorVersion, 10);
598
+ }
599
+ return -1;
600
+ };
601
+
602
+ /**
603
+ * @private
604
+ */
605
+ webfont.UserAgentParser.prototype.getMatchingGroup_ = function(str,
606
+ regexp, index) {
607
+ var groups = str.match(regexp);
608
+
609
+ if (groups && groups[index]) {
610
+ return groups[index];
611
+ }
612
+ return "";
613
+ };
614
+
615
+ /**
616
+ * @private
617
+ */
618
+ webfont.UserAgentParser.prototype.getDocumentMode_ = function(doc) {
619
+ if (doc.documentMode) return doc.documentMode;
620
+ return undefined;
621
+ };
622
+
623
+ /**
624
+ * A class to dispatch events and manage the event class names on an html
625
+ * element that represent the current state of fonts on the page. Active class
626
+ * names always overwrite inactive class names of the same type, while loading
627
+ * class names may be present whenever a font is loading (regardless of if an
628
+ * associated active or inactive class name is also present).
629
+ * @param {webfont.DomHelper} domHelper
630
+ * @param {HTMLElement} htmlElement
631
+ * @param {Object} callbacks
632
+ * @param {string=} opt_namespace
633
+ * @constructor
634
+ */
635
+ webfont.EventDispatcher = function(domHelper, htmlElement, callbacks,
636
+ opt_namespace) {
637
+ this.domHelper_ = domHelper;
638
+ this.htmlElement_ = htmlElement;
639
+ this.callbacks_ = callbacks;
640
+ this.namespace_ = opt_namespace || webfont.EventDispatcher.DEFAULT_NAMESPACE;
641
+ this.cssClassName_ = new webfont.CssClassName('-');
642
+ };
643
+
644
+ /**
645
+ * @const
646
+ * @type {string}
647
+ */
648
+ webfont.EventDispatcher.DEFAULT_NAMESPACE = 'wf';
649
+
650
+ /**
651
+ * @const
652
+ * @type {string}
653
+ */
654
+ webfont.EventDispatcher.LOADING = 'loading';
655
+
656
+ /**
657
+ * @const
658
+ * @type {string}
659
+ */
660
+ webfont.EventDispatcher.ACTIVE = 'active';
661
+
662
+ /**
663
+ * @const
664
+ * @type {string}
665
+ */
666
+ webfont.EventDispatcher.INACTIVE = 'inactive';
667
+
668
+ /**
669
+ * @const
670
+ * @type {string}
671
+ */
672
+ webfont.EventDispatcher.FONT = 'font';
673
+
674
+ /**
675
+ * Dispatch the loading event and append the loading class name.
676
+ */
677
+ webfont.EventDispatcher.prototype.dispatchLoading = function() {
678
+ this.domHelper_.appendClassName(this.htmlElement_,
679
+ this.cssClassName_.build(
680
+ this.namespace_, webfont.EventDispatcher.LOADING));
681
+ this.dispatch_(webfont.EventDispatcher.LOADING);
682
+ };
683
+
684
+ /**
685
+ * Dispatch the font loading event and append the font loading class name.
686
+ * @param {string} fontFamily
687
+ * @param {string} fontDescription
688
+ */
689
+ webfont.EventDispatcher.prototype.dispatchFontLoading = function(fontFamily, fontDescription) {
690
+ this.domHelper_.appendClassName(this.htmlElement_,
691
+ this.cssClassName_.build(
692
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
693
+ this.dispatch_(
694
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.LOADING, fontFamily, fontDescription);
695
+ };
696
+
697
+ /**
698
+ * Dispatch the font active event, remove the font loading class name, remove
699
+ * the font inactive class name, and append the font active class name.
700
+ * @param {string} fontFamily
701
+ * @param {string} fontDescription
702
+ */
703
+ webfont.EventDispatcher.prototype.dispatchFontActive = function(fontFamily, fontDescription) {
704
+ this.domHelper_.removeClassName(this.htmlElement_,
705
+ this.cssClassName_.build(
706
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
707
+ this.domHelper_.removeClassName(this.htmlElement_,
708
+ this.cssClassName_.build(
709
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.INACTIVE));
710
+ this.domHelper_.appendClassName(this.htmlElement_,
711
+ this.cssClassName_.build(
712
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.ACTIVE));
713
+ this.dispatch_(
714
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.ACTIVE, fontFamily, fontDescription);
715
+ };
716
+
717
+ /**
718
+ * Dispatch the font inactive event, remove the font loading class name, and
719
+ * append the font inactive class name (unless the font active class name is
720
+ * already present).
721
+ * @param {string} fontFamily
722
+ * @param {string} fontDescription
723
+ */
724
+ webfont.EventDispatcher.prototype.dispatchFontInactive = function(fontFamily, fontDescription) {
725
+ this.domHelper_.removeClassName(this.htmlElement_,
726
+ this.cssClassName_.build(
727
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
728
+ var hasFontActive = this.domHelper_.hasClassName(this.htmlElement_,
729
+ this.cssClassName_.build(
730
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.ACTIVE));
731
+ if (!hasFontActive) {
732
+ this.domHelper_.appendClassName(this.htmlElement_,
733
+ this.cssClassName_.build(
734
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.INACTIVE));
735
+ }
736
+ this.dispatch_(
737
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.INACTIVE, fontFamily, fontDescription);
738
+ };
739
+
740
+ /**
741
+ * Dispatch the inactive event, remove the loading class name, and append the
742
+ * inactive class name (unless the active class name is already present).
743
+ */
744
+ webfont.EventDispatcher.prototype.dispatchInactive = function() {
745
+ this.domHelper_.removeClassName(this.htmlElement_,
746
+ this.cssClassName_.build(
747
+ this.namespace_, webfont.EventDispatcher.LOADING));
748
+ var hasActive = this.domHelper_.hasClassName(this.htmlElement_,
749
+ this.cssClassName_.build(
750
+ this.namespace_, webfont.EventDispatcher.ACTIVE));
751
+ if (!hasActive) {
752
+ this.domHelper_.appendClassName(this.htmlElement_,
753
+ this.cssClassName_.build(
754
+ this.namespace_, webfont.EventDispatcher.INACTIVE));
755
+ }
756
+ this.dispatch_(webfont.EventDispatcher.INACTIVE);
757
+ };
758
+
759
+ /**
760
+ * Dispatch the active event, remove the loading class name, remove the inactive
761
+ * class name, and append the active class name.
762
+ */
763
+ webfont.EventDispatcher.prototype.dispatchActive = function() {
764
+ this.domHelper_.removeClassName(this.htmlElement_,
765
+ this.cssClassName_.build(
766
+ this.namespace_, webfont.EventDispatcher.LOADING));
767
+ this.domHelper_.removeClassName(this.htmlElement_,
768
+ this.cssClassName_.build(
769
+ this.namespace_, webfont.EventDispatcher.INACTIVE));
770
+ this.domHelper_.appendClassName(this.htmlElement_,
771
+ this.cssClassName_.build(
772
+ this.namespace_, webfont.EventDispatcher.ACTIVE));
773
+ this.dispatch_(webfont.EventDispatcher.ACTIVE);
774
+ };
775
+
776
+ /**
777
+ * @param {string} event
778
+ * @param {string=} opt_arg1
779
+ * @param {string=} opt_arg2
780
+ */
781
+ webfont.EventDispatcher.prototype.dispatch_ = function(event, opt_arg1, opt_arg2) {
782
+ if (this.callbacks_[event]) {
783
+ this.callbacks_[event](opt_arg1, opt_arg2);
784
+ }
785
+ };
786
+
787
+ /**
788
+ * @constructor
789
+ */
790
+ webfont.FontModuleLoader = function() {
791
+ this.modules_ = {};
792
+ };
793
+
794
+ webfont.FontModuleLoader.prototype.addModuleFactory = function(name, factory) {
795
+ this.modules_[name] = factory;
796
+ };
797
+
798
+ webfont.FontModuleLoader.prototype.getModules = function(configuration) {
799
+ var modules = [];
800
+
801
+ for (var key in configuration) {
802
+ if (configuration.hasOwnProperty(key)) {
803
+ var moduleFactory = this.modules_[key];
804
+
805
+ if (moduleFactory) {
806
+ modules.push(moduleFactory(configuration[key]));
807
+ }
808
+ }
809
+ }
810
+ return modules;
811
+ };
812
+
813
+ /**
814
+ * @constructor
815
+ * @param {webfont.DomHelper} domHelper
816
+ * @param {webfont.EventDispatcher} eventDispatcher
817
+ * @param {Object.<string, function(Object): number>} fontSizer
818
+ * @param {function(function(), number=)} asyncCall
819
+ * @param {function(): number} getTime
820
+ */
821
+ webfont.FontWatcher = function(domHelper, eventDispatcher, fontSizer,
822
+ asyncCall, getTime) {
823
+ this.domHelper_ = domHelper;
824
+ this.eventDispatcher_ = eventDispatcher;
825
+ this.fontSizer_ = fontSizer;
826
+ this.asyncCall_ = asyncCall;
827
+ this.getTime_ = getTime;
828
+ this.currentlyWatched_ = 0;
829
+ this.last_ = false;
830
+ this.success_ = false;
831
+ };
832
+
833
+ /**
834
+ * @type {string}
835
+ * @const
836
+ */
837
+ webfont.FontWatcher.DEFAULT_VARIATION = 'n4';
838
+
839
+ /**
840
+ * Watches a set of font families.
841
+ * @param {Array.<string>} fontFamilies The font family names to watch.
842
+ * @param {Object.<string, Array.<string>>} fontDescriptions The font variations
843
+ * of each family to watch. Described with FVD.
844
+ * @param {Object.<string, string>} fontTestStrings The font test strings for
845
+ * each family.
846
+ * @param {boolean} last True if this is the last set of families to watch.
847
+ */
848
+ webfont.FontWatcher.prototype.watch = function(fontFamilies, fontDescriptions,
849
+ fontTestStrings, fontWatchRunnerCtor, last) {
850
+ var length = fontFamilies.length;
851
+
852
+ for (var i = 0; i < length; i++) {
853
+ var fontFamily = fontFamilies[i];
854
+ if (!fontDescriptions[fontFamily]) {
855
+ fontDescriptions[fontFamily] = [webfont.FontWatcher.DEFAULT_VARIATION];
856
+ }
857
+ this.currentlyWatched_ += fontDescriptions[fontFamily].length;
858
+ }
859
+
860
+ if (last) {
861
+ this.last_ = last;
862
+ }
863
+
864
+ for (var i = 0; i < length; i++) {
865
+ var fontFamily = fontFamilies[i];
866
+ var descriptions = fontDescriptions[fontFamily];
867
+ var fontTestString = fontTestStrings[fontFamily];
868
+
869
+ for (var j = 0, len = descriptions.length; j < len; j++) {
870
+ var fontDescription = descriptions[j];
871
+
872
+ this.eventDispatcher_.dispatchFontLoading(fontFamily, fontDescription);
873
+
874
+ var activeCallback = webfont.bind(this, this.fontActive_);
875
+ var inactiveCallback = webfont.bind(this, this.fontInactive_)
876
+ var fontWatchRunner = new fontWatchRunnerCtor(activeCallback,
877
+ inactiveCallback, this.domHelper_, this.fontSizer_, this.asyncCall_,
878
+ this.getTime_, fontFamily, fontDescription, fontTestString);
879
+
880
+ fontWatchRunner.start();
881
+ }
882
+ }
883
+ };
884
+
885
+ /**
886
+ * Called by a FontWatchRunner when a font has been detected as active.
887
+ * @param {string} fontFamily
888
+ * @param {string} fontDescription
889
+ * @private
890
+ */
891
+ webfont.FontWatcher.prototype.fontActive_ = function(fontFamily, fontDescription) {
892
+ this.eventDispatcher_.dispatchFontActive(fontFamily, fontDescription);
893
+ this.success_ = true;
894
+ this.decreaseCurrentlyWatched_();
895
+ };
896
+
897
+ /**
898
+ * Called by a FontWatchRunner when a font has been detected as inactive.
899
+ * @param {string} fontFamily
900
+ * @param {string} fontDescription
901
+ * @private
902
+ */
903
+ webfont.FontWatcher.prototype.fontInactive_ = function(fontFamily, fontDescription) {
904
+ this.eventDispatcher_.dispatchFontInactive(fontFamily, fontDescription);
905
+ this.decreaseCurrentlyWatched_();
906
+ };
907
+
908
+ /**
909
+ * @private
910
+ */
911
+ webfont.FontWatcher.prototype.decreaseCurrentlyWatched_ = function() {
912
+ if (--this.currentlyWatched_ == 0 && this.last_) {
913
+ if (this.success_) {
914
+ this.eventDispatcher_.dispatchActive();
915
+ } else {
916
+ this.eventDispatcher_.dispatchInactive();
917
+ }
918
+ }
919
+ };
920
+
921
+ /**
922
+ * @constructor
923
+ * @param {function(string, string)} activeCallback
924
+ * @param {function(string, string)} inactiveCallback
925
+ * @param {webfont.DomHelper} domHelper
926
+ * @param {Object.<string, function(Object): number>} fontSizer
927
+ * @param {function(function(), number=)} asyncCall
928
+ * @param {function(): number} getTime
929
+ * @param {string} fontFamily
930
+ * @param {string} fontDescription
931
+ * @param {string=} opt_fontTestString
932
+ */
933
+ webfont.FontWatchRunner = function(activeCallback, inactiveCallback, domHelper,
934
+ fontSizer, asyncCall, getTime, fontFamily, fontDescription, opt_fontTestString) {
935
+ this.activeCallback_ = activeCallback;
936
+ this.inactiveCallback_ = inactiveCallback;
937
+ this.domHelper_ = domHelper;
938
+ this.fontSizer_ = fontSizer;
939
+ this.asyncCall_ = asyncCall;
940
+ this.getTime_ = getTime;
941
+ this.nameHelper_ = new webfont.CssFontFamilyName();
942
+ this.fvd_ = new webfont.FontVariationDescription();
943
+ this.fontFamily_ = fontFamily;
944
+ this.fontDescription_ = fontDescription;
945
+ this.fontTestString_ = opt_fontTestString || webfont.FontWatchRunner.DEFAULT_TEST_STRING;
946
+ this.originalSizeA_ = this.getDefaultFontSize_(
947
+ webfont.FontWatchRunner.DEFAULT_FONTS_A);
948
+ this.originalSizeB_ = this.getDefaultFontSize_(
949
+ webfont.FontWatchRunner.DEFAULT_FONTS_B);
950
+ this.lastObservedSizeA_ = this.originalSizeA_;
951
+ this.lastObservedSizeB_ = this.originalSizeB_;
952
+ this.requestedFontA_ = this.createHiddenElementWithFont_(
953
+ webfont.FontWatchRunner.DEFAULT_FONTS_A);
954
+ this.requestedFontB_ = this.createHiddenElementWithFont_(
955
+ webfont.FontWatchRunner.DEFAULT_FONTS_B);
956
+ };
957
+
958
+ /**
959
+ * A set of sans-serif fonts and a generic family that cover most platforms:
960
+ * Windows - arial - 99.71%
961
+ * Mac - arial - 97.67%
962
+ * Linux - 97.67%
963
+ * (Based on http://www.codestyle.org/css/font-family/sampler-CombinedResults.shtml)
964
+ * @type {string}
965
+ * @const
966
+ */
967
+ webfont.FontWatchRunner.DEFAULT_FONTS_A = "arial,'URW Gothic L',sans-serif";
968
+
969
+ /**
970
+ * A set of serif fonts and a generic family that cover most platforms. We
971
+ * want each of these fonts to have a different width when rendering the test
972
+ * string than each of the fonts in DEFAULT_FONTS_A:
973
+ * Windows - Georgia - 98.98%
974
+ * Mac - Georgia - 95.60%
975
+ * Linux - Century Schoolbook L - 97.97%
976
+ * (Based on http://www.codestyle.org/css/font-family/sampler-CombinedResults.shtml)
977
+ * @type {string}
978
+ * @const
979
+ */
980
+ webfont.FontWatchRunner.DEFAULT_FONTS_B = "Georgia,'Century Schoolbook L',serif";
981
+
982
+ /**
983
+ * Default test string. Characters are chosen so that their widths vary a lot
984
+ * between the fonts in the default stacks. We want each fallback stack
985
+ * to always start out at a different width than the other.
986
+ * @type {string}
987
+ * @const
988
+ */
989
+ webfont.FontWatchRunner.DEFAULT_TEST_STRING = 'BESbswy';
990
+
991
+ webfont.FontWatchRunner.prototype.start = function() {
992
+ this.started_ = this.getTime_();
993
+ this.check_();
994
+ };
995
+
996
+ /**
997
+ * Checks the size of the two spans against their original sizes during each
998
+ * async loop. If the size of one of the spans is different than the original
999
+ * size, then we know that the font is rendering and finish with the active
1000
+ * callback. If we wait more than 5 seconds and nothing has changed, we finish
1001
+ * with the inactive callback.
1002
+ *
1003
+ * Because of an odd Webkit quirk, we wait to observe the new width twice
1004
+ * in a row before finishing with the active callback. Sometimes, Webkit will
1005
+ * render the spans with a changed width for one iteration even though the font
1006
+ * is broken. This only happens for one async loop, so waiting for 2 consistent
1007
+ * measurements allows us to work around the quirk.
1008
+ *
1009
+ * @private
1010
+ */
1011
+ webfont.FontWatchRunner.prototype.check_ = function() {
1012
+ var sizeA = this.fontSizer_.getWidth(this.requestedFontA_);
1013
+ var sizeB = this.fontSizer_.getWidth(this.requestedFontB_);
1014
+
1015
+ if ((this.originalSizeA_ != sizeA || this.originalSizeB_ != sizeB) &&
1016
+ this.lastObservedSizeA_ == sizeA && this.lastObservedSizeB_ == sizeB) {
1017
+ this.finish_(this.activeCallback_);
1018
+ } else if (this.getTime_() - this.started_ >= 5000) {
1019
+ this.finish_(this.inactiveCallback_);
1020
+ } else {
1021
+ this.lastObservedSizeA_ = sizeA;
1022
+ this.lastObservedSizeB_ = sizeB;
1023
+ this.asyncCheck_();
1024
+ }
1025
+ };
1026
+
1027
+ /**
1028
+ * @private
1029
+ */
1030
+ webfont.FontWatchRunner.prototype.asyncCheck_ = function() {
1031
+ this.asyncCall_(function(context, func) {
1032
+ return function() {
1033
+ func.call(context);
1034
+ }
1035
+ }(this, this.check_), 25);
1036
+ };
1037
+
1038
+ /**
1039
+ * @private
1040
+ * @param {function(string, string)} callback
1041
+ */
1042
+ webfont.FontWatchRunner.prototype.finish_ = function(callback) {
1043
+ this.domHelper_.removeElement(this.requestedFontA_);
1044
+ this.domHelper_.removeElement(this.requestedFontB_);
1045
+ callback(this.fontFamily_, this.fontDescription_);
1046
+ };
1047
+
1048
+ /**
1049
+ * @private
1050
+ * @param {string} defaultFonts
1051
+ */
1052
+ webfont.FontWatchRunner.prototype.getDefaultFontSize_ = function(defaultFonts) {
1053
+ var defaultFont = this.createHiddenElementWithFont_(defaultFonts, true);
1054
+ var size = this.fontSizer_.getWidth(defaultFont);
1055
+
1056
+ this.domHelper_.removeElement(defaultFont);
1057
+ return size;
1058
+ };
1059
+
1060
+ /**
1061
+ * @private
1062
+ * @param {string} defaultFonts
1063
+ * @param {boolean=} opt_withoutFontFamily
1064
+ */
1065
+ webfont.FontWatchRunner.prototype.createHiddenElementWithFont_ = function(
1066
+ defaultFonts, opt_withoutFontFamily) {
1067
+ var styleString = this.computeStyleString_(defaultFonts,
1068
+ this.fontDescription_, opt_withoutFontFamily);
1069
+ var span = this.domHelper_.createElement('span', { 'style': styleString },
1070
+ this.fontTestString_);
1071
+
1072
+ this.domHelper_.insertInto('body', span);
1073
+ return span;
1074
+ };
1075
+
1076
+ webfont.FontWatchRunner.prototype.computeStyleString_ = function(defaultFonts,
1077
+ fontDescription, opt_withoutFontFamily) {
1078
+ var variationCss = this.fvd_.expand(fontDescription);
1079
+ var styleString = "position:absolute;top:-999px;left:-999px;" +
1080
+ "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" +
1081
+ "padding:0;font-variant:normal;font-family:"
1082
+ + (opt_withoutFontFamily ? "" :
1083
+ this.nameHelper_.quote(this.fontFamily_) + ",")
1084
+ + defaultFonts + ";" + variationCss;
1085
+ return styleString;
1086
+ };
1087
+
1088
+ /**
1089
+ * @constructor
1090
+ */
1091
+ webfont.WebFont = function(domHelper, fontModuleLoader, htmlElement, asyncCall,
1092
+ userAgent) {
1093
+ this.domHelper_ = domHelper;
1094
+ this.fontModuleLoader_ = fontModuleLoader;
1095
+ this.htmlElement_ = htmlElement;
1096
+ this.asyncCall_ = asyncCall;
1097
+ this.userAgent_ = userAgent;
1098
+ this.moduleLoading_ = 0;
1099
+ this.moduleFailedLoading_ = 0;
1100
+ };
1101
+
1102
+ webfont.WebFont.prototype.addModule = function(name, factory) {
1103
+ this.fontModuleLoader_.addModuleFactory(name, factory);
1104
+ };
1105
+
1106
+ webfont.WebFont.prototype.load = function(configuration) {
1107
+ var eventDispatcher = new webfont.EventDispatcher(
1108
+ this.domHelper_, this.htmlElement_, configuration);
1109
+
1110
+ if (this.userAgent_.isSupportingWebFont()) {
1111
+ this.load_(eventDispatcher, configuration);
1112
+ } else {
1113
+ eventDispatcher.dispatchInactive();
1114
+ }
1115
+ };
1116
+
1117
+ webfont.WebFont.prototype.isModuleSupportingUserAgent_ = function(module, eventDispatcher,
1118
+ fontWatcher, support) {
1119
+ var fontWatchRunnerCtor = module.getFontWatchRunnerCtor ?
1120
+ module.getFontWatchRunnerCtor() : webfont.FontWatchRunner;
1121
+ if (!support) {
1122
+ var allModulesLoaded = --this.moduleLoading_ == 0;
1123
+
1124
+ this.moduleFailedLoading_--;
1125
+ if (allModulesLoaded) {
1126
+ if (this.moduleFailedLoading_ == 0) {
1127
+ eventDispatcher.dispatchInactive();
1128
+ } else {
1129
+ eventDispatcher.dispatchLoading();
1130
+ }
1131
+ }
1132
+ fontWatcher.watch([], {}, {}, fontWatchRunnerCtor, allModulesLoaded);
1133
+ return;
1134
+ }
1135
+ module.load(webfont.bind(this, this.onModuleReady_, eventDispatcher,
1136
+ fontWatcher, fontWatchRunnerCtor));
1137
+ };
1138
+
1139
+ webfont.WebFont.prototype.onModuleReady_ = function(eventDispatcher, fontWatcher,
1140
+ fontWatchRunnerCtor, fontFamilies, opt_fontDescriptions, opt_fontTestStrings) {
1141
+ var allModulesLoaded = --this.moduleLoading_ == 0;
1142
+
1143
+ if (allModulesLoaded) {
1144
+ eventDispatcher.dispatchLoading();
1145
+ }
1146
+ this.asyncCall_(webfont.bind(this, function(_fontWatcher, _fontFamilies,
1147
+ _fontDescriptions, _fontTestStrings, _fontWatchRunnerCtor,
1148
+ _allModulesLoaded) {
1149
+ _fontWatcher.watch(_fontFamilies, _fontDescriptions || {},
1150
+ _fontTestStrings || {}, _fontWatchRunnerCtor, _allModulesLoaded);
1151
+ }, fontWatcher, fontFamilies, opt_fontDescriptions, opt_fontTestStrings,
1152
+ fontWatchRunnerCtor, allModulesLoaded));
1153
+ };
1154
+
1155
+ webfont.WebFont.prototype.load_ = function(eventDispatcher, configuration) {
1156
+ var modules = this.fontModuleLoader_.getModules(configuration),
1157
+ self = this;
1158
+
1159
+ this.moduleFailedLoading_ = this.moduleLoading_ = modules.length;
1160
+
1161
+ var fontWatcher = new webfont.FontWatcher(this.domHelper_,
1162
+ eventDispatcher, {
1163
+ getWidth: function(elem) {
1164
+ return elem.offsetWidth;
1165
+ }}, self.asyncCall_, function() {
1166
+ return new Date().getTime();
1167
+ });
1168
+
1169
+ for (var i = 0, len = modules.length; i < len; i++) {
1170
+ var module = modules[i];
1171
+
1172
+ module.supportUserAgent(this.userAgent_,
1173
+ webfont.bind(this, this.isModuleSupportingUserAgent_, module,
1174
+ eventDispatcher, fontWatcher));
1175
+ }
1176
+ };
1177
+
1178
+ /**
1179
+ * Handles sanitization and construction of css class names.
1180
+ * @param {string=} opt_joinChar The character to join parts of the name on.
1181
+ * Defaults to '-'.
1182
+ * @constructor
1183
+ */
1184
+ webfont.CssClassName = function(opt_joinChar) {
1185
+ /** @type {string} */
1186
+ this.joinChar_ = opt_joinChar || webfont.CssClassName.DEFAULT_JOIN_CHAR;
1187
+ };
1188
+
1189
+ /**
1190
+ * @const
1191
+ * @type {string}
1192
+ */
1193
+ webfont.CssClassName.DEFAULT_JOIN_CHAR = '-';
1194
+
1195
+ /**
1196
+ * Sanitizes a string for use as a css class name. Removes non-word and
1197
+ * underscore characters.
1198
+ * @param {string} name The string.
1199
+ * @return {string} The sanitized string.
1200
+ */
1201
+ webfont.CssClassName.prototype.sanitize = function(name) {
1202
+ return name.replace(/[\W_]+/g, '').toLowerCase();
1203
+ };
1204
+
1205
+ /**
1206
+ * Builds a complete css class name given a variable number of parts.
1207
+ * Sanitizes, then joins the parts together.
1208
+ * @param {...string} var_args The parts to join.
1209
+ * @return {string} The sanitized and joined string.
1210
+ */
1211
+ webfont.CssClassName.prototype.build = function(var_args) {
1212
+ var parts = []
1213
+ for (var i = 0; i < arguments.length; i++) {
1214
+ parts.push(this.sanitize(arguments[i]));
1215
+ }
1216
+ return parts.join(this.joinChar_);
1217
+ };
1218
+
1219
+
1220
+ /**
1221
+ * Handles quoting rules for a font family name in css.
1222
+ * @constructor
1223
+ */
1224
+ webfont.CssFontFamilyName = function() {
1225
+ /** @type {string} */
1226
+ this.quote_ = "'";
1227
+ };
1228
+
1229
+ /**
1230
+ * Quotes the name.
1231
+ * @param {string} name The name to quote.
1232
+ * @return {string} The quoted name.
1233
+ */
1234
+ webfont.CssFontFamilyName.prototype.quote = function(name) {
1235
+ var quoted = [];
1236
+ var split = name.split(/,\s*/);
1237
+ for (var i = 0; i < split.length; i++) {
1238
+ var part = split[i].replace(/['"]/g, '');
1239
+ if (part.indexOf(' ') == -1) {
1240
+ quoted.push(part);
1241
+ } else {
1242
+ quoted.push(this.quote_ + part + this.quote_);
1243
+ }
1244
+ }
1245
+ return quoted.join(',');
1246
+ };
1247
+
1248
+ /**
1249
+ * @constructor
1250
+ */
1251
+ webfont.FontVariationDescription = function() {
1252
+ this.properties_ = webfont.FontVariationDescription.PROPERTIES;
1253
+ this.values_ = webfont.FontVariationDescription.VALUES;
1254
+ };
1255
+
1256
+ /**
1257
+ * @const
1258
+ */
1259
+ webfont.FontVariationDescription.PROPERTIES = [
1260
+ 'font-style',
1261
+ 'font-weight'
1262
+ ];
1263
+
1264
+ /**
1265
+ * @const
1266
+ */
1267
+ webfont.FontVariationDescription.VALUES = {
1268
+ 'font-style': [
1269
+ ['n', 'normal'],
1270
+ ['i', 'italic'],
1271
+ ['o', 'oblique']
1272
+ ],
1273
+ 'font-weight': [
1274
+ ['1', '100'],
1275
+ ['2', '200'],
1276
+ ['3', '300'],
1277
+ ['4', '400'],
1278
+ ['5', '500'],
1279
+ ['6', '600'],
1280
+ ['7', '700'],
1281
+ ['8', '800'],
1282
+ ['9', '900'],
1283
+ ['4', 'normal'],
1284
+ ['7', 'bold']
1285
+ ]
1286
+ };
1287
+
1288
+ /**
1289
+ * @private
1290
+ * @constructor
1291
+ */
1292
+ webfont.FontVariationDescription.Item = function(index, property, values) {
1293
+ this.index_ = index;
1294
+ this.property_ = property;
1295
+ this.values_ = values;
1296
+ }
1297
+
1298
+ webfont.FontVariationDescription.Item.prototype.compact = function(output, value) {
1299
+ for (var i = 0; i < this.values_.length; i++) {
1300
+ if (value == this.values_[i][1]) {
1301
+ output[this.index_] = this.values_[i][0];
1302
+ return;
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ webfont.FontVariationDescription.Item.prototype.expand = function(output, value) {
1308
+ for (var i = 0; i < this.values_.length; i++) {
1309
+ if (value == this.values_[i][0]) {
1310
+ output[this.index_] = this.property_ + ':' + this.values_[i][1];
1311
+ return;
1312
+ }
1313
+ }
1314
+ }
1315
+
1316
+ /**
1317
+ * Compacts CSS declarations into an FVD.
1318
+ * @param {string} input A string of CSS declarations such as
1319
+ * 'font-weight:normal;font-style:italic'.
1320
+ * @return {string} The equivalent FVD such as 'n4'.
1321
+ */
1322
+ webfont.FontVariationDescription.prototype.compact = function(input) {
1323
+ var result = ['n', '4'];
1324
+ var descriptors = input.split(';');
1325
+
1326
+ for (var i = 0, len = descriptors.length; i < len; i++) {
1327
+ var pair = descriptors[i].replace(/\s+/g, '').split(':');
1328
+ if (pair.length == 2) {
1329
+ var property = pair[0];
1330
+ var value = pair[1];
1331
+ var item = this.getItem_(property);
1332
+ if (item) {
1333
+ item.compact(result, value);
1334
+ }
1335
+ }
1336
+ }
1337
+
1338
+ return result.join('');
1339
+ };
1340
+
1341
+ /**
1342
+ * Expands a FVD string into equivalent CSS declarations.
1343
+ * @param {string} fvd The FVD string, such as 'n4'.
1344
+ * @return {?string} The equivalent CSS such as
1345
+ * 'font-weight:normal;font-style:italic' or null if it cannot be parsed.
1346
+ */
1347
+ webfont.FontVariationDescription.prototype.expand = function(fvd) {
1348
+ if (fvd.length != 2) {
1349
+ return null;
1350
+ }
1351
+
1352
+ var result = [null, null];
1353
+
1354
+ for (var i = 0, len = this.properties_.length; i < len; i++) {
1355
+ var property = this.properties_[i];
1356
+ var key = fvd.substr(i, 1);
1357
+ var values = this.values_[property];
1358
+ var item = new webfont.FontVariationDescription.Item(i, property, values);
1359
+ item.expand(result, key);
1360
+ }
1361
+
1362
+ if (result[0] && result[1]) {
1363
+ return result.join(';') + ';';
1364
+ } else {
1365
+ return null;
1366
+ }
1367
+ }
1368
+
1369
+ /**
1370
+ * @private
1371
+ */
1372
+ webfont.FontVariationDescription.prototype.getItem_ = function(property) {
1373
+ for (var i = 0; i < this.properties_.length; i++) {
1374
+ if (property == this.properties_[i]) {
1375
+ var values = this.values_[property];
1376
+ return new webfont.FontVariationDescription.Item(i, property, values);
1377
+ }
1378
+ }
1379
+
1380
+ return null;
1381
+ };
1382
+
1383
+ // Name of the global object.
1384
+ var globalName = 'WebFont';
1385
+
1386
+ // Provide an instance of WebFont in the global namespace.
1387
+ window[globalName] = (function() {
1388
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
1389
+ var userAgent = userAgentParser.parse();
1390
+ var domHelper = new webfont.DomHelper(document, userAgent);
1391
+ var asyncCall = function(func, timeout) { setTimeout(func, timeout); };
1392
+
1393
+ return new webfont.WebFont(domHelper, new webfont.FontModuleLoader(),
1394
+ document.documentElement, asyncCall, userAgent);
1395
+ })();
1396
+
1397
+ // Export the public API.
1398
+ window[globalName]['load'] = window[globalName].load;
1399
+ window[globalName]['addModule'] = window[globalName].addModule;
1400
+
1401
+ // Export the UserAgent API because we pass this object to external modules.
1402
+ webfont.UserAgent.prototype['getName'] = webfont.UserAgent.prototype.getName;
1403
+ webfont.UserAgent.prototype['getVersion'] = webfont.UserAgent.prototype.getVersion;
1404
+ webfont.UserAgent.prototype['getEngine'] = webfont.UserAgent.prototype.getEngine;
1405
+ webfont.UserAgent.prototype['getEngineVersion'] = webfont.UserAgent.prototype.getEngineVersion;
1406
+ webfont.UserAgent.prototype['getPlatform'] = webfont.UserAgent.prototype.getPlatform;
1407
+ webfont.UserAgent.prototype['getPlatformVersion'] = webfont.UserAgent.prototype.getPlatformVersion;
1408
+ webfont.UserAgent.prototype['getDocumentMode'] = webfont.UserAgent.prototype.getDocumentMode;
1409
+ webfont.UserAgent.prototype['isSupportingWebFont'] = webfont.UserAgent.prototype.isSupportingWebFont;
1410
+
1411
+ /**
1412
+ *
1413
+ * WebFont.load({
1414
+ * ascender: {
1415
+ * key:'ec2de397-11ae-4c10-937f-bf94283a70c1',
1416
+ * families:['AyitaPro:regular,bold,bolditalic,italic']
1417
+ * }
1418
+ * });
1419
+ *
1420
+ * @constructor
1421
+ */
1422
+ webfont.AscenderScript = function(domHelper, configuration) {
1423
+ this.domHelper_ = domHelper;
1424
+ this.configuration_ = configuration;
1425
+ };
1426
+
1427
+ webfont.AscenderScript.NAME = 'ascender';
1428
+
1429
+ webfont.AscenderScript.VARIATIONS = {
1430
+ 'regular': 'n4',
1431
+ 'bold': 'n7',
1432
+ 'italic': 'i4',
1433
+ 'bolditalic': 'i7',
1434
+ 'r': 'n4',
1435
+ 'b': 'n7',
1436
+ 'i': 'i4',
1437
+ 'bi': 'i7'
1438
+ };
1439
+
1440
+ webfont.AscenderScript.prototype.supportUserAgent = function(userAgent, support) {
1441
+ return support(userAgent.isSupportingWebFont());
1442
+ };
1443
+
1444
+ webfont.AscenderScript.prototype.load = function(onReady) {
1445
+ var key = this.configuration_['key'];
1446
+ var protocol = (('https:' == document.location.protocol) ? 'https:' : 'http:');
1447
+ var url = protocol + '//webfonts.fontslive.com/css/' + key + '.css';
1448
+ this.domHelper_.insertInto('head', this.domHelper_.createCssLink(url));
1449
+ var fv = this.parseFamiliesAndVariations(this.configuration_['families']);
1450
+ onReady(fv.families, fv.variations);
1451
+ };
1452
+
1453
+ webfont.AscenderScript.prototype.parseFamiliesAndVariations = function(providedFamilies){
1454
+ var families, variations, fv;
1455
+ families = [];
1456
+ variations = {};
1457
+ for(var i = 0, len = providedFamilies.length; i < len; i++){
1458
+ fv = this.parseFamilyAndVariations(providedFamilies[i]);
1459
+ families.push(fv.family);
1460
+ variations[fv.family] = fv.variations;
1461
+ }
1462
+ return { families:families, variations:variations };
1463
+ };
1464
+
1465
+ webfont.AscenderScript.prototype.parseFamilyAndVariations = function(providedFamily){
1466
+ var family, variations, parts;
1467
+ parts = providedFamily.split(':');
1468
+ family = parts[0];
1469
+ variations = [];
1470
+ if(parts[1]){
1471
+ variations = this.parseVariations(parts[1]);
1472
+ }else{
1473
+ variations = ['n4'];
1474
+ }
1475
+ return { family:family, variations:variations };
1476
+ };
1477
+
1478
+ webfont.AscenderScript.prototype.parseVariations = function(source){
1479
+ var providedVariations = source.split(',');
1480
+ var variations = [];
1481
+ for(var i = 0, len = providedVariations.length; i < len; i++){
1482
+ var pv = providedVariations[i];
1483
+ if(pv){
1484
+ var v = webfont.AscenderScript.VARIATIONS[pv];
1485
+ variations.push(v ? v : pv);
1486
+ }
1487
+ }
1488
+ return variations;
1489
+ };
1490
+
1491
+ window['WebFont'].addModule(webfont.AscenderScript.NAME, function(configuration) {
1492
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
1493
+ var userAgent = userAgentParser.parse();
1494
+ var domHelper = new webfont.DomHelper(document, userAgent);
1495
+ return new webfont.AscenderScript(domHelper, configuration);
1496
+ });
1497
+
1498
+ /**
1499
+ * @constructor
1500
+ */
1501
+ webfont.LastResortWebKitFontWatchRunner = function(activeCallback,
1502
+ inactiveCallback, domHelper, fontSizer, asyncCall, getTime, fontFamily,
1503
+ fontDescription, opt_fontTestString) {
1504
+ webfont.LastResortWebKitFontWatchRunner.superCtor_.call(this,
1505
+ activeCallback, inactiveCallback, domHelper, fontSizer, asyncCall,
1506
+ getTime, fontFamily, fontDescription, opt_fontTestString);
1507
+ this.webKitLastResortFontSizes_ = this.setUpWebKitLastResortFontSizes_();
1508
+ this.webKitLastResortSizeChange_ = false;
1509
+ };
1510
+ webfont.extendsClass(webfont.FontWatchRunner, webfont.LastResortWebKitFontWatchRunner);
1511
+
1512
+ webfont.LastResortWebKitFontWatchRunner.METRICS_COMPATIBLE_FONTS = {
1513
+ "Arimo": true,
1514
+ "Cousine": true,
1515
+ "Tinos": true
1516
+ };
1517
+
1518
+ /**
1519
+ * While loading a web font webkit applies a last resort fallback font to the
1520
+ * element on which the web font is applied.
1521
+ * See file: WebKit/Source/WebCore/css/CSSFontFaceSource.cpp.
1522
+ * Looking at the different implementation for the different platforms,
1523
+ * the last resort fallback font is different. This code uses the default
1524
+ * OS/browsers values.
1525
+ */
1526
+ webfont.LastResortWebKitFontWatchRunner.prototype
1527
+ .setUpWebKitLastResortFontSizes_ = function() {
1528
+ var lastResortFonts = ["Times New Roman",
1529
+ "Lucida Sans Unicode", "Courier New", "Tahoma", "Arial",
1530
+ "Microsoft Sans Serif", "Times", "Lucida Console", "Sans", "Serif",
1531
+ "Monospace"];
1532
+ var lastResortFontSizes = lastResortFonts.length;
1533
+ var webKitLastResortFontSizes = {};
1534
+ var element = this.createHiddenElementWithFont_(lastResortFonts[0], true);
1535
+
1536
+ webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true;
1537
+ for (var i = 1; i < lastResortFontSizes; i++) {
1538
+ var font = lastResortFonts[i];
1539
+ this.domHelper_.setStyle(element, this.computeStyleString_(font,
1540
+ this.fontDescription_, true));
1541
+ webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true;
1542
+
1543
+ // Another WebKit quirk if the normal weight/style is loaded first,
1544
+ // the size of the normal weight is returned when loading another weight.
1545
+ if (this.fontDescription_[1] != '4') {
1546
+ this.domHelper_.setStyle(element, this.computeStyleString_(font,
1547
+ this.fontDescription_[0] + '4', true));
1548
+ webKitLastResortFontSizes[this.fontSizer_.getWidth(element)] = true;
1549
+ }
1550
+ }
1551
+ this.domHelper_.removeElement(element);
1552
+ return webKitLastResortFontSizes;
1553
+ };
1554
+
1555
+ webfont.LastResortWebKitFontWatchRunner.prototype.check_ = function() {
1556
+ var sizeA = this.fontSizer_.getWidth(this.requestedFontA_);
1557
+ var sizeB = this.fontSizer_.getWidth(this.requestedFontB_);
1558
+
1559
+ if (!this.webKitLastResortSizeChange_ && sizeA == sizeB &&
1560
+ this.webKitLastResortFontSizes_[sizeA]) {
1561
+ this.webKitLastResortFontSizes_ = {};
1562
+ this.webKitLastResortFontSizes_[sizeA] = true;
1563
+ this.webKitLastResortSizeChange_ = true;
1564
+ }
1565
+ if ((this.originalSizeA_ != sizeA || this.originalSizeB_ != sizeB) &&
1566
+ (!this.webKitLastResortFontSizes_[sizeA] &&
1567
+ !this.webKitLastResortFontSizes_[sizeB])) {
1568
+ this.finish_(this.activeCallback_);
1569
+ } else if (this.getTime_() - this.started_ >= 5000) {
1570
+
1571
+ // In order to handle the fact that a font could be the same size as the
1572
+ // default browser font on a webkit browser, mark the font as active
1573
+ // after 5 seconds if the latest 2 sizes are in webKitLastResortFontSizes_
1574
+ // and the font name is known to be metrics compatible.
1575
+ if (this.webKitLastResortFontSizes_[sizeA]
1576
+ && this.webKitLastResortFontSizes_[sizeB] &&
1577
+ webfont.LastResortWebKitFontWatchRunner.METRICS_COMPATIBLE_FONTS[
1578
+ this.fontFamily_]) {
1579
+ this.finish_(this.activeCallback_);
1580
+ } else {
1581
+ this.finish_(this.inactiveCallback_);
1582
+ }
1583
+ } else {
1584
+ this.asyncCheck_();
1585
+ }
1586
+ };
1587
+
1588
+ /**
1589
+ * @constructor
1590
+ */
1591
+ webfont.FontApiUrlBuilder = function(apiUrl) {
1592
+ if (apiUrl) {
1593
+ this.apiUrl_ = apiUrl;
1594
+ } else {
1595
+ var protocol = 'https:' == window.location.protocol ? 'https:' : 'http:';
1596
+
1597
+ this.apiUrl_ = protocol + webfont.FontApiUrlBuilder.DEFAULT_API_URL;
1598
+ }
1599
+ this.fontFamilies_ = [];
1600
+ this.subsets_ = [];
1601
+ };
1602
+
1603
+
1604
+ webfont.FontApiUrlBuilder.DEFAULT_API_URL = '//fonts.googleapis.com/css';
1605
+
1606
+
1607
+ webfont.FontApiUrlBuilder.prototype.setFontFamilies = function(fontFamilies) {
1608
+ this.parseFontFamilies_(fontFamilies);
1609
+ };
1610
+
1611
+
1612
+ webfont.FontApiUrlBuilder.prototype.parseFontFamilies_ =
1613
+ function(fontFamilies) {
1614
+ var length = fontFamilies.length;
1615
+
1616
+ for (var i = 0; i < length; i++) {
1617
+ var elements = fontFamilies[i].split(':');
1618
+
1619
+ if (elements.length == 3) {
1620
+ this.subsets_.push(elements.pop());
1621
+ }
1622
+ this.fontFamilies_.push(elements.join(':'));
1623
+ }
1624
+ };
1625
+
1626
+
1627
+ webfont.FontApiUrlBuilder.prototype.webSafe = function(string) {
1628
+ return string.replace(/ /g, '+');
1629
+ };
1630
+
1631
+
1632
+ webfont.FontApiUrlBuilder.prototype.build = function() {
1633
+ if (this.fontFamilies_.length == 0) {
1634
+ throw new Error('No fonts to load !');
1635
+ }
1636
+ if (this.apiUrl_.indexOf("kit=") != -1) {
1637
+ return this.apiUrl_;
1638
+ }
1639
+ var length = this.fontFamilies_.length;
1640
+ var sb = [];
1641
+
1642
+ for (var i = 0; i < length; i++) {
1643
+ sb.push(this.webSafe(this.fontFamilies_[i]));
1644
+ }
1645
+ var url = this.apiUrl_ + '?family=' + sb.join('%7C'); // '|' escaped.
1646
+
1647
+ if (this.subsets_.length > 0) {
1648
+ url += '&subset=' + this.subsets_.join(',');
1649
+ }
1650
+
1651
+ return url;
1652
+ };
1653
+
1654
+ /**
1655
+ * @constructor
1656
+ */
1657
+ webfont.FontApiParser = function(fontFamilies) {
1658
+ this.fontFamilies_ = fontFamilies;
1659
+ this.parsedFontFamilies_ = [];
1660
+ this.variations_ = {};
1661
+ this.fontTestStrings_ = {};
1662
+ this.fvd_ = new webfont.FontVariationDescription();
1663
+ };
1664
+
1665
+ webfont.FontApiParser.VARIATIONS = {
1666
+ 'ultralight': 'n2',
1667
+ 'light': 'n3',
1668
+ 'regular': 'n4',
1669
+ 'bold': 'n7',
1670
+ 'italic': 'i4',
1671
+ 'bolditalic': 'i7',
1672
+ 'ul': 'n2',
1673
+ 'l': 'n3',
1674
+ 'r': 'n4',
1675
+ 'b': 'n7',
1676
+ 'i': 'i4',
1677
+ 'bi': 'i7'
1678
+ };
1679
+
1680
+ webfont.FontApiParser.INT_FONTS = {
1681
+ 'latin': webfont.FontWatchRunner.DEFAULT_TEST_STRING,
1682
+ 'cyrillic': '&#1081;&#1103;&#1046;',
1683
+ 'greek': '&#945;&#946;&#931;',
1684
+ 'khmer': '&#x1780;&#x1781;&#x1782;',
1685
+ 'Hanuman': '&#x1780;&#x1781;&#x1782;' // For backward compatibility
1686
+ };
1687
+
1688
+ webfont.FontApiParser.prototype.parse = function() {
1689
+ var length = this.fontFamilies_.length;
1690
+
1691
+ for (var i = 0; i < length; i++) {
1692
+ var elements = this.fontFamilies_[i].split(":");
1693
+ var fontFamily = elements[0];
1694
+ var variations = ['n4'];
1695
+
1696
+ if (elements.length >= 2) {
1697
+ var fvds = this.parseVariations_(elements[1]);
1698
+
1699
+ if (fvds.length > 0) {
1700
+ variations = fvds;
1701
+ }
1702
+ if (elements.length == 3) {
1703
+ var subsets = this.parseSubsets_(elements[2]);
1704
+ if (subsets.length > 0) {
1705
+ var fontTestString = webfont.FontApiParser.INT_FONTS[subsets[0]];
1706
+
1707
+ if (fontTestString) {
1708
+ this.fontTestStrings_[fontFamily] = fontTestString;
1709
+ }
1710
+ }
1711
+ }
1712
+ }
1713
+
1714
+ // For backward compatibility
1715
+ if (!this.fontTestStrings_[fontFamily]) {
1716
+ var hanumanTestString = webfont.FontApiParser.INT_FONTS[fontFamily];
1717
+ if (hanumanTestString) {
1718
+ this.fontTestStrings_[fontFamily] = hanumanTestString;
1719
+ }
1720
+ }
1721
+ this.parsedFontFamilies_.push(fontFamily);
1722
+ this.variations_[fontFamily] = variations;
1723
+ }
1724
+ };
1725
+
1726
+ webfont.FontApiParser.prototype.generateFontVariationDescription_ = function(variation) {
1727
+ if (!variation.match(/^[\w ]+$/)) {
1728
+ return '';
1729
+ }
1730
+
1731
+ var fvd = webfont.FontApiParser.VARIATIONS[variation];
1732
+
1733
+ if (fvd) {
1734
+ return fvd;
1735
+ } else {
1736
+ var groups = variation.match(/^(\d*)(\w*)$/);
1737
+ var numericMatch = groups[1];
1738
+ var styleMatch = groups[2];
1739
+ var s = styleMatch ? styleMatch : 'n';
1740
+ var w = numericMatch ? numericMatch.substr(0, 1) : '4';
1741
+ var css = this.fvd_.expand([s, w].join(''));
1742
+ if (css) {
1743
+ return this.fvd_.compact(css);
1744
+ } else {
1745
+ return null;
1746
+ }
1747
+ }
1748
+ };
1749
+
1750
+ webfont.FontApiParser.prototype.parseVariations_ = function(variations) {
1751
+ var finalVariations = [];
1752
+
1753
+ if (!variations) {
1754
+ return finalVariations;
1755
+ }
1756
+ var providedVariations = variations.split(",");
1757
+ var length = providedVariations.length;
1758
+
1759
+ for (var i = 0; i < length; i++) {
1760
+ var variation = providedVariations[i];
1761
+ var fvd = this.generateFontVariationDescription_(variation);
1762
+
1763
+ if (fvd) {
1764
+ finalVariations.push(fvd);
1765
+ }
1766
+ }
1767
+ return finalVariations;
1768
+ };
1769
+
1770
+
1771
+ webfont.FontApiParser.prototype.parseSubsets_ = function(subsets) {
1772
+ var finalSubsets = [];
1773
+
1774
+ if (!subsets) {
1775
+ return finalSubsets;
1776
+ }
1777
+ return subsets.split(",");
1778
+ };
1779
+
1780
+
1781
+ webfont.FontApiParser.prototype.getFontFamilies = function() {
1782
+ return this.parsedFontFamilies_;
1783
+ };
1784
+
1785
+ webfont.FontApiParser.prototype.getVariations = function() {
1786
+ return this.variations_;
1787
+ };
1788
+
1789
+ webfont.FontApiParser.prototype.getFontTestStrings = function() {
1790
+ return this.fontTestStrings_;
1791
+ };
1792
+
1793
+ /**
1794
+ * @constructor
1795
+ */
1796
+ webfont.GoogleFontApi = function(userAgent, domHelper, configuration) {
1797
+ this.userAgent_ = userAgent;
1798
+ this.domHelper_ = domHelper;
1799
+ this.configuration_ = configuration;
1800
+ };
1801
+
1802
+ webfont.GoogleFontApi.NAME = 'google';
1803
+
1804
+ webfont.GoogleFontApi.prototype.supportUserAgent = function(userAgent, support) {
1805
+ support(userAgent.isSupportingWebFont());
1806
+ };
1807
+
1808
+ webfont.GoogleFontApi.prototype.getFontWatchRunnerCtor = function() {
1809
+ if (this.userAgent_.getEngine() == "AppleWebKit") {
1810
+ return webfont.LastResortWebKitFontWatchRunner;
1811
+ }
1812
+ return webfont.FontWatchRunner;
1813
+ };
1814
+
1815
+ webfont.GoogleFontApi.prototype.load = function(onReady) {
1816
+ var domHelper = this.domHelper_;
1817
+ var nonBlockingIe = this.userAgent_.getName() == 'MSIE' &&
1818
+ this.configuration_['blocking'] != true;
1819
+
1820
+ if (nonBlockingIe) {
1821
+ domHelper.whenBodyExists(webfont.bind(this, this.insertLink_, onReady));
1822
+ } else {
1823
+ this.insertLink_(onReady);
1824
+ }
1825
+ };
1826
+
1827
+ webfont.GoogleFontApi.prototype.insertLink_ = function(onReady) {
1828
+ var domHelper = this.domHelper_;
1829
+ var fontApiUrlBuilder = new webfont.FontApiUrlBuilder(
1830
+ this.configuration_['api']);
1831
+ var fontFamilies = this.configuration_['families'];
1832
+ fontApiUrlBuilder.setFontFamilies(fontFamilies);
1833
+
1834
+ var fontApiParser = new webfont.FontApiParser(fontFamilies);
1835
+ fontApiParser.parse();
1836
+
1837
+ domHelper.insertInto('head', domHelper.createCssLink(
1838
+ fontApiUrlBuilder.build()));
1839
+ onReady(fontApiParser.getFontFamilies(), fontApiParser.getVariations(),
1840
+ fontApiParser.getFontTestStrings());
1841
+ };
1842
+
1843
+ window['WebFont'].addModule(webfont.GoogleFontApi.NAME, function(configuration) {
1844
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
1845
+ var userAgent = userAgentParser.parse();
1846
+ return new webfont.GoogleFontApi(userAgent,
1847
+ new webfont.DomHelper(document, userAgent), configuration);
1848
+ });
1849
+
1850
+ /**
1851
+ *
1852
+ * WebFont.load({
1853
+ * custom: {
1854
+ * families: ['Font1', 'Font2'],
1855
+ * urls: [ 'http://moo', 'http://meuh' ] }
1856
+ * });
1857
+ *
1858
+ * @constructor
1859
+ */
1860
+ webfont.CustomCss = function(domHelper, configuration) {
1861
+ this.domHelper_ = domHelper;
1862
+ this.configuration_ = configuration;
1863
+ };
1864
+
1865
+ webfont.CustomCss.NAME = 'custom';
1866
+
1867
+ webfont.CustomCss.prototype.load = function(onReady) {
1868
+ var urls = this.configuration_['urls'] || [];
1869
+ var families = this.configuration_['families'] || [];
1870
+
1871
+ for (var i = 0, len = urls.length; i < len; i++) {
1872
+ var url = urls[i];
1873
+
1874
+ this.domHelper_.insertInto('head', this.domHelper_.createCssLink(url));
1875
+ }
1876
+ onReady(families);
1877
+ };
1878
+
1879
+ webfont.CustomCss.prototype.supportUserAgent = function(userAgent, support) {
1880
+ return support(userAgent.isSupportingWebFont());
1881
+ };
1882
+
1883
+ window['WebFont'].addModule(webfont.CustomCss.NAME, function(configuration) {
1884
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
1885
+ var userAgent = userAgentParser.parse();
1886
+ var domHelper = new webfont.DomHelper(document, userAgent);
1887
+ return new webfont.CustomCss(domHelper, configuration);
1888
+ });
1889
+
1890
+ /**
1891
+ * @constructor
1892
+ */
1893
+ webfont.FontdeckScript = function(global, domHelper, configuration) {
1894
+ this.global_ = global;
1895
+ this.domHelper_ = domHelper;
1896
+ this.configuration_ = configuration;
1897
+ this.fontFamilies_ = [];
1898
+ this.fontVariations_ = {};
1899
+ this.fvd_ = new webfont.FontVariationDescription();
1900
+ };
1901
+
1902
+ webfont.FontdeckScript.NAME = 'fontdeck';
1903
+ webfont.FontdeckScript.HOOK = '__webfontfontdeckmodule__';
1904
+ webfont.FontdeckScript.API = '//f.fontdeck.com/s/css/js/';
1905
+
1906
+ webfont.FontdeckScript.prototype.getScriptSrc = function(projectId) {
1907
+ var protocol = 'https:' == this.global_.location.protocol ? 'https:' : 'http:';
1908
+ var api = this.configuration_['api'] || webfont.FontdeckScript.API;
1909
+ return protocol + api + this.global_.document.location.hostname + '/' + projectId + '.js';
1910
+ };
1911
+
1912
+ webfont.FontdeckScript.prototype.supportUserAgent = function(userAgent, support) {
1913
+ var projectId = this.configuration_['id'];
1914
+ var self = this;
1915
+
1916
+ if (projectId) {
1917
+ // Provide data to Fontdeck for processing.
1918
+ if (!this.global_[webfont.FontdeckScript.HOOK]) {
1919
+ this.global_[webfont.FontdeckScript.HOOK] = {};
1920
+ }
1921
+
1922
+ // Fontdeck will call this function to indicate support status
1923
+ // and what fonts are provided.
1924
+ this.global_[webfont.FontdeckScript.HOOK][projectId] = function(fontdeckSupports, data) {
1925
+ for (var i = 0, j = data['fonts'].length; i<j; ++i) {
1926
+ var font = data['fonts'][i];
1927
+ // Add the FVDs
1928
+ self.fontFamilies_.push(font['name']);
1929
+ self.fontVariations_[font['name']] = [self.fvd_.compact("font-weight:" + font['weight'] + ";font-style:" + font['style'])];
1930
+ }
1931
+ support(fontdeckSupports);
1932
+ };
1933
+
1934
+ // Call the Fontdeck API.
1935
+ var script = this.domHelper_.createScriptSrc(this.getScriptSrc(projectId));
1936
+ this.domHelper_.insertInto('head', script);
1937
+
1938
+ } else {
1939
+ support(true);
1940
+ }
1941
+ };
1942
+
1943
+ webfont.FontdeckScript.prototype.load = function(onReady) {
1944
+ onReady(this.fontFamilies_, this.fontVariations_);
1945
+ };
1946
+
1947
+ window['WebFont'].addModule(webfont.FontdeckScript.NAME, function(configuration) {
1948
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
1949
+ var userAgent = userAgentParser.parse();
1950
+ var domHelper = new webfont.DomHelper(document, userAgent);
1951
+ return new webfont.FontdeckScript(window, domHelper, configuration);
1952
+ });
1953
+
1954
+ /**
1955
+ webfont.load({
1956
+ monotype: {
1957
+ projectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'//this is your Fonts.com Web fonts projectId
1958
+ }
1959
+ });
1960
+ */
1961
+
1962
+ /**
1963
+ * @constructor
1964
+ */
1965
+ webfont.MonotypeScript = function (global, userAgent, domHelper, doc, configuration) {
1966
+ this.global_ = global;
1967
+ this.userAgent_ = userAgent;
1968
+ this.domHelper_ = domHelper;
1969
+ this.doc_ = doc;
1970
+ this.configuration_ = configuration;
1971
+ this.fontFamilies_ = [];
1972
+ this.fontVariations_ = {};
1973
+ };
1974
+
1975
+ /**
1976
+ * name of the module through which external API is supposed to call the MonotypeFontAPI.
1977
+ * @const
1978
+ */
1979
+ webfont.MonotypeScript.NAME = 'monotype';
1980
+
1981
+ /**
1982
+ * __mti_fntLst is the name of function that exposes Monotype's font list.
1983
+ * @const
1984
+ */
1985
+ webfont.MonotypeScript.HOOK = '__mti_fntLst';
1986
+
1987
+ /**
1988
+ * __MonotypeAPIScript__ is the id of script added by google API. Currently 'webfonts.fonts.com' supports only one script in a page.
1989
+ * This may require change in future if 'webfonts.fonts.com' begins supporting multiple scripts per page.
1990
+ * @const
1991
+ */
1992
+ webfont.MonotypeScript.SCRIPTID = '__MonotypeAPIScript__';
1993
+
1994
+ webfont.MonotypeScript.prototype.supportUserAgent = function (userAgent, support) {
1995
+ var self = this;
1996
+ var projectId = self.configuration_['projectId'];
1997
+ if (projectId) {
1998
+ var sc = self.domHelper_.createScriptSrc(self.getScriptSrc(projectId));
1999
+ sc["id"] = webfont.MonotypeScript.SCRIPTID + projectId;
2000
+
2001
+ sc["onreadystatechange"] = function (e) {
2002
+ if (sc["readyState"] === "loaded" || sc["readyState"] === "complete") {
2003
+ sc["onreadystatechange"] = null;
2004
+ sc["onload"](e);
2005
+ }
2006
+ };
2007
+
2008
+ sc["onload"] = function (e) {
2009
+ if (self.global_[webfont.MonotypeScript.HOOK + projectId]) {
2010
+ var mti_fnts = self.global_[webfont.MonotypeScript.HOOK + projectId]();
2011
+ if (mti_fnts && mti_fnts.length) {
2012
+ var i;
2013
+ for (i = 0; i < mti_fnts.length; i++) {
2014
+ self.fontFamilies_.push(mti_fnts[i]["fontfamily"]);
2015
+ }
2016
+ }
2017
+ }
2018
+ support(userAgent.isSupportingWebFont());
2019
+ };
2020
+
2021
+ this.domHelper_.insertInto('head', sc);
2022
+ }
2023
+ else {
2024
+ support(true);
2025
+ }
2026
+ };
2027
+
2028
+ webfont.MonotypeScript.prototype.getScriptSrc = function (projectId) {
2029
+ var p = this.protocol();
2030
+ var api = (this.configuration_['api'] || 'fast.fonts.com/jsapi').replace(/^.*http(s?):(\/\/)?/, "");
2031
+ return p + "//" + api + '/' + projectId + '.js';
2032
+ };
2033
+
2034
+ webfont.MonotypeScript.prototype.load = function (onReady) {
2035
+ onReady(this.fontFamilies_, this.fontVariations_);
2036
+ };
2037
+
2038
+ webfont.MonotypeScript.prototype.protocol = function () {
2039
+ var supportedProtocols = ["http:", "https:"];
2040
+ var defaultProtocol = supportedProtocols[0];
2041
+ if (this.doc_ && this.doc_.location && this.doc_.location.protocol) {
2042
+ var i = 0;
2043
+ for (i = 0; i < supportedProtocols.length; i++) {
2044
+ if (this.doc_.location.protocol === supportedProtocols[i]) {
2045
+ return this.doc_.location.protocol;
2046
+ }
2047
+ }
2048
+ }
2049
+
2050
+ return defaultProtocol;
2051
+ };
2052
+
2053
+ window['WebFont'].addModule(webfont.MonotypeScript.NAME, function (configuration) {
2054
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
2055
+ var userAgent = userAgentParser.parse();
2056
+ var domHelper = new webfont.DomHelper(document, userAgent);
2057
+ return new webfont.MonotypeScript(window, userAgent, domHelper, document, configuration);
2058
+ });
2059
+
2060
+ /**
2061
+ * @constructor
2062
+ */
2063
+ webfont.TypekitScript = function(global, domHelper, configuration) {
2064
+ this.global_ = global;
2065
+ this.domHelper_ = domHelper;
2066
+ this.configuration_ = configuration;
2067
+ this.fontFamilies_ = [];
2068
+ this.fontVariations_ = {};
2069
+ };
2070
+
2071
+ webfont.TypekitScript.NAME = 'typekit';
2072
+ webfont.TypekitScript.HOOK = '__webfonttypekitmodule__';
2073
+
2074
+ webfont.TypekitScript.prototype.getScriptSrc = function(kitId) {
2075
+ var protocol = 'https:' == window.location.protocol ? 'https:' : 'http:';
2076
+ var api = this.configuration_['api'] || protocol + '//use.typekit.com';
2077
+ return api + '/' + kitId + '.js';
2078
+ };
2079
+
2080
+ webfont.TypekitScript.prototype.supportUserAgent = function(userAgent, support) {
2081
+ var kitId = this.configuration_['id'];
2082
+ var configuration = this.configuration_;
2083
+ var self = this;
2084
+
2085
+ if (kitId) {
2086
+ // Provide data to Typekit for processing.
2087
+ if (!this.global_[webfont.TypekitScript.HOOK]) {
2088
+ this.global_[webfont.TypekitScript.HOOK] = {};
2089
+ }
2090
+
2091
+ // Typekit will call 'init' to indicate whether it supports fonts
2092
+ // and what fonts will be provided.
2093
+ this.global_[webfont.TypekitScript.HOOK][kitId] = function(callback) {
2094
+ var init = function(typekitSupports, fontFamilies, fontVariations) {
2095
+ self.fontFamilies_ = fontFamilies;
2096
+ self.fontVariations_ = fontVariations;
2097
+ support(typekitSupports);
2098
+ };
2099
+ callback(userAgent, configuration, init);
2100
+ };
2101
+
2102
+ // Load the Typekit script.
2103
+ var script = this.domHelper_.createScriptSrc(this.getScriptSrc(kitId))
2104
+ this.domHelper_.insertInto('head', script);
2105
+
2106
+ } else {
2107
+ support(true);
2108
+ }
2109
+ };
2110
+
2111
+ webfont.TypekitScript.prototype.load = function(onReady) {
2112
+ onReady(this.fontFamilies_, this.fontVariations_);
2113
+ };
2114
+
2115
+ window['WebFont'].addModule(webfont.TypekitScript.NAME, function(configuration) {
2116
+ var userAgentParser = new webfont.UserAgentParser(navigator.userAgent, document);
2117
+ var userAgent = userAgentParser.parse();
2118
+ var domHelper = new webfont.DomHelper(document, userAgent);
2119
+ return new webfont.TypekitScript(window, domHelper, configuration);
2120
+ });
2121
+
2122
+
2123
+ if (window['WebFontConfig']) {
2124
+ window['WebFont']['load'](window['WebFontConfig']);
2125
+ }
2126
+ ;