webfontloader 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/Gemfile +9 -0
  2. data/LICENSE +201 -0
  3. data/README.md +148 -0
  4. data/Rakefile +243 -0
  5. data/bin/webfontloader-demos +28 -0
  6. data/docs/EVENTS.md +115 -0
  7. data/docs/MODULES.md +49 -0
  8. data/docs/TRANSITIONS.md +107 -0
  9. data/lib/webfontloader.rb +10 -0
  10. data/lib/webfontloader/demo/public/ascender.html +99 -0
  11. data/lib/webfontloader/demo/public/basic.css +9 -0
  12. data/lib/webfontloader/demo/public/custom.html +88 -0
  13. data/lib/webfontloader/demo/public/event-css-active-multiple.html +44 -0
  14. data/lib/webfontloader/demo/public/event-css-active.html +38 -0
  15. data/lib/webfontloader/demo/public/event-css-inactive.html +38 -0
  16. data/lib/webfontloader/demo/public/event-css-loading.html +55 -0
  17. data/lib/webfontloader/demo/public/event-js-active.html +39 -0
  18. data/lib/webfontloader/demo/public/event-js-font-active.html +40 -0
  19. data/lib/webfontloader/demo/public/event-js-loading.html +60 -0
  20. data/lib/webfontloader/demo/public/events-variations.html +130 -0
  21. data/lib/webfontloader/demo/public/events.html +103 -0
  22. data/lib/webfontloader/demo/public/google-css.html +27 -0
  23. data/lib/webfontloader/demo/public/google.html +33 -0
  24. data/lib/webfontloader/demo/public/ie-fast-js.html +47 -0
  25. data/lib/webfontloader/demo/public/ie-slow-js.html +48 -0
  26. data/lib/webfontloader/demo/public/ie-slow-link.html +38 -0
  27. data/lib/webfontloader/demo/public/index.html +70 -0
  28. data/lib/webfontloader/demo/public/typekit-variations.html +50 -0
  29. data/lib/webfontloader/demo/public/typekit.html +41 -0
  30. data/lib/webfontloader/demo/server.rb +92 -0
  31. data/lib/webfontloader/modules.rb +44 -0
  32. data/src-test/ascender/ascender_script_test.js +48 -0
  33. data/src-test/core/cssclassnametest.js +42 -0
  34. data/src-test/core/cssfontfamilynametest.js +54 -0
  35. data/src-test/core/domhelpertest.js +81 -0
  36. data/src-test/core/eventdispatchertest.js +99 -0
  37. data/src-test/core/fontmoduleloadertest.js +30 -0
  38. data/src-test/core/fonttest.js +92 -0
  39. data/src-test/core/fontvariationdescriptiontest.js +76 -0
  40. data/src-test/core/fontwatchertest.js +510 -0
  41. data/src-test/core/useragenttest.js +395 -0
  42. data/src-test/custom/customcsstest.js +30 -0
  43. data/src-test/google/fontapiparsertest.js +92 -0
  44. data/src-test/google/fontapiurlbuildertest.js +28 -0
  45. data/src-test/google/googlefontapitest.js +173 -0
  46. data/src-test/typekit/typekit_script_test.js +171 -0
  47. data/src/ascender/ascender_script.js +84 -0
  48. data/src/async_load.js +3 -0
  49. data/src/closure.js +3 -0
  50. data/src/core/cssclassname.js +21 -0
  51. data/src/core/cssfontfamilyname.js +20 -0
  52. data/src/core/domhelper.js +103 -0
  53. data/src/core/eventdispatcher.js +78 -0
  54. data/src/core/font.js +84 -0
  55. data/src/core/fontmoduleloader.js +25 -0
  56. data/src/core/fontvariationdescription.js +112 -0
  57. data/src/core/fontwatcher.js +121 -0
  58. data/src/core/initialize.js +26 -0
  59. data/src/core/namespace.js +11 -0
  60. data/src/core/useragent.js +41 -0
  61. data/src/core/useragentparser.js +234 -0
  62. data/src/custom/customcss.js +37 -0
  63. data/src/google/fontapiparser.js +94 -0
  64. data/src/google/fontapiurlbuilder.js +39 -0
  65. data/src/google/googlefontapi.js +49 -0
  66. data/src/modules.yml +27 -0
  67. data/src/typekit/typekit_script.js +58 -0
  68. data/tools/compiler/compiler.jar +0 -0
  69. data/tools/jstestdriver/JsTestDriver-1.2.1.jar +0 -0
  70. data/webfontloader.gemspec +144 -0
  71. metadata +191 -0
