// fontfaceonload.js ;(function( win, doc ) { "use strict"; var TEST_STRING = 'AxmTYklsjo190QW', SANS_SERIF_FONTS = 'sans-serif', SERIF_FONTS = 'serif', defaultOptions = { tolerance: 2, // px delay: 100, glyphs: '', success: function() {}, error: function() {}, timeout: 5000, weight: '400', // normal style: 'normal' }, // See https://github.com/typekit/webfontloader/blob/master/src/core/fontruler.js#L41 style = [ 'display:block', 'position:absolute', 'top:-999px', 'left:-999px', 'font-size:48px', 'width:auto', 'height:auto', 'line-height:normal', 'margin:0', 'padding:0', 'font-variant:normal', 'white-space:nowrap' ], html = '
' + TEST_STRING + '
'; var FontFaceOnloadInstance = function() { this.fontFamily = ''; this.appended = false; this.serif = undefined; this.sansSerif = undefined; this.parent = undefined; this.options = {}; }; FontFaceOnloadInstance.prototype.getMeasurements = function () { return { sansSerif: { width: this.sansSerif.offsetWidth, height: this.sansSerif.offsetHeight }, serif: { width: this.serif.offsetWidth, height: this.serif.offsetHeight } }; }; FontFaceOnloadInstance.prototype.load = function () { var startTime = new Date(), that = this, serif = that.serif, sansSerif = that.sansSerif, parent = that.parent, appended = that.appended, dimensions, options = that.options, ref = options.reference; function getStyle( family ) { return style .concat( [ 'font-weight:' + options.weight, 'font-style:' + options.style ] ) .concat( "font-family:" + family ) .join( ";" ); } var sansSerifHtml = html.replace( /\%s/, getStyle( SANS_SERIF_FONTS ) ), serifHtml = html.replace( /\%s/, getStyle( SERIF_FONTS ) ); if( !parent ) { parent = that.parent = doc.createElement( "div" ); } parent.innerHTML = sansSerifHtml + serifHtml; sansSerif = that.sansSerif = parent.firstChild; serif = that.serif = sansSerif.nextSibling; if( options.glyphs ) { sansSerif.innerHTML += options.glyphs; serif.innerHTML += options.glyphs; } function hasNewDimensions( dims, el, tolerance ) { return Math.abs( dims.width - el.offsetWidth ) > tolerance || Math.abs( dims.height - el.offsetHeight ) > tolerance; } function isTimeout() { return ( new Date() ).getTime() - startTime.getTime() > options.timeout; } (function checkDimensions() { if( !ref ) { ref = doc.body; } if( !appended && ref ) { ref.appendChild( parent ); appended = that.appended = true; dimensions = that.getMeasurements(); // Make sure we set the new font-family after we take our initial dimensions: // handles the case where FontFaceOnload is called after the font has already // loaded. sansSerif.style.fontFamily = that.fontFamily + ', ' + SANS_SERIF_FONTS; serif.style.fontFamily = that.fontFamily + ', ' + SERIF_FONTS; } if( appended && dimensions && ( hasNewDimensions( dimensions.sansSerif, sansSerif, options.tolerance ) || hasNewDimensions( dimensions.serif, serif, options.tolerance ) ) ) { options.success(); } else if( isTimeout() ) { options.error(); } else { if( !appended && "requestAnimationFrame" in window ) { win.requestAnimationFrame( checkDimensions ); } else { win.setTimeout( checkDimensions, options.delay ); } } })(); }; // end load() FontFaceOnloadInstance.prototype.cleanFamilyName = function( family ) { return family.replace( /[\'\"]/g, '' ).toLowerCase(); }; FontFaceOnloadInstance.prototype.cleanWeight = function( weight ) { // lighter and bolder not supported var weightLookup = { normal: '400', bold: '700' }; return '' + (weightLookup[ weight ] || weight); }; FontFaceOnloadInstance.prototype.checkFontFaces = function( timeout ) { var _t = this; doc.fonts.forEach(function( font ) { if( _t.cleanFamilyName( font.family ) === _t.cleanFamilyName( _t.fontFamily ) && _t.cleanWeight( font.weight ) === _t.cleanWeight( _t.options.weight ) && font.style === _t.options.style ) { font.load().then(function() { _t.options.success(); win.clearTimeout( timeout ); }); } }); }; FontFaceOnloadInstance.prototype.init = function( fontFamily, options ) { var timeout; for( var j in defaultOptions ) { if( !options.hasOwnProperty( j ) ) { options[ j ] = defaultOptions[ j ]; } } this.options = options; this.fontFamily = fontFamily; // For some reason this was failing on afontgarde + icon fonts. if( !options.glyphs && "fonts" in doc ) { if( options.timeout ) { timeout = win.setTimeout(function() { options.error(); }, options.timeout ); } this.checkFontFaces( timeout ); } else { this.load(); } }; var FontFaceOnload = function( fontFamily, options ) { var instance = new FontFaceOnloadInstance(); instance.init(fontFamily, options); return instance; }; // intentional global win.FontFaceOnload = FontFaceOnload; })( this, this.document );