├── .gitignore
├── .travis.yml
├── CHANGELOG
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── bin
└── webfontloader-demos
├── bower.json
├── browsers.json
├── externs.js
├── lib
├── webfontloader.rb
└── webfontloader
│ ├── demo
│ ├── public
│ │ ├── basic.css
│ │ ├── blank.html
│ │ ├── custom-iframe.html
│ │ ├── custom.html
│ │ ├── event-css-active-multiple.html
│ │ ├── event-css-active.html
│ │ ├── event-css-inactive.html
│ │ ├── event-css-loading.html
│ │ ├── event-js-active.html
│ │ ├── event-js-font-active.html
│ │ ├── event-js-loading.html
│ │ ├── events-variations.html
│ │ ├── events.html
│ │ ├── fontdeck.html
│ │ ├── fontwatchrunner-default-fonts.html
│ │ ├── google-css.html
│ │ ├── google-iframe.html
│ │ ├── google.html
│ │ ├── ie-fast-js.html
│ │ ├── ie-slow-js.html
│ │ ├── ie-slow-link.html
│ │ ├── index.html
│ │ ├── jquery.min.js
│ │ ├── monotype-iframe.html
│ │ ├── monotype.html
│ │ ├── typekit-iframe.html
│ │ ├── typekit-variations.html
│ │ └── typekit.html
│ └── server.rb
│ └── modules.rb
├── package.json
├── spec
├── core
│ ├── cssclassname_spec.js
│ ├── domhelper_spec.js
│ ├── eventdispatcher_spec.js
│ ├── font_spec.js
│ ├── fontmoduleloader_spec.js
│ ├── fontruler_spec.js
│ ├── fontwatcher_spec.js
│ ├── fontwatchrunner_spec.js
│ ├── nativefontwatchrunner_spec.js
│ ├── size_spec.js
│ └── webfont_spec.js
├── deps.js
├── fixtures
│ ├── external_script.js
│ ├── external_stylesheet.css
│ └── fonts
│ │ ├── LICENSE.txt
│ │ ├── nullfont.css
│ │ ├── nullfont1.css
│ │ ├── nullfont2.css
│ │ ├── nullfont3.css
│ │ ├── sourcesans.eot
│ │ ├── sourcesans.otf
│ │ ├── sourcesans.svg
│ │ ├── sourcesans.ttf
│ │ ├── sourcesans.woff
│ │ ├── sourcesansa.css
│ │ ├── sourcesansb.css
│ │ ├── sourcesansc.css
│ │ ├── sourcesansd.css
│ │ ├── sourcesansdup1.css
│ │ └── sourcesansdup2.css
├── index.html
└── modules
│ ├── custom_spec.js
│ ├── fontdeck_spec.js
│ ├── google
│ ├── fontapiparser_spec.js
│ ├── fontapiurlbuilder_spec.js
│ └── googlefontapi_spec.js
│ ├── monotype_spec.js
│ └── typekit_spec.js
├── src
├── closure.js
├── core
│ ├── cssclassname.js
│ ├── domhelper.js
│ ├── eventdispatcher.js
│ ├── font.js
│ ├── fontmodule.js
│ ├── fontmoduleloader.js
│ ├── fontruler.js
│ ├── fontwatcher.js
│ ├── fontwatchrunner.js
│ ├── initialize.js
│ ├── nativefontwatchrunner.js
│ ├── stylesheetwaiter.js
│ └── webfont.js
├── modules.yml
└── modules
│ ├── custom.js
│ ├── fontdeck.js
│ ├── google
│ ├── fontapiparser.js
│ ├── fontapiurlbuilder.js
│ └── googlefontapi.js
│ ├── monotype.js
│ └── typekit.js
├── tools
├── compiler
│ ├── base.js
│ └── compiler.jar
├── jasmine-browserstack
│ └── jasmine-browserstack.js
├── jasmine-phantomjs
│ ├── jasmine-phantomjs.js
│ └── terminal-reporter.js
└── jasmine
│ ├── MIT.LICENSE
│ ├── jasmine-html.js
│ ├── jasmine.css
│ └── jasmine.js
├── webfontloader.gemspec
└── webfontloader.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .bundle
2 | *~
3 | target
4 | tmp
5 | _site
6 | pkg
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | before_install:
2 | - wget https://s3.amazonaws.com/travis-phantomjs/phantomjs-2.0.0-ubuntu-12.04.tar.bz2
3 | - tar -xjf phantomjs-2.0.0-ubuntu-12.04.tar.bz2
4 | - sudo mv /usr/local/phantomjs/bin/phantomjs /usr/local/phantomjs/bin/phantomjs1
5 | - sudo mv phantomjs /usr/local/phantomjs/bin/phantomjs
6 | language: node_js
7 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Please open [an issue](https://github.com/typekit/webfontloader/issues) if you find or suspect any problems. Sample pages and test cases are greatly appreciated.
4 |
5 | ## Development requirements
6 |
7 | You'll need a few rubygems to run the tests, demo server, and other rake tasks, which should be installed with [Bundler](http://gembundler.com/).
8 |
9 | $ gem install bundler
10 | $ bundle install
11 |
12 | To run the tests in a headless WebKit you will also need to have [PhantomJS](http://www.phantomjs.org) installed. You can install PhantomJS by downloading a binary or using HomeBrew.
13 |
14 | $ brew install phantomjs
15 |
16 | ## Building
17 |
18 | To build a JS file from source, just run rake:
19 |
20 | $ rake
21 |
22 | If you want to build a JS file with only specific modules you can specify them on the command line:
23 |
24 | $ rake compile['custom google typekit']
25 |
26 | This will compile a JS file with only the `custom`, `google` and `typekit` modules. The available modules are: `custom`, `google`, `typekit`, `ascender`, `monotype`, `fontdeck`. By default all modules are included.
27 |
28 | ## Demos
29 |
30 | A full suite of demo pages is included in this source. Here you can find some
31 | live examples using the JS and CSS events. Run the demo server with:
32 |
33 | $ rake demo
34 |
35 | You can also run the demos with uncompressed, debuggable code to aid in
36 | development. Just start the server in dev mode:
37 |
38 | $ rake demodev
39 |
40 | Browse the demos [source code](http://github.com/typekit/webfontloader/blob/master/lib/webfontloader/demo/public).
41 |
42 | ## Testing
43 |
44 | Web Font Loader has an extensive test suite that runs via Jasmine. The test suite
45 | should be passing before submitting a pull request, and new tests should be added for any new functionality.
46 |
47 | To run tests, open up `spec/index.html` in a browser and check the results. The
48 | test suite will run automatically. Again, before submitting a pull request
49 | please run the test suite in multiple browsers and list them in the pull request.
50 |
51 | To run tests in a headless WebKit using [PhantomJS](http://www.phantomjs.org) run:
52 |
53 | $ rake test
54 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'rake'
3 | require 'date'
4 |
5 | #############################################################################
6 | #
7 | # Helper functions
8 | #
9 | #############################################################################
10 |
11 | def name
12 | @name ||= Dir['*.gemspec'].first.split('.').first
13 | end
14 |
15 | def version
16 | line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17 | line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18 | end
19 |
20 | def date
21 | Date.today.to_s
22 | end
23 |
24 | def gemspec_file
25 | "#{name}.gemspec"
26 | end
27 |
28 | def gem_file
29 | "#{name}-#{version}.gem"
30 | end
31 |
32 | def replace_header(head, header_name)
33 | head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
34 | end
35 |
36 | #############################################################################
37 | #
38 | # Standard tasks
39 | #
40 | #############################################################################
41 |
42 | desc "Open an irb session preloaded with this library"
43 | task :console do
44 | sh "irb -rubygems -r ./lib/#{name}.rb"
45 | end
46 |
47 | #############################################################################
48 | #
49 | # Custom tasks (add your own tasks here)
50 | #
51 | #############################################################################
52 |
53 | require 'rake/clean'
54 |
55 | $LOAD_PATH.unshift File.dirname(__FILE__) + "/lib"
56 | require 'webfontloader'
57 |
58 | #
59 | # Setup
60 | #
61 |
62 | # Build targets (remove with `rake clean`)
63 | CLEAN.include("target")
64 | CLEAN.include("tmp")
65 |
66 | # JsCompiler
67 | JsCompilerJar = "tools/compiler/compiler.jar"
68 |
69 | # JS Source dependencies
70 | AllJs = FileList["{src,src-test}/**/*"]
71 | SourceJs = FileList["src/**/*"]
72 |
73 | # JS Source loader
74 | @modules = WebFontLoader::Modules.new
75 |
76 | #
77 | # Build
78 | #
79 |
80 | directory "target"
81 | directory "tmp"
82 |
83 | desc "Compile the JavaScript into target/webfont.js"
84 | task :compile, [:modules] => "target/webfont.js"
85 |
86 | file "webfontloader.js" => "target/webfont.js" do
87 | cp "target/webfont.js", "webfontloader.js"
88 | end
89 |
90 | file "target/webfont.js", [:modules] => SourceJs + ["target"] do |t, args|
91 | args.with_defaults(:modules => 'custom google typekit monotype fontdeck')
92 |
93 | modules = args[:modules].split ' '
94 |
95 | output_marker = "%output%"
96 | output_wrapper = @modules.js_output_wrapper(output_marker, version)
97 |
98 | args = [
99 | ["-jar", JsCompilerJar],
100 | ["--compilation_level", "ADVANCED_OPTIMIZATIONS"],
101 | ["--js_output_file", t.name],
102 | ["--output_wrapper", %("#{output_wrapper}")],
103 | ["--warning_level", "VERBOSE"],
104 | ["--summary_detail_level", "3"],
105 | ["--externs", "externs.js"],
106 | "--define goog.DEBUG=false"
107 | ]
108 |
109 | args.concat modules.map { |m| "--define INCLUDE_" + m.upcase + "_MODULE" }
110 |
111 | # Extra args to add warnings.
112 | args.concat([
113 | ["--warning_level", "VERBOSE"],
114 | ["--summary_detail_level", "1"]
115 | ])
116 |
117 | source = @modules.all_source_files
118 | args.concat source.map { |f| ["--js", f] }
119 |
120 | output = `java #{args.flatten.join(' ')} 2>&1`
121 | $?.success? ? (puts output) : (fail output)
122 | end
123 |
124 | desc "Creates debug version into target/webfont.js"
125 | task :debug, [:modules] => "target/webfont_debug.js"
126 |
127 | file "target/webfont_debug.js", [:modules] => SourceJs + ["target"] do |t, args|
128 | args.with_defaults(:modules => 'custom google typekit monotype fontdeck')
129 |
130 | modules = args[:modules].split ' '
131 |
132 | output_marker = "%output%"
133 | output_wrapper = @modules.js_output_wrapper(output_marker, version)
134 |
135 | args = [
136 | ["-jar", JsCompilerJar],
137 | ["--compilation_level", "ADVANCED_OPTIMIZATIONS"],
138 | ["--js_output_file", t.name],
139 | ["--output_wrapper", %("#{output_wrapper}")],
140 | ["--warning_level", "VERBOSE"],
141 | ["--summary_detail_level", "3"],
142 | ["--externs", "externs.js"],
143 | "--debug=true",
144 | "--formatting=PRETTY_PRINT",
145 | "--formatting=PRINT_INPUT_DELIMITER"
146 | ]
147 |
148 | args.concat modules.map { |m| "--define INCLUDE_" + m.upcase + "_MODULE" }
149 |
150 | # Extra args to add warnings.
151 | args.concat([
152 | ["--warning_level", "VERBOSE"],
153 | ["--summary_detail_level", "1"]
154 | ])
155 |
156 | source = @modules.all_source_files
157 | args.concat source.map { |f| ["--js", f] }
158 |
159 | output = `java #{args.flatten.join(' ')} 2>&1`
160 | $?.success? ? (puts output) : (fail output)
161 | end
162 |
163 | #
164 | # Run
165 | #
166 | desc "BrowserStack tests"
167 | task :bstest do |t|
168 | exec "browserstack-test -u $BROWSERSTACK_USERNAME -p $BROWSERSTACK_PASSWORD -k $BROWSERSTACK_KEY -b browsers.json -t 300 http://localhost:9999/spec/index.html"
169 | end
170 |
171 | desc "Test everything"
172 | task :default => [:clean, :gzipbytes, :test]
173 |
174 | desc "Run all tests"
175 | task :test do |t|
176 | exec "phantomjs tools/jasmine-phantomjs/jasmine-phantomjs.js spec/index.html"
177 | end
178 |
179 | desc "Start the demo server"
180 | task :demo => "target/webfont.js" do |t|
181 | js = t.prerequisites.first
182 | exec "bin/webfontloader-demos -F --compiled_js #{js}"
183 | end
184 |
185 | desc "Start the demo server for development"
186 | task :demodev do
187 | exec "bin/webfontloader-demos -F -L --modules"
188 | end
189 |
190 | desc "Find out how many bytes the source is"
191 | task :bytes => [:clean, "target/webfont.js"] do |t|
192 | js = t.prerequisites.last
193 | bytes = File.read(js).size
194 | puts "#{bytes} bytes uncompressed"
195 | end
196 |
197 | desc "Find out how many bytes the source is when gzipped"
198 | task :gzipbytes => [:clean, "target/webfont.js"] do |t|
199 | require 'zlib'
200 | js = t.prerequisites.last
201 | bytes = Zlib::Deflate.deflate(File.read(js)).size
202 | puts "#{bytes} bytes gzipped"
203 | end
204 |
205 |
206 | #############################################################################
207 | #
208 | # Packaging tasks
209 | #
210 | #############################################################################
211 |
212 | task :release => [:build] do
213 | unless `git branch` =~ /^\* master$/
214 | puts "You must be on the master branch to release!"
215 | exit!
216 | end
217 | sh "git add webfontloader.js"
218 | sh "git commit --allow-empty -a -m 'Release #{version}'"
219 | sh "npm version #{version}"
220 | sh "git push --tags origin master"
221 | sh "gem push pkg/#{name}-#{version}.gem"
222 | sh "npm publish"
223 | end
224 |
225 | task :build => :gemspec do
226 | Rake::Task["target/webfont.js"].execute
227 | Rake::Task["webfontloader.js"].execute
228 | sh "mkdir -p pkg"
229 | sh "gem build #{gemspec_file}"
230 | sh "mv #{gem_file} pkg"
231 | end
232 |
233 | task :gemspec => :validate do
234 | # read spec file and split out manifest section
235 | spec = File.read(gemspec_file)
236 | head, manifest, tail = spec.split(" # = MANIFEST =\n")
237 |
238 | # replace name version and date
239 | replace_header(head, :name)
240 | replace_header(head, :version)
241 | replace_header(head, :date)
242 |
243 | # determine file list from git ls-files
244 | files = `git ls-files`.
245 | split("\n").
246 | sort.
247 | reject { |file| file =~ /^\./ }.
248 | reject { |file| file =~ /^(rdoc|pkg)/ }.
249 | map { |file| " #{file.gsub(/\s/, '\ ')}" }.
250 | join("\n")
251 |
252 | # piece file back together and write
253 | manifest = " s.files = %w[\n#{files}\n ]\n"
254 | spec = [head, manifest, tail].join(" # = MANIFEST =\n")
255 | File.open(gemspec_file, 'w') { |io| io.write(spec) }
256 | puts "Updated #{gemspec_file}"
257 | end
258 |
259 | task :validate do
260 | libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
261 | unless libfiles.empty?
262 | puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
263 | exit!
264 | end
265 | unless Dir['VERSION*'].empty?
266 | puts "A `VERSION` file at root level violates Gem best practices."
267 | exit!
268 | end
269 | end
270 |
--------------------------------------------------------------------------------
/bin/webfontloader-demos:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'rubygems'
4 |
5 | $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
6 | require 'webfontloader'
7 |
8 | begin
9 | require 'webfontloader/demo/server'
10 | rescue LoadError => e
11 | abort "Please gem install sinatra"
12 | end
13 |
14 | begin
15 | require 'vegas'
16 | rescue LoadError => e
17 | abort "Please gem install vegas"
18 | end
19 |
20 | Vegas::Runner.new(WebFontLoader::Demo::Server, 'font-demos', :host => "localhost") do |runner, opts, app|
21 | opts.on('--compiled_js FILE', "Dynamically build the JS with the given modules") { |file|
22 | app.set :compiled_js, File.read(file)
23 | }
24 | opts.on('--modules [MODULES]', "Dynamically build the JS with the given modules") { |opt_modules|
25 | modules = opt_modules ? opt_modules.split(",") : []
26 | app.set :modules, WebFontLoader::Modules.new(*modules)
27 | }
28 | end
29 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webfontloader",
3 | "main": "webfontloader.js",
4 | "description": "Web Font Loader gives you added control when using linked fonts via @font-face.",
5 | "moduleType": ["amd", "node"],
6 | "license": "Apache-2.0",
7 | "ignore": [
8 | "**/.*",
9 | "node_modules",
10 | "spec",
11 | "tools",
12 | "lib",
13 | "bin"
14 | ],
15 | "keywords": [
16 | "web",
17 | "fonts",
18 | "webfonts",
19 | "font",
20 | "loader",
21 | "@font-face"
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/browsers.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "os_version": "XP",
4 | "os": "Windows",
5 | "browser_version": "12.16",
6 | "browser": "opera"
7 | },
8 | {
9 | "os_version": "XP",
10 | "os": "Windows",
11 | "browser_version": "3.6",
12 | "browser": "firefox"
13 | },
14 | {
15 | "os_version": "XP",
16 | "os": "Windows",
17 | "browser_version": "20.0",
18 | "browser": "firefox"
19 | },
20 | {
21 | "os_version": "XP",
22 | "os": "Windows",
23 | "browser_version": "6.0",
24 | "browser": "ie",
25 | "timeout": "300"
26 | },
27 | {
28 | "os_version": "XP",
29 | "os": "Windows",
30 | "browser_version": "7.0",
31 | "browser": "ie",
32 | "timeout": "300"
33 | },
34 | {
35 | "os_version": "XP",
36 | "os": "Windows",
37 | "browser_version": "8.0",
38 | "browser": "ie"
39 | },
40 | {
41 | "os_version": "8",
42 | "os": "Windows",
43 | "browser_version": "10.0 Desktop",
44 | "browser": "ie"
45 | },
46 | {
47 | "os_version": "7",
48 | "os": "Windows",
49 | "browser_version": "9.0",
50 | "browser": "ie"
51 | },
52 | {
53 | "os_version": "Mountain Lion",
54 | "os": "OS X",
55 | "browser_version": "6.0",
56 | "browser": "safari"
57 | },
58 | {
59 | "os_version": "Mountain Lion",
60 | "os": "OS X",
61 | "browser_version": "25.0",
62 | "browser": "chrome"
63 | },
64 | {
65 | "os_version": "Snow Leopard",
66 | "os": "OS X",
67 | "browser_version": "5.0",
68 | "browser": "safari"
69 | },
70 | {
71 | "os_version": "5.0",
72 | "device": "iPad 2 (5.0)",
73 | "os": "ios",
74 | "browser": "Mobile Safari",
75 | "timeout": "300"
76 | },
77 | {
78 | "os_version": "5.1",
79 | "device": "iPad 3rd",
80 | "os": "ios",
81 | "browser": "Mobile Safari",
82 | "timeout": "300"
83 | },
84 | {
85 | "os_version": "6.0",
86 | "device": "iPhone 5",
87 | "os": "ios",
88 | "browser": "Mobile Safari",
89 | "timeout": "300"
90 | },
91 | {
92 | "os_version": "4.3.2",
93 | "device": "iPad 2",
94 | "os": "ios",
95 | "browser": "Mobile Safari",
96 | "timeout": "300"
97 | },
98 | {
99 | "os_version": "2.3",
100 | "device": "Samsung Galaxy S II",
101 | "os": "android",
102 | "browser": "Android Browser",
103 | "timeout": "300"
104 | },
105 | {
106 | "os_version": "2.2",
107 | "device": "Samsung Galaxy S",
108 | "os": "android",
109 | "browser": "Android Browser",
110 | "timeout": "300"
111 | },
112 | {
113 | "os_version": "4.2",
114 | "device": "LG Nexus 4",
115 | "os": "android",
116 | "browser": "Android Browser",
117 | "timeout": "300"
118 | },
119 | {
120 | "os_version": "4.0",
121 | "device": "Samsung Galaxy Nexus",
122 | "os": "android",
123 | "browser": "Android Browser",
124 | "timeout": "300"
125 | },
126 | {
127 | "os_version": "4.1",
128 | "device": "Samsung Galaxy S III",
129 | "os": "android",
130 | "browser": "Android Browser",
131 | "timeout": "300"
132 | }
133 | ]
134 |
--------------------------------------------------------------------------------
/externs.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @type {function(function():*)}
3 | */
4 | var define;
5 |
6 | /**
7 | * @type {boolean?}
8 | */
9 | define.amd;
10 |
11 | /**
12 | * @type {Object}
13 | */
14 | var module;
15 |
16 | /**
17 | * @type {Object?}
18 | */
19 | module.exports;
20 |
--------------------------------------------------------------------------------
/lib/webfontloader.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 | require 'webfontloader/modules'
4 |
5 | module WebFontLoader
6 | VERSION = '1.6.28'
7 |
8 | ProjectRoot = File.expand_path(File.dirname(__FILE__) + "/..")
9 |
10 | end
11 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/basic.css:
--------------------------------------------------------------------------------
1 | body {
2 | line-height: 1;
3 | font-size: 14px;
4 | margin: 10px;
5 | }
6 | h1 {
7 | font-size: 5em;
8 | margin: 0;
9 | }
10 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/blank.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Blank page
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/custom-iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Module
5 |
6 |
12 |
13 |
14 |
27 |
28 |
29 |
30 |
31 |
32 | Hide Page |
33 | Reload Cached
34 |
35 |
36 | The goal of this page is to show how fonts load from a custom module in a
37 | child iframe.
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/custom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Custom Module
5 |
6 |
24 |
25 |
26 |
27 | Hello World. I am ChunkFive.
28 |
29 |
30 |
31 | Hide Page |
32 | Reload Cached
33 |
34 |
35 | The goal of this page is to show how fonts load from a custom module.
36 |
37 | CSS Hook Status
38 |
39 | Loading
40 | Active
41 | Inactive
42 | ChunkFive Loading
43 | ChunkFive Active
44 | ChunkFive Inactive
45 |
46 | JavaScript Event Progress
47 |
48 |
49 |
50 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-css-active-multiple.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
26 |
27 |
28 |
29 | Hello World. I am Droid Sans.
30 |
31 |
32 | Hello World. I am Tangerine.
33 |
34 |
35 |
36 | Hide Page |
37 | Reload Cached
38 |
39 |
40 | The goal of this page is to use CSS to show each part of the page when
41 | its font has loaded.
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-css-active.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
23 |
24 |
25 |
26 | Hello World. I am Droid Sans.
27 |
28 |
29 |
30 | Hide Page |
31 | Reload Cached
32 |
33 |
34 | The goal of this page is to use CSS to hide the headline until its font
35 | has completely rendered.
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-css-inactive.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
23 |
24 |
25 |
26 | Hello World. I am Droid Sans.
27 |
28 |
29 |
30 | Hide Page |
31 | Reload Cached
32 |
33 |
34 | The goal of this page is to use CSS to present a fallback font until the custom font
35 | has completely rendered.
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-css-loading.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
15 |
36 |
37 |
38 |
39 | I'm loading!
40 |
41 |
42 | Hello World. I am Droid Sans.
43 |
44 |
45 |
46 | Hide Page |
47 | Reload Cached
48 |
49 |
50 | The goal of this page is to use CSS to show a loading message while the
51 | headline's font is loading, then hide the loading message and show the
52 | headline once the font has rendered.
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-js-active.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
19 |
24 |
25 |
26 |
27 | Hello World. I am Droid Sans.
28 |
29 |
30 |
31 | Hide Page |
32 | Reload Cached
33 |
34 |
35 | The goal of this page is to use a combination of JavaScript and CSS to
36 | hide the headline until its font has completely rendered.
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-js-font-active.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
20 |
25 |
26 |
27 |
28 | Hello World.
29 |
30 |
31 |
32 | Hide Page |
33 | Reload Cached
34 |
35 |
36 | The goal of this page is to use JavaScript to manipulate the page when
37 | a particular font loads.
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/event-js-loading.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
37 |
42 |
43 |
44 |
45 | I'm loading!
46 |
47 |
48 | Hello World. I am Droid Sans.
49 |
50 |
51 |
52 | Hide Page |
53 | Reload Cached
54 |
55 |
56 | The goal of this page is to use JavaScript to manipulate the DOM while
57 | fonts are loading, and once they have all rendered.
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/events-variations.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
41 |
84 |
85 |
86 |
87 |
88 | Droid Serif Regular
89 |
90 |
91 | Droid Serif Italic
92 |
93 |
94 | Droid Serif Bold
95 |
96 |
97 | Droid Serif Bold Italic
98 |
99 |
100 |
101 |
102 | Hide Page |
103 | Reload Cached
104 |
105 |
106 | The goal of this page is to show all of the font loading event callbacks when using
107 | multiple weights and styles of one typeface.
108 |
109 | CSS Hook Status
110 |
111 | Loading
112 | Active
113 | Inactive
114 | Droid Serif Regular Loading
115 | Droid Serif Regular Active
116 | Droid Serif Regular Inactive
117 | Droid Serif Italic Loading
118 | Droid Serif Italic Active
119 | Droid Serif Italic Inactive
120 | Droid Serif Bold Loading
121 | Droid Serif Bold Active
122 | Droid Serif Bold Inactive
123 | Droid Serif Bold Italic Loading
124 | Droid Serif Bold Italic Active
125 | Droid Serif Bold Italic Inactive
126 |
127 | JavaScript Event Progress
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
41 |
71 |
72 |
73 |
74 | Hello World. I am Droid Sans.
75 |
76 |
77 | Hello World. I am Tangerine.
78 |
79 |
80 |
81 | Hide Page |
82 | Reload Cached
83 |
84 |
85 | The goal of this page is to show all of the font loading event callbacks when
86 | using multiple typefaces.
87 |
88 | CSS Hook Status
89 |
90 | Loading
91 | Active
92 | Inactive
93 | Droid Sans Loading
94 | Droid Sans Active
95 | Droid Sans Inactive
96 | Tangerine Loading
97 | Tangerine Active
98 | Tangerine Inactive
99 |
100 | JavaScript Event Progress
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/fontdeck.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
42 |
58 |
59 |
60 | Hello World. I am Fertigo Pro Regular.
61 | Hello World. I am Bodoni Display Bold Italic.
62 |
63 |
64 | Hide Page |
65 | Reload Cached
66 |
67 |
68 | The goal of this page is to show how Fontdeck fonts load.
69 |
70 |
71 | You must use "localhost" when testing Fontdeck fonts.
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/fontwatchrunner-default-fonts.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
23 |
24 |
25 | Calculating...
26 |
27 | The goal of this page is to verify that the two default font stacks in
28 | FontWatchRunner have different widths on a given platform when rendering the
29 | default test string. The pairs of headings below should render in different
30 | fonts and the results above should indicate that they all have different
31 | widths.
32 |
33 |
34 |
35 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/google-css.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
16 | Hello World. I am Droid Sans.
17 |
18 |
19 |
20 | Hide Page |
21 | Reload Cached
22 |
23 |
24 | The goal of this page is simply to use fonts directly via CSS.
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/google-iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 |
14 |
27 |
28 |
29 |
30 |
31 |
32 | Hide Page |
33 | Reload Cached
34 |
35 |
36 | The goal of this page is demonstrate fonts loading from Google via
37 | Javascript into a child iframe.
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/google.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
19 |
20 |
21 |
22 | Hello World. I am Droid Sans.
23 |
24 |
25 |
26 | Hide Page |
27 | Reload Cached
28 |
29 |
30 | The goal of this page is simply to use fonts via the JavaScript API.
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/ie-fast-js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Show me Fonts
6 |
7 |
11 |
12 |
20 |
21 |
29 |
30 |
31 |
32 | I am a serif font.
33 |
34 |
35 | I am Droid Sans.
36 |
37 |
38 |
39 | Hide Page |
40 | Reload Cached
41 |
42 |
43 | The goal of this page is to show non-blocking behavior in MSIE. This
44 | causes IE to load fonts without blocking the entire page.
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/ie-slow-js.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Show me Fonts
6 |
7 |
11 |
12 |
21 |
22 |
30 |
31 |
32 |
33 | I am a serif font.
34 |
35 |
36 | I am Droid Sans.
37 |
38 |
39 |
40 | Hide Page |
41 | Reload Cached
42 |
43 |
44 | The goal of this page is to restore blocking behavior in MSIE. This causes
45 | IE to block the entire page while loading fonts.
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/ie-slow-link.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Show me Fonts
6 |
7 |
10 |
11 |
12 |
20 |
21 |
22 |
23 | I am a serif font.
24 |
25 |
26 | I am Droid Sans.
27 |
28 |
29 |
30 | Hide Page |
31 | Reload Cached
32 |
33 |
34 | The goal of this page is to show that by default, MSIE will block the entire
35 | page while an external font loads.
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Web Font Loader Demos
7 |
8 | Demonstrations of pure CSS and JavaScript-enhanced use of @font-face.
9 |
10 |
11 | Note that many of these demonstrations use a slow proxy to
12 | increase the amount of time it takes to load a font. We do this to make it
13 | more obvious that the events system is working. It does not represent
14 | real world usage.
15 |
16 |
17 | Modules
18 |
19 | Web Font Loader provides modules to load fonts from many places.
20 |
21 |
22 | Google / CSS Link : Load fonts from Google with a link
tag. Consider this a base case for font loading.
23 | Google / Web Font Loader : Load fonts from Google with Web Font Loader.
24 | Typekit / Web Font Loader : Load fonts from Typekit with Web Font Loader.
25 | Custom / Web Font Loader : Load fonts from your own CSS with Web Font Loader.
26 | Fontdeck / Web Font Loader : Load fonts from Fontdeck with Web Font Loader.
27 | Monotype / Web Font Loader : Load fonts from fonts.com with Web Font Loader.
28 |
29 |
30 | Modules in Iframes
31 |
32 | Web Font Loader provides the ability to load fonts in child iframes using modules, instead of the main window.
33 |
34 |
35 | Google / Web Font Loader : Load fonts from Google in a child iframe with Web Font Loader.
36 | Typekit / Web Font Loader : Load fonts from Typekit in a child iframe with Web Font Loader.
37 | Custom / Web Font Loader : Load fonts from your own CSS in a child iframe with Web Font Loader.
38 | Fontdeck / Web Font Loader: Their demo fonts seem to be broken at the moment, so we don't have an iframe demo of this module.
39 | Monotype / Web Font Loader : Load fonts from fonts.com in a child iframe with Web Font Loader.
40 |
41 |
42 | Events
43 |
44 | Web Font Loader provides events to help control font rendering across browsers. Here are some sample uses.
45 |
46 |
47 | Show when rendered (CSS) : Use CSS to show part of the page only when the font has rendered. (Webkit style)
48 | Show when rendered (JS) : Use JS to show part of the page only when the font has rendered. (Webkit style)
49 | Fallback before rendered (CSS) : Use CSS to show fallback font before the font has rendered. (Mozilla style)
50 | Show loading message (CSS) : Use CSS to show a message while the font loads.
51 | Show loading message (JS) : Use JS to show a message while the font loads.
52 |
53 |
54 | More Events
55 |
56 | More complex samples using events.
57 |
58 |
59 | Multiple font loads : Use CSS to control more than one font.
60 | Multiple typefaces : The full CSS and JS event cycle when using multiple typefaces.
61 | Multiple variations : The full CSS and JS event cycle when using multiple weights and styles of one typeface.
62 |
63 |
64 | IE Behavior
65 |
66 | Web Font Loader helps workaround IE's page blocking behavior.
67 |
68 |
69 | Slow Link : Demonstrate that IE blocks the whole page when loading fonts via a LINK tag.
70 | Fast JS : By default, Web Font Loader works around the default IE loading behavior.
71 | Slow JS : Restore the default IE loading behavior.
72 |
73 |
74 | Tests
75 |
76 | Additional demo pages to test specific functionality.
77 |
78 |
79 | Typekit with Multiple Variations
80 | Default font stacks for FontWatchRunner
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/monotype-iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 |
14 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Hide Page |
33 |
34 | Reload Cached
35 |
36 |
37 |
38 |
39 | The goal of this page is to show how monotype fonts load in a child iframe.
40 |
41 |
42 |
43 | You must use "localhost" when testing monotype fonts.
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/monotype.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
14 |
15 |
16 | Hello World. I am DIN Next Bold.
17 |
18 |
19 |
20 |
21 | Hide Page |
22 | Reload Cached
23 |
24 |
25 | The goal of this page is to show how monotype fonts load. And I'm Albertus Regular
26 |
27 |
28 |
29 | You must use "localhost" when testing monotype fonts. And this is Trade Gothic Condensed
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/typekit-iframe.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
31 | Hide Page |
32 | Reload Cached
33 |
34 |
35 | The goal of this page is to show how Typekit fonts load into an iframe.
36 |
37 |
38 | You must load the fonts on "localhost" for this demo to work.
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/typekit-variations.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
28 |
29 |
30 |
31 |
32 | Georgia Italic
33 |
34 |
35 | Georgia Bold Italic
36 |
37 |
38 |
39 |
40 | Hide Page |
41 | Reload Cached
42 |
43 |
44 | The goal of this page is to show how Typekit fonts load. Note that it uses
45 | a minimal Typekit script in order to reduce dependencies. This script
46 | simply provides the system font 'Georgia' in italic and bold italic
47 | instead of loading a web font.
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/public/typekit.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
13 |
22 |
23 |
24 |
25 | Hello World. I am Futura PT.
26 |
27 |
28 |
29 | Hide Page |
30 | Reload Cached
31 |
32 |
33 | The goal of this page is to show how Typekit fonts load.
34 |
35 |
36 | You must load this page on "localhost" in order for the fonts to load.
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/lib/webfontloader/demo/server.rb:
--------------------------------------------------------------------------------
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 = "https://fonts.googleapis.com/css"
12 | GoogleFontApi = "https://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 '/webfont-fontwatchrunner.js' do
32 | headers 'Content-Type' => 'application/javascript'
33 | headers 'Cache-Control' => 'max-age=300'
34 | [
35 | 'var webfont = {};',
36 | File.read(File.join(WebFontLoader::ProjectRoot, 'src/core/fontwatchrunner.js'))
37 | ]
38 | end
39 |
40 | get '/fonts/api' do
41 | url = "#{GoogleApi}?#{env['QUERY_STRING']}"
42 | headers 'Content-Type' => 'text/css'
43 | headers 'Cache-Control' => 'max-age=300'
44 | response = open(url, 'User-Agent' => env['HTTP_USER_AGENT'])
45 | source = response.read
46 | source.gsub!(%r[https://themes.googleusercontent.com/font], '/fonts/font')
47 | source
48 | end
49 |
50 | get '/fonts/font' do
51 | sleep 1
52 | url = "#{GoogleFontApi}?#{env['QUERY_STRING']}"
53 | headers 'Cache-Control' => 'max-age=300'
54 | headers 'Content-Encoding' => 'gzip'
55 | response = open(url, 'User-Agent' => env['HTTP_USER_AGENT'])
56 | response.read
57 | end
58 |
59 | get %r[/typekit/(\w+)\.js] do |kit_id|
60 | headers 'Content-Type' => 'application/javascript'
61 | headers 'Cache-Control' => 'max-age=300'
62 | case kit_id
63 | when "kitwitharialblack"
64 | families = "['Arial Black']"
65 | variations = "{}"
66 | when "kitwithgeorgia"
67 | families = "['Georgia']"
68 | variations = "{ 'Georgia': ['i4', 'i7' ]}"
69 | else
70 | families = "[]"
71 | variations = "{}"
72 | end
73 | <<-JS
74 | if (window.__webfonttypekitmodule__) {
75 | var module = window.__webfonttypekitmodule__['#{kit_id}'];
76 | if (module) {
77 | module(function(userAgent, configuration, init) {
78 | // Here you may use the userAgent object to determine
79 | // browser support.
80 | init(true, #{families}, #{variations});
81 | });
82 | }
83 | }
84 | JS
85 | end
86 |
87 | protected
88 |
89 | def get_js_code
90 | if settings.compiled_js
91 | settings.compiled_js
92 | elsif settings.modules
93 | settings.modules.all_source_files.map { |file| File.read(File.join(WebFontLoader::ProjectRoot, file)) }
94 | else
95 | "alert('No JavaScript has been configured in the demo server');"
96 | end
97 | end
98 |
99 | end
100 | end
101 | end
--------------------------------------------------------------------------------
/lib/webfontloader/modules.rb:
--------------------------------------------------------------------------------
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) }
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, version)
31 | File.read(File.join(js_src, "closure.js")).sub("{{source}}", source).sub("{{version}}", version).gsub(/\n|\r/,"")
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
45 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webfontloader",
3 | "version": "1.6.28",
4 | "description": "Web Font Loader gives you added control when using linked fonts via @font-face.",
5 | "main": "webfontloader.js",
6 | "scripts": {
7 | "test": "phantomjs tools/jasmine-phantomjs/jasmine-phantomjs.js spec/index.html"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/typekit/webfontloader.git"
12 | },
13 | "keywords": [
14 | "web",
15 | "fonts",
16 | "webfonts",
17 | "font",
18 | "loader",
19 | "@font-face"
20 | ],
21 | "files": [
22 | "webfontloader.js",
23 | "src/**/*.js"
24 | ],
25 | "contributors": [
26 | "Ryan Carver ",
27 | "Jeremie Lenfant-engelmann ",
28 | "Sean McBride ",
29 | "Bram Stein "
30 | ],
31 | "license": "Apache-2.0",
32 | "bugs": {
33 | "url": "https://github.com/typekit/webfontloader/issues"
34 | },
35 | "homepage": "https://github.com/typekit/webfontloader",
36 | "devDependencies": {}
37 | }
38 |
--------------------------------------------------------------------------------
/spec/core/cssclassname_spec.js:
--------------------------------------------------------------------------------
1 | describe('CssClassName', function () {
2 | var CssClassName = webfont.CssClassName,
3 | sanitizer = new CssClassName();
4 |
5 | describe('#sanitize', function () {
6 | it('should sanitize spaces in names', function () {
7 | expect(sanitizer.sanitize(' My Family ')).toEqual('myfamily');
8 | });
9 |
10 | it('should sanitize numbers in names', function () {
11 | expect(sanitizer.sanitize('99 My Family 99')).toEqual('99myfamily99');;
12 | });
13 |
14 | it('should sanitize other characters', function () {
15 | expect(sanitizer.sanitize('_My+Family!-')).toEqual('myfamily');
16 | });
17 | });
18 |
19 | describe('#build', function () {
20 | it('should build many parts', function () {
21 | expect(sanitizer.build('pre_', 'My Family', '_post')).toEqual('pre-myfamily-post');
22 | });
23 |
24 | it('should build some parts', function () {
25 | expect(sanitizer.build('pre!', 'My Family')).toEqual('pre-myfamily');
26 | });
27 | });
28 |
29 | describe('#constructor', function () {
30 | it('should use a hyphen as a default separator', function () {
31 | var sanitizer = new CssClassName();
32 |
33 | expect(sanitizer.build('pre', 'post')).toEqual('pre-post');
34 | });
35 |
36 | it('should use the configured separator', function () {
37 | var sanitizer = new CssClassName('_');
38 |
39 | expect(sanitizer.build('pre', 'post')).toEqual('pre_post');
40 | });
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/spec/core/eventdispatcher_spec.js:
--------------------------------------------------------------------------------
1 | describe('EventDispatcher', function () {
2 | var EventDispatcher = webfont.EventDispatcher,
3 | DomHelper = webfont.DomHelper,
4 | Font = webfont.Font,
5 | domHelper = new DomHelper(window),
6 | element = null
7 | eventDispatcher = null,
8 | font = null;
9 |
10 | beforeEach(function () {
11 | element = domHelper.getLoadWindow().document.documentElement;
12 | config = {
13 | loading: jasmine.createSpy('loading'),
14 | active: jasmine.createSpy('active'),
15 | inactive: jasmine.createSpy('inactive'),
16 | fontloading: jasmine.createSpy('fontloading'),
17 | fontactive: jasmine.createSpy('fontactive'),
18 | fontinactive: jasmine.createSpy('fontinactive'),
19 | classes: true,
20 | events: true
21 | };
22 |
23 | element.className = '';
24 |
25 | eventDispatcher = new EventDispatcher(domHelper, config);
26 |
27 | font = new Font('My Family', 'n4');
28 | });
29 |
30 | describe('#dispatchLoading', function () {
31 | beforeEach(function () {
32 | eventDispatcher.dispatchLoading();
33 | });
34 |
35 | it('should call the correct callback', function () {
36 | expect(config.loading).toHaveBeenCalled();
37 | });
38 |
39 | it('should set the correct class name', function () {
40 | expect(element.className).toEqual('wf-loading');
41 | });
42 | });
43 |
44 | describe('#dispatchFontLoading', function () {
45 | beforeEach(function () {
46 | eventDispatcher.dispatchFontLoading(font);
47 | });
48 |
49 | it('should call the correct callback', function () {
50 | expect(config.fontloading).toHaveBeenCalledWith('My Family', 'n4');
51 | });
52 |
53 | it('should set the correct class name', function () {
54 | expect(element.className).toEqual('wf-myfamily-n4-loading');
55 | });
56 | });
57 |
58 | describe('#dispatchFontInactive', function () {
59 | beforeEach(function () {
60 | eventDispatcher.dispatchFontInactive(font);
61 | });
62 |
63 | it('should call the correct callback', function () {
64 | expect(config.fontinactive).toHaveBeenCalledWith('My Family', 'n4');
65 | });
66 |
67 | it('should set the correct class name', function () {
68 | expect(element.className).toEqual('wf-myfamily-n4-inactive');
69 | });
70 | });
71 |
72 | describe('#dispatchFontInactive - with loading class', function () {
73 | beforeEach(function () {
74 | eventDispatcher.dispatchFontLoading(font);
75 | eventDispatcher.dispatchFontInactive(font);
76 | });
77 |
78 | it('should set the correct class name', function () {
79 | expect(element.className).toEqual('wf-myfamily-n4-inactive');
80 | });
81 | });
82 |
83 | describe('#dispatchFontInactive - with active class', function () {
84 | beforeEach(function () {
85 | eventDispatcher.dispatchFontActive(font);
86 | eventDispatcher.dispatchFontInactive(font);
87 | });
88 |
89 | it('should not append the inactive class name', function () {
90 | expect(element.className).toEqual('wf-myfamily-n4-active');
91 | });
92 |
93 | it('should still call the correct callback', function () {
94 | expect(config.fontinactive).toHaveBeenCalledWith('My Family', 'n4');
95 | });
96 | });
97 |
98 | describe('#dispatchFontActive', function () {
99 | beforeEach(function () {
100 | eventDispatcher.dispatchFontActive(font);
101 | });
102 |
103 | it('should call the correct callback', function () {
104 | expect(config.fontactive).toHaveBeenCalledWith('My Family', 'n4');
105 | });
106 |
107 | it('should set the correct class name', function () {
108 | expect(element.className).toEqual('wf-myfamily-n4-active');
109 | });
110 | });
111 |
112 | describe('#dispatchFontActive - with loading class', function () {
113 | beforeEach(function () {
114 | eventDispatcher.dispatchFontLoading(font);
115 | eventDispatcher.dispatchFontActive(font);
116 | });
117 |
118 | it('should set the correct class name', function () {
119 | expect(element.className).toEqual('wf-myfamily-n4-active');
120 | });
121 | });
122 |
123 | describe('#dispatchFontActive - with inactive class', function () {
124 | beforeEach(function () {
125 | eventDispatcher.dispatchFontInactive(font);
126 | eventDispatcher.dispatchFontActive(font);
127 | });
128 |
129 | it('should set the correct class', function () {
130 | expect(element.className).toEqual('wf-myfamily-n4-active');
131 | });
132 | });
133 |
134 | describe('#dispatchInactive', function () {
135 | beforeEach(function () {
136 | eventDispatcher.dispatchInactive();
137 | });
138 |
139 | it('should call the correct callback', function () {
140 | expect(config.inactive).toHaveBeenCalled();
141 | });
142 |
143 | it('should set the correct class name', function () {
144 | expect(element.className).toEqual('wf-inactive');
145 | });
146 | });
147 |
148 | describe('#dispatchInactive - with loading class', function () {
149 | beforeEach(function () {
150 | eventDispatcher.dispatchLoading();
151 | eventDispatcher.dispatchInactive();
152 | });
153 |
154 | it('should set the correct class name', function () {
155 | expect(element.className).toEqual('wf-inactive');
156 | });
157 | });
158 |
159 | describe('#dispatchInactive - with active class', function () {
160 | beforeEach(function () {
161 | eventDispatcher.dispatchActive();
162 | eventDispatcher.dispatchInactive();
163 | });
164 |
165 | it('should not set the the inactive class', function () {
166 | expect(element.className).toEqual('wf-active');
167 | });
168 |
169 | it('should still call the inactive callback', function () {
170 | expect(config.inactive).toHaveBeenCalled();
171 | });
172 | });
173 |
174 | describe('#dispatchActive', function () {
175 | beforeEach(function () {
176 | eventDispatcher.dispatchActive();
177 | });
178 |
179 | it('should call the correct callback', function () {
180 | expect(config.active).toHaveBeenCalled();
181 | });
182 |
183 | it('should set the correct class name', function () {
184 | expect(element.className).toEqual('wf-active');
185 | });
186 | });
187 |
188 | describe('#dispatchActive - with loading class', function () {
189 | beforeEach(function () {
190 | eventDispatcher.dispatchLoading();
191 | eventDispatcher.dispatchActive();
192 | });
193 |
194 | it('should set the correct class name', function () {
195 | expect(element.className).toEqual('wf-active');
196 | });
197 | });
198 |
199 | describe('#dispatchActive - with inactive class', function () {
200 | beforeEach(function () {
201 | eventDispatcher.dispatchInactive();
202 | eventDispatcher.dispatchActive();
203 | });
204 |
205 | it('should set the correct class name', function () {
206 | expect(element.className).toEqual('wf-active');
207 | });
208 | });
209 |
210 | describe('disable classes and events', function () {
211 | beforeEach(function () {
212 | config.classes = false;
213 | config.events = false;
214 | eventDispatcher = new EventDispatcher(domHelper, config);
215 | eventDispatcher.dispatchInactive();
216 | eventDispatcher.dispatchActive();
217 | eventDispatcher.dispatchLoading();
218 | eventDispatcher.dispatchFontInactive(font);
219 | eventDispatcher.dispatchFontActive(font);
220 | eventDispatcher.dispatchFontLoading(font);
221 | });
222 |
223 | afterEach(function () {
224 | config.classes = true;
225 | config.events = true;
226 | });
227 |
228 | it('should not fire any events', function () {
229 | expect(config.inactive).not.toHaveBeenCalled();
230 | expect(config.active).not.toHaveBeenCalled();
231 | expect(config.loading).not.toHaveBeenCalled();
232 | expect(config.fontinactive).not.toHaveBeenCalled();
233 | expect(config.fontactive).not.toHaveBeenCalled();
234 | expect(config.fontloading).not.toHaveBeenCalled();
235 | });
236 | });
237 |
238 | describe('disable classes', function () {
239 | beforeEach(function () {
240 | config.classes = false;
241 | eventDispatcher = new EventDispatcher(domHelper, config);
242 | eventDispatcher.dispatchInactive();
243 | eventDispatcher.dispatchActive();
244 | eventDispatcher.dispatchLoading();
245 | eventDispatcher.dispatchFontInactive(font);
246 | eventDispatcher.dispatchFontActive(font);
247 | eventDispatcher.dispatchFontLoading(font);
248 | });
249 |
250 | afterEach(function () {
251 | config.classes = true;
252 | });
253 |
254 | it('should not fire any events', function () {
255 | expect(element.className).toEqual('');
256 | });
257 | });
258 | });
259 |
--------------------------------------------------------------------------------
/spec/core/font_spec.js:
--------------------------------------------------------------------------------
1 | describe('Font', function () {
2 | var Font = webfont.Font;
3 |
4 | describe('#quote', function () {
5 | var quote = function (font) {
6 | return new Font(font).getCssName();
7 | };
8 |
9 | it('should quote names with spaces', function () {
10 | expect(quote('My Family')).toEqual("'My Family'");
11 | });
12 |
13 | it('should quote names with spaces and double quotes', function () {
14 | expect(quote('"My Family"')).toEqual("'My Family'");
15 | });
16 |
17 | it('should quote names with spaces and single quotes', function () {
18 | expect(quote("'My Family'")).toEqual("'My Family'");
19 | });
20 |
21 | it('should quote multiple single quoted names separated with a comma', function () {
22 | expect(quote("'family 1','family 2'")).toEqual("'family 1','family 2'");
23 | });
24 |
25 | it('should quote multiple single quoted names separated with a comma and space', function () {
26 | expect(quote("'family 1', 'family 2'")).toEqual("'family 1','family 2'");
27 | });
28 |
29 | it('should quote family names starting with a number', function () {
30 | expect(quote('5test')).toEqual("'5test'");
31 | });
32 |
33 | it('should not quote when there is no space', function () {
34 | expect(quote('MyFamily')).toEqual('MyFamily');
35 | });
36 |
37 | it('should remove quotes when they are unnecesssary', function () {
38 | expect(quote('"MyFamily"')).toEqual('MyFamily');
39 | });
40 |
41 | it('should not quote multiple names when there is no space', function () {
42 | expect(quote("'family-1', 'family-2'")).toEqual('family-1,family-2');
43 | });
44 | });
45 |
46 | describe('#toCssString', function () {
47 | function toCssString(fvd) {
48 | return new Font('My Family', fvd).toCssString();
49 | }
50 |
51 | it('should expand font styles correctly', function () {
52 | expect(toCssString('n4')).toEqual("normal 400 300px 'My Family'");
53 | expect(toCssString('i4')).toEqual("italic 400 300px 'My Family'");
54 | expect(toCssString('o4')).toEqual("oblique 400 300px 'My Family'");
55 | });
56 |
57 | it('should expand weights correctly', function () {
58 | for (var i = 1; i < 10; i += 1) {
59 | expect(toCssString('n' + i)).toEqual("normal " + (i * 100) + " 300px 'My Family'");
60 | }
61 | });
62 | });
63 |
64 | describe('#getCssVariation', function () {
65 | function toCss(fvd) {
66 | return new Font('My Family', fvd).getCssVariation();
67 | }
68 |
69 | it('should expand font-style', function () {
70 | expect(toCss('n4')).toEqual('font-style:normal;font-weight:400;');
71 | expect(toCss('i4')).toEqual('font-style:italic;font-weight:400;');
72 | expect(toCss('o4')).toEqual('font-style:oblique;font-weight:400;');
73 | });
74 |
75 | it('should expand weights correctly', function () {
76 | for (var i = 1; i < 10; i += 1) {
77 | expect(toCss('n' + i)).toEqual('font-style:normal;font-weight:' + (i * 100) + ';');
78 | }
79 | });
80 |
81 | it('should not expand incorrect input', function () {
82 | expect(toCss('')).toEqual('font-style:normal;font-weight:400;');
83 | expect(toCss('n')).toEqual('font-style:normal;font-weight:400;');
84 | expect(toCss('1')).toEqual('font-style:normal;font-weight:400;');
85 | expect(toCss('n1x')).toEqual('font-style:normal;font-weight:400;');
86 | });
87 | });
88 |
89 | describe('parseCssVariation', function () {
90 | function toFvd(css) {
91 | return Font.parseCssVariation(css);
92 | }
93 |
94 | it('should default to n4 when there is no description', function () {
95 | expect(toFvd('')).toEqual('n4');
96 | expect(toFvd(null)).toEqual('n4');
97 | expect(toFvd(undefined)).toEqual('n4');
98 | });
99 |
100 | it('should compact font style', function () {
101 | expect(toFvd('font-style: normal;')).toEqual('n4');
102 | expect(toFvd('font-style: italic;')).toEqual('i4');
103 | expect(toFvd('font-style: oblique;')).toEqual('o4');
104 | });
105 |
106 | it('should return the default value when font-style is incorrect', function () {
107 | expect(toFvd('font-style: other;')).toEqual('n4');
108 | });
109 |
110 | it('should compact font weight', function () {
111 | expect(toFvd('font-weight: normal;')).toEqual('n4');
112 | expect(toFvd('font-weight: bold;')).toEqual('n7');
113 | for (var i = 1; i < 10; i += 1) {
114 | expect(toFvd('font-weight: ' + (i * 100) + ';')).toEqual('n' + i);
115 | }
116 | });
117 |
118 | it('should return the default value when font-weight is incorrect', function () {
119 | expect(toFvd('font-weight: 140;')).toEqual('n4');
120 | expect(toFvd('font-weight: other;')).toEqual('n4');
121 | });
122 |
123 | it('should compact multiple properties', function () {
124 | expect(toFvd('font-weight: bold; font-style: italic;')).toEqual('i7');
125 | expect(toFvd('; font-weight: bold; font-style: italic;')).toEqual('i7');
126 | expect(toFvd('font-style:italic;font-weight:bold;')).toEqual('i7');
127 | expect(toFvd(' font-style: italic ;\n\nfont-weight: bold; ')).toEqual('i7');
128 | });
129 |
130 | it('should return default values for incorrect individual properties', function () {
131 | expect(toFvd('src: url(/font.otf)')).toEqual('n4');
132 | expect(toFvd('font-weight: 900; src: url(/font.otf);')).toEqual('n9');
133 | expect(toFvd('font-weight: 800; font-stretch:condensed;')).toEqual('n8');
134 | });
135 | });
136 | });
137 |
--------------------------------------------------------------------------------
/spec/core/fontmoduleloader_spec.js:
--------------------------------------------------------------------------------
1 | describe('FontModuleLoader', function () {
2 | var FontModuleLoader = webfont.FontModuleLoader;
3 |
4 | describe('#getModules', function () {
5 | var fontModuleLoader = null;
6 |
7 | beforeEach(function () {
8 | fontModuleLoader = new FontModuleLoader();
9 | });
10 |
11 | it('should return an empty array without modules', function () {
12 | var modules = fontModuleLoader.getModules();
13 |
14 | expect(modules).not.toBeNull();
15 | expect(modules.length).toEqual(0);
16 | });
17 |
18 | it('should have modules', function () {
19 | fontModuleLoader.addModuleFactory('booh', function () {
20 | return {
21 | scary: true
22 | };
23 | });
24 |
25 | fontModuleLoader.addModuleFactory('haha', function () {
26 | return {
27 | funny: true
28 | };
29 | });
30 |
31 | fontModuleLoader.addModuleFactory('moo', function () {
32 | return {
33 | cowy: true
34 | };
35 | });
36 |
37 | var modules = fontModuleLoader.getModules({
38 | booh: {},
39 | moo: {},
40 | nothing: {}
41 | });
42 |
43 | expect(modules).not.toBeNull();
44 | expect(modules.length).toEqual(2);
45 |
46 | var module = modules[0];
47 | expect(module).not.toBeNull();
48 | expect(module.scary || module.cowy).toBe(true);
49 |
50 | var module = modules[1];
51 | expect(module).not.toBeNull();
52 | expect(module.scary || module.cowy).toBe(true);
53 | });
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/spec/core/fontruler_spec.js:
--------------------------------------------------------------------------------
1 | describe('FontRuler', function () {
2 | var Font = webfont.Font,
3 | FontRuler = webfont.FontRuler,
4 | DomHelper = webfont.DomHelper,
5 | Size = webfont.Size,
6 | domHelper = null,
7 | font = null;
8 |
9 | beforeEach(function () {
10 | font = new Font('sans-serif');
11 | domHelper = new DomHelper(window);
12 | });
13 |
14 | it('should prevent a long test string from word wrapping', function () {
15 | var fontRulerA = new FontRuler(domHelper, 'abc'),
16 | fontRulerB = new FontRuler(domHelper, 'abc HelloWorld,thisshouldwrap!!!!');
17 |
18 | fontRulerA.insert();
19 | fontRulerB.insert();
20 |
21 | fontRulerA.setFont(font);
22 | fontRulerB.setFont(font);
23 |
24 | var widthA = fontRulerA.getWidth(),
25 | widthB = fontRulerB.getWidth();
26 |
27 | expect(widthA).not.toEqual(widthB);
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/spec/core/fontwatchrunner_spec.js:
--------------------------------------------------------------------------------
1 | describe('FontWatchRunner', function () {
2 | var FontWatchRunner = webfont.FontWatchRunner,
3 | Font = webfont.Font,
4 | BrowserInfo = webfont.BrowserInfo,
5 | DomHelper = webfont.DomHelper,
6 | FontRuler = webfont.FontRuler;
7 |
8 | var domHelper = null,
9 | activeCallback = null,
10 | inactiveCallback = null,
11 | nullFont = null,
12 | sourceSansA = null,
13 | sourceSansB = null,
14 | elena = null;
15 |
16 | beforeEach(function () {
17 | domHelper = new DomHelper(window);
18 |
19 | activeCallback = jasmine.createSpy('activeCallback');
20 | inactiveCallback = jasmine.createSpy('inactiveCallback');
21 |
22 | nullFont = new Font('__webfontloader_test__');
23 | sourceSansA = new Font('SourceSansA');
24 | sourceSansB = new Font('SourceSansB');
25 | elena = new Font('Elena');
26 | });
27 |
28 | it('should fail to load a null font', function () {
29 | var fontWatchRunner = new FontWatchRunner(activeCallback, inactiveCallback,
30 | domHelper, nullFont, 500, {});
31 |
32 | runs(function () {
33 | fontWatchRunner.start();
34 | });
35 |
36 | waitsFor(function () {
37 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
38 | });
39 |
40 | runs(function () {
41 | expect(inactiveCallback).toHaveBeenCalledWith(nullFont);
42 | });
43 | });
44 |
45 | it('should load font succesfully', function () {
46 | var fontWatchRunner = new FontWatchRunner(activeCallback, inactiveCallback,
47 | domHelper, sourceSansA, 5000),
48 | ruler = new FontRuler(domHelper, 'abcdef'),
49 | monospace = new Font('monospace'),
50 | sourceSansAFallback = new Font("'SourceSansA', monospace"),
51 | activeWidth = null,
52 | originalWidth = null,
53 | finalCheck = false;
54 |
55 | runs(function () {
56 | ruler.insert();
57 | ruler.setFont(monospace);
58 | originalWidth = ruler.getWidth();
59 | ruler.setFont(sourceSansAFallback);
60 | fontWatchRunner.start();
61 | });
62 |
63 | waitsFor(function () {
64 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
65 | });
66 |
67 | runs(function () {
68 | expect(activeCallback).toHaveBeenCalledWith(sourceSansA);
69 | activeWidth = ruler.getWidth();
70 | expect(activeWidth).not.toEqual(originalWidth);
71 |
72 | window.setTimeout(function () {
73 | finalCheck = true;
74 | }, 200);
75 | });
76 |
77 | waitsFor(function () {
78 | return finalCheck;
79 | });
80 |
81 | runs(function () {
82 | expect(ruler.getWidth()).not.toEqual(originalWidth);
83 | expect(ruler.getWidth()).toEqual(activeWidth);
84 | });
85 | });
86 |
87 | it('should attempt to load a non-existing font', function () {
88 | var fontWatchRunner = new FontWatchRunner(activeCallback, inactiveCallback,
89 | domHelper, elena, 500, {});
90 |
91 | runs(function () {
92 | fontWatchRunner.start();
93 | });
94 |
95 | waitsFor(function () {
96 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
97 | });
98 |
99 | runs(function () {
100 | expect(inactiveCallback).toHaveBeenCalledWith(elena);
101 | });
102 | });
103 |
104 | it('should load even if @font-face is inserted after watching has started', function () {
105 | var fontWatchRunner = new FontWatchRunner(activeCallback, inactiveCallback,
106 | domHelper, sourceSansB, 5000),
107 | ruler = new FontRuler(domHelper, 'abcdef'),
108 | monospace = new Font('monospace'),
109 | sourceSansBFallback = new Font("'SourceSansB', monospace"),
110 | activeWidth = null,
111 | originalWidth = null,
112 | finalCheck = false;
113 |
114 | runs(function () {
115 | ruler.insert();
116 | ruler.setFont(monospace);
117 | originalWidth = ruler.getWidth();
118 | ruler.setFont(sourceSansBFallback);
119 | fontWatchRunner.start();
120 | var link = document.createElement('link');
121 |
122 | link.rel = "stylesheet";
123 | link.href= "fixtures/fonts/sourcesansb.css";
124 |
125 | domHelper.insertInto('head', link);
126 | });
127 |
128 | waitsFor(function () {
129 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
130 | });
131 |
132 | runs(function () {
133 | expect(activeCallback).toHaveBeenCalledWith(sourceSansB);
134 | activeWidth = ruler.getWidth();
135 | expect(activeWidth).not.toEqual(originalWidth);
136 |
137 | window.setTimeout(function () {
138 | finalCheck = true;
139 | }, 200);
140 | });
141 |
142 | waitsFor(function () {
143 | return finalCheck;
144 | });
145 |
146 | runs(function () {
147 | expect(ruler.getWidth()).not.toEqual(originalWidth);
148 | expect(ruler.getWidth()).toEqual(activeWidth);
149 | });
150 | });
151 | });
152 |
--------------------------------------------------------------------------------
/spec/core/nativefontwatchrunner_spec.js:
--------------------------------------------------------------------------------
1 | describe('NativeFontWatchRunner', function () {
2 | var NativeFontWatchRunner = webfont.NativeFontWatchRunner,
3 | Font = webfont.Font,
4 | DomHelper = webfont.DomHelper,
5 | FontRuler = webfont.FontRuler;
6 |
7 | var domHelper = null,
8 | activeCallback = null,
9 | inactiveCallback = null,
10 | nullFont = null,
11 | sourceSansC = null,
12 | sourceSansDup = null,
13 | elena = null;
14 |
15 | beforeEach(function () {
16 | domHelper = new DomHelper(window);
17 |
18 | activeCallback = jasmine.createSpy('activeCallback');
19 | inactiveCallback = jasmine.createSpy('inactiveCallback');
20 |
21 | nullFont = new Font('__webfontloader_test_3__');
22 | sourceSansC = new Font('SourceSansC');
23 | sourceSansDup = new Font('SourceSansDup');
24 | elena = new Font('Elena');
25 | });
26 |
27 | if (window['FontFace']) {
28 | it('should fail to load a null font', function () {
29 | var fontWatchRunner = new NativeFontWatchRunner(activeCallback, inactiveCallback,
30 | domHelper, nullFont, 500);
31 |
32 | runs(function () {
33 | fontWatchRunner.start();
34 | });
35 |
36 | waitsFor(function () {
37 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
38 | });
39 |
40 | runs(function () {
41 | expect(inactiveCallback).toHaveBeenCalledWith(nullFont);
42 | });
43 | });
44 |
45 | function succesfulLoadingSpec(getFontToBeLoaded, getFontNameToBeLoaded) {
46 | var fontToBeLoaded = getFontToBeLoaded(),
47 | fontNameToBeLoaded = getFontNameToBeLoaded(),
48 | fontWatchRunner = new NativeFontWatchRunner(activeCallback, inactiveCallback,
49 | domHelper, fontToBeLoaded),
50 | ruler = new FontRuler(domHelper, 'abcdef'),
51 | monospace = new Font('monospace'),
52 | fallbackFont = new Font(fontNameToBeLoaded + ', monospace'),
53 | activeWidth = null,
54 | originalWidth = null,
55 | finalCheck = false;
56 |
57 | runs(function () {
58 | ruler.insert();
59 | ruler.setFont(monospace);
60 | originalWidth = ruler.getWidth();
61 | ruler.setFont(fallbackFont);
62 | fontWatchRunner.start();
63 | });
64 |
65 | waitsFor(function () {
66 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
67 | });
68 |
69 | runs(function () {
70 | expect(activeCallback).toHaveBeenCalledWith(fontToBeLoaded);
71 | activeWidth = ruler.getWidth();
72 | expect(activeWidth).not.toEqual(originalWidth);
73 |
74 | window.setTimeout(function () {
75 | finalCheck = true;
76 | }, 200);
77 | });
78 |
79 | waitsFor(function () {
80 | return finalCheck;
81 | });
82 |
83 | runs(function () {
84 | expect(ruler.getWidth()).not.toEqual(originalWidth);
85 | expect(ruler.getWidth()).toEqual(activeWidth);
86 | });
87 | }
88 |
89 | it('should load font succesfully',
90 | succesfulLoadingSpec.bind(null, function() { return sourceSansC; }, function() { return 'SourceSansC'; }));
91 |
92 | it('should load font succesfully even if it is duplicated',
93 | succesfulLoadingSpec.bind(null, function() { return sourceSansDup; }, function() { return 'SourceSansDup'; }));
94 |
95 | it('should attempt to load a non-existing font', function () {
96 | var fontWatchRunner = new NativeFontWatchRunner(activeCallback, inactiveCallback,
97 | domHelper, elena, 500);
98 |
99 | runs(function () {
100 | fontWatchRunner.start();
101 | });
102 |
103 | waitsFor(function () {
104 | return activeCallback.wasCalled || inactiveCallback.wasCalled;
105 | });
106 |
107 | runs(function () {
108 | expect(inactiveCallback).toHaveBeenCalledWith(elena);
109 | });
110 | });
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/spec/core/size_spec.js:
--------------------------------------------------------------------------------
1 | describe('Size', function () {
2 | var Size = webfont.Size;
3 |
4 | it('should return true on identical sizes', function () {
5 | expect(new Size(10, 10).equals(new Size(10, 10))).toBe(true);
6 | });
7 |
8 | it('should return false when two sizes are different', function () {
9 | expect(new Size(10, 10).equals(new Size(20, 20))).toBe(false);
10 | expect(new Size(10, 10).equals(new Size(10, 20))).toBe(false);
11 | });
12 |
13 | it('should return false when one font is undefined or null', function () {
14 | expect(new Size(10, 10).equals(undefined)).toBe(false);
15 | expect(new Size(10, 10).equals(null)).toBe(false);
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/spec/core/webfont_spec.js:
--------------------------------------------------------------------------------
1 | describe('WebFont', function () {
2 | var WebFont = webfont.WebFont,
3 | Font = webfont.Font;
4 | FontWatchRunner = webfont.FontWatchRunner,
5 | NativeFontWatchRunner = webfont.NativeFontWatchRunner,
6 | Version = webfont.Version,
7 | Font = webfont.Font,
8 | FontModuleLoader = webfont.FontModuleLoader,
9 | fontModuleLoader = null;
10 |
11 | beforeEach(function () {
12 | fontModuleLoader = new FontModuleLoader();
13 | });
14 |
15 | describe('font load with context', function () {
16 | var font = null,
17 | testModule = null,
18 | fakeMainWindow = {
19 | document: {}
20 | };
21 |
22 | beforeEach(function () {
23 | font = new WebFont(fakeMainWindow);
24 | font.addModule('test', function (conf, domHelper) {
25 | testModule = new function () {
26 | this.domHelper = domHelper;
27 | };
28 | testModule.load = function (onReady) {
29 | onReady([]);
30 | };
31 |
32 | return testModule;
33 | });
34 | });
35 |
36 | it('should load with the correct context', function () {
37 | font.load({
38 | test: {
39 | somedata: 'in french a cow says meuh'
40 | },
41 | context: window
42 | });
43 |
44 | expect(testModule.domHelper).not.toBeNull();
45 | expect(testModule.domHelper).not.toBeUndefined();
46 |
47 | expect(testModule.domHelper.getMainWindow()).toEqual(fakeMainWindow);
48 | expect(testModule.domHelper.getLoadWindow()).toEqual(window);
49 | });
50 | });
51 |
52 | describe('module failed to provide families and descriptions because it did not initialize properly', function () {
53 | var webfont = null,
54 | testModule = null,
55 | font = null,
56 | inactive = jasmine.createSpy('inactive'),
57 | active = jasmine.createSpy('active');
58 |
59 | beforeEach(function () {
60 | font = new Font('Font1');
61 | jasmine.Clock.useMock();
62 | webfont = new WebFont(window);
63 | webfont.addModule('test', function (conf, domHelper) {
64 | testModule = new function () {
65 | this.conf = conf;
66 | };
67 |
68 | spyOn(FontWatchRunner.prototype, 'start').andCallFake(function () {
69 | if (conf.id) {
70 | active(font);
71 | } else {
72 | inactive(font);
73 | }
74 | });
75 |
76 | spyOn(NativeFontWatchRunner.prototype, 'start').andCallFake(function () {
77 | if (conf.id) {
78 | active(font);
79 | } else {
80 | inactive(font);
81 | }
82 | });
83 |
84 | testModule.load = function (onReady) {
85 | if (conf.id) {
86 | onReady([font]);
87 | } else {
88 | onReady([]);
89 | }
90 | };
91 |
92 | return testModule;
93 | });
94 | });
95 |
96 | it('should load with a project id', function () {
97 | webfont.load({
98 | test: {
99 | id: 'hello world'
100 | },
101 | inactive: inactive,
102 | active: active
103 | });
104 |
105 | jasmine.Clock.tick(1);
106 |
107 | expect(testModule).not.toBeNull();
108 | expect(active).toHaveBeenCalled();
109 | });
110 |
111 | it('should not load without a project id', function () {
112 | webfont.load({
113 | test: {
114 | },
115 | inactive: inactive,
116 | active: active
117 | });
118 |
119 | jasmine.Clock.tick(1);
120 |
121 | expect(testModule).not.toBeNull();
122 | expect(inactive).toHaveBeenCalled();
123 | });
124 | });
125 |
126 | describe('should pass both fonts and test strings to onready', function () {
127 | var font = null,
128 | fontTestStrings = null,
129 | testModule = null;
130 |
131 | beforeEach(function () {
132 | font = new WebFont(window);
133 |
134 | font.addModule('test', function (conf, domHelper) {
135 | testModule = new function () {};
136 | testModule.load = function (onReady) {
137 | onReady([new Font('Elena')], { 'Elena': '1234567' });
138 | };
139 |
140 | return testModule;
141 | });
142 |
143 | spyOn(font, 'onModuleReady_');
144 | });
145 |
146 | it('should have called onModuleReady with the correct font and test string', function () {
147 | font.load({
148 | 'test': {}
149 | });
150 |
151 | expect(font.onModuleReady_).toHaveBeenCalled();
152 | expect(font.onModuleReady_.calls[0].args[2]).toEqual([new Font('Elena')]);
153 | expect(font.onModuleReady_.calls[0].args[3]).toEqual({ 'Elena': '1234567' });
154 | });
155 | });
156 |
157 | describe('module fails to load', function () {
158 | var font = null,
159 | testModule = null,
160 | inactive = null,
161 | active = null;
162 |
163 | beforeEach(function () {
164 | inactive = jasmine.createSpy('inactive'),
165 | active = jasmine.createSpy('active');
166 |
167 | font = new WebFont(window, fontModuleLoader);
168 |
169 | font.addModule('test', function (conf, domHelper) {
170 | testModule = new function () {};
171 | testModule.load = function (onReady) {
172 | onReady([]);
173 | };
174 |
175 | return testModule;
176 | });
177 | });
178 |
179 | it('times out and calls inactive', function () {
180 | runs(function () {
181 | font.load({
182 | 'test': {},
183 | inactive: inactive,
184 | active: active
185 | });
186 | });
187 |
188 | waitsFor(function () {
189 | return active.wasCalled || inactive.wasCalled;
190 | });
191 |
192 | runs(function () {
193 | expect(inactive).toHaveBeenCalled();
194 | expect(active).not.toHaveBeenCalled();
195 | });
196 | });
197 | });
198 |
199 | describe('synchronous load event', function () {
200 | var font = null,
201 | testModule = null,
202 | inactive = null,
203 | loading = null,
204 | active = null;
205 |
206 | beforeEach(function () {
207 | inactive = jasmine.createSpy('inactive'),
208 | active = jasmine.createSpy('active');
209 | loading = jasmine.createSpy('loading');
210 |
211 | font = new WebFont(window, fontModuleLoader);
212 |
213 | font.addModule('test', function (conf, domHelper) {
214 | testModule = new function () {};
215 | testModule.load = function (onReady) {
216 | onReady([new Font('Elena')]);
217 | };
218 |
219 | return testModule;
220 | });
221 | });
222 |
223 | it('fires loading event correctly', function () {
224 | runs(function () {
225 | font.load({
226 | 'test': {},
227 | inactive: inactive,
228 | active: active,
229 | loading: loading
230 | });
231 | expect(loading).toHaveBeenCalled();
232 | });
233 |
234 | waitsFor(function () {
235 | return active.wasCalled || inactive.wasCalled;
236 | });
237 |
238 | runs(function () {
239 | expect(inactive).toHaveBeenCalled();
240 | expect(active).not.toHaveBeenCalled();
241 | });
242 | });
243 | });
244 | });
245 |
--------------------------------------------------------------------------------
/spec/deps.js:
--------------------------------------------------------------------------------
1 | // This file was autogenerated by calcdeps.js
2 | goog.addDependency("../../src/closure.js", [], []);
3 | goog.addDependency("../../src/core/cssclassname.js", ["webfont.CssClassName"], []);
4 | goog.addDependency("../../src/core/domhelper.js", ["webfont.DomHelper"], []);
5 | goog.addDependency("../../src/core/stylesheetwaiter.js", ["webfont.StyleSheetWaiter"], []);
6 | goog.addDependency("../../src/core/eventdispatcher.js", ["webfont.EventDispatcher"], ["webfont.CssClassName"]);
7 | goog.addDependency("../../src/core/font.js", ["webfont.Font"], []);
8 | goog.addDependency("../../src/core/fontmodule.js", ["webfont.FontModule"], []);
9 | goog.addDependency("../../src/core/fontmoduleloader.js", ["webfont.FontModuleLoader","webfont.FontModuleFactory"], []);
10 | goog.addDependency("../../src/core/fontruler.js", ["webfont.FontRuler"], []);
11 | goog.addDependency("../../src/core/fontwatcher.js", ["webfont.FontWatcher"], ["webfont.FontWatchRunner","webfont.NativeFontWatchRunner"]);
12 | goog.addDependency("../../src/core/fontwatchrunner.js", ["webfont.FontWatchRunner"], ["webfont.Font","webfont.FontRuler"]);
13 | goog.addDependency("../../src/core/initialize.js", ["webfont"], ["webfont.WebFont","webfont.modules.Typekit","webfont.modules.Fontdeck","webfont.modules.Monotype","webfont.modules.Custom","webfont.modules.google.GoogleFontApi"]);
14 | goog.addDependency("../../src/core/nativefontwatchrunner.js", ["webfont.NativeFontWatchRunner"], ["webfont.Font"]);
15 | goog.addDependency("../../src/core/webfont.js", ["webfont.WebFont"], ["webfont.DomHelper","webfont.EventDispatcher","webfont.FontWatcher","webfont.FontModuleLoader"]);
16 | goog.addDependency("../../src/modules/custom.js", ["webfont.modules.Custom"], ["webfont.Font", "webfont.StyleSheetWaiter"]);
17 | goog.addDependency("../../src/modules/fontdeck.js", ["webfont.modules.Fontdeck"], ["webfont.Font"]);
18 | goog.addDependency("../../src/modules/google/fontapiparser.js", ["webfont.modules.google.FontApiParser"], ["webfont.Font"]);
19 | goog.addDependency("../../src/modules/google/fontapiurlbuilder.js", ["webfont.modules.google.FontApiUrlBuilder"], []);
20 | goog.addDependency("../../src/modules/google/googlefontapi.js", ["webfont.modules.google.GoogleFontApi"], ["webfont.modules.google.FontApiUrlBuilder","webfont.modules.google.FontApiParser","webfont.FontWatchRunner", "webfont.StyleSheetWaiter"]);
21 | goog.addDependency("../../src/modules/monotype.js", ["webfont.modules.Monotype"], ["webfont.Font"]);
22 | goog.addDependency("../../src/modules/typekit.js", ["webfont.modules.Typekit"], ["webfont.Font"]);
23 |
--------------------------------------------------------------------------------
/spec/fixtures/external_script.js:
--------------------------------------------------------------------------------
1 | window.EXTERNAL_SCRIPT_LOADED = true;
2 |
--------------------------------------------------------------------------------
/spec/fixtures/external_stylesheet.css:
--------------------------------------------------------------------------------
1 | #TEST_ELEMENT {
2 | display: block;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | width: 300px;
7 | }
8 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 |
5 | This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/nullfont.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:__webfontloader_test__;src:url(data:application/x-font-woff;base64,) format('woff'),url(data:font/truetype;base64,) format('truetype');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/nullfont1.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:__webfontloader_test_1__;src:url(data:application/x-font-woff;base64,) format('woff'),url(data:font/truetype;base64,) format('truetype');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/nullfont2.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:__webfontloader_test_2__;src:url(data:application/x-font-woff;base64,) format('woff'),url(data:font/truetype;base64,) format('truetype');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/nullfont3.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:__webfontloader_test_3__;src:url(data:application/x-font-woff;base64,) format('woff'),url(data:font/truetype;base64,) format('truetype');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesans.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typekit/webfontloader/117e48d521d6408f78cbfe4d23923cc828fdf576/spec/fixtures/fonts/sourcesans.eot
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesans.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typekit/webfontloader/117e48d521d6408f78cbfe4d23923cc828fdf576/spec/fixtures/fonts/sourcesans.otf
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typekit/webfontloader/117e48d521d6408f78cbfe4d23923cc828fdf576/spec/fixtures/fonts/sourcesans.ttf
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesans.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typekit/webfontloader/117e48d521d6408f78cbfe4d23923cc828fdf576/spec/fixtures/fonts/sourcesans.woff
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansa.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansA;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansb.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansB;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansc.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansC;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansd.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansD;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansdup1.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansDup;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/fixtures/fonts/sourcesansdup2.css:
--------------------------------------------------------------------------------
1 | @font-face{font-family:SourceSansDup;src:url(sourcesans.eot?#iefix) format('embedded-opentype'),url(sourcesans.woff) format('woff'),url(sourcesans.otf) format('opentype'),url(sourcesans.ttf) format('truetype'),url(sourcesans.svg#source_sans_proregular) format('svg');}
2 |
--------------------------------------------------------------------------------
/spec/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Webfontloader tests
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/spec/modules/custom_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.Custom', function () {
2 | var Custom = webfont.modules.Custom,
3 | FontFamily = webfont.FontFamily,
4 | Any = jasmine.Matchers.Any;
5 |
6 | describe('insert links correctly', function () {
7 | var fakeDomHelper = null,
8 | load = null;
9 |
10 | function notifySheetsLoaded() {
11 | var argsForCall = fakeDomHelper.loadStylesheet.argsForCall;
12 | for (var i = 0; i < argsForCall.length; i++) {
13 | var args = argsForCall[i];
14 | args[1]();
15 | }
16 | }
17 |
18 | beforeEach(function () {
19 | fakeDomHelper = {
20 | loadStylesheet: jasmine.createSpy('createCssLink')
21 | };
22 |
23 | load = jasmine.createSpy('load');
24 |
25 | var defaultModule = new Custom(fakeDomHelper, {
26 | families: ['Font1', 'Font2', 'Font3'],
27 | urls: ['https://moo', 'https://meuh'],
28 | testStrings: {
29 | Font3: 'hello world'
30 | }
31 | });
32 |
33 | defaultModule.load(load);
34 | });
35 |
36 | it('should have inserted the links correctly', function () {
37 | expect(fakeDomHelper.loadStylesheet.callCount).toEqual(2);
38 | expect(fakeDomHelper.loadStylesheet).toHaveBeenCalledWith('https://moo', new Any(Function));
39 | expect(fakeDomHelper.loadStylesheet).toHaveBeenCalledWith('https://meuh', new Any(Function));
40 | });
41 |
42 | if (webfont.DomHelper.CAN_WAIT_STYLESHEET) {
43 | it('should not invoke callback before all CSS are loaded', function () {
44 | expect(load.callCount).toEqual(0);
45 | notifySheetsLoaded();
46 | expect(load.callCount).toEqual(1);
47 | });
48 | }
49 |
50 | it('should have loaded the families correctly', function () {
51 | notifySheetsLoaded();
52 | expect(load.callCount).toEqual(1);
53 | expect(load.calls[0].args[0].length).toEqual(3);
54 | expect(load.calls[0].args[0][0].getName()).toEqual('Font1');
55 | expect(load.calls[0].args[0][1].getName()).toEqual('Font2');
56 | expect(load.calls[0].args[0][2].getName()).toEqual('Font3');
57 | });
58 |
59 | it('should have set a custom test string', function () {
60 | notifySheetsLoaded();
61 | expect(load.callCount).toEqual(1);
62 | expect(load.calls[0].args[1]).toEqual({ Font3: 'hello world' });
63 | });
64 | });
65 |
66 | });
67 |
--------------------------------------------------------------------------------
/spec/modules/fontdeck_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.Fontdeck', function () {
2 | var Fontdeck = webfont.modules.Fontdeck,
3 | Font = webfont.Font;
4 |
5 | var configuration = {
6 | id: '2282'
7 | };
8 |
9 | var apiResponse = {
10 | "domain" : "localhost",
11 | "cssurl" : "https://f.fontdeck.com/s/css/03BmCXiV2AHwX/Rp+OBFTfD2oFs/localhost/2282.css",
12 | "project" : 2282,
13 | "cssbase" : "https://f.fontdeck.com/s/css/03BmCXiV2AHwX/Rp+OBFTfD2oFs",
14 | "fonts" : [
15 | {
16 | "font_family" : "'Fertigo Pro Regular', Fertigo, Constantia, Palatino, serif",
17 | "font_size_adjust" : 0.508,
18 | "name" : "Fertigo Pro Regular",
19 | "style" : "normal",
20 | "weight" : "normal",
21 | "font_urls" : {
22 | "eot" : "https://f.fontdeck.com/f/1/SUlFR0tid0kAA2vb11Ly/IGWDK+wV8TMAfV0J1Ej1J1GFRT1bssqrn6a.eot",
23 | "ttf" : "https://f.fontdeck.com/f/1/SUlFR0tid0kAA2vb11Ly/IGWDK+wV8TMAfV0J1Ej1J1GFRT1bssqrn6a.ttf",
24 | "woff" : "https://f.fontdeck.com/f/1/SUlFR0tid0kAA2vb11Ly/IGWDK+wV8TMAfV0J1Ej1J1GFRT1bssqrn6a.woff",
25 | "svg" : "https://f.fontdeck.com/f/1/SUlFR0tid0kAA2vb11Ly/IGWDK+wV8TMAfV0J1Ej1J1GFRT1bssqrn6a.svg#104"
26 | },
27 | "id" : 104
28 | },
29 | {
30 | "font_family" : "'Bodoni Display Bold Italic', Georgia, 'Times New Roman', Times, serif",
31 | "font_size_adjust" : 0.45,
32 | "name" : "Bodoni Display Bold Italic",
33 | "style" : "italic",
34 | "weight" : "bold",
35 | "font_urls" : {
36 | "eot" : "https://f.fontdeck.com/f/1/azJEbTVyc1QAA11+CAE5C93+l/bAQx1ipRo6Maba19w3Yy5ng+qVWlfj.eot",
37 | "ttf" : "https://f.fontdeck.com/f/1/azJEbTVyc1QAA11+CAE5C93+l/bAQx1ipRo6Maba19w3Yy5ng+qVWlfj.ttf",
38 | "woff" : "https://f.fontdeck.com/f/1/azJEbTVyc1QAA11+CAE5C93+l/bAQx1ipRo6Maba19w3Yy5ng+qVWlfj.woff",
39 | "svg" : "https://f.fontdeck.com/f/1/azJEbTVyc1QAA11+CAE5C93+l/bAQx1ipRo6Maba19w3Yy5ng+qVWlfj.svg#2256"
40 | },
41 | "id" : 2256
42 | }
43 | ]
44 | };
45 |
46 | var fakeDomHelper = null,
47 | global = null;
48 |
49 | beforeEach(function () {
50 | global = {
51 | location: {}
52 | };
53 |
54 | fakeDomHelper = {
55 | loadScript: jasmine.createSpy('loadScript'),
56 | getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global),
57 | getHostName: function () { return 'test-host-name'; }
58 | };
59 | });
60 |
61 | describe('support and load life cycle', function () {
62 | var fontdeck = null,
63 | onReady = jasmine.createSpy('onReady');
64 |
65 | beforeEach(function () {
66 | fontdeck = new Fontdeck(fakeDomHelper, configuration);
67 | fontdeck.load(onReady);
68 | });
69 |
70 | it('should create the script correctly', function () {
71 | expect(fakeDomHelper.loadScript).toHaveBeenCalled();
72 | expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('https://f.fontdeck.com/s/css/js/test-host-name/2282.js');
73 | });
74 |
75 | it('should have created a global', function () {
76 | expect(global.__webfontfontdeckmodule__).not.toBeNull();
77 | expect(global.__webfontfontdeckmodule__['2282']).not.toBeNull();
78 | });
79 |
80 | it('should load correctly after calling the callback', function () {
81 | global.__webfontfontdeckmodule__['2282'](true, apiResponse);
82 |
83 | expect(fontdeck.fonts_).toEqual([new Font(apiResponse.fonts[0].name), new Font(apiResponse.fonts[1].name, 'i7')]);
84 | });
85 | });
86 |
87 | describe('no project id', function () {
88 | var fontdeck = null,
89 | support = null;
90 |
91 | beforeEach(function () {
92 | fontdeck = new Fontdeck(fakeDomHelper, { id: null });
93 | });
94 |
95 | it('should not have loaded any fonts', function () {
96 | expect(fontdeck.fonts_).toEqual([]);
97 | });
98 | });
99 | });
100 |
--------------------------------------------------------------------------------
/spec/modules/google/fontapiparser_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.google.FontApiParser', function () {
2 | var FontApiParser = webfont.modules.google.FontApiParser,
3 | Font = webfont.Font;
4 |
5 | describe('parsed values are coherent', function () {
6 | var parser = null;
7 |
8 | beforeEach(function () {
9 | parser = new FontApiParser(['Tangerine', 'Droid Serif:bi', 'Yanone Kaffeesatz:200,300,400,700', 'Cantarell:italic,b', 'Exo:100italic', 'Lobster:200n']);
10 | parser.parse();
11 | });
12 |
13 | it('should parse fonts correctly', function () {
14 | var fonts = parser.getFonts();
15 |
16 | expect(fonts.length).toEqual(10);
17 | expect(fonts).toEqual([
18 | new Font('Tangerine', 'n4'),
19 | new Font('Droid Serif', 'i7'),
20 | new Font('Yanone Kaffeesatz', 'n2'),
21 | new Font('Yanone Kaffeesatz', 'n3'),
22 | new Font('Yanone Kaffeesatz', 'n4'),
23 | new Font('Yanone Kaffeesatz', 'n7'),
24 | new Font('Cantarell', 'i4'),
25 | new Font('Cantarell', 'n7'),
26 | new Font('Exo', 'i1'),
27 | new Font('Lobster', 'n2')
28 | ]);
29 | });
30 | });
31 |
32 | describe('mix of numeric weight and style', function () {
33 | var parser = null;
34 |
35 | beforeEach(function () {
36 | parser = new FontApiParser(['Nobile:700i,b,200i,r,i700']);
37 | parser.parse();
38 | });
39 |
40 | it('should parse fonts correctly', function () {
41 | var fonts = parser.getFonts();
42 |
43 | expect(fonts.length).toEqual(4);
44 | expect(fonts).toEqual([
45 | new Font('Nobile', 'i7'),
46 | new Font('Nobile', 'n7'),
47 | new Font('Nobile', 'i2'),
48 | new Font('Nobile', 'n4')
49 | ]);
50 | });
51 | });
52 |
53 | describe('typo bild instead of bold', function () {
54 | var parser = null;
55 |
56 | beforeEach(function () {
57 | parser = new FontApiParser(['Nobile:bild']);
58 | parser.parse();
59 | });
60 |
61 | it('should parse families correctly', function () {
62 | var fonts = parser.getFonts();
63 |
64 | expect(fonts.length).toEqual(1);
65 | expect(fonts[0]).toEqual(new Font('Nobile', 'n4'));
66 | });
67 | });
68 |
69 | describe('variations with dashes', function () {
70 | var parser = null;
71 |
72 | beforeEach(function () {
73 | parser = new FontApiParser(['Nobile:semi-bold']);
74 | parser.parse();
75 | });
76 |
77 | it('should parse the variation correctly', function () {
78 | var fonts = parser.getFonts();
79 |
80 | expect(fonts.length).toEqual(1);
81 | expect(fonts[0]).toEqual(new Font('Nobile', 'n6'));
82 | });
83 | });
84 |
85 | describe('nonsense', function () {
86 | var parser = null;
87 |
88 | beforeEach(function () {
89 | parser = new FontApiParser(['Nobile:dwe,^%^%fewf,$9940@#!@#$%^&*()_+}POIBJ{}{']);
90 | parser.parse();
91 | });
92 |
93 | it('should parse families correctly', function () {
94 | var fonts = parser.getFonts();
95 |
96 | expect(fonts.length).toEqual(1);
97 | expect(fonts[0]).toEqual(new Font('Nobile', 'n4'));
98 | });
99 | });
100 |
101 | describe('no weight and one subset defined', function () {
102 | var parser = null;
103 |
104 | beforeEach(function () {
105 | parser = new FontApiParser(['Cantarell::greek']);
106 | parser.parse();
107 | });
108 |
109 | it('should parse families correctly', function () {
110 | var fonts = parser.getFonts();
111 |
112 | expect(fonts.length).toEqual(1);
113 | expect(fonts[0]).toEqual(new Font('Cantarell', 'n4'));
114 | });
115 |
116 | it('should parse pick test strings correctly', function () {
117 | var testStrings = parser.getFontTestStrings(),
118 | cantarell = testStrings['Cantarell'];
119 |
120 | expect(cantarell).not.toBeNull();
121 | expect(cantarell).toEqual(FontApiParser.INT_FONTS['greek']);
122 | });
123 | });
124 |
125 | describe('no weight and multiple subsets defined', function () {
126 | var parser = null;
127 |
128 | beforeEach(function () {
129 | parser = new FontApiParser(['Cantarell::cyrillic,greek,latin']);
130 | parser.parse();
131 | });
132 |
133 | it('should parse families correctly', function () {
134 | var fonts = parser.getFonts();
135 |
136 | expect(fonts.length).toEqual(1);
137 | expect(fonts[0]).toEqual(new Font('Cantarell', 'n4'));
138 | });
139 |
140 | it('should parse pick test strings correctly', function () {
141 | var testStrings = parser.getFontTestStrings(),
142 | cantarell = testStrings['Cantarell'];
143 |
144 | expect(cantarell).not.toBeNull();
145 | expect(cantarell).toEqual(FontApiParser.INT_FONTS['cyrillic']);
146 | });
147 | });
148 |
149 | describe('weight and multiple subsets defined', function () {
150 | var parser = null;
151 |
152 | beforeEach(function () {
153 | parser = new FontApiParser(['Cantarell:regular,bold:cyrillic,greek,latin']);
154 | parser.parse();
155 | });
156 |
157 | it('should parse families correctly', function () {
158 | var fonts = parser.getFonts();
159 |
160 | expect(fonts.length).toEqual(2);
161 | expect(fonts).toEqual([
162 | new Font('Cantarell', 'n4'),
163 | new Font('Cantarell', 'n7')
164 | ]);
165 | });
166 |
167 | it('should parse pick test strings correctly', function () {
168 | var testStrings = parser.getFontTestStrings(),
169 | cantarell = testStrings['Cantarell'];
170 |
171 | expect(cantarell).not.toBeNull();
172 | expect(cantarell).toEqual(FontApiParser.INT_FONTS['cyrillic']);
173 | });
174 | });
175 |
176 | describe('Hanuman is backward compatible', function () {
177 | var parser = null;
178 |
179 | beforeEach(function () {
180 | parser = new FontApiParser(['Hanuman']);
181 | parser.parse();
182 | });
183 |
184 | it('should parse families correctly', function () {
185 | var fonts = parser.getFonts();
186 |
187 | expect(fonts.length).toEqual(1);
188 | expect(fonts[0]).toEqual(new Font('Hanuman', 'n4'));
189 | });
190 |
191 | it('should parse pick test strings correctly', function () {
192 | var testStrings = parser.getFontTestStrings(),
193 | hanuman = testStrings['Hanuman'];
194 |
195 | expect(hanuman).not.toBeNull();
196 | expect(hanuman).toEqual(FontApiParser.INT_FONTS['Hanuman']);
197 | });
198 | });
199 |
200 | describe('Hanuman is forward compatible', function () {
201 | var parser = null;
202 |
203 | beforeEach(function () {
204 | parser = new FontApiParser(['Hanuman::khmer']);
205 | parser.parse();
206 | });
207 |
208 | it('should parse families correctly', function () {
209 | var fonts = parser.getFonts();
210 |
211 | expect(fonts.length).toEqual(1);
212 | expect(fonts[0]).toEqual(new Font('Hanuman', 'n4'));
213 | });
214 |
215 | it('should parse pick test strings correctly', function () {
216 | var testStrings = parser.getFontTestStrings(),
217 | hanuman = testStrings['Hanuman'];
218 |
219 | expect(hanuman).not.toBeNull();
220 | expect(hanuman).toEqual(FontApiParser.INT_FONTS['khmer']);
221 | });
222 | });
223 |
224 | describe('plus replaced with space', function () {
225 | var parser = null;
226 |
227 | beforeEach(function () {
228 | parser = new FontApiParser(['Erica+One', 'Droid+Serif::latin', 'Yanone+Kaffeesatz:400,700:latin']);
229 | parser.parse();
230 | });
231 |
232 | it('should parse families correctly', function () {
233 | var fonts = parser.getFonts();
234 |
235 | expect(fonts.length).toEqual(4);
236 | expect(fonts).toEqual([
237 | new Font('Erica One', 'n4'),
238 | new Font('Droid Serif', 'n4'),
239 | new Font('Yanone Kaffeesatz', 'n4'),
240 | new Font('Yanone Kaffeesatz', 'n7')
241 | ]);
242 | });
243 | });
244 | });
245 |
--------------------------------------------------------------------------------
/spec/modules/google/fontapiurlbuilder_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.google.FontApiUrlBuilder', function () {
2 | var FontApiUrlBuilder = webfont.modules.google.FontApiUrlBuilder;
3 |
4 | it('should throw an exception if there are no font families', function () {
5 | var builder = new FontApiUrlBuilder('https://moo');
6 | expect(builder.build).toThrow();
7 | });
8 |
9 | it('should build a proper url', function () {
10 | var builder = new FontApiUrlBuilder('https://moo');
11 | builder.setFontFamilies(['Font1', 'Font2']);
12 | expect(builder.build()).toEqual('https://moo?family=Font1%7CFont2');
13 | });
14 |
15 | it('should build a proper url', function () {
16 | var builder = new FontApiUrlBuilder(undefined);
17 | builder.setFontFamilies(['Font1', 'Font2']);
18 | expect(builder.build()).toEqual(
19 | FontApiUrlBuilder.DEFAULT_API_URL +
20 | '?family=Font1%7CFont2');
21 | });
22 |
23 | it('should build a proper url', function () {
24 | var builder = new FontApiUrlBuilder(undefined);
25 | builder.setFontFamilies(['Font1:bold:greek,cyrillic', 'Font2:italic', 'Font3']);
26 | expect(builder.build()).toEqual(
27 | FontApiUrlBuilder.DEFAULT_API_URL +
28 | '?family=Font1:bold%7CFont2:italic%7CFont3' +
29 | '&subset=greek,cyrillic');
30 | });
31 |
32 | it('should build a proper url', function () {
33 | var builder = new FontApiUrlBuilder(undefined);
34 | builder.setFontFamilies(['Font1:bold,italic:greek,cyrillic', 'Font2:italic', 'Font3::latin']);
35 | expect(builder.build()).toEqual(
36 | FontApiUrlBuilder.DEFAULT_API_URL +
37 | '?family=Font1:bold,italic%7CFont2:italic%7CFont3' +
38 | '&subset=greek,cyrillic,latin');
39 | });
40 | });
41 |
--------------------------------------------------------------------------------
/spec/modules/google/googlefontapi_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.google.GoogleFontApi', function () {
2 | var GoogleFontApi = webfont.modules.google.GoogleFontApi,
3 | Any = jasmine.Matchers.Any,
4 | Font = webfont.Font,
5 | link = '',
6 | insert = '',
7 | onload = null,
8 | fakeDomHelper = {
9 | whenBodyExists: function (callback) {
10 | callback();
11 | },
12 | loadStylesheet: function (cssLink, cb) {
13 | link = cssLink;
14 | onload = cb;
15 | }
16 | };
17 |
18 |
19 | beforeEach(function () {
20 | insert = '';
21 | link = '';
22 | onload = null;
23 | });
24 |
25 | function notifySheetsLoaded() {
26 | if (onload)
27 | onload();
28 | };
29 |
30 | describe('call onReady with font family loading', function () {
31 | var googleFontApi = null,
32 | fonts = null;
33 |
34 | beforeEach(function () {
35 | googleFontApi = new GoogleFontApi(fakeDomHelper, { families: ['Font1', 'Font2'] });
36 | googleFontApi.load(function (f) {
37 | fonts = f;
38 | });
39 | });
40 |
41 | it('has inserted the link element correctly', function () {
42 | expect(link).toEqual('https://fonts.googleapis.com/css?family=Font1%7CFont2');
43 | });
44 |
45 | it('has the correct families', function () {
46 | notifySheetsLoaded();
47 | expect(fonts).not.toBeNull();
48 | expect(fonts.length).toEqual(2);
49 | expect(fonts[0]).toEqual(new Font('Font1'));
50 | expect(fonts[1]).toEqual(new Font('Font2'));
51 | });
52 | });
53 |
54 | describe('call onReady with font family loading and custom API url', function () {
55 | var googleFontApi = null;
56 | var loaded = false;
57 |
58 | beforeEach(function () {
59 | loaded = false;
60 | googleFontApi = new GoogleFontApi(fakeDomHelper, {
61 | api: 'https://moo',
62 | families: ['Font1', 'Font2']
63 | });
64 | googleFontApi.load(function () { loaded = true; });
65 | });
66 |
67 | it('has inserted the link element correctly', function () {
68 | expect(link).toEqual('https://moo?family=Font1%7CFont2');
69 | });
70 |
71 | if (webfont.DomHelper.CAN_WAIT_STYLESHEET) {
72 | it('does not call onReady until sheets are loaded', function () {
73 | expect(onload).toMatch(new Any(Function));
74 | expect(loaded).toBe(false);
75 |
76 | notifySheetsLoaded();
77 | expect(loaded).toBe(true);
78 | });
79 | }
80 | });
81 |
82 | describe('spaces replaced by plus', function () {
83 | var googleFontApi = null;
84 |
85 | beforeEach(function () {
86 | googleFontApi = new GoogleFontApi(fakeDomHelper, { families: ['Font1 WithSpace', 'Font2 WithSpaceToo'] });
87 | googleFontApi.load(function () {});
88 | });
89 |
90 | it('has inserted the link element correctly', function () {
91 | expect(link).toEqual('https://fonts.googleapis.com/css?family=Font1+WithSpace%7CFont2+WithSpaceToo');
92 | });
93 | });
94 |
95 | describe('load with variations', function () {
96 | var googleFontApi = null;
97 |
98 | beforeEach(function () {
99 | googleFontApi = new GoogleFontApi(fakeDomHelper, { families: ['Font1 WithSpace:bi', 'Font2 WithSpaceToo:b,r'] });
100 | googleFontApi.load(function () {});
101 | });
102 |
103 | it('has inserted the link element correctly', function () {
104 | expect(link).toEqual('https://fonts.googleapis.com/css?family=Font1+WithSpace:bi%7CFont2+WithSpaceToo:b,r');
105 | });
106 | });
107 | });
108 |
--------------------------------------------------------------------------------
/spec/modules/monotype_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.Monotype', function () {
2 | var Monotype = webfont.modules.Monotype,
3 | Font = webfont.Font,
4 | BrowserInfo = webfont.BrowserInfo,
5 | UserAgent = webfont.UserAgent,
6 | Version = webfont.Version;
7 |
8 | var configuration = {
9 | projectId: '01e2ff27-25bf-4801-a23e-73d328e6c7cc',
10 | api: 'https://fast.fonts.net/jsapidev'
11 | };
12 |
13 | var fakeDomHelper = null,
14 | global = null,
15 | script = {},
16 | monotype = null,
17 | load = null,
18 | support = null;
19 |
20 | beforeEach(function () {
21 | global = {};
22 |
23 | fakeDomHelper = {
24 | loadScript: jasmine.createSpy('loadScript').andCallFake(function (src, callback) {
25 | script.onload = callback;
26 | return script;
27 | }),
28 | getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global)
29 | };
30 | support = jasmine.createSpy('support');
31 | load = jasmine.createSpy('load');
32 |
33 | monotype = new Monotype(fakeDomHelper, configuration);
34 | monotype.load(load);
35 |
36 | global[Monotype.HOOK + configuration.projectId] = function () {
37 | return [{fontfamily: 'aachen bold'}, {fontfamily: 'kid print regular'}];
38 | };
39 |
40 | script.onload();
41 | });
42 |
43 |
44 | it('should create a script element', function () {
45 | expect(fakeDomHelper.loadScript).toHaveBeenCalled();
46 | expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('https://fast.fonts.net/jsapidev/01e2ff27-25bf-4801-a23e-73d328e6c7cc.js');
47 | expect(load).toHaveBeenCalledWith([new Font('aachen bold'), new Font('kid print regular')]);
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/spec/modules/typekit_spec.js:
--------------------------------------------------------------------------------
1 | describe('modules.Typekit', function () {
2 | var Typekit = webfont.modules.Typekit,
3 | Font = webfont.Font;
4 |
5 | var configuration = {
6 | id: 'abc'
7 | };
8 |
9 | var fakeDomHelper = null,
10 | global = {},
11 | load = null,
12 | onReady = null;
13 |
14 | beforeEach(function () {
15 | global = {
16 | Typekit: {
17 | config: {
18 | fn: ['Font1', ['n4'], 'Font2', ['n4', 'n7']]
19 | },
20 | load: jasmine.createSpy('load')
21 | }
22 | };
23 |
24 | onReady = jasmine.createSpy('onReady');
25 |
26 | load = jasmine.createSpy('load');
27 |
28 | fakeDomHelper = {
29 | loadScript: jasmine.createSpy('loadScript').andCallFake(function (url, cb) {
30 | cb(null);
31 | }),
32 | getLoadWindow: jasmine.createSpy('getLoadWindow').andReturn(global)
33 | };
34 | });
35 |
36 | it('should load with variations', function () {
37 | var typekit = new Typekit(fakeDomHelper, configuration);
38 |
39 | typekit.load(onReady);
40 |
41 | expect(fakeDomHelper.loadScript).toHaveBeenCalled();
42 | expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('https://use.typekit.net/abc.js');
43 |
44 | expect(global.Typekit.load).toHaveBeenCalled();
45 | typekit.load(load);
46 |
47 | expect(load).toHaveBeenCalledWith([new Font('Font1', 'n4'), new Font('Font2', 'n4'), new Font('Font2', 'n7')]);
48 | });
49 |
50 | it('should load through the alternative API', function () {
51 | var typekit = new Typekit(fakeDomHelper, { id: 'abc', api: '/test' });
52 |
53 | typekit.load(onReady);
54 |
55 | expect(fakeDomHelper.loadScript).toHaveBeenCalled();
56 | expect(fakeDomHelper.loadScript.calls[0].args[0]).toEqual('/test/abc.js');
57 | });
58 |
59 | it('should not load without a kit id', function () {
60 | var typekit = new Typekit(fakeDomHelper, { id: null });
61 |
62 | typekit.load(onReady);
63 |
64 | expect(fakeDomHelper.loadScript).not.toHaveBeenCalled();
65 |
66 | typekit.load(load);
67 |
68 | expect(load).toHaveBeenCalledWith([]);
69 | });
70 | });
71 |
--------------------------------------------------------------------------------
/src/closure.js:
--------------------------------------------------------------------------------
1 | /* Web Font Loader v{{version}} - (c) Adobe Systems, Google. License: Apache 2.0 */
2 | (function(){{{source}}}());
3 |
--------------------------------------------------------------------------------
/src/core/cssclassname.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.CssClassName');
2 |
3 | /**
4 | * Handles sanitization and construction of css class names.
5 | * @param {string=} opt_joinChar The character to join parts of the name on.
6 | * Defaults to '-'.
7 | * @constructor
8 | */
9 | webfont.CssClassName = function(opt_joinChar) {
10 | /** @type {string} */
11 | this.joinChar_ = opt_joinChar || webfont.CssClassName.DEFAULT_JOIN_CHAR;
12 | };
13 |
14 | /**
15 | * @const
16 | * @type {string}
17 | */
18 | webfont.CssClassName.DEFAULT_JOIN_CHAR = '-';
19 |
20 | goog.scope(function () {
21 | var CssClassName = webfont.CssClassName;
22 |
23 | /**
24 | * Sanitizes a string for use as a css class name. Removes non-word and
25 | * underscore characters.
26 | * @param {string} name The string.
27 | * @return {string} The sanitized string.
28 | */
29 | CssClassName.prototype.sanitize = function(name) {
30 | return name.replace(/[\W_]+/g, '').toLowerCase();
31 | };
32 |
33 | /**
34 | * Builds a complete css class name given a variable number of parts.
35 | * Sanitizes, then joins the parts together.
36 | * @param {...string} var_args The parts to join.
37 | * @return {string} The sanitized and joined string.
38 | */
39 | CssClassName.prototype.build = function(var_args) {
40 | var parts = []
41 | for (var i = 0; i < arguments.length; i++) {
42 | parts.push(this.sanitize(arguments[i]));
43 | }
44 | return parts.join(this.joinChar_);
45 | };
46 | });
47 |
--------------------------------------------------------------------------------
/src/core/eventdispatcher.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.EventDispatcher');
2 |
3 | goog.require('webfont.CssClassName');
4 |
5 | /**
6 | * A class to dispatch events and manage the event class names on an html
7 | * element that represent the current state of fonts on the page. Active class
8 | * names always overwrite inactive class names of the same type, while loading
9 | * class names may be present whenever a font is loading (regardless of if an
10 | * associated active or inactive class name is also present).
11 | *
12 | * @param {webfont.DomHelper} domHelper
13 | * @param {Object} config
14 | * @constructor
15 | */
16 | webfont.EventDispatcher = function(domHelper, config) {
17 | this.domHelper_ = domHelper;
18 | this.htmlElement_ = domHelper.getLoadWindow().document.documentElement;
19 | this.callbacks_ = config;
20 | this.namespace_ = webfont.EventDispatcher.DEFAULT_NAMESPACE;
21 | this.cssClassName_ = new webfont.CssClassName('-');
22 | this.dispatchEvents_ = config['events'] !== false;
23 | this.setClasses_ = config['classes'] !== false;
24 | };
25 |
26 | /**
27 | * @const
28 | * @type {string}
29 | */
30 | webfont.EventDispatcher.DEFAULT_NAMESPACE = 'wf';
31 |
32 | /**
33 | * @const
34 | * @type {string}
35 | */
36 | webfont.EventDispatcher.LOADING = 'loading';
37 |
38 | /**
39 | * @const
40 | * @type {string}
41 | */
42 | webfont.EventDispatcher.ACTIVE = 'active';
43 |
44 | /**
45 | * @const
46 | * @type {string}
47 | */
48 | webfont.EventDispatcher.INACTIVE = 'inactive';
49 |
50 | /**
51 | * @const
52 | * @type {string}
53 | */
54 | webfont.EventDispatcher.FONT = 'font';
55 |
56 | goog.scope(function () {
57 | var EventDispatcher = webfont.EventDispatcher;
58 |
59 | /**
60 | * Dispatch the loading event and append the loading class name.
61 | */
62 | EventDispatcher.prototype.dispatchLoading = function() {
63 | if (this.setClasses_) {
64 | this.domHelper_.updateClassName(this.htmlElement_,
65 | [
66 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.LOADING)
67 | ]
68 | );
69 | }
70 |
71 | this.dispatch_(webfont.EventDispatcher.LOADING);
72 | };
73 |
74 | /**
75 | * Dispatch the font loading event and append the font loading class name.
76 | * @param {webfont.Font} font
77 | */
78 | EventDispatcher.prototype.dispatchFontLoading = function(font) {
79 | if (this.setClasses_) {
80 | this.domHelper_.updateClassName(this.htmlElement_,
81 | [
82 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.LOADING)
83 | ]
84 | );
85 | }
86 |
87 | this.dispatch_(webfont.EventDispatcher.FONT + webfont.EventDispatcher.LOADING, font);
88 | };
89 |
90 | /**
91 | * Dispatch the font active event, remove the font loading class name, remove
92 | * the font inactive class name, and append the font active class name.
93 | * @param {webfont.Font} font
94 | */
95 | EventDispatcher.prototype.dispatchFontActive = function(font) {
96 | if (this.setClasses_) {
97 | this.domHelper_.updateClassName(
98 | this.htmlElement_,
99 | [
100 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.ACTIVE)
101 | ],
102 | [
103 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.LOADING),
104 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.INACTIVE)
105 | ]
106 | );
107 | }
108 |
109 | this.dispatch_(webfont.EventDispatcher.FONT + webfont.EventDispatcher.ACTIVE, font);
110 | };
111 |
112 | /**
113 | * Dispatch the font inactive event, remove the font loading class name, and
114 | * append the font inactive class name (unless the font active class name is
115 | * already present).
116 | * @param {webfont.Font} font
117 | */
118 | EventDispatcher.prototype.dispatchFontInactive = function(font) {
119 | if (this.setClasses_) {
120 | var hasFontActive = this.domHelper_.hasClassName(this.htmlElement_,
121 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.ACTIVE)
122 | ),
123 | add = [],
124 | remove = [
125 | this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.LOADING)
126 | ];
127 |
128 | if (!hasFontActive) {
129 | add.push(this.cssClassName_.build(this.namespace_, font.getName(), font.getVariation().toString(), webfont.EventDispatcher.INACTIVE));
130 | }
131 |
132 | this.domHelper_.updateClassName(this.htmlElement_, add, remove);
133 | }
134 |
135 | this.dispatch_(webfont.EventDispatcher.FONT + webfont.EventDispatcher.INACTIVE, font);
136 | };
137 |
138 | /**
139 | * Dispatch the inactive event, remove the loading class name, and append the
140 | * inactive class name (unless the active class name is already present).
141 | */
142 | EventDispatcher.prototype.dispatchInactive = function() {
143 | if (this.setClasses_) {
144 | var hasActive = this.domHelper_.hasClassName(this.htmlElement_,
145 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.ACTIVE)
146 | ),
147 | add = [],
148 | remove = [
149 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.LOADING)
150 | ];
151 |
152 | if (!hasActive) {
153 | add.push(this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.INACTIVE));
154 | }
155 |
156 | this.domHelper_.updateClassName(this.htmlElement_, add, remove);
157 | }
158 |
159 | this.dispatch_(webfont.EventDispatcher.INACTIVE);
160 | };
161 |
162 | /**
163 | * Dispatch the active event, remove the loading class name, remove the inactive
164 | * class name, and append the active class name.
165 | */
166 | EventDispatcher.prototype.dispatchActive = function() {
167 | if (this.setClasses_) {
168 | this.domHelper_.updateClassName(this.htmlElement_,
169 | [
170 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.ACTIVE)
171 | ],
172 | [
173 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.LOADING),
174 | this.cssClassName_.build(this.namespace_, webfont.EventDispatcher.INACTIVE)
175 | ]
176 | );
177 | }
178 |
179 | this.dispatch_(webfont.EventDispatcher.ACTIVE);
180 | };
181 |
182 | /**
183 | * @param {string} event
184 | * @param {webfont.Font=} opt_font
185 | */
186 | EventDispatcher.prototype.dispatch_ = function(event, opt_font) {
187 | if (this.dispatchEvents_ && this.callbacks_[event]) {
188 | if (opt_font) {
189 | this.callbacks_[event](opt_font.getName(), opt_font.getVariation());
190 | } else {
191 | this.callbacks_[event]();
192 | }
193 | }
194 | };
195 | });
196 |
--------------------------------------------------------------------------------
/src/core/font.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.Font');
2 |
3 | /**
4 | * This class is an abstraction for a single font or typeface.
5 | * It contains the font name and the variation (i.e. style
6 | * and weight.) A collection Font instances can represent a
7 | * font family.
8 | *
9 | * @constructor
10 | * @param {string} name The font family name
11 | * @param {string=} opt_variation A font variation description
12 | */
13 | webfont.Font = function (name, opt_variation) {
14 | this.name_ = name;
15 | this.weight_ = 4;
16 | this.style_ = 'n'
17 |
18 | var variation = opt_variation || 'n4',
19 | match = variation.match(/^([nio])([1-9])$/i);
20 |
21 | if (match) {
22 | this.style_ = match[1];
23 | this.weight_ = parseInt(match[2], 10);
24 | }
25 | };
26 |
27 | goog.scope(function () {
28 | var Font = webfont.Font;
29 |
30 | /**
31 | * @return {string}
32 | */
33 | Font.prototype.getName = function () {
34 | return this.name_;
35 | };
36 |
37 | /**
38 | * @return {string}
39 | */
40 | Font.prototype.getCssName = function () {
41 | return this.quote_(this.name_);
42 | };
43 |
44 | /**
45 | * Returns a CSS string representation of the font that
46 | * can be used as the CSS font property shorthand.
47 | *
48 | * @return {string}
49 | */
50 | Font.prototype.toCssString = function () {
51 | return this.getCssStyle() + ' ' + this.getCssWeight() + ' 300px ' + this.getCssName();
52 | };
53 |
54 | /**
55 | * @private
56 | * @param {string} name
57 | * @return {string}
58 | */
59 | Font.prototype.quote_ = function (name) {
60 | var quoted = [];
61 | var split = name.split(/,\s*/);
62 | for (var i = 0; i < split.length; i++) {
63 | var part = split[i].replace(/['"]/g, '');
64 | if (part.indexOf(' ') == -1 && !(/^\d/.test(part))) {
65 | quoted.push(part);
66 | } else {
67 | quoted.push("'" + part + "'");
68 | }
69 | }
70 | return quoted.join(',');
71 | };
72 |
73 | /**
74 | * @return {string}
75 | */
76 | Font.prototype.getVariation = function () {
77 | return this.style_ + this.weight_;
78 | };
79 |
80 | /**
81 | * @return {string}
82 | */
83 | Font.prototype.getCssVariation = function () {
84 | return 'font-style:' + this.getCssStyle() + ';font-weight:' + this.getCssWeight() + ';';
85 | };
86 |
87 | /**
88 | * @return {string}
89 | */
90 | Font.prototype.getCssWeight = function () {
91 | return this.weight_ + '00';
92 | };
93 |
94 | /**
95 | * @return {string}
96 | */
97 | Font.prototype.getCssStyle = function () {
98 | var style = 'normal';
99 |
100 | if (this.style_ === 'o') {
101 | style = 'oblique';
102 | } else if (this.style_ === 'i') {
103 | style = 'italic';
104 | }
105 |
106 | return style;
107 | };
108 |
109 | /**
110 | * Parses a CSS font declaration and returns a font
111 | * variation description.
112 | *
113 | * @param {string} css
114 | * @return {string}
115 | */
116 | Font.parseCssVariation = function (css) {
117 | var weight = 4,
118 | style = 'n',
119 | m = null;
120 |
121 | if (css) {
122 | m = css.match(/(normal|oblique|italic)/i);
123 |
124 | if (m && m[1]) {
125 | style = m[1].substr(0, 1).toLowerCase();
126 | }
127 |
128 | m = css.match(/([1-9]00|normal|bold)/i);
129 |
130 | if (m && m[1]) {
131 | if (/bold/i.test(m[1])) {
132 | weight = 7;
133 | } else if (/[1-9]00/.test(m[1])) {
134 | weight = parseInt(m[1].substr(0, 1), 10);
135 | }
136 | }
137 | }
138 | return style + weight;
139 | }
140 | });
141 |
--------------------------------------------------------------------------------
/src/core/fontmodule.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.FontModule');
2 |
3 | /**
4 | * @interface
5 | */
6 | webfont.FontModule = function () {};
7 |
8 | goog.scope(function () {
9 | var FontModule = webfont.FontModule;
10 |
11 | /**
12 | * @param {function(Array., webfont.FontTestStrings=, Object.=)} onReady
13 | */
14 | FontModule.prototype.load = function (onReady) {};
15 | });
16 |
17 |
--------------------------------------------------------------------------------
/src/core/fontmoduleloader.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.FontModuleLoader');
2 | goog.provide('webfont.FontModuleFactory');
3 |
4 | /** @typedef {function(Object, webfont.DomHelper): webfont.FontModule} */
5 | webfont.FontModuleFactory;
6 |
7 | /**
8 | * @constructor
9 | */
10 | webfont.FontModuleLoader = function() {
11 | /**
12 | * @type {Object.}
13 | */
14 | this.modules_ = {};
15 | };
16 |
17 | goog.scope(function () {
18 | var FontModuleLoader = webfont.FontModuleLoader;
19 |
20 | /**
21 | * @param {string} name
22 | * @param {webfont.FontModuleFactory} factory
23 | */
24 | FontModuleLoader.prototype.addModuleFactory = function(name, factory) {
25 | this.modules_[name] = factory;
26 | };
27 |
28 | /**
29 | * @param {Object} configuration
30 | * @param {webfont.DomHelper} domHelper
31 | * @return {Array.}
32 | */
33 | FontModuleLoader.prototype.getModules = function(configuration, domHelper) {
34 | var modules = [];
35 |
36 | for (var key in configuration) {
37 | if (configuration.hasOwnProperty(key)) {
38 | var moduleFactory = this.modules_[key];
39 |
40 | if (moduleFactory) {
41 | modules.push(moduleFactory(configuration[key], domHelper));
42 | }
43 | }
44 | }
45 | return modules;
46 | };
47 | });
48 |
--------------------------------------------------------------------------------
/src/core/fontruler.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.FontRuler');
2 |
3 | /**
4 | * An element that can be used to measure the metrics
5 | * of a given font and string.
6 | * @constructor
7 | * @param {webfont.DomHelper} domHelper
8 | * @param {string} fontTestString
9 | */
10 | webfont.FontRuler = function (domHelper, fontTestString) {
11 | this.domHelper_ = domHelper;
12 | this.fontTestString_ = fontTestString;
13 | this.el_ = this.domHelper_.createElement('span', {
14 | "aria-hidden": "true"
15 | }, this.fontTestString_);
16 | };
17 |
18 | goog.scope(function () {
19 | var FontRuler = webfont.FontRuler;
20 |
21 | /**
22 | * @param {webfont.Font} font
23 | */
24 | FontRuler.prototype.setFont = function(font) {
25 | this.domHelper_.setStyle(this.el_, this.computeStyleString_(font));
26 | };
27 |
28 | /**
29 | * Inserts the ruler into the DOM.
30 | */
31 | FontRuler.prototype.insert = function() {
32 | this.domHelper_.insertInto('body', this.el_);
33 | };
34 |
35 | /**
36 | * @private
37 | * @param {webfont.Font} font
38 | * @return {string}
39 | */
40 | FontRuler.prototype.computeStyleString_ = function(font) {
41 | return "display:block;position:absolute;top:-9999px;left:-9999px;" +
42 | "font-size:300px;width:auto;height:auto;line-height:normal;margin:0;" +
43 | "padding:0;font-variant:normal;white-space:nowrap;font-family:" +
44 | font.getCssName() + ";" + font.getCssVariation();
45 | };
46 |
47 | /**
48 | * @return {number}
49 | */
50 | FontRuler.prototype.getWidth = function() {
51 | return this.el_.offsetWidth;
52 | };
53 |
54 | /**
55 | * Removes the ruler element from the DOM.
56 | */
57 | FontRuler.prototype.remove = function() {
58 | this.domHelper_.removeElement(this.el_);
59 | };
60 | });
61 |
--------------------------------------------------------------------------------
/src/core/fontwatcher.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.FontWatcher');
2 |
3 | goog.require('webfont.FontWatchRunner');
4 | goog.require('webfont.NativeFontWatchRunner');
5 |
6 | /**
7 | * @typedef {Object.>}
8 | */
9 | webfont.FontTestStrings;
10 |
11 | /**
12 | * @constructor
13 | * @param {webfont.DomHelper} domHelper
14 | * @param {webfont.EventDispatcher} eventDispatcher
15 | * @param {number=} opt_timeout
16 | */
17 | webfont.FontWatcher = function(domHelper, eventDispatcher, opt_timeout) {
18 | this.domHelper_ = domHelper;
19 | this.eventDispatcher_ = eventDispatcher;
20 | this.currentlyWatched_ = 0;
21 | this.last_ = false;
22 | this.success_ = false;
23 | this.timeout_ = opt_timeout;
24 | };
25 |
26 | goog.scope(function () {
27 | var FontWatcher = webfont.FontWatcher,
28 | FontWatchRunner = webfont.FontWatchRunner,
29 | NativeFontWatchRunner = webfont.NativeFontWatchRunner;
30 |
31 | /**
32 | * @type {null|boolean}
33 | */
34 | FontWatcher.SHOULD_USE_NATIVE_LOADER = null;
35 |
36 | /**
37 | * @return {string}
38 | */
39 | FontWatcher.getUserAgent = function () {
40 | return window.navigator.userAgent;
41 | };
42 |
43 | /**
44 | * @return {string}
45 | */
46 | FontWatcher.getVendor = function () {
47 | return window.navigator.vendor;
48 | };
49 |
50 | /**
51 | * Returns true if this browser has support for
52 | * the CSS font loading API.
53 | *
54 | * @return {boolean}
55 | */
56 | FontWatcher.shouldUseNativeLoader = function () {
57 | if (FontWatcher.SHOULD_USE_NATIVE_LOADER === null) {
58 | if (!!window.FontFace) {
59 | var match = /Gecko.*Firefox\/(\d+)/.exec(FontWatcher.getUserAgent());
60 | var safari10Match = /OS X.*Version\/10\..*Safari/.exec(FontWatcher.getUserAgent()) && /Apple/.exec(FontWatcher.getVendor());
61 |
62 | if (match) {
63 | FontWatcher.SHOULD_USE_NATIVE_LOADER = parseInt(match[1], 10) > 42;
64 | } else if (safari10Match) {
65 | FontWatcher.SHOULD_USE_NATIVE_LOADER = false;
66 | } else {
67 | FontWatcher.SHOULD_USE_NATIVE_LOADER = true;
68 | }
69 | } else {
70 | FontWatcher.SHOULD_USE_NATIVE_LOADER = false;
71 | }
72 | }
73 | return FontWatcher.SHOULD_USE_NATIVE_LOADER;
74 | };
75 |
76 | /**
77 | * Watches a set of font families.
78 | * @param {Array.} fonts The fonts to watch.
79 | * @param {webfont.FontTestStrings} fontTestStrings The font test strings for
80 | * each family.
81 | * @param {Object.} metricCompatibleFonts
82 | * @param {boolean} last True if this is the last set of fonts to watch.
83 | */
84 | FontWatcher.prototype.watchFonts = function(fonts,
85 | fontTestStrings, metricCompatibleFonts, last) {
86 | var length = fonts.length,
87 | testStrings = fontTestStrings || {};
88 |
89 | if (length === 0 && last) {
90 | this.eventDispatcher_.dispatchInactive();
91 | return;
92 | }
93 |
94 | this.currentlyWatched_ += fonts.length;
95 |
96 | if (last) {
97 | this.last_ = last;
98 | }
99 |
100 | var i, fontWatchRunners = [];
101 | for (i = 0; i < fonts.length; i++) {
102 | var font = fonts[i],
103 | testString = testStrings[font.getName()];
104 |
105 | this.eventDispatcher_.dispatchFontLoading(font);
106 |
107 | var fontWatchRunner = null;
108 |
109 | if (FontWatcher.shouldUseNativeLoader()) {
110 | fontWatchRunner = new NativeFontWatchRunner(
111 | goog.bind(this.fontActive_, this),
112 | goog.bind(this.fontInactive_, this),
113 | this.domHelper_,
114 | font,
115 | this.timeout_,
116 | testString
117 | );
118 | } else {
119 | fontWatchRunner = new FontWatchRunner(
120 | goog.bind(this.fontActive_, this),
121 | goog.bind(this.fontInactive_, this),
122 | this.domHelper_,
123 | font,
124 | this.timeout_,
125 | metricCompatibleFonts,
126 | testString
127 | );
128 | }
129 |
130 | fontWatchRunners.push(fontWatchRunner);
131 | }
132 |
133 | for (i = 0; i < fontWatchRunners.length; i++) {
134 | fontWatchRunners[i].start();
135 | }
136 | };
137 |
138 | /**
139 | * Called by a FontWatchRunner when a font has been detected as active.
140 | * @param {webfont.Font} font
141 | * @private
142 | */
143 | FontWatcher.prototype.fontActive_ = function(font) {
144 | this.eventDispatcher_.dispatchFontActive(font);
145 | this.success_ = true;
146 | this.decreaseCurrentlyWatched_();
147 | };
148 |
149 | /**
150 | * Called by a FontWatchRunner when a font has been detected as inactive.
151 | * @param {webfont.Font} font
152 | * @private
153 | */
154 | FontWatcher.prototype.fontInactive_ = function(font) {
155 | this.eventDispatcher_.dispatchFontInactive(font);
156 | this.decreaseCurrentlyWatched_();
157 | };
158 |
159 | /**
160 | * @private
161 | */
162 | FontWatcher.prototype.decreaseCurrentlyWatched_ = function() {
163 | if (--this.currentlyWatched_ == 0 && this.last_) {
164 | if (this.success_) {
165 | this.eventDispatcher_.dispatchActive();
166 | } else {
167 | this.eventDispatcher_.dispatchInactive();
168 | }
169 | }
170 | };
171 | });
172 |
--------------------------------------------------------------------------------
/src/core/initialize.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont');
2 |
3 | goog.require('webfont.WebFont');
4 |
5 | goog.require('webfont.modules.Typekit');
6 | goog.require('webfont.modules.Fontdeck');
7 | goog.require('webfont.modules.Monotype');
8 | goog.require('webfont.modules.Custom');
9 | goog.require('webfont.modules.google.GoogleFontApi');
10 |
11 | /**
12 | * @define {boolean}
13 | */
14 | var INCLUDE_CUSTOM_MODULE = false;
15 |
16 | /**
17 | * @define {boolean}
18 | */
19 | var INCLUDE_FONTDECK_MODULE = false;
20 |
21 | /**
22 | * @define {boolean}
23 | */
24 | var INCLUDE_MONOTYPE_MODULE = false;
25 |
26 | /**
27 | * @define {boolean}
28 | */
29 | var INCLUDE_TYPEKIT_MODULE = false;
30 |
31 | /**
32 | * @define {boolean}
33 | */
34 | var INCLUDE_GOOGLE_MODULE = false;
35 |
36 | /**
37 | * @define {string}
38 | */
39 | var WEBFONT = 'WebFont';
40 |
41 | /**
42 | * @define {string}
43 | */
44 | var WEBFONT_CONFIG = 'WebFontConfig';
45 |
46 | /**
47 | * @type {webfont.WebFont}
48 | */
49 | var webFontLoader = new webfont.WebFont(window);
50 |
51 | if (INCLUDE_CUSTOM_MODULE) {
52 | webFontLoader.addModule(webfont.modules.Custom.NAME, function (configuration, domHelper) {
53 | return new webfont.modules.Custom(domHelper, configuration);
54 | });
55 | }
56 |
57 | if (INCLUDE_FONTDECK_MODULE) {
58 | webFontLoader.addModule(webfont.modules.Fontdeck.NAME, function (configuration, domHelper) {
59 | return new webfont.modules.Fontdeck(domHelper, configuration);
60 | });
61 | }
62 |
63 | if (INCLUDE_MONOTYPE_MODULE) {
64 | webFontLoader.addModule(webfont.modules.Monotype.NAME, function (configuration, domHelper) {
65 | return new webfont.modules.Monotype(domHelper, configuration);
66 | });
67 | }
68 |
69 | if (INCLUDE_TYPEKIT_MODULE) {
70 | webFontLoader.addModule(webfont.modules.Typekit.NAME, function (configuration, domHelper) {
71 | return new webfont.modules.Typekit(domHelper, configuration);
72 | });
73 | }
74 |
75 | if (INCLUDE_GOOGLE_MODULE) {
76 | webFontLoader.addModule(webfont.modules.google.GoogleFontApi.NAME, function (configuration, domHelper) {
77 | return new webfont.modules.google.GoogleFontApi(domHelper, configuration);
78 | });
79 | }
80 |
81 | var exports = {
82 | 'load': goog.bind(webFontLoader.load, webFontLoader)
83 | };
84 |
85 | if (typeof define === "function" && define.amd) {
86 | define(function () {
87 | return exports;
88 | });
89 | } else if (typeof module !== "undefined" && module.exports) {
90 | module.exports = exports;
91 | } else {
92 | window[WEBFONT] = exports;
93 |
94 | if (window[WEBFONT_CONFIG]) {
95 | webFontLoader.load(window[WEBFONT_CONFIG]);
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/core/nativefontwatchrunner.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.NativeFontWatchRunner');
2 |
3 | goog.require('webfont.Font');
4 |
5 | goog.scope(function () {
6 | /**
7 | * @constructor
8 | * @param {function(webfont.Font)} activeCallback
9 | * @param {function(webfont.Font)} inactiveCallback
10 | * @param {webfont.DomHelper} domHelper
11 | * @param {webfont.Font} font
12 | * @param {number=} opt_timeout
13 | * @param {string=} opt_fontTestString
14 | */
15 | webfont.NativeFontWatchRunner = function(activeCallback, inactiveCallback, domHelper, font, opt_timeout, opt_fontTestString) {
16 | this.activeCallback_ = activeCallback;
17 | this.inactiveCallback_ = inactiveCallback;
18 | this.font_ = font;
19 | this.domHelper_ = domHelper;
20 | this.timeout_ = opt_timeout || 3000;
21 | this.fontTestString_ = opt_fontTestString || undefined;
22 | };
23 |
24 | var NativeFontWatchRunner = webfont.NativeFontWatchRunner;
25 |
26 | NativeFontWatchRunner.prototype.start = function () {
27 | var doc = this.domHelper_.getLoadWindow().document,
28 | that = this;
29 |
30 | var start = goog.now();
31 |
32 | var loader = new Promise(function (resolve, reject) {
33 | var check = function () {
34 | var now = goog.now();
35 |
36 | if (now - start >= that.timeout_) {
37 | reject();
38 | } else {
39 | doc.fonts.load(that.font_.toCssString(), that.fontTestString_).then(function (fonts) {
40 | if (fonts.length >= 1) {
41 | resolve();
42 | } else {
43 | setTimeout(check, 25);
44 | }
45 | }, function () {
46 | reject();
47 | });
48 | }
49 | };
50 |
51 | check();
52 | });
53 |
54 | var timeoutId = null,
55 | timer = new Promise(function (resolve, reject) {
56 | timeoutId = setTimeout(reject, that.timeout_);
57 | });
58 |
59 | Promise.race([timer, loader]).then(function () {
60 | if (timeoutId) {
61 | clearTimeout(timeoutId);
62 | timeoutId = null;
63 | }
64 | that.activeCallback_(that.font_);
65 | }, function () {
66 | that.inactiveCallback_(that.font_);
67 | });
68 | };
69 | });
70 |
--------------------------------------------------------------------------------
/src/core/stylesheetwaiter.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.StyleSheetWaiter');
2 |
3 | /**
4 | * A utility class for handling callback from DomHelper.loadStylesheet().
5 | *
6 | * @constructor
7 | */
8 | webfont.StyleSheetWaiter = function() {
9 | /** @private @type {number} */
10 | this.waitingCount_ = 0;
11 | /** @private @type {Function} */
12 | this.onReady_ = null;
13 | };
14 |
15 | goog.scope(function () {
16 | var StyleSheetWaiter = webfont.StyleSheetWaiter;
17 |
18 | /**
19 | * @return {function(Error)}
20 | */
21 | StyleSheetWaiter.prototype.startWaitingLoad = function() {
22 | var self = this;
23 | self.waitingCount_++;
24 | return function(error) {
25 | self.waitingCount_--;
26 | self.fireIfReady_();
27 | };
28 | };
29 |
30 | /**
31 | * @param {Function} fn
32 | */
33 | StyleSheetWaiter.prototype.waitWhileNeededThen = function(fn) {
34 | this.onReady_ = fn;
35 | this.fireIfReady_();
36 | };
37 |
38 | /**
39 | * @private
40 | */
41 | StyleSheetWaiter.prototype.fireIfReady_ = function() {
42 | var isReady = 0 == this.waitingCount_;
43 | if (isReady && this.onReady_) {
44 | this.onReady_();
45 | this.onReady_ = null;
46 | }
47 | };
48 | });
49 |
--------------------------------------------------------------------------------
/src/core/webfont.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.WebFont');
2 |
3 | goog.require('webfont.DomHelper');
4 | goog.require('webfont.EventDispatcher');
5 | goog.require('webfont.FontWatcher');
6 | goog.require('webfont.FontModuleLoader');
7 |
8 | /**
9 | * @param {Window} mainWindow The main application window containing
10 | * webfontloader.js.
11 | * @constructor
12 | */
13 | webfont.WebFont = function(mainWindow) {
14 | this.mainWindow_ = mainWindow;
15 | this.fontModuleLoader_ = new webfont.FontModuleLoader();
16 | this.moduleLoading_ = 0;
17 | this.events_ = true;
18 | this.classes_ = true;
19 | };
20 |
21 | goog.scope(function () {
22 | var WebFont = webfont.WebFont,
23 | DomHelper = webfont.DomHelper,
24 | EventDispatcher = webfont.EventDispatcher,
25 | FontWatcher = webfont.FontWatcher;
26 |
27 | /**
28 | * @param {string} name
29 | * @param {webfont.FontModuleFactory} factory
30 | */
31 | WebFont.prototype.addModule = function(name, factory) {
32 | this.fontModuleLoader_.addModuleFactory(name, factory);
33 | };
34 |
35 | /**
36 | * @param {Object} configuration
37 | */
38 | WebFont.prototype.load = function(configuration) {
39 | var context = configuration['context'] || this.mainWindow_;
40 | this.domHelper_ = new DomHelper(this.mainWindow_, context);
41 |
42 | this.events_ = configuration['events'] !== false;
43 | this.classes_ = configuration['classes'] !== false;
44 |
45 | var eventDispatcher = new EventDispatcher(
46 | this.domHelper_,
47 | configuration
48 | );
49 |
50 | this.load_(eventDispatcher, configuration);
51 | };
52 |
53 | /**
54 | * @param {webfont.EventDispatcher} eventDispatcher
55 | * @param {webfont.FontWatcher} fontWatcher
56 | * @param {Array.} fonts
57 | * @param {webfont.FontTestStrings=} opt_fontTestStrings
58 | * @param {Object.=} opt_metricCompatibleFonts
59 | */
60 | WebFont.prototype.onModuleReady_ = function(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts) {
61 | var allModulesLoaded = --this.moduleLoading_ == 0;
62 |
63 | if (this.classes_ || this.events_) {
64 | setTimeout(function () {
65 | fontWatcher.watchFonts(fonts, opt_fontTestStrings || null, opt_metricCompatibleFonts || null, allModulesLoaded);
66 | }, 0);
67 | }
68 | };
69 |
70 | /**
71 | * @param {webfont.EventDispatcher} eventDispatcher
72 | * @param {Object} configuration
73 | */
74 | WebFont.prototype.load_ = function(eventDispatcher, configuration) {
75 | var modules = [],
76 | timeout = configuration['timeout'],
77 | self = this;
78 |
79 | // Immediately dispatch the loading event before initializing the modules
80 | // so we know for sure that the loading event is synchronous.
81 | eventDispatcher.dispatchLoading();
82 |
83 | modules = this.fontModuleLoader_.getModules(configuration, this.domHelper_);
84 |
85 | var fontWatcher = new webfont.FontWatcher(this.domHelper_, eventDispatcher, timeout);
86 |
87 | this.moduleLoading_ = modules.length;
88 |
89 | for (var i = 0, len = modules.length; i < len; i++) {
90 | var module = modules[i];
91 |
92 | module.load(function (fonts, opt_fontTestStrings, opt_metricCompatibleFonts) {
93 | self.onModuleReady_(eventDispatcher, fontWatcher, fonts, opt_fontTestStrings, opt_metricCompatibleFonts);
94 | });
95 | }
96 | };
97 | });
98 |
--------------------------------------------------------------------------------
/src/modules.yml:
--------------------------------------------------------------------------------
1 | core:
2 | - ../tools/compiler/base.js
3 | - core/domhelper.js
4 | - core/stylesheetwaiter.js
5 | - core/cssclassname.js
6 | - core/font.js
7 | - core/eventdispatcher.js
8 | - core/fontmodule.js
9 | - core/fontmoduleloader.js
10 | - core/fontruler.js
11 | - core/nativefontwatchrunner.js
12 | - core/fontwatchrunner.js
13 | - core/fontwatcher.js
14 | - core/webfont.js
15 | - core/initialize.js
16 |
17 |
18 |
19 | google:
20 | - modules/google/fontapiurlbuilder.js
21 | - modules/google/fontapiparser.js
22 | - modules/google/googlefontapi.js
23 |
24 | fontdeck:
25 | - modules/fontdeck.js
26 |
27 | typekit:
28 | - modules/typekit.js
29 |
30 | monotype:
31 | - modules/monotype.js
32 |
33 | custom:
34 | - modules/custom.js
35 |
--------------------------------------------------------------------------------
/src/modules/custom.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.Custom');
2 |
3 | goog.require('webfont.Font');
4 | goog.require('webfont.StyleSheetWaiter');
5 |
6 | /**
7 | *
8 | * WebFont.load({
9 | * custom: {
10 | * families: ['Font1', 'Font2'],
11 | * urls: [ 'https://moo', 'https://meuh' ] }
12 | * });
13 | *
14 | * @constructor
15 | * @implements {webfont.FontModule}
16 | */
17 | webfont.modules.Custom = function(domHelper, configuration) {
18 | this.domHelper_ = domHelper;
19 | this.configuration_ = configuration;
20 | };
21 |
22 | /**
23 | * @const
24 | * @type {string}
25 | */
26 | webfont.modules.Custom.NAME = 'custom';
27 |
28 | goog.scope(function () {
29 | var Custom = webfont.modules.Custom,
30 | Font = webfont.Font,
31 | StyleSheetWaiter = webfont.StyleSheetWaiter;
32 |
33 | Custom.prototype.load = function(onReady) {
34 | var i, len;
35 | var urls = this.configuration_['urls'] || [];
36 | var familiesConfiguration = this.configuration_['families'] || [];
37 | var fontTestStrings = this.configuration_['testStrings'] || {};
38 | var waiter = new StyleSheetWaiter();
39 | for (i = 0, len = urls.length; i < len; i++) {
40 | this.domHelper_.loadStylesheet(urls[i], waiter.startWaitingLoad());
41 | }
42 |
43 | var fonts = [];
44 |
45 | for (i = 0, len = familiesConfiguration.length; i < len; i++) {
46 | var components = familiesConfiguration[i].split(":");
47 |
48 | if (components[1]) {
49 | var variations = components[1].split(",");
50 |
51 | for (var j = 0; j < variations.length; j += 1) {
52 | fonts.push(new Font(components[0], variations[j]));
53 | }
54 | } else {
55 | fonts.push(new Font(components[0]));
56 | }
57 | }
58 |
59 | waiter.waitWhileNeededThen(function() {
60 | onReady(fonts, fontTestStrings);
61 | });
62 | };
63 | });
64 |
--------------------------------------------------------------------------------
/src/modules/fontdeck.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.Fontdeck');
2 |
3 | goog.require('webfont.Font');
4 |
5 | /**
6 | * @constructor
7 | * @implements {webfont.FontModule}
8 | */
9 | webfont.modules.Fontdeck = function(domHelper, configuration) {
10 | this.domHelper_ = domHelper;
11 | this.configuration_ = configuration;
12 | this.fonts_ = [];
13 | };
14 |
15 | /**
16 | * @const
17 | * @type {string}
18 | */
19 | webfont.modules.Fontdeck.NAME = 'fontdeck';
20 | webfont.modules.Fontdeck.HOOK = '__webfontfontdeckmodule__';
21 | webfont.modules.Fontdeck.API = 'https://f.fontdeck.com/s/css/js/';
22 |
23 | goog.scope(function () {
24 | var Fontdeck = webfont.modules.Fontdeck,
25 | Font = webfont.Font,
26 | FontVariationDescription = webfont.FontVariationDescription;
27 |
28 | Fontdeck.prototype.getScriptSrc = function(projectId) {
29 | // For empty iframes, fall back to main window's hostname.
30 | var hostname = this.domHelper_.getHostName();
31 | var api = this.configuration_['api'] || webfont.modules.Fontdeck.API;
32 | return api + hostname + '/' + projectId + '.js';
33 | };
34 |
35 | Fontdeck.prototype.load = function(onReady) {
36 | var projectId = this.configuration_['id'];
37 | var loadWindow = this.domHelper_.getLoadWindow();
38 | var self = this;
39 |
40 | if (projectId) {
41 | // Provide data to Fontdeck for processing.
42 | if (!loadWindow[webfont.modules.Fontdeck.HOOK]) {
43 | loadWindow[webfont.modules.Fontdeck.HOOK] = {};
44 | }
45 |
46 | // Fontdeck will call this function to indicate support status
47 | // and what fonts are provided.
48 | loadWindow[webfont.modules.Fontdeck.HOOK][projectId] = function(fontdeckSupports, data) {
49 | for (var i = 0, j = data['fonts'].length; i= 2) {
74 | var fvds = this.parseVariations_(elements[1]);
75 |
76 | if (fvds.length > 0) {
77 | variations = fvds;
78 | }
79 | if (elements.length == 3) {
80 | var subsets = this.parseSubsets_(elements[2]);
81 | if (subsets.length > 0) {
82 | var fontTestString = FontApiParser.INT_FONTS[subsets[0]];
83 |
84 | if (fontTestString) {
85 | this.fontTestStrings_[fontFamily] = fontTestString;
86 | }
87 | }
88 | }
89 | }
90 |
91 | // For backward compatibility
92 | if (!this.fontTestStrings_[fontFamily]) {
93 | var hanumanTestString = FontApiParser.INT_FONTS[fontFamily];
94 | if (hanumanTestString) {
95 | this.fontTestStrings_[fontFamily] = hanumanTestString;
96 | }
97 | }
98 |
99 | for (var j = 0; j < variations.length; j += 1) {
100 | this.parsedFonts_.push(new Font(fontFamily, variations[j]));
101 | }
102 | }
103 | };
104 |
105 | FontApiParser.prototype.generateFontVariationDescription_ = function(variation) {
106 | if (!variation.match(/^[\w-]+$/)) {
107 | return '';
108 | }
109 | var normalizedVariation = variation.toLowerCase();
110 | var groups = FontApiParser.VARIATION_MATCH.exec(normalizedVariation);
111 | if (groups == null) {
112 | return '';
113 | }
114 | var styleMatch = this.normalizeStyle_(groups[2]);
115 | var weightMatch = this.normalizeWeight_(groups[1]);
116 | return [styleMatch, weightMatch].join('');
117 | };
118 |
119 |
120 | FontApiParser.prototype.normalizeStyle_ = function(parsedStyle) {
121 | if (parsedStyle == null || parsedStyle == '') {
122 | return 'n';
123 | }
124 | return FontApiParser.STYLES[parsedStyle];
125 | };
126 |
127 |
128 | FontApiParser.prototype.normalizeWeight_ = function(parsedWeight) {
129 | if (parsedWeight == null || parsedWeight == '') {
130 | return '4';
131 | }
132 | var weight = FontApiParser.WEIGHTS[parsedWeight];
133 | if (weight) {
134 | return weight;
135 | }
136 | if (isNaN(parsedWeight)) {
137 | return '4';
138 | }
139 | return parsedWeight.substr(0, 1);
140 | };
141 |
142 |
143 | FontApiParser.prototype.parseVariations_ = function(variations) {
144 | var finalVariations = [];
145 |
146 | if (!variations) {
147 | return finalVariations;
148 | }
149 | var providedVariations = variations.split(",");
150 | var length = providedVariations.length;
151 |
152 | for (var i = 0; i < length; i++) {
153 | var variation = providedVariations[i];
154 | var fvd = this.generateFontVariationDescription_(variation);
155 |
156 | if (fvd) {
157 | finalVariations.push(fvd);
158 | }
159 | }
160 | return finalVariations;
161 | };
162 |
163 |
164 | FontApiParser.prototype.parseSubsets_ = function(subsets) {
165 | var finalSubsets = [];
166 |
167 | if (!subsets) {
168 | return finalSubsets;
169 | }
170 | return subsets.split(",");
171 | };
172 |
173 |
174 | FontApiParser.prototype.getFonts = function() {
175 | return this.parsedFonts_;
176 | };
177 |
178 | FontApiParser.prototype.getFontTestStrings = function() {
179 | return this.fontTestStrings_;
180 | };
181 | });
182 |
--------------------------------------------------------------------------------
/src/modules/google/fontapiurlbuilder.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.google.FontApiUrlBuilder');
2 |
3 | /**
4 | * @constructor
5 | */
6 | webfont.modules.google.FontApiUrlBuilder = function(apiUrl, text) {
7 | if (apiUrl) {
8 | this.apiUrl_ = apiUrl;
9 | } else {
10 | this.apiUrl_ = webfont.modules.google.FontApiUrlBuilder.DEFAULT_API_URL;
11 | }
12 | this.fontFamilies_ = [];
13 | this.subsets_ = [];
14 | this.text_ = text || '';
15 | };
16 |
17 |
18 | webfont.modules.google.FontApiUrlBuilder.DEFAULT_API_URL = 'https://fonts.googleapis.com/css';
19 |
20 | goog.scope(function () {
21 | var FontApiUrlBuilder = webfont.modules.google.FontApiUrlBuilder;
22 |
23 | FontApiUrlBuilder.prototype.setFontFamilies = function(fontFamilies) {
24 | this.parseFontFamilies_(fontFamilies);
25 | };
26 |
27 |
28 | FontApiUrlBuilder.prototype.parseFontFamilies_ =
29 | function(fontFamilies) {
30 | var length = fontFamilies.length;
31 |
32 | for (var i = 0; i < length; i++) {
33 | var elements = fontFamilies[i].split(':');
34 |
35 | if (elements.length == 3) {
36 | this.subsets_.push(elements.pop());
37 | }
38 | var joinCharacter = '';
39 | if (elements.length == 2 && elements[1] != ''){
40 | joinCharacter = ':';
41 | }
42 | this.fontFamilies_.push(elements.join(joinCharacter));
43 | }
44 | };
45 |
46 |
47 | FontApiUrlBuilder.prototype.webSafe = function(string) {
48 | return string.replace(/ /g, '+');
49 | };
50 |
51 |
52 | FontApiUrlBuilder.prototype.build = function() {
53 | if (this.fontFamilies_.length == 0) {
54 | throw new Error('No fonts to load!');
55 | }
56 | if (this.apiUrl_.indexOf("kit=") != -1) {
57 | return this.apiUrl_;
58 | }
59 | var length = this.fontFamilies_.length;
60 | var sb = [];
61 |
62 | for (var i = 0; i < length; i++) {
63 | sb.push(this.webSafe(this.fontFamilies_[i]));
64 | }
65 | var url = this.apiUrl_ + '?family=' + sb.join('%7C'); // '|' escaped.
66 |
67 | if (this.subsets_.length > 0) {
68 | url += '&subset=' + this.subsets_.join(',');
69 | }
70 |
71 | if (this.text_.length > 0) {
72 | url += '&text=' + encodeURIComponent(this.text_);
73 | }
74 |
75 | return url;
76 | };
77 | });
78 |
--------------------------------------------------------------------------------
/src/modules/google/googlefontapi.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.google.GoogleFontApi');
2 |
3 | goog.require('webfont.modules.google.FontApiUrlBuilder');
4 | goog.require('webfont.modules.google.FontApiParser');
5 | goog.require('webfont.FontWatchRunner');
6 | goog.require('webfont.StyleSheetWaiter');
7 |
8 | /**
9 | * @constructor
10 | * @implements {webfont.FontModule}
11 | */
12 | webfont.modules.google.GoogleFontApi = function(domHelper, configuration) {
13 | this.domHelper_ = domHelper;
14 | this.configuration_ = configuration;
15 | };
16 |
17 | /**
18 | * @const
19 | * @type {string}
20 | */
21 | webfont.modules.google.GoogleFontApi.NAME = 'google';
22 |
23 | goog.scope(function () {
24 | var GoogleFontApi = webfont.modules.google.GoogleFontApi,
25 | FontWatchRunner = webfont.FontWatchRunner,
26 | StyleSheetWaiter = webfont.StyleSheetWaiter,
27 | FontApiUrlBuilder = webfont.modules.google.FontApiUrlBuilder,
28 | FontApiParser = webfont.modules.google.FontApiParser;
29 |
30 | GoogleFontApi.METRICS_COMPATIBLE_FONTS = {
31 | "Arimo": true,
32 | "Cousine": true,
33 | "Tinos": true
34 | };
35 |
36 | GoogleFontApi.prototype.load = function(onReady) {
37 | var waiter = new StyleSheetWaiter();
38 | var domHelper = this.domHelper_;
39 | var fontApiUrlBuilder = new FontApiUrlBuilder(
40 | this.configuration_['api'],
41 | this.configuration_['text']
42 | );
43 | var fontFamilies = this.configuration_['families'];
44 | fontApiUrlBuilder.setFontFamilies(fontFamilies);
45 |
46 | var fontApiParser = new FontApiParser(fontFamilies);
47 | fontApiParser.parse();
48 |
49 | domHelper.loadStylesheet(fontApiUrlBuilder.build(), waiter.startWaitingLoad());
50 | waiter.waitWhileNeededThen(function() {
51 | onReady(fontApiParser.getFonts(), fontApiParser.getFontTestStrings(), GoogleFontApi.METRICS_COMPATIBLE_FONTS);
52 | });
53 | };
54 | });
55 |
--------------------------------------------------------------------------------
/src/modules/monotype.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.Monotype');
2 |
3 | goog.require('webfont.Font');
4 |
5 | /**
6 | webfont.load({
7 | monotype: {
8 | projectId: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'//this is your Fonts.com Web fonts projectId
9 | }
10 | });
11 | */
12 |
13 | /**
14 | * @constructor
15 | * @implements {webfont.FontModule}
16 | */
17 | webfont.modules.Monotype = function(domHelper, configuration) {
18 | this.domHelper_ = domHelper;
19 | this.configuration_ = configuration;
20 | };
21 |
22 | /**
23 | * name of the module through which external API is supposed to call the MonotypeFontAPI.
24 | *
25 | * @const
26 | * @type {string}
27 | */
28 | webfont.modules.Monotype.NAME = 'monotype';
29 |
30 | /**
31 | * __mti_fntLst is the name of function that exposes Monotype's font list.
32 | * @const
33 | */
34 | webfont.modules.Monotype.HOOK = '__mti_fntLst';
35 |
36 | /**
37 | * __MonotypeAPIScript__ is the id of script added by google API. Currently 'fonts.com' supports only one script in a page.
38 | * This may require change in future if 'fonts.com' begins supporting multiple scripts per page.
39 | * @const
40 | */
41 | webfont.modules.Monotype.SCRIPTID = '__MonotypeAPIScript__';
42 |
43 | /**
44 | * __MonotypeConfiguration__ is function exposed to fonts.com. fonts.com will use this function to get webfontloader configuration
45 | * @const
46 | */
47 | webfont.modules.Monotype.CONFIGURATION = '__MonotypeConfiguration__';
48 |
49 | goog.scope(function() {
50 | var Monotype = webfont.modules.Monotype,
51 | Font = webfont.Font;
52 |
53 |
54 | Monotype.prototype.getScriptSrc = function(projectId, version) {
55 | var api = (this.configuration_['api'] || 'https://fast.fonts.net/jsapi')
56 | return api + '/' + projectId + '.js' + (version ? '?v=' + version : '');
57 | };
58 |
59 | Monotype.prototype.load = function(onReady) {
60 | var self = this;
61 | var projectId = self.configuration_['projectId'];
62 | var version = self.configuration_['version'];
63 |
64 |
65 | function checkAndLoadIfDownloaded() {
66 | if (loadWindow[Monotype.HOOK + projectId]) {
67 | var mti_fnts = loadWindow[Monotype.HOOK + projectId](),
68 | fonts = [],
69 | fntVariation;
70 |
71 | if (mti_fnts) {
72 | for (var i = 0; i < mti_fnts.length; i++) {
73 | var fnt = mti_fnts[i]["fontfamily"];
74 |
75 | //Check if font-style and font-weight is available
76 | if (mti_fnts[i]["fontStyle"] != undefined && mti_fnts[i]["fontWeight"] != undefined) {
77 | fntVariation = mti_fnts[i]["fontStyle"] + mti_fnts[i]["fontWeight"];
78 | fonts.push(new Font(fnt, fntVariation));
79 | } else {
80 | fonts.push(new Font(fnt));
81 | }
82 | }
83 | }
84 | onReady(fonts);
85 | } else {
86 | setTimeout(function() {
87 | checkAndLoadIfDownloaded();
88 | }, 50);
89 | }
90 | }
91 | if (projectId) {
92 | var loadWindow = self.domHelper_.getLoadWindow();
93 |
94 | var script = this.domHelper_.loadScript(self.getScriptSrc(projectId, version), function(err) {
95 | if (err) {
96 | onReady([]);
97 | } else {
98 | loadWindow[Monotype.CONFIGURATION+ projectId] = function() {
99 | return self.configuration_;
100 | };
101 |
102 | checkAndLoadIfDownloaded();
103 | }
104 | });
105 | script["id"] = Monotype.SCRIPTID + projectId;
106 | } else {
107 | onReady([]);
108 | }
109 | };
110 | });
--------------------------------------------------------------------------------
/src/modules/typekit.js:
--------------------------------------------------------------------------------
1 | goog.provide('webfont.modules.Typekit');
2 |
3 | goog.require('webfont.Font');
4 |
5 | /**
6 | * @constructor
7 | * @implements {webfont.FontModule}
8 | */
9 | webfont.modules.Typekit = function(domHelper, configuration) {
10 | this.domHelper_ = domHelper;
11 | this.configuration_ = configuration;
12 | };
13 |
14 | /**
15 | * @const
16 | * @type {string}
17 | */
18 | webfont.modules.Typekit.NAME = 'typekit';
19 |
20 | goog.scope(function () {
21 | var Typekit = webfont.modules.Typekit,
22 | Font = webfont.Font;
23 |
24 | Typekit.prototype.getScriptSrc = function(kitId) {
25 | var api = this.configuration_['api'] || 'https://use.typekit.net';
26 | return api + '/' + kitId + '.js';
27 | };
28 |
29 | Typekit.prototype.load = function(onReady) {
30 | var kitId = this.configuration_['id'];
31 | var configuration = this.configuration_;
32 | var loadWindow = this.domHelper_.getLoadWindow();
33 | var that = this;
34 |
35 | if (kitId) {
36 | // Load the Typekit script. Once it is done loading we grab its configuration
37 | // and use that to populate the fonts we should watch.
38 | this.domHelper_.loadScript(this.getScriptSrc(kitId), function (err) {
39 | if (err) {
40 | onReady([]);
41 | } else {
42 | if (loadWindow['Typekit'] && loadWindow['Typekit']['config'] && loadWindow['Typekit']['config']['fn']) {
43 | var fn = loadWindow['Typekit']['config']['fn'],
44 | fonts = [];
45 |
46 | for (var i = 0; i < fn.length; i += 2) {
47 | var font = fn[i],
48 | variations = fn[i + 1];
49 |
50 | for (var j = 0; j < variations.length; j++) {
51 | fonts.push(new Font(font, variations[j]));
52 | }
53 | }
54 |
55 | // Kick off font loading but disable font events so
56 | // we don't duplicate font watching.
57 | try {
58 | loadWindow['Typekit']['load']({
59 | 'events': false,
60 | 'classes': false,
61 | 'async': true
62 | });
63 | } catch (e) {}
64 |
65 | onReady(fonts);
66 | }
67 | }
68 | }, 2000);
69 | } else {
70 | onReady([]);
71 | }
72 | };
73 | });
74 |
--------------------------------------------------------------------------------
/tools/compiler/compiler.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/typekit/webfontloader/117e48d521d6408f78cbfe4d23923cc828fdf576/tools/compiler/compiler.jar
--------------------------------------------------------------------------------
/tools/jasmine-browserstack/jasmine-browserstack.js:
--------------------------------------------------------------------------------
1 | (function (root, factory) {
2 | if (typeof define === 'function' && define.amd) {
3 | define(['jasmine'], factory);
4 | } else {
5 | factory(jasmine);
6 | }
7 | }(this, function (jasmine) {
8 | function stack(err) {
9 | var str = err.stack || err.toString();
10 |
11 | if (!~str.indexOf(err.message)) {
12 | str = err.message + '\n' + str;
13 | }
14 |
15 | if ('[object Error]' == str) {
16 | str = err.message;
17 | }
18 |
19 | if (!err.stack && err.sourceURL && err.line !== undefined) {
20 | str += '\n(' + err.sourceURL + ':' + err.line + ')';
21 | }
22 | return str.replace(/^/gm, ' ');
23 | }
24 |
25 | function BrowserStackReporter() {
26 | this.stats = {
27 | suites: 0,
28 | tests: 0,
29 | passes: 0,
30 | pending: 0,
31 | failures: 0
32 | };
33 | this.tests = [];
34 | }
35 |
36 | BrowserStackReporter.prototype.reportRunnerStarting = function (runner) {
37 | this.stats.start = new Date();
38 | };
39 |
40 | BrowserStackReporter.prototype.reportSpecStarting = function (spec) {
41 | spec.startedAt = new Date().getTime();
42 | };
43 |
44 | BrowserStackReporter.prototype.reportSpecResults = function (spec) {
45 | var currentTime = new Date().getTime();
46 | spec.duration = currentTime - spec.startedAt;
47 |
48 | var result = spec.results();
49 |
50 | var test = {
51 | status: null,
52 | title: spec.getFullName().replace(/#/g, ''),
53 | duration: currentTime - spec.startedAt
54 | };
55 |
56 | if (result.skipped) {
57 | this.stats.pending += 1;
58 | test.status = 'skipped';
59 | } else if (result.failedCount === 0) {
60 | this.stats.passes += 1;
61 | test.status = 'passed';
62 | } else {
63 | var items = result.getItems(),
64 | message = [];
65 |
66 | for (var i = 0; i < items.length; i += 1) {
67 | message.push(stack(items[i].trace));
68 | }
69 |
70 | test.err = message;
71 | test.status = 'failed';
72 | this.stats.failures += 1;
73 | }
74 |
75 | this.stats.tests += 1;
76 | this.tests.push(test);
77 | };
78 |
79 | BrowserStackReporter.prototype.reportSuiteResults = function (suite) {
80 | };
81 |
82 | BrowserStackReporter.prototype.reportRunnerResults = function (runner) {
83 | var suites = runner.suites();
84 |
85 | this.stats.end = new Date();
86 | this.stats.duration = this.stats.end - this.stats.end;
87 |
88 | this.stats.suites = suites.length;
89 |
90 | var result = '1..' + this.stats.tests + '\n';
91 |
92 | for (var i = 0; i < this.tests.length; i += 1) {
93 | var count = i + 1;
94 |
95 | if (this.tests[i].status === 'pending') {
96 | result += 'ok ' + count + ' ' + this.tests[i].title + ' # SKIP -\n';
97 | } else if (this.tests[i].status === 'failed') {
98 | result += 'not ok ' + count + ' ' + this.tests[i].title + '\n';
99 | for (var j = 0; j < this.tests[i].err.length; j += 1) {
100 | result += this.tests[i].err[j] + '\n';
101 | }
102 | } else {
103 | result += 'ok ' + count + ' ' + this.tests[i].title + '\n';
104 | }
105 | }
106 |
107 | result += '# tests ' + this.stats.tests + '\n';
108 | result += '# pass ' + this.stats.passes + '\n';
109 | result += '# fail ' + this.stats.failures + '\n';
110 |
111 | if (/browser=/i.test(window.location.search)) {
112 | var xhr = null;
113 |
114 | if (window.XMLHttpRequest) {
115 | xhr = new XMLHttpRequest();
116 | } else {
117 | xhr = new ActiveXObject('Microsoft.XMLHTTP');
118 | }
119 |
120 | xhr.open('POST', window.location.href);
121 | xhr.setRequestHeader('Content-Type', 'text/plain');
122 | xhr.send(result);
123 | }
124 | };
125 |
126 | // Attach to the jasmine object like many other reporters do
127 | jasmine.BrowserStackReporter = BrowserStackReporter;
128 | }));
129 |
--------------------------------------------------------------------------------
/tools/jasmine-phantomjs/jasmine-phantomjs.js:
--------------------------------------------------------------------------------
1 | var webpage = require('webpage'),
2 | system = require('system');
3 |
4 | if (system.args.length !== 1) {
5 | var page = webpage.create();
6 |
7 | page.onConsoleMessage = function (msg) {
8 | console.log(msg);
9 | if (/SUCCESS|FAILURE/.test(msg)) {
10 | if (/SUCCESS/.test(msg)) {
11 | phantom.exit(0);
12 | } else {
13 | phantom.exit(1);
14 | }
15 | }
16 | };
17 |
18 | page.open(system.args[1], function (status) {
19 | if (status !== 'success') {
20 | phantom.exit(1);
21 | }
22 | });
23 | } else {
24 | console.log('Usage: jasmine-phantomjs [FILE]');
25 | phantom.exit(1);
26 | }
27 |
--------------------------------------------------------------------------------
/tools/jasmine-phantomjs/terminal-reporter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Taken from https://github.com/larrymyers/jasmine-reporters
3 | * Licensed under the MIT license.
4 | */
5 | (function() {
6 | if (! jasmine) {
7 | throw new Exception("jasmine library does not exist in global namespace!");
8 | }
9 |
10 | /**
11 | * Basic reporter that outputs spec results to the terminal.
12 | * Use this reporter in your build pipeline.
13 | *
14 | * Usage:
15 | *
16 | * jasmine.getEnv().addReporter(new jasmine.TerminalReporter({
17 | verbosity: 2,
18 | color: true
19 | }));
20 | * jasmine.getEnv().execute();
21 | */
22 | var DEFAULT_VERBOSITY = 2,
23 | ATTRIBUTES_TO_ANSI = {
24 | "off": 0,
25 | "bold": 1,
26 | "red": 31,
27 | "green": 32
28 | };
29 |
30 | var TerminalReporter = function(params) {
31 | var parameters = params || {};
32 |
33 | if (parameters.verbosity === 0) {
34 | this.verbosity = 0;
35 | } else {
36 | this.verbosity = parameters.verbosity || DEFAULT_VERBOSITY;
37 | }
38 | this.color = parameters.color;
39 |
40 | this.started = false;
41 | this.finished = false;
42 | this.current_suite_hierarchy = [];
43 | this.indent_string = ' ';
44 | };
45 |
46 | TerminalReporter.prototype = {
47 | reportRunnerResults: function(runner) {
48 | var dur = (new Date()).getTime() - this.start_time,
49 | failed = this.executed_specs - this.passed_specs,
50 | spec_str = this.executed_specs + (this.executed_specs === 1 ? " spec, " : " specs, "),
51 | fail_str = failed + (failed === 1 ? " failure in " : " failures in "),
52 | summary_str = spec_str + fail_str + (dur/1000) + "s.",
53 | result_str = (failed && "FAILURE: " || "SUCCESS: ") + summary_str,
54 | result_color = failed && "red+bold" || "green+bold";
55 |
56 | if (this.verbosity === 2) {
57 | this.log("");
58 | }
59 |
60 | if (this.verbosity > 0) {
61 | this.log(this.inColor(result_str, result_color));
62 | }
63 |
64 | this.finished = true;
65 | },
66 |
67 | reportRunnerStarting: function(runner) {
68 | this.started = true;
69 | this.start_time = (new Date()).getTime();
70 | this.executed_specs = 0;
71 | this.passed_specs = 0;
72 | },
73 |
74 | reportSpecResults: function(spec) {
75 | var color = "red";
76 |
77 | if (spec.results().passed()) {
78 | this.passed_specs++;
79 | color = "green";
80 | }
81 |
82 | if (this.verbosity === 2) {
83 | var resultText = 'F';
84 |
85 | if (spec.results().passed()) {
86 | resultText = '.';
87 | }
88 | this.log(this.inColor(resultText, color));
89 | } else if (this.verbosity > 2) {
90 | resultText = "Failed";
91 |
92 | if (spec.results().passed()) {
93 | resultText = 'Passed';
94 | }
95 | this.log(' ' + this.inColor(resultText, color));
96 | }
97 | },
98 |
99 | reportSpecStarting: function(spec) {
100 | this.executed_specs++;
101 | if (this.verbosity > 2) {
102 | this.logCurrentSuite(spec.suite);
103 |
104 | this.log(this.indentWithCurrentLevel(this.indent_string + spec.description + ' ...'));
105 | }
106 | },
107 |
108 | reportSuiteResults: function(suite) {
109 | var results = suite.results(),
110 | failed = results.totalCount - results.passedCount,
111 | color = failed ? "red+bold" : "green+bold";
112 |
113 | if (this.verbosity > 2) {
114 | this.logCurrentSuite(suite);
115 | this.log(this.indentWithCurrentLevel(this.inColor(results.passedCount + " of "
116 | + results.totalCount + " passed.", color)));
117 | }
118 | },
119 |
120 | indentWithCurrentLevel: function(string) {
121 | return new Array(this.current_suite_hierarchy.length).join(this.indent_string) + string;
122 | },
123 |
124 | recursivelyUpdateHierarchyUpToRootAndLogNewBranches: function(suite) {
125 | var suite_path = [],
126 | current_level;
127 |
128 | if (suite.parentSuite != null) {
129 | suite_path = this.recursivelyUpdateHierarchyUpToRootAndLogNewBranches(suite.parentSuite);
130 | }
131 |
132 | suite_path.push(suite);
133 | current_level = suite_path.length - 1;
134 |
135 | if (this.current_suite_hierarchy.length <= current_level
136 | || this.current_suite_hierarchy[current_level] !== suite) {
137 |
138 | this.current_suite_hierarchy = suite_path.slice(0);
139 | this.log(this.indentWithCurrentLevel(this.inColor(suite.description, "bold")));
140 | }
141 | return suite_path;
142 | },
143 |
144 | logCurrentSuite: function(suite) {
145 | var suite_path = this.recursivelyUpdateHierarchyUpToRootAndLogNewBranches(suite);
146 | // If we just popped down from a higher path, we need to update here
147 | this.current_suite_hierarchy = suite_path;
148 | },
149 |
150 | inColor: function (string, color) {
151 | var color_attributes = color && color.split("+"),
152 | ansi_string = "",
153 | i, attr;
154 |
155 | if (! this.color || ! color_attributes) {
156 | return string;
157 | }
158 |
159 | for(i = 0; i < color_attributes.length; i++) {
160 | ansi_string += "\033[" + ATTRIBUTES_TO_ANSI[color_attributes[i]] + "m";
161 | }
162 | ansi_string += string + "\033[" + ATTRIBUTES_TO_ANSI["off"] + "m";
163 |
164 | return ansi_string;
165 | },
166 |
167 | log: function(str) {
168 | var console = jasmine.getGlobal().console;
169 | if (console && console.log) {
170 | console.log(str);
171 | }
172 | }
173 | };
174 |
175 | // export public
176 | jasmine.TerminalReporter = TerminalReporter;
177 | })();
178 |
--------------------------------------------------------------------------------
/tools/jasmine/MIT.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Pivotal Labs
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/tools/jasmine/jasmine.css:
--------------------------------------------------------------------------------
1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
2 |
3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
4 | #HTMLReporter a { text-decoration: none; }
5 | #HTMLReporter a:hover { text-decoration: underline; }
6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; }
9 | #HTMLReporter .version { color: #aaaaaa; }
10 | #HTMLReporter .banner { margin-top: 14px; }
11 | #HTMLReporter .duration { color: #aaaaaa; float: right; }
12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; }
15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; }
17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; }
21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
24 | #HTMLReporter .runningAlert { background-color: #666666; }
25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; }
26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; }
27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
28 | #HTMLReporter .passingAlert { background-color: #a6b779; }
29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
30 | #HTMLReporter .failingAlert { background-color: #cf867e; }
31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; }
32 | #HTMLReporter .results { margin-top: 14px; }
33 | #HTMLReporter #details { display: none; }
34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
38 | #HTMLReporter.showDetails .summary { display: none; }
39 | #HTMLReporter.showDetails #details { display: block; }
40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
41 | #HTMLReporter .summary { margin-top: 14px; }
42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; }
45 | #HTMLReporter .description + .suite { margin-top: 0; }
46 | #HTMLReporter .suite { margin-top: 14px; }
47 | #HTMLReporter .suite a { color: #333333; }
48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; }
49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
51 | #HTMLReporter .resultMessage span.result { display: block; }
52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
53 |
54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; }
56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
61 | #TrivialReporter .runner.running { background-color: yellow; }
62 | #TrivialReporter .options { text-align: right; font-size: .8em; }
63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
64 | #TrivialReporter .suite .suite { margin: 5px; }
65 | #TrivialReporter .suite.passed { background-color: #dfd; }
66 | #TrivialReporter .suite.failed { background-color: #fdd; }
67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
71 | #TrivialReporter .spec.skipped { background-color: #bbb; }
72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
73 | #TrivialReporter .passed { background-color: #cfc; display: none; }
74 | #TrivialReporter .failed { background-color: #fbb; }
75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
77 | #TrivialReporter .resultMessage .mismatch { color: black; }
78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; }
82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
83 |
--------------------------------------------------------------------------------
/webfontloader.gemspec:
--------------------------------------------------------------------------------
1 | ## This is the rakegem gemspec template. Make sure you read and understand
2 | ## all of the comments. Some sections require modification, and others can
3 | ## be deleted if you don't need them. Once you understand the contents of
4 | ## this file, feel free to delete any comments that begin with two hash marks.
5 | ## You can find comprehensive Gem::Specification documentation, at
6 | ## http://docs.rubygems.org/read/chapter/20
7 | Gem::Specification.new do |s|
8 | s.specification_version = 2 if s.respond_to? :specification_version=
9 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10 | s.rubygems_version = '1.3.5'
11 |
12 | ## Leave these as is they will be modified for you by the rake gemspec task.
13 | ## If your rubyforge_project name is different, then edit it and comment out
14 | ## the sub! line in the Rakefile
15 | s.name = 'webfontloader'
16 | s.version = '1.6.28'
17 | s.date = '2017-05-27'
18 |
19 | ## Make sure your summary is short. The description may be as long
20 | ## as you like.
21 | s.summary = "WebFont Loader gives you added control when using linked fonts via @font-face."
22 | s.description = <<-DESC
23 | WebFont Loader gives you added control when using linked fonts via
24 | `@font-face`. It provides a common interface to loading fonts regardless of
25 | the source, then adds a standard set of events you may use to control the
26 | loading experience.
27 | DESC
28 |
29 | ## List the primary authors. If there are a bunch of authors, it's probably
30 | ## better to set the email to an email list or something. If you don't have
31 | ## a custom homepage, consider using your GitHub URL or the like.
32 | s.authors = ["Ryan Carver", "Jeremie Lenfant-engelmann"]
33 | s.email = 'ryan@typekit.com'
34 | s.homepage = 'http://github.com/typekit/webfontloader'
35 |
36 | ## License
37 | s.license = "Apache-2.0"
38 |
39 | ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
40 | ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
41 | s.require_paths = %w[lib]
42 |
43 | ## This sections is only necessary if you have C extensions.
44 | # s.require_paths << 'ext'
45 | # s.extensions = %w[ext/extconf.rb]
46 |
47 | ## If your gem includes any executables, list them here.
48 | # s.executables = []
49 | # s.default_executable = 'name'
50 |
51 | ## Specify any RDoc options here. You'll want to add your README and
52 | ## LICENSE files to the extra_rdoc_files list.
53 | s.rdoc_options = ["--charset=UTF-8"]
54 | s.extra_rdoc_files = %w[README.md] + Dir["docs/*.md"]
55 |
56 | ## List your runtime dependencies here. Runtime dependencies are those
57 | ## that are needed for an end user to actually USE your code.
58 | # s.add_dependency('DEPNAME', [">= 1.1.0", "< 2.0.0"])
59 |
60 | ## List your development dependencies here. Development dependencies are
61 | ## those that are only needed during development
62 | s.add_development_dependency('rake', '~>0')
63 | s.add_development_dependency('rack', '~>1.5', '>=1.5.1')
64 | s.add_development_dependency('sinatra', '~>1.3', '>=1.3.4')
65 | s.add_development_dependency('vegas', '~>0.1.11')
66 |
67 | ## Leave this section as-is. It will be automatically generated from the
68 | ## contents of your Git repository via the gemspec task. DO NOT REMOVE
69 | ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
70 | # = MANIFEST =
71 | s.files = %w[
72 | CHANGELOG
73 | CONTRIBUTING.md
74 | Gemfile
75 | LICENSE
76 | README.md
77 | Rakefile
78 | bin/webfontloader-demos
79 | bower.json
80 | browsers.json
81 | externs.js
82 | lib/webfontloader.rb
83 | lib/webfontloader/demo/public/basic.css
84 | lib/webfontloader/demo/public/blank.html
85 | lib/webfontloader/demo/public/custom-iframe.html
86 | lib/webfontloader/demo/public/custom.html
87 | lib/webfontloader/demo/public/event-css-active-multiple.html
88 | lib/webfontloader/demo/public/event-css-active.html
89 | lib/webfontloader/demo/public/event-css-inactive.html
90 | lib/webfontloader/demo/public/event-css-loading.html
91 | lib/webfontloader/demo/public/event-js-active.html
92 | lib/webfontloader/demo/public/event-js-font-active.html
93 | lib/webfontloader/demo/public/event-js-loading.html
94 | lib/webfontloader/demo/public/events-variations.html
95 | lib/webfontloader/demo/public/events.html
96 | lib/webfontloader/demo/public/fontdeck.html
97 | lib/webfontloader/demo/public/fontwatchrunner-default-fonts.html
98 | lib/webfontloader/demo/public/google-css.html
99 | lib/webfontloader/demo/public/google-iframe.html
100 | lib/webfontloader/demo/public/google.html
101 | lib/webfontloader/demo/public/ie-fast-js.html
102 | lib/webfontloader/demo/public/ie-slow-js.html
103 | lib/webfontloader/demo/public/ie-slow-link.html
104 | lib/webfontloader/demo/public/index.html
105 | lib/webfontloader/demo/public/jquery.min.js
106 | lib/webfontloader/demo/public/monotype-iframe.html
107 | lib/webfontloader/demo/public/monotype.html
108 | lib/webfontloader/demo/public/typekit-iframe.html
109 | lib/webfontloader/demo/public/typekit-variations.html
110 | lib/webfontloader/demo/public/typekit.html
111 | lib/webfontloader/demo/server.rb
112 | lib/webfontloader/modules.rb
113 | package.json
114 | spec/core/cssclassname_spec.js
115 | spec/core/domhelper_spec.js
116 | spec/core/eventdispatcher_spec.js
117 | spec/core/font_spec.js
118 | spec/core/fontmoduleloader_spec.js
119 | spec/core/fontruler_spec.js
120 | spec/core/fontwatcher_spec.js
121 | spec/core/fontwatchrunner_spec.js
122 | spec/core/nativefontwatchrunner_spec.js
123 | spec/core/size_spec.js
124 | spec/core/webfont_spec.js
125 | spec/deps.js
126 | spec/fixtures/external_script.js
127 | spec/fixtures/external_stylesheet.css
128 | spec/fixtures/fonts/LICENSE.txt
129 | spec/fixtures/fonts/nullfont.css
130 | spec/fixtures/fonts/nullfont1.css
131 | spec/fixtures/fonts/nullfont2.css
132 | spec/fixtures/fonts/nullfont3.css
133 | spec/fixtures/fonts/sourcesans.eot
134 | spec/fixtures/fonts/sourcesans.otf
135 | spec/fixtures/fonts/sourcesans.svg
136 | spec/fixtures/fonts/sourcesans.ttf
137 | spec/fixtures/fonts/sourcesans.woff
138 | spec/fixtures/fonts/sourcesansa.css
139 | spec/fixtures/fonts/sourcesansb.css
140 | spec/fixtures/fonts/sourcesansc.css
141 | spec/fixtures/fonts/sourcesansd.css
142 | spec/fixtures/fonts/sourcesansdup1.css
143 | spec/fixtures/fonts/sourcesansdup2.css
144 | spec/index.html
145 | spec/modules/custom_spec.js
146 | spec/modules/fontdeck_spec.js
147 | spec/modules/google/fontapiparser_spec.js
148 | spec/modules/google/fontapiurlbuilder_spec.js
149 | spec/modules/google/googlefontapi_spec.js
150 | spec/modules/monotype_spec.js
151 | spec/modules/typekit_spec.js
152 | src/closure.js
153 | src/core/cssclassname.js
154 | src/core/domhelper.js
155 | src/core/eventdispatcher.js
156 | src/core/font.js
157 | src/core/fontmodule.js
158 | src/core/fontmoduleloader.js
159 | src/core/fontruler.js
160 | src/core/fontwatcher.js
161 | src/core/fontwatchrunner.js
162 | src/core/initialize.js
163 | src/core/nativefontwatchrunner.js
164 | src/core/stylesheetwaiter.js
165 | src/core/webfont.js
166 | src/modules.yml
167 | src/modules/custom.js
168 | src/modules/fontdeck.js
169 | src/modules/google/fontapiparser.js
170 | src/modules/google/fontapiurlbuilder.js
171 | src/modules/google/googlefontapi.js
172 | src/modules/monotype.js
173 | src/modules/typekit.js
174 | tools/compiler/base.js
175 | tools/compiler/compiler.jar
176 | tools/jasmine-browserstack/jasmine-browserstack.js
177 | tools/jasmine-phantomjs/jasmine-phantomjs.js
178 | tools/jasmine-phantomjs/terminal-reporter.js
179 | tools/jasmine/MIT.LICENSE
180 | tools/jasmine/jasmine-html.js
181 | tools/jasmine/jasmine.css
182 | tools/jasmine/jasmine.js
183 | webfontloader.gemspec
184 | webfontloader.js
185 | ]
186 | # = MANIFEST =
187 |
188 | ## Test files will be grabbed from the file list. Make sure the path glob
189 | ## matches what you actually use.
190 | s.test_files = s.files.select { |path| path =~ /^spec\/.*_spec\.rb/ }
191 | end
192 |
--------------------------------------------------------------------------------