data/src/async_load.js ADDED
@@ -0,0 +1,3 @@
1
+ if (window['WebFontConfig']) {
2
+ window['WebFont']['load'](window['WebFontConfig']);
3
+ }
data/src/closure.js ADDED
@@ -0,0 +1,3 @@
1
+ ;(function(window,document,undefined){
2
+ {{source}}
3
+ })(this,document);
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.CssClassName = function(opt_joinChar) {
5
+ this.joinChar_ = opt_joinChar || webfont.CssClassName.DEFAULT_JOIN_CHAR;
6
+ };
7
+
8
+ webfont.CssClassName.DEFAULT_JOIN_CHAR = '-';
9
+
10
+ webfont.CssClassName.prototype.sanitize = function(name) {
11
+ return name.replace(/[\W_]+/g, '').toLowerCase();
12
+ };
13
+
14
+ webfont.CssClassName.prototype.build = function(__args__) {
15
+ var parts = []
16
+ for (var i = 0; i < arguments.length; i++) {
17
+ parts.push(this.sanitize(arguments[i]));
18
+ }
19
+ return parts.join(this.joinChar_);
20
+ };
21
+
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.CssFontFamilyName = function() {
5
+ this.quote_ = '"';
6
+ };
7
+
8
+ webfont.CssFontFamilyName.prototype.quote = function(name) {
9
+ var quoted = [];
10
+ var split = name.split(/,\s*/);
11
+ for (var i = 0; i < split.length; i++) {
12
+ var part = split[i].replace(/['"]/g, '');
13
+ if (part.indexOf(' ') == -1) {
14
+ quoted.push(part);
15
+ } else {
16
+ quoted.push(this.quote_ + part + this.quote_);
17
+ }
18
+ }
19
+ return quoted.join(',');
20
+ };
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.DomHelper = function(doc, userAgent) {
5
+ this.document_ = doc;
6
+ this.userAgent_ = userAgent;
7
+ };
8
+
9
+ webfont.DomHelper.prototype.createElement = function(elem, opt_attr,
10
+ opt_innerHtml) {
11
+ var domElement = this.document_.createElement(elem);
12
+
13
+ if (opt_attr) {
14
+ for (var attr in opt_attr) {
15
+ // protect against native prototype augmentations
16
+ if (opt_attr.hasOwnProperty(attr)) {
17
+ if (attr == "style" && this.userAgent_.getName() == "MSIE") {
18
+ domElement.style.cssText = opt_attr[attr];
19
+ } else {
20
+ domElement.setAttribute(attr, opt_attr[attr]);
21
+ }
22
+ }
23
+ }
24
+ }
25
+ if (opt_innerHtml) {
26
+ domElement.appendChild(this.document_.createTextNode(opt_innerHtml));
27
+ }
28
+ return domElement;
29
+ };
30
+
31
+ webfont.DomHelper.prototype.insertInto = function(tagName, e) {
32
+ var t = this.document_.getElementsByTagName(tagName)[0];
33
+
34
+ if (!t) { // opera allows documents without a head
35
+ t = document.documentElement;
36
+ }
37
+
38
+ if (t && t.lastChild) {
39
+ // This is safer than appendChild in IE. appendChild causes random
40
+ // JS errors in IE. Sometimes errors in other JS exectution, sometimes
41
+ // complete 'This page cannot be displayed' errors. For our purposes,
42
+ // it's equivalent because we don't need to insert at any specific
43
+ // location.
44
+ t.insertBefore(e, t.lastChild);
45
+ return true;
46
+ }
47
+ return false;
48
+ };
49
+
50
+ webfont.DomHelper.prototype.whenBodyExists = function(callback) {
51
+ var check = function() {
52
+ if (document.body) {
53
+ callback();
54
+ } else {
55
+ setTimeout(check, 0);
56
+ }
57
+ }
58
+ check();
59
+ };
60
+
61
+ webfont.DomHelper.prototype.removeElement = function(node) {
62
+ if (node.parentNode) {
63
+ node.parentNode.removeChild(node);
64
+ return true;
65
+ }
66
+ return false;
67
+ };
68
+
69
+ webfont.DomHelper.prototype.createCssLink = function(src) {
70
+ return this.createElement('link', {
71
+ 'rel': 'stylesheet',
72
+ 'href': src
73
+ });
74
+ };
75
+
76
+ webfont.DomHelper.prototype.createScriptSrc = function(src) {
77
+ return this.createElement('script', {
78
+ 'src': src
79
+ });
80
+ };
81
+
82
+ webfont.DomHelper.prototype.appendClassName = function(e, name) {
83
+ var classes = e.className.split(/\s+/);
84
+ for (var i = 0, len = classes.length; i < len; i++) {
85
+ if (classes[i] == name) {
86
+ return;
87
+ }
88
+ }
89
+ classes.push(name);
90
+ e.className = classes.join(' ').replace(/^\s+/, '');
91
+ };
92
+
93
+ webfont.DomHelper.prototype.removeClassName = function(e, name) {
94
+ var classes = e.className.split(/\s+/);
95
+ var remainingClasses = [];
96
+ for (var i = 0, len = classes.length; i < len; i++) {
97
+ if (classes[i] != name) {
98
+ remainingClasses.push(classes[i]);
99
+ }
100
+ }
101
+ e.className = remainingClasses.join(' ').replace(/^\s+/, '')
102
+ .replace(/\s+$/, '');
103
+ };
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.EventDispatcher = function(domHelper, htmlElement, callbacks,
5
+ opt_namespace) {
6
+ this.domHelper_ = domHelper;
7
+ this.htmlElement_ = htmlElement;
8
+ this.callbacks_ = callbacks;
9
+ this.namespace_ = opt_namespace || webfont.EventDispatcher.DEFAULT_NAMESPACE;
10
+ this.cssClassName_ = new webfont.CssClassName('-');
11
+ };
12
+
13
+ webfont.EventDispatcher.DEFAULT_NAMESPACE = 'wf';
14
+ webfont.EventDispatcher.LOADING = 'loading';
15
+ webfont.EventDispatcher.ACTIVE = 'active';
16
+ webfont.EventDispatcher.INACTIVE = 'inactive';
17
+ webfont.EventDispatcher.FONT = 'font';
18
+
19
+ webfont.EventDispatcher.prototype.dispatchLoading = function() {
20
+ this.domHelper_.appendClassName(this.htmlElement_,
21
+ this.cssClassName_.build(
22
+ this.namespace_, webfont.EventDispatcher.LOADING));
23
+ this.dispatch_(webfont.EventDispatcher.LOADING);
24
+ };
25
+
26
+ webfont.EventDispatcher.prototype.dispatchFontLoading = function(fontFamily, fontDescription) {
27
+ this.domHelper_.appendClassName(this.htmlElement_,
28
+ this.cssClassName_.build(
29
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
30
+ this.dispatch_(
31
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.LOADING, fontFamily, fontDescription);
32
+ };
33
+
34
+ webfont.EventDispatcher.prototype.dispatchFontActive = function(fontFamily, fontDescription) {
35
+ this.domHelper_.removeClassName(this.htmlElement_,
36
+ this.cssClassName_.build(
37
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
38
+ this.domHelper_.appendClassName(this.htmlElement_,
39
+ this.cssClassName_.build(
40
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.ACTIVE));
41
+ this.dispatch_(
42
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.ACTIVE, fontFamily, fontDescription);
43
+ };
44
+
45
+ webfont.EventDispatcher.prototype.dispatchFontInactive = function(fontFamily, fontDescription) {
46
+ this.domHelper_.removeClassName(this.htmlElement_,
47
+ this.cssClassName_.build(
48
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.LOADING));
49
+ this.domHelper_.appendClassName(this.htmlElement_,
50
+ this.cssClassName_.build(
51
+ this.namespace_, fontFamily, fontDescription, webfont.EventDispatcher.INACTIVE));
52
+ this.dispatch_(
53
+ webfont.EventDispatcher.FONT + webfont.EventDispatcher.INACTIVE, fontFamily, fontDescription);
54
+ };
55
+
56
+ webfont.EventDispatcher.prototype.dispatchInactive = function() {
57
+ this.domHelper_.appendClassName(this.htmlElement_,
58
+ this.cssClassName_.build(
59
+ this.namespace_, webfont.EventDispatcher.INACTIVE));
60
+ this.dispatch_(webfont.EventDispatcher.INACTIVE);
61
+ };
62
+
63
+ webfont.EventDispatcher.prototype.dispatchActive = function() {
64
+ // what about inactive? maybe if all fonts failed to load?
65
+ this.domHelper_.removeClassName(this.htmlElement_,
66
+ this.cssClassName_.build(
67
+ this.namespace_, webfont.EventDispatcher.LOADING));
68
+ this.domHelper_.appendClassName(this.htmlElement_,
69
+ this.cssClassName_.build(
70
+ this.namespace_, webfont.EventDispatcher.ACTIVE));
71
+ this.dispatch_(webfont.EventDispatcher.ACTIVE);
72
+ };
73
+
74
+ webfont.EventDispatcher.prototype.dispatch_ = function(event, opt_arg1, opt_arg2) {
75
+ if (this.callbacks_[event]) {
76
+ this.callbacks_[event](opt_arg1, opt_arg2);
77
+ }
78
+ };
data/src/core/font.js ADDED
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.WebFont = function(domHelper, fontModuleLoader, htmlElement, asyncCall,
5
+ userAgent) {
6
+ this.domHelper_ = domHelper;
7
+ this.fontModuleLoader_ = fontModuleLoader;
8
+ this.htmlElement_ = htmlElement;
9
+ this.asyncCall_ = asyncCall;
10
+ this.userAgent_ = userAgent;
11
+ this.moduleLoading_ = 0;
12
+ this.moduleFailedLoading_ = 0;
13
+ };
14
+
15
+ webfont.WebFont.prototype.addModule = function(name, factory) {
16
+ this.fontModuleLoader_.addModuleFactory(name, factory);
17
+ };
18
+
19
+ webfont.WebFont.prototype.load = function(configuration) {
20
+ var eventDispatcher = new webfont.EventDispatcher(
21
+ this.domHelper_, this.htmlElement_, configuration);
22
+
23
+ if (this.userAgent_.isSupportingWebFont()) {
24
+ this.load_(eventDispatcher, configuration);
25
+ } else {
26
+ eventDispatcher.dispatchInactive();
27
+ }
28
+ };
29
+
30
+ webfont.WebFont.prototype.isModuleSupportingUserAgent_ = function(module, eventDispatcher,
31
+ fontWatcher, support) {
32
+ if (!support) {
33
+ var allModulesLoaded = --this.moduleLoading_ == 0;
34
+
35
+ this.moduleFailedLoading_--;
36
+ if (allModulesLoaded) {
37
+ if (this.moduleFailedLoading_ == 0) {
38
+ eventDispatcher.dispatchInactive();
39
+ } else {
40
+ eventDispatcher.dispatchLoading();
41
+ }
42
+ }
43
+ fontWatcher.watch([], {}, allModulesLoaded);
44
+ return;
45
+ }
46
+ module.load(webfont.bind(this, this.onModuleReady_, eventDispatcher,
47
+ fontWatcher));
48
+ };
49
+
50
+ webfont.WebFont.prototype.onModuleReady_ = function(eventDispatcher, fontWatcher,
51
+ fontFamilies, opt_fontDescriptions) {
52
+ var allModulesLoaded = --this.moduleLoading_ == 0;
53
+
54
+ if (allModulesLoaded) {
55
+ eventDispatcher.dispatchLoading();
56
+ }
57
+ this.asyncCall_(webfont.bind(this, function(_fontWatcher, _fontFamilies,
58
+ _fontDescriptions, _allModulesLoaded) {
59
+ _fontWatcher.watch(_fontFamilies, _fontDescriptions || {}, _allModulesLoaded);
60
+ }, fontWatcher, fontFamilies, opt_fontDescriptions, allModulesLoaded));
61
+ };
62
+
63
+ webfont.WebFont.prototype.load_ = function(eventDispatcher, configuration) {
64
+ var modules = this.fontModuleLoader_.getModules(configuration),
65
+ self = this;
66
+
67
+ this.moduleFailedLoading_ = this.moduleLoading_ = modules.length;
68
+
69
+ var fontWatcher = new webfont.FontWatcher(this.domHelper_,
70
+ eventDispatcher, {
71
+ getWidth: function(elem) {
72
+ return elem.offsetWidth;
73
+ }}, self.asyncCall_, function() {
74
+ return new Date().getTime();
75
+ });
76
+
77
+ for (var i = 0, len = modules.length; i < len; i++) {
78
+ var module = modules[i];
79
+
80
+ module.supportUserAgent(this.userAgent_,
81
+ webfont.bind(this, this.isModuleSupportingUserAgent_, module,
82
+ eventDispatcher, fontWatcher));
83
+ }
84
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.FontModuleLoader = function() {
5
+ this.modules_ = {};
6
+ };
7
+
8
+ webfont.FontModuleLoader.prototype.addModuleFactory = function(name, factory) {
9
+ this.modules_[name] = factory;
10
+ };
11
+
12
+ webfont.FontModuleLoader.prototype.getModules = function(configuration) {
13
+ var modules = [];
14
+
15
+ for (var key in configuration) {
16
+ if (configuration.hasOwnProperty(key)) {
17
+ var moduleFactory = this.modules_[key];
18
+
19
+ if (moduleFactory) {
20
+ modules.push(moduleFactory(configuration[key]));
21
+ }
22
+ }
23
+ }
24
+ return modules;
25
+ };
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @constructor
3
+ */
4
+ webfont.FontVariationDescription = function() {
5
+ this.properties_ = webfont.FontVariationDescription.PROPERTIES;
6
+ this.values_ = webfont.FontVariationDescription.VALUES;
7
+ };
8
+
9
+ webfont.FontVariationDescription.PROPERTIES = [
10
+ 'font-style',
11
+ 'font-weight'
12
+ ];
13
+
14
+ webfont.FontVariationDescription.VALUES = {
15
+ 'font-style': [
16
+ ['n', 'normal'],
17
+ ['i', 'italic'],
18
+ ['o', 'oblique']
19
+ ],
20
+ 'font-weight': [
21
+ ['1', '100'],
22
+ ['2', '200'],
23
+ ['3', '300'],
24
+ ['4', '400'],
25
+ ['5', '500'],
26
+ ['6', '600'],
27
+ ['7', '700'],
28
+ ['8', '800'],
29
+ ['9', '900'],
30
+ ['4', 'normal'],
31
+ ['7', 'bold']
32
+ ]
33
+ };
34
+
35
+ /**
36
+ * @constructor
37
+ */
38
+ webfont.FontVariationDescription.Item = function(index, property, values) {
39
+ this.index_ = index;
40
+ this.property_ = property;
41
+ this.values_ = values;
42
+ }
43
+
44
+ webfont.FontVariationDescription.Item.prototype.compact = function(output, value) {
45
+ for (var i = 0; i < this.values_.length; i++) {
46
+ if (value == this.values_[i][1]) {
47
+ output[this.index_] = this.values_[i][0];
48
+ return;
49
+ }
50
+ }
51
+ }
52
+
53
+ webfont.FontVariationDescription.Item.prototype.expand = function(output, value) {
54
+ for (var i = 0; i < this.values_.length; i++) {
55
+ if (value == this.values_[i][0]) {
56
+ output[this.index_] = this.property_ + ':' + this.values_[i][1];
57
+ return;
58
+ }
59
+ }
60
+ }
61
+
62
+ webfont.FontVariationDescription.prototype.compact = function(input) {
63
+ var result = ['n', '4'];
64
+ var descriptors = input.split(';');
65
+
66
+ for (var i = 0, len = descriptors.length; i < len; i++) {
67
+ var pair = descriptors[i].replace(/\s+/g, '').split(':');
68
+ if (pair.length == 2) {
69
+ var property = pair[0];
70
+ var value = pair[1];
71
+ var item = this.getItem_(property);
72
+ if (item) {
73
+ item.compact(result, value);
74
+ }
75
+ }
76
+ }
77
+
78
+ return result.join('');
79
+ };
80
+
81
+ webfont.FontVariationDescription.prototype.expand = function(fvd) {
82
+ if (fvd.length != 2) {
83
+ return null;
84
+ }
85
+
86
+ var result = [null, null];
87
+
88
+ for (var i = 0, len = this.properties_.length; i < len; i++) {
89
+ var property = this.properties_[i];
90
+ var key = fvd.substr(i, 1);
91
+ var values = this.values_[property];
92
+ var item = new webfont.FontVariationDescription.Item(i, property, values);
93
+ item.expand(result, key);
94
+ }
95
+
96
+ if (result[0] && result[1]) {
97
+ return result.join(';') + ';';
98
+ } else {
99
+ return null;
100
+ }
101
+ }
102
+
103
+ webfont.FontVariationDescription.prototype.getItem_ = function(property) {
104
+ for (var i = 0; i < this.properties_.length; i++) {
105
+ if (property == this.properties_[i]) {
106
+ var values = this.values_[property];
107
+ return new webfont.FontVariationDescription.Item(i, property, values);
108
+ }
109
+ }
110
+
111
+ return null;
112
+ };