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
@@ -0,0 +1,92 @@
1
+ require 'sinatra/base'
2
+ require 'open-uri'
3
+
4
+ module WebFontLoader
5
+ module Demo
6
+ class Server < Sinatra::Base
7
+
8
+ DemoRoot = File.expand_path(File.join(File.dirname(__FILE__)))
9
+ ProjectRoot = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", ".."))
10
+
11
+ GoogleApi = "http://fonts.googleapis.com/css"
12
+ GoogleFontApi = "http://themes.googleusercontent.com/font"
13
+
14
+ set :app_file, __FILE__
15
+ set :sessions, false
16
+ set :static, true
17
+
18
+ set :modules, nil
19
+ set :compiled_js, nil
20
+
21
+ get '/' do
22
+ File.read(File.join(DemoRoot, "public", "index.html"))
23
+ end
24
+
25
+ get '/webfont.js' do
26
+ headers 'Content-Type' => "application/javascript"
27
+ headers 'Cache-Control' => 'max-age=300'
28
+ get_js_code
29
+ end
30
+
31
+ get '/fonts/api' do
32
+ url = "#{GoogleApi}?#{env['QUERY_STRING']}"
33
+ headers 'Content-Type' => 'text/css'
34
+ headers 'Cache-Control' => 'max-age=300'
35
+ response = open(url, 'User-Agent' => env['HTTP_USER_AGENT'])
36
+ source = response.read
37
+ source.gsub!(%r[http://themes.googleusercontent.com/font], '/fonts/font')
38
+ source
39
+ end
40
+
41
+ get '/fonts/font' do
42
+ sleep 1
43
+ url = "#{GoogleFontApi}?#{env['QUERY_STRING']}"
44
+ headers 'Cache-Control' => 'max-age=300'
45
+ headers 'Content-Encoding' => 'gzip'
46
+ response = open(url, 'User-Agent' => env['HTTP_USER_AGENT'])
47
+ response.read
48
+ end
49
+
50
+ get %r[/typekit/(\w+)\.js] do |kit_id|
51
+ headers 'Content-Type' => 'application/javascript'
52
+ headers 'Cache-Control' => 'max-age=300'
53
+ case kit_id
54
+ when "kitwitharialblack"
55
+ families = "['Arial Black']"
56
+ variations = "{}"
57
+ when "kitwithgeorgia"
58
+ families = "['Georgia']"
59
+ variations = "{ 'Georgia': ['i4', 'i7' ]}"
60
+ else
61
+ families = "[]"
62
+ variations = "{}"
63
+ end
64
+ <<-JS
65
+ if (window.__webfonttypekitmodule__) {
66
+ var module = window.__webfonttypekitmodule__['#{kit_id}'];
67
+ if (module) {
68
+ module(function(userAgent, configuration, init) {
69
+ // Here you may use the userAgent object to determine
70
+ // browser support.
71
+ init(true, #{families}, #{variations});
72
+ });
73
+ }
74
+ }
75
+ JS
76
+ end
77
+
78
+ protected
79
+
80
+ def get_js_code
81
+ if settings.compiled_js
82
+ settings.compiled_js
83
+ elsif settings.modules
84
+ settings.modules.all_source_files.map { |file| File.read(File.join(WebFontLoader::ProjectRoot, file)) }
85
+ else
86
+ "alert('No JavaScript has been configured in the demo server');"
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,44 @@
1
+ module WebFontLoader
2
+ class Modules
3
+
4
+ def initialize(*modules)
5
+ @project_root = WebFontLoader::ProjectRoot
6
+ @js_src = "src"
7
+ @js_test = "src-test"
8
+ @modules = modules.empty? ? config.keys : modules
9
+ # Make sure 'core' is first.
10
+ @modules.unshift "core"
11
+ @modules.uniq!
12
+ end
13
+
14
+ attr_reader :modules
15
+ attr_accessor :project_root, :js_src, :js_test
16
+
17
+ def all_source_files
18
+ @all_source_files ||= begin
19
+ modules.map { |mod| config[mod] }.compact.flatten.map { |f| File.join(js_src, f) }.push File.join(js_src, "async_load.js")
20
+ end
21
+ end
22
+
23
+ def all_test_globs
24
+ @all_test_globs ||= begin
25
+ js_test_dirs = Dir[File.join(project_root, js_test, "*")].map { |d| File.basename(d) }
26
+ js_test_dirs.map { |dir| File.join(js_test, dir, "*.js") if modules.include?(dir) }.compact
27
+ end
28
+ end
29
+
30
+ def js_output_wrapper(source)
31
+ File.read(File.join(js_src, "closure.js")).sub("{{source}}", source)
32
+ end
33
+
34
+ protected
35
+
36
+ def config
37
+ @config ||= begin
38
+ path = File.join(project_root, js_src)
39
+ YAML.load_file(File.join(path, "modules.yml"))
40
+ end
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ var AscenderScriptTest = TestCase('AscenderScriptTest');
2
+
3
+ AscenderScriptTest.prototype.testLoadAndFamilyVariations = function(){
4
+
5
+ var insert, css, element;
6
+ var key = 'ec2de397-11ae-4c10-937f-bf94283a70c1';
7
+ var onReadyTriggered = false;
8
+
9
+ var fakeDomHelper = {
10
+ insertInto: function(tag, el) {
11
+ insert = tag;
12
+ element = el;
13
+ },
14
+ createCssLink: function(cssLink) {
15
+ css = cssLink;
16
+ return '<link href="' + css + '" type="text/css" />';
17
+ }
18
+ };
19
+
20
+ var configuration = {
21
+ key:key,
22
+ families: ['AndyBold','Arial:bold,regular']
23
+ };
24
+
25
+ var fakeOnReady = function(){
26
+ onReadyTriggered = true;
27
+ };
28
+
29
+ var as = new webfont.AscenderScript(fakeDomHelper, configuration);
30
+
31
+ assertFalse(onReadyTriggered);
32
+ as.load(fakeOnReady);
33
+
34
+ assertEquals('http://webfonts.fontslive.com/css/' + key + '.css', css);
35
+ assertEquals('<link href="http://webfonts.fontslive.com/css/' + key + '.css" type="text/css" />', element);
36
+ assertEquals('head', insert);
37
+ assertTrue(onReadyTriggered);
38
+
39
+ assertEquals(['n4'], as.parseVariations('regular'));
40
+ assertEquals(['n7'], as.parseVariations('bold'));
41
+ assertEquals(['i4'], as.parseVariations('italic'));
42
+ assertEquals(['i7'], as.parseVariations('bolditalic'));
43
+ assertEquals(['n4'], as.parseVariations('regular,'));
44
+ assertEquals(['n4','n7'], as.parseVariations('regular,bold'));
45
+ assertEquals(['n4','n7'], as.parseVariations('regular,,bold'));
46
+ assertEquals(['n4','n7'], as.parseVariations('n4,n7'));
47
+
48
+ };
@@ -0,0 +1,42 @@
1
+ var CssClassNameTest = TestCase('CssClassName');
2
+
3
+ CssClassNameTest.prototype.setUp = function() {
4
+ this.sanitizer_ = new webfont.CssClassName();
5
+ };
6
+
7
+ CssClassNameTest.prototype.testSanitizeSpacesInName = function() {
8
+ var result = this.sanitizer_.sanitize(' My Family ');
9
+
10
+ assertEquals('myfamily', result);
11
+ };
12
+
13
+ CssClassNameTest.prototype.testSanitizeNumbersInName = function() {
14
+ var result = this.sanitizer_.sanitize('99 My Family 99');
15
+
16
+ assertEquals('99myfamily99', result);
17
+ };
18
+
19
+ CssClassNameTest.prototype.testSanitizeOtherChars = function() {
20
+ var result = this.sanitizer_.sanitize('_My+Family!-');
21
+
22
+ assertEquals('myfamily', result);
23
+ };
24
+
25
+ CssClassNameTest.prototype.testBuildManyParts = function() {
26
+ var result = this.sanitizer_.build('pre_', 'My Family', '_post');
27
+
28
+ assertEquals('pre-myfamily-post', result);
29
+ };
30
+
31
+ CssClassNameTest.prototype.testBuildSomeParts = function() {
32
+ var result = this.sanitizer_.build('pre!', 'My Family');
33
+
34
+ assertEquals('pre-myfamily', result);
35
+ };
36
+
37
+ CssClassNameTest.prototype.testBuildOtherJoinChar = function() {
38
+ this.sanitizer_ = new webfont.CssClassName('_');
39
+ var result = this.sanitizer_.build('pre', 'My Family');
40
+
41
+ assertEquals('pre_myfamily', result);
42
+ };
@@ -0,0 +1,54 @@
1
+ var CssFontFamilyNameTest = TestCase('CssFontFamilyName');
2
+
3
+ CssFontFamilyNameTest.prototype.setUp = function() {
4
+ this.sanitizer_ = new webfont.CssFontFamilyName();
5
+ };
6
+
7
+ CssFontFamilyNameTest.prototype.testSpaceNameWithoutQuotes = function() {
8
+ var result = this.sanitizer_.quote('My Family');
9
+
10
+ assertEquals('"My Family"', result);
11
+ };
12
+
13
+ CssFontFamilyNameTest.prototype.testSpaceNameWithDoubleQuotes = function() {
14
+ var result = this.sanitizer_.quote('"My Family"');
15
+
16
+ assertEquals('"My Family"', result);
17
+ };
18
+
19
+ CssFontFamilyNameTest.prototype.testSpaceNameWithSingleQuotes = function() {
20
+ var result = this.sanitizer_.quote('\'My Family\'');
21
+
22
+ assertEquals('"My Family"', result);
23
+ };
24
+
25
+ CssFontFamilyNameTest.prototype.testSpaceNameWithCommasAndQuotes = function() {
26
+ var result = this.sanitizer_.quote('\'family 1\',\'family 2\'');
27
+
28
+ assertEquals('\"family 1\",\"family 2\"', result);
29
+ };
30
+
31
+ CssFontFamilyNameTest.prototype.testSpaceNameWithCommaSpaceAndQuotes = function() {
32
+ var result = this.sanitizer_.quote('\'family 1\', \'family 2\'');
33
+
34
+ assertEquals('\"family 1\",\"family 2\"', result);
35
+ };
36
+
37
+ CssFontFamilyNameTest.prototype.testNoSpaceNameWithoutQuotes = function() {
38
+ var result = this.sanitizer_.quote('MyFamily');
39
+
40
+ assertEquals('MyFamily', result);
41
+ };
42
+
43
+ CssFontFamilyNameTest.prototype.testNoSpaceNameWithQuotes = function() {
44
+ var result = this.sanitizer_.quote('"MyFamily"');
45
+
46
+ assertEquals('MyFamily', result);
47
+ };
48
+
49
+ CssFontFamilyNameTest.prototype.testNoSpaceNameWithCommasAndQuotes = function() {
50
+ var result = this.sanitizer_.quote('\'family-1\', \'family-2\'');
51
+
52
+ assertEquals('family-1,family-2', result);
53
+ };
54
+
@@ -0,0 +1,81 @@
1
+ var DomHelperTest = TestCase('DomHelperTest');
2
+
3
+ DomHelperTest.prototype.setUp = function() {
4
+ this.domHelper_ = new webfont.DomHelper(document, new webfont.UserAgent("name", "version",
5
+ "engine", "engineVersion", "platform", "platformVersion", true));
6
+ };
7
+
8
+ DomHelperTest.prototype.testCreateElementNoAttr = function() {
9
+ var span = this.domHelper_.createElement('span');
10
+
11
+ assertNotNull(span);
12
+ };
13
+
14
+ DomHelperTest.prototype.testCreateElementEmptyAttrInnerHtml = function() {
15
+ var span = this.domHelper_.createElement('span', {}, 'moo');
16
+
17
+ assertNotNull(span);
18
+ assertEquals('moo', span.innerHTML);
19
+ };
20
+
21
+ DomHelperTest.prototype.testCreateElementWithAttrInnerHtml = function() {
22
+ var span = this.domHelper_.createElement('span', { style: 'font-size: 42px',
23
+ id: 'mySpan' }, 'hello');
24
+
25
+ assertNotNull(span);
26
+ assertEquals('mySpan', span.id);
27
+ assertEquals('42px', span.style.fontSize);
28
+ assertEquals('hello', span.innerHTML);
29
+ };
30
+
31
+ DomHelperTest.prototype.testCreateElementWithPrototypeAugments = function(){
32
+
33
+ Object.prototype.extrastuff = function(){ return 'I am a troublemaker.'; }
34
+
35
+ var span = this.domHelper_.createElement('span', { id : "augmented" });
36
+ var spanPar = this.domHelper_.createElement('div', { id : "augmentedpar" });
37
+ spanPar.appendChild(span);
38
+
39
+
40
+ assertNotNull(span);
41
+ assertSame(false,!!span.getAttribute('extrastuff'));
42
+ assertSame(-1,spanPar.innerHTML.indexOf('extrastuff'))
43
+
44
+
45
+ delete Object.prototype.extrastuff;
46
+ span = spanPar = undefined;
47
+ }
48
+
49
+ DomHelperTest.prototype.testCreateCssLink = function() {
50
+ var cssLink = this.domHelper_.createCssLink('http://moo/somecss.css');
51
+
52
+ assertEquals('stylesheet', cssLink.rel);
53
+ assertEquals('http://moo/somecss.css', cssLink.href);
54
+ };
55
+
56
+ DomHelperTest.prototype.testCreateScriptSrc = function() {
57
+ var cssLink = this.domHelper_.createScriptSrc('http://moo/somescript.js');
58
+
59
+ assertEquals('http://moo/somescript.js', cssLink.src);
60
+ };
61
+
62
+ DomHelperTest.prototype.testAppendAndRemoveClassNames = function() {
63
+ var div = this.domHelper_.createElement('div');
64
+
65
+ this.domHelper_.appendClassName(div, 'moo');
66
+ assertEquals('moo', div.className);
67
+ this.domHelper_.appendClassName(div, 'meuh');
68
+ assertEquals('moo meuh', div.className);
69
+ this.domHelper_.removeClassName(div, 'moo');
70
+ assertEquals('meuh', div.className);
71
+
72
+ this.domHelper_.removeClassName(div, 'meuh');
73
+ this.domHelper_.appendClassName(div, 'spaces and tabs');
74
+
75
+ this.domHelper_.removeClassName(div, 'and');
76
+ assertEquals('spaces tabs', div.className);
77
+ this.domHelper_.removeClassName(div, 'spaces');
78
+ this.domHelper_.removeClassName(div, 'tabs');
79
+ assertEquals('', div.className);
80
+
81
+ };
@@ -0,0 +1,99 @@
1
+ var EventDispatcherTest = TestCase('EventDispatcherTest');
2
+
3
+ EventDispatcherTest.prototype.setUp = function() {
4
+ this.fakeHtmlElement_ = { className: '' };
5
+ this.loadingEventCalled_ = false;
6
+ this.fontLoadingEventCalled_ = false;
7
+ this.fontLoading_ = '';
8
+ this.fontActiveEventCalled_ = false;
9
+ this.fontActive_ = '';
10
+ this.fontInactvieEventCalled_ = false;
11
+ this.fontInactive_ = '';
12
+ this.activeEventCalled_ = false;
13
+ this.inactiveEventCalled_ = false;
14
+ var namespace = 'ns';
15
+ var self = this;
16
+
17
+ this.eventDispatcher_ = new webfont.EventDispatcher(new webfont.DomHelper(
18
+ document), this.fakeHtmlElement_, {
19
+ loading: function() {
20
+ self.loadingEventCalled_ = true;
21
+ },
22
+ active: function() {
23
+ self.activeEventCalled_ = true;
24
+ },
25
+ inactive: function() {
26
+ self.inactiveEventCalled_ = true;
27
+ },
28
+ fontloading: function(fontFamily, fontDescription) {
29
+ self.fontLoadingEventCalled_ = true;
30
+ self.fontLoading_ = fontFamily + ' ' + fontDescription;
31
+ },
32
+ fontactive: function(fontFamily, fontDescription) {
33
+ self.fontActiveEventCalled_ = true;
34
+ self.fontActive_ = fontFamily + ' ' + fontDescription;
35
+ },
36
+ fontinactive: function(fontFamily, fontDescription) {
37
+ self.fontInactvieEventCalled_ = true;
38
+ self.fontInactive_ = fontFamily + ' ' + fontDescription;
39
+ }
40
+ }, namespace);
41
+ };
42
+
43
+ EventDispatcherTest.prototype.testClassNamesOnActiveLoad = function() {
44
+ this.eventDispatcher_.dispatchLoading();
45
+ assertEquals('ns-loading', this.fakeHtmlElement_.className);
46
+ this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
47
+ assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
48
+ this.eventDispatcher_.dispatchFontActive('My Family', 'n4');
49
+ assertEquals('ns-loading ns-myfamily-n4-active', this.fakeHtmlElement_.className);
50
+ this.eventDispatcher_.dispatchActive();
51
+ assertEquals('ns-myfamily-n4-active ns-active', this.fakeHtmlElement_.className);
52
+ };
53
+
54
+ EventDispatcherTest.prototype.testClassNamesOnInactiveLoad = function() {
55
+ this.eventDispatcher_.dispatchLoading();
56
+ assertEquals('ns-loading', this.fakeHtmlElement_.className);
57
+ this.eventDispatcher_.dispatchFontLoading('My Family', 'n4');
58
+ assertEquals('ns-loading ns-myfamily-n4-loading', this.fakeHtmlElement_.className);
59
+ this.eventDispatcher_.dispatchFontInactive('My Family', 'n4');
60
+ assertEquals('ns-loading ns-myfamily-n4-inactive', this.fakeHtmlElement_.className);
61
+ this.eventDispatcher_.dispatchActive();
62
+ assertEquals('ns-myfamily-n4-inactive ns-active', this.fakeHtmlElement_.className);
63
+ };
64
+
65
+ EventDispatcherTest.prototype.testEventsOnActiveLoad = function() {
66
+ this.eventDispatcher_.dispatchLoading();
67
+ assertTrue(this.loadingEventCalled_);
68
+ this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
69
+ assertTrue(this.fontLoadingEventCalled_);
70
+ assertEquals('fontFamilyLoading n4', this.fontLoading_);
71
+ this.eventDispatcher_.dispatchFontActive('fontFamilyActive', 'n4');
72
+ assertTrue(this.fontActiveEventCalled_);
73
+ assertEquals('fontFamilyActive n4', this.fontActive_);
74
+ this.eventDispatcher_.dispatchActive();
75
+ assertTrue(this.activeEventCalled_);
76
+ };
77
+
78
+ EventDispatcherTest.prototype.testEventsOnInactiveLoad = function() {
79
+ this.eventDispatcher_.dispatchLoading();
80
+ assertTrue(this.loadingEventCalled_);
81
+ this.eventDispatcher_.dispatchFontLoading('fontFamilyLoading', 'n4');
82
+ assertTrue(this.fontLoadingEventCalled_);
83
+ assertEquals('fontFamilyLoading n4', this.fontLoading_);
84
+ this.eventDispatcher_.dispatchFontInactive('fontFamilyInactive', 'n4');
85
+ assertTrue(this.fontInactvieEventCalled_);
86
+ assertEquals('fontFamilyInactive n4', this.fontInactive_);
87
+ this.eventDispatcher_.dispatchActive();
88
+ assertTrue(this.activeEventCalled_);
89
+ };
90
+
91
+ EventDispatcherTest.prototype.testClassNamesOnInactive = function() {
92
+ this.eventDispatcher_.dispatchInactive();
93
+ assertEquals('ns-inactive', this.fakeHtmlElement_.className);
94
+ };
95
+
96
+ EventDispatcherTest.prototype.testEventsOnInactive = function() {
97
+ this.eventDispatcher_.dispatchInactive();
98
+ assertTrue(this.inactiveEventCalled_);
99
+ };