govuk_template 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
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
+ ;