Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

View File

@ -0,0 +1,23 @@
Copyright (c) 2014 - Bram Stein
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,63 @@
# Font Face Observer (Modular)
Font Face Observer is a small `@font-face` loader and monitor compatible with any web-font service. It will monitor when a web font is applied to the page and notify you. It does not limit you in any way in where, when, or how you load your web fonts. Unlike the [Web Font Loader](https://github.com/typekit/webfontloader) Font Face Observer uses scroll events to detect font loads efficiently and with minimum overhead.
## How to use
Include your `@font-face` rules as usual. Fonts can be supplied by either a font service such as [Google Fonts](http://www.google.com/fonts), [Typekit](http://typekit.com), and [Webtype](http://webtype.com) or be self-hosted. It doesn't matter where, when, or how you load your fonts. You can set up monitoring for a single font family at a time:
```javascript
var FontFaceObserver = require('font-face-observer');
var observer = new FontFaceObserver('My Family', {
weight: 400
});
observer.check().then(function () {
console.log('Font is available');
}, function () {
console.log('Font is not available');
});
```
The `FontFaceObserver` constructor takes two (required) arguments: the font family name and an object describing the variation. The object can contain `weight`, `style`, `stretch`, `variant`, and `featureSettings` properties. If a property is not present it will default to `normal`. To start observing font loads, call the `check` method. It'll immediately return a new Promise that resolves when the font is available and rejected when the font is not available.
If your font doesn't contain latin characters you can pass a custom test string to the `check` method.
```javascript
var FontFaceObserver = require('font-face-observer');
var observer = new FontFaceObserver('My Family', {});
observer.check('中国').then(function () {
console.log('Font is available');
}, function () {
console.log('Font is not available');
});
```
The default timeout for giving up on font loading is 3 seconds. You can increase or decrease this by passing a number of milliseconds as the second parameter to the `check` method.
```javascript
var FontFaceObserver = require('font-face-observer');
var observer = new FontFaceObserver('My Family', {});
observer.check(null, 5000).then(function () {
console.log('Font is available');
}, function () {
console.log('Font is not available after waiting 5 seconds');
});
```
## Browser support
FontFaceObserver has been tested and works on the following browsers:
* Chrome (desktop & Android)
* Firefox
* Opera
* Safari (desktop & iOS)
* IE9+
* Android WebKit
## License
FontFaceObserver is licensed under the BSD License. Copyright 2014-2015 Bram Stein. All rights reserved.

View File

@ -0,0 +1,64 @@
{
"_from": "font-face-observer@1.0.0",
"_id": "font-face-observer@1.0.0",
"_inBundle": false,
"_integrity": "sha1-r3poGd1X9yZDAVAmAgrqNCQqN38=",
"_location": "/font-face-observer",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "font-face-observer@1.0.0",
"name": "font-face-observer",
"escapedName": "font-face-observer",
"rawSpec": "1.0.0",
"saveSpec": null,
"fetchSpec": "1.0.0"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/font-face-observer/-/font-face-observer-1.0.0.tgz",
"_shasum": "af7a6819dd57f72643015026020aea34242a377f",
"_spec": "font-face-observer@1.0.0",
"_where": "/home/manfred/enviPath/ketcher2/ketcher",
"bugs": {
"url": "https://github.com/cymen/font-face-observer/issues"
},
"bundleDependencies": false,
"contributors": [
{
"name": "Bram Stein",
"email": "b.l.stein@gmail.com"
},
{
"name": "Cymen Vig",
"email": "cymenvig@gmail.com"
},
{
"name": "Justin McCandless",
"email": "justinjmccandless@gmail.com"
}
],
"dependencies": {
"promise": "^6.1.0"
},
"deprecated": false,
"description": "Font face observer for eventing when web fonts are loaded",
"devDependencies": {
"jasmine-node": "^1.14.5",
"jsdom": "^3.1.2"
},
"homepage": "https://github.com/cymen/font-face-observer#readme",
"license": "BSD",
"main": "src/observer.js",
"name": "font-face-observer",
"repository": {
"type": "git",
"url": "git+https://github.com/cymen/font-face-observer.git"
},
"scripts": {
"test": "jasmine-node --forceexit test"
},
"version": "1.0.0"
}

View File

@ -0,0 +1,43 @@
var dom = {};
module.exports = dom;
/**
* @param {string} name
* @return {Element}
*/
dom.createElement = function (name) {
return document.createElement(name);
};
/**
* @param {string} text
* @return {Text}
*/
dom.createText = function (text) {
return document.createTextNode(text);
};
/**
* @param {Element} element
* @param {string} style
*/
dom.style = function (element, style) {
element.style.cssText = style;
};
/**
* @param {Node} parent
* @param {Node} child
*/
dom.append = function (parent, child) {
parent.appendChild(child);
};
/**
* @param {Node} parent
* @param {Node} child
*/
dom.remove = function (parent, child) {
parent.removeChild(child);
};

View File

@ -0,0 +1,207 @@
var Promise = require('promise');
var dom = require('./dom');
var Ruler = require('./ruler');
/**
* @constructor
*
* @param {string} family
* @param [fontface.Descriptors] descriptors
*/
var Observer = function (family, descriptors) {
descriptors = descriptors || {weight: 'normal'};
/**
* @type {string}
*/
this['family'] = family;
/**
* @type {string}
*/
this['style'] = descriptors.style || 'normal';
/**
* @type {string}
*/
this['variant'] = descriptors.variant || 'normal';
/**
* @type {string}
*/
this['weight'] = descriptors.weight || 'normal';
/**
* @type {string}
*/
this['stretch'] = descriptors.stretch || 'stretch';
/**
* @type {string}
*/
this['featureSettings'] = descriptors.featureSettings || 'normal';
};
module.exports = Observer;
/**
* @type {null|boolean}
*/
Observer.HAS_WEBKIT_FALLBACK_BUG = null;
/**
* @type {number}
*/
Observer.DEFAULT_TIMEOUT = 3000;
/**
* @return {string}
*/
Observer.getUserAgent = function () {
return window.navigator.userAgent;
};
/**
* Returns true if this browser is WebKit and it has the fallback bug
* which is present in WebKit 536.11 and earlier.
*
* @return {boolean}
*/
Observer.hasWebKitFallbackBug = function () {
if (Observer.HAS_WEBKIT_FALLBACK_BUG === null) {
var match = /AppleWeb[kK]it\/([0-9]+)(?:\.([0-9]+))/.exec(Observer.getUserAgent());
Observer.HAS_WEBKIT_FALLBACK_BUG = !!match &&
(parseInt(match[1], 10) < 536 ||
(parseInt(match[1], 10) === 536 &&
parseInt(match[2], 10) <= 11));
}
return Observer.HAS_WEBKIT_FALLBACK_BUG;
};
/**
* @private
* @return {string}
*/
Observer.prototype.getStyle = function () {
return 'font-style:' + this['style'] + ';' +
'font-variant:' + this['variant'] + ';' +
'font-weight:' + this['weight'] + ';' +
'font-stretch:' + this['stretch'] + ';' +
'font-feature-settings:' + this['featureSettings'] + ';' +
'-moz-font-feature-settings:' + this['featureSettings'] + ';' +
'-webkit-font-feature-settings:' + this['featureSettings'] + ';';
};
/**
* @param {string=} text Optional test string to use for detecting if a font is available.
* @param {number=} timeout Optional timeout for giving up on font load detection and rejecting the promise (defaults to 3 seconds).
* @return {Promise.<fontface.Observer>}
*/
Observer.prototype.check = function (text, timeout) {
var testString = text || 'BESbswy',
timeoutValue = timeout || Observer.DEFAULT_TIMEOUT,
style = this.getStyle(),
container = dom.createElement('div'),
rulerA = new Ruler(testString),
rulerB = new Ruler(testString),
rulerC = new Ruler(testString),
widthA = -1,
widthB = -1,
widthC = -1,
fallbackWidthA = -1,
fallbackWidthB = -1,
fallbackWidthC = -1,
that = this;
rulerA.setFont('"Times New Roman", sans-serif', style);
rulerB.setFont('serif', style);
rulerC.setFont('monospace', style);
dom.append(container, rulerA.getElement());
dom.append(container, rulerB.getElement());
dom.append(container, rulerC.getElement());
dom.append(document.body, container);
fallbackWidthA = rulerA.getWidth();
fallbackWidthB = rulerB.getWidth();
fallbackWidthC = rulerC.getWidth();
return new Promise(function (resolve, reject) {
/**
* @private
*/
function removeContainer() {
if (container.parentNode !== null) {
dom.remove(document.body, container);
}
}
/**
* @private
*
* Cases:
* 1) Font loads: both a, b and c are called and have the same value.
* 2) Font fails to load: resize callback is never called and timeout happens.
* 3) WebKit bug: both a, b and c are called and have the same value, but the
* values are equal to one of the last resort fonts, we ignore this and
* continue waiting until we get new values (or a timeout).
*/
function check() {
if (widthA !== -1 && widthB !== -1 && widthC !== -1) {
// All values are changed from their initial state
if (widthA === widthB && widthB === widthC) {
// All values are the same, so the browser has most likely loaded the web font
if (Observer.hasWebKitFallbackBug()) {
// Except if the browser has the WebKit fallback bug, in which case we check to see if all
// values are set to one of the last resort fonts.
if (!((widthA === fallbackWidthA && widthB === fallbackWidthA && widthC === fallbackWidthA) ||
(widthA === fallbackWidthB && widthB === fallbackWidthB && widthC === fallbackWidthB) ||
(widthA === fallbackWidthC && widthB === fallbackWidthC && widthC === fallbackWidthC))) {
// The width we got doesn't match any of the known last resort fonts, so let's assume fonts are loaded.
removeContainer();
resolve(that);
}
} else {
removeContainer();
resolve(that);
}
}
}
}
setTimeout(function () {
removeContainer();
reject(that);
}, timeoutValue);
rulerA.onResize(function (width) {
widthA = width;
check();
});
rulerA.setFont(that['family'] + ',sans-serif', style);
rulerB.onResize(function (width) {
widthB = width;
check();
});
rulerB.setFont(that['family'] + ',serif', style);
rulerC.onResize(function (width) {
widthC = width;
check();
});
rulerC.setFont(that['family'] + ',monospace', style);
});
};

View File

@ -0,0 +1,125 @@
var dom = require('./dom');
/**
* @constructor
* @param {string} text
*/
var Ruler = function (text) {
var style = 'display:inline-block;' +
'position:absolute;' +
'height:100%;' +
'width:100%;' +
'overflow:scroll;';
this.element = dom.createElement('div');
this.element.setAttribute('aria-hidden', 'true');
dom.append(this.element, dom.createText(text));
this.collapsible = dom.createElement('span');
this.expandable = dom.createElement('span');
this.collapsibleInner = dom.createElement('span');
this.expandableInner = dom.createElement('span');
this.lastOffsetWidth = -1;
dom.style(this.collapsible, style);
dom.style(this.expandable, style);
dom.style(this.expandableInner, style);
dom.style(this.collapsibleInner, 'display:inline-block;width:200%;height:200%;');
dom.append(this.collapsible, this.collapsibleInner);
dom.append(this.expandable, this.expandableInner);
dom.append(this.element, this.collapsible);
dom.append(this.element, this.expandable);
};
module.exports = Ruler;
/**
* @return {Element}
*/
Ruler.prototype.getElement = function () {
return this.element;
};
/**
* @param {string} family
* @param {string} description
*/
Ruler.prototype.setFont = function (family, description) {
dom.style(this.element, 'min-width:20px;' +
'min-height:20px;' +
'display:inline-block;' +
'position:absolute;' +
'width:auto;' +
'margin:0;' +
'padding:0;' +
'top:-999px;' +
'left:-999px;' +
'white-space:nowrap;' +
'font-size:100px;' +
'font-family:' + family + ';' +
description);
};
/**
* @return {number}
*/
Ruler.prototype.getWidth = function () {
return this.element.offsetWidth;
};
/**
* @param {string} width
*/
Ruler.prototype.setWidth = function (width) {
this.element.style.width = width + 'px';
};
/**
* @private
*
* @return {boolean}
*/
Ruler.prototype.reset = function () {
var offsetWidth = this.getWidth(),
width = offsetWidth + 100;
this.expandableInner.style.width = width + 'px';
this.expandable.scrollLeft = width;
this.collapsible.scrollLeft = this.collapsible.scrollWidth + 100;
if (this.lastOffsetWidth !== offsetWidth) {
this.lastOffsetWidth = offsetWidth;
return true;
} else {
return false;
}
};
/**
* @private
* @param {function(number)} callback
*/
Ruler.prototype.onScroll = function (callback) {
if (this.reset() && this.element.parentNode !== null) {
callback(this.lastOffsetWidth);
}
};
/**
* @param {function(number)} callback
*/
Ruler.prototype.onResize = function (callback) {
var that = this;
this.collapsible.addEventListener('scroll', function () {
that.onScroll(callback);
}, false);
this.expandable.addEventListener('scroll', function () {
that.onScroll(callback);
}, false);
this.reset();
};

View File

@ -0,0 +1,8 @@
<!doctype html>
<html>
<head>
</head>
<body>
hello
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,63 @@
describe('dom', function () {
var dom = require('../src/dom');
var jsdom = require('jsdom').jsdom;
beforeEach(function() {
document = jsdom('<html><head></head><body></body></html>');
});
describe('createElement', function () {
it('creates an element', function () {
expect(dom.createElement('div'), 'not to be null');
expect(dom.createElement('div').nodeName, 'to equal', 'DIV');
});
});
describe('createText', function () {
it('creates a text node', function () {
expect(dom.createText('hello'), 'not to be null');
expect(dom.createText('world').textContent, 'to equal', 'world');
});
});
describe('style', function () {
it('sets the style', function () {
var el = dom.createElement('div');
dom.style(el, 'font-size:12px');
expect(el.style.fontSize, 'to equal', '12px');
});
});
describe('append', function () {
it('adds a child node', function () {
var parent = dom.createElement('div');
dom.append(parent, dom.createElement('div'));
expect(parent.childNodes.length, 'to equal', 1);
dom.append(parent, dom.createElement('div'));
expect(parent.childNodes.length, 'to equal', 2);
});
});
describe('remove', function () {
it('removes child nodes', function () {
var parent = dom.createElement('div'),
child1 = dom.createElement('div'),
child2 = dom.createElement('div');
dom.append(parent, child1);
dom.append(parent, child2);
dom.remove(parent, child1);
expect(parent.childNodes.length, 'to equal', 1);
dom.remove(parent, child2);
expect(parent.childNodes.length, 'to equal', 0);
});
});
});

View File

@ -0,0 +1,73 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>FontFaceObserver</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="../node_modules/mocha/mocha.css" rel="stylesheet">
<style>
@font-face {
font-family: observer-test1;
src: url(assets/sourcesanspro-regular.woff) format('woff');
}
@font-face {
font-family: observer-test2;
src: url(unknown.woff) format('woff');
}
@font-face {
font-family: observer-test3;
src: url(assets/sourcesanspro-regular.woff) format('woff');
}
@font-face {
font-family: observer-test4;
src: url(assets/subset.woff) format('woff');
unicode-range: u+0021;
}
@font-face {
font-family: observer-test5;
src: url(assets/subset.woff) format('woff');
unicode-range: u+4e2d,u+56fd;
}
@font-face {
font-family: observer-test6;
src: url(assets/subset.woff) format('woff');
unicode-range: u+10ffff;
}
@font-face {
font-family: observer-test7;
src: url(assets/subset.woff) format('woff');
unicode-range: u+23;
}
</style>
</head>
<body>
<div id="mocha"></div>
<script>CLOSURE_NO_DEPS = true;</script>
<script src="../vendor/google/base.js"></script>
<script src="../vendor/sunesimonsen/unexpected.js"></script>
<script src="../node_modules/mocha/mocha.js"></script>
<script src="../node_modules/sinon/pkg/sinon.js"></script>
<script src="../node_modules/promis/promise.js"></script>
<script src="deps.js"></script>
<script>
goog.require('fontface.Observer');
mocha.ui('bdd');
expect = weknowhow.expect;
</script>
<script src="./dom-test.js"></script>
<script src="./ruler-test.js"></script>
<script src="./observer-test.js"></script>
<script>
window.onload = function () {
mocha.run();
};
</script>
</body>
</html>

View File

@ -0,0 +1,255 @@
describe('Observer', function () {
var Observer = fontface.Observer,
Ruler = fontface.Ruler;
describe('#constructor', function () {
it('creates a new instance with the correct signature', function () {
var observer = new Observer('my family', {});
expect(observer, 'not to be', null);
expect(observer.check, 'to be a function');
});
it('parses descriptors', function () {
var observer = new Observer('my family', {
weight: 'bold'
});
expect(observer.family, 'to equal', 'my family');
expect(observer.weight, 'to equal', 'bold');
});
it('defaults descriptors that are not given', function () {
var observer = new Observer('my family', {
weight: 'bold'
});
expect(observer.variant, 'to equal', 'normal');
});
});
describe('#getStyle', function () {
it('creates the correct default style', function () {
var observer = new Observer('my family', {});
expect(observer.getStyle(), 'to equal', 'font-style:normal;font-variant:normal;font-weight:normal;font-stretch:stretch;font-feature-settings:normal;-moz-font-feature-settings:normal;-webkit-font-feature-settings:normal;');
});
it('passes through all descriptors', function () {
var observer = new Observer('my family', {
style: 'italic',
variant: 'small-caps',
weight: 'bold',
stretch: 'condensed',
featureSettings: '"kern" 1'
});
expect(observer.getStyle(), 'to equal', 'font-style:italic;font-variant:small-caps;font-weight:bold;font-stretch:condensed;font-feature-settings:"kern" 1;-moz-font-feature-settings:"kern" 1;-webkit-font-feature-settings:"kern" 1;');
});
});
describe('#check', function () {
this.timeout(5000);
it('finds a font and resolve the promise', function (done) {
var observer = new Observer('observer-test1', {}),
ruler = new Ruler('hello');
document.body.appendChild(ruler.getElement());
ruler.setFont('monospace', '');
var beforeWidth = ruler.getWidth();
ruler.setFont('observer-test1, monospace', '');
observer.check(null, 5000).then(function () {
var activeWidth = ruler.getWidth();
expect(activeWidth, 'not to equal', beforeWidth);
setTimeout(function () {
var afterWidth = ruler.getWidth();
expect(afterWidth, 'to equal', activeWidth);
expect(afterWidth, 'not to equal', beforeWidth);
document.body.removeChild(ruler.getElement());
done();
}, 0);
}, function () {
done(new Error('Timeout'));
});
});
it('fails to find a font and reject the promise', function (done) {
var observer = new Observer('observer-test2', {});
observer.check(null, 50).then(function () {
done(new Error('Should not resolve'));
}, function () {
done();
});
});
it('finds the font even if it is already loaded', function (done) {
var observer = new Observer('observer-test3', {});
observer.check(null, 5000).then(function () {
observer.check(null, 5000).then(function () {
done();
}, function () {
done(new Error('Second call failed'));
});
}, function () {
done(new Error('Timeout'));
});
});
it('finds a font with a custom unicode range within ASCII', function (done) {
var observer = new Observer('observer-test4', {}),
ruler = new Ruler('\u0021');
ruler.setFont('monospace', '');
document.body.appendChild(ruler.getElement());
var beforeWidth = ruler.getWidth();
ruler.setFont('observer-test4,monospace', '');
observer.check('\u0021', 5000).then(function () {
var activeWidth = ruler.getWidth();
expect(activeWidth, 'not to equal', beforeWidth);
setTimeout(function () {
var afterWidth = ruler.getWidth();
expect(afterWidth, 'to equal', activeWidth);
expect(afterWidth, 'not to equal', beforeWidth);
document.body.removeChild(ruler.getElement());
done();
}, 0);
}, function () {
done(new Error('Timeout'));
});
});
it('finds a font with a custom unicode range outside ASCII (but within BMP)', function (done) {
var observer = new Observer('observer-test5', {}),
ruler = new Ruler('\u4e2d\u56fd');
ruler.setFont('monospace', '');
document.body.appendChild(ruler.getElement());
var beforeWidth = ruler.getWidth();
ruler.setFont('observer-test5,monospace', '');
observer.check('\u4e2d\u56fd', 5000).then(function () {
var activeWidth = ruler.getWidth();
expect(activeWidth, 'not to equal', beforeWidth);
setTimeout(function () {
var afterWidth = ruler.getWidth();
expect(afterWidth, 'to equal', activeWidth);
expect(afterWidth, 'not to equal', beforeWidth);
document.body.removeChild(ruler.getElement());
done();
}, 0);
}, function () {
done(new Error('Timeout'));
});
});
it('finds a font with a custom unicode range outside the BMP', function (done) {
var observer = new Observer('observer-test6', {}),
ruler = new Ruler('\udbff\udfff');
ruler.setFont('monospace', '');
document.body.appendChild(ruler.getElement());
var beforeWidth = ruler.getWidth();
ruler.setFont('observer-test6,monospace', '');
observer.check('\udbff\udfff', 5000).then(function () {
var activeWidth = ruler.getWidth();
expect(activeWidth, 'not to equal', beforeWidth);
setTimeout(function () {
var afterWidth = ruler.getWidth();
expect(afterWidth, 'to equal', activeWidth);
expect(afterWidth, 'not to equal', beforeWidth);
document.body.removeChild(ruler.getElement());
done();
}, 0);
}, function () {
done(new Error('Timeout'));
});
});
it('fails to find the font if it is available but does not contain the test string', function (done) {
var observer = new Observer('observer-test7', {});
observer.check(null, 50).then(function () {
done(new Error('Should not be called'));
}, function () {
done();
});
});
});
describe('hasWebKitFallbackBug', function () {
var getUserAgent = null;
beforeEach(function () {
Observer.HAS_WEBKIT_FALLBACK_BUG = null;
getUserAgent = sinon.stub(Observer, 'getUserAgent');
});
afterEach(function () {
getUserAgent.restore();
});
it('returns false when the user agent is not WebKit', function () {
getUserAgent.returns('Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/15.0 Firefox/14.0');
expect(Observer.hasWebKitFallbackBug(), 'to be false');
});
it('returns false when the user agent is WebKit but the bug is not present', function () {
getUserAgent.returns('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.12 (KHTML, like Gecko) Chrome/20.0.814.2 Safari/536.12');
expect(Observer.hasWebKitFallbackBug(), 'to be false');
});
it('returns true when the user agent is WebKit and the bug is present', function () {
getUserAgent.returns('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.814.2 Safari/536.11');
expect(Observer.hasWebKitFallbackBug(), 'to be true');
});
it('returns true when the user agent is WebKit and the bug is present in an old version', function () {
getUserAgent.returns('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/20.0.814.2 Safari/535.19');
expect(Observer.hasWebKitFallbackBug(), 'to be true');
});
it('caches the results', function () {
getUserAgent.returns('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.814.2 Safari/536.11');
expect(Observer.hasWebKitFallbackBug(), 'to be true');
getUserAgent.returns('Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/15.0 Firefox/14.0');
expect(Observer.hasWebKitFallbackBug(), 'to be true');
});
});
});

View File

@ -0,0 +1,122 @@
describe('Ruler', function () {
var Ruler = require('../src/ruler');
var ruler = null;
var jsdom = require('jsdom').jsdom;
beforeEach(function (done) {
jsdom.env(
'<html><head></head><body></body></html>',
[],
function (errors, window) {
ruler = new Ruler('hello');
ruler.setFont('', '');
ruler.setWidth(100);
document.body.appendChild(ruler.getElement());
done();
}
);
});
afterEach(function () {
document.body.removeChild(ruler.getElement());
ruler = null;
});
describe('#constructor', function () {
it('creates a new instance with the correct signature', function () {
expect(ruler, 'not to be', null);
expect(ruler.onResize, 'to be a function');
expect(ruler.setFont, 'to be a function');
});
});
// describe('#onResize', function () {
// it('detects expansion', function (done) {
// ruler.onResize(function (width) {
// expect(width, 'to equal', 200);
// done();
// });
//
// ruler.setWidth(200);
// });
//
// it('detects multiple expansions', function (done) {
// var first = true;
//
// ruler.onResize(function (width) {
// if (first) {
// expect(width, 'to equal', 200);
// ruler.setWidth(300);
// first = false;
// } else {
// expect(width, 'to equal', 300);
// done();
// }
// });
//
// ruler.setWidth(200);
// });
//
// it('detects collapse', function (done) {
// ruler.onResize(function (width) {
// expect(width, 'to equal', 50);
// done();
// });
//
// ruler.setWidth(50);
// });
//
// it('detects multiple collapses', function (done) {
// var first = true;
//
// ruler.onResize(function (width) {
// if (first) {
// expect(width, 'to equal', 70);
// ruler.setWidth(50);
// first = false;
// } else {
// expect(width, 'to equal', 50);
// done();
// }
// });
//
// ruler.setWidth(70);
// });
//
// it('detects a collapse and an expansion', function (done) {
// var first = true;
//
// ruler.onResize(function (width) {
// if (first) {
// expect(width, 'to equal', 70);
// ruler.setWidth(100);
// first = false;
// } else {
// expect(width, 'to equal', 100);
// done();
// }
// });
//
// ruler.setWidth(70);
// });
//
// it('detects an expansion and a collapse', function (done) {
// var first = true;
//
// ruler.onResize(function (width) {
// if (first) {
// expect(width, 'to equal', 200);
// ruler.setWidth(100);
// first = false;
// } else {
// expect(width, 'to equal', 100);
// done();
// }
// });
//
// ruler.setWidth(200);
// });
// });
});