1/** 2 * FontDetect - A simple library to detect if an internal font is present or an external font got loaded. 3 * Updated by Ahmad Azimi: Add some functionality to support other languages, for example Farsi (Persian). 4 * 5 * TO USE: 6 * Include this file. If desired, you can load this file after the BODY. 7 * 8 * After you load the fonts you want to test, call either of these methods: 9 * 10 * // Checks that the font is loaded now. 11 * isLoaded = FontDetect.isFontLoaded(fontname); 12 * 13 * // Polls for the font getting loaded and calls a callback when it does. 14 * FontDetect.onFontLoaded(fontname, callback [, {onFail: xxx, msInterval: yyy, msTimeout: zzz}]); 15 * 16 * Note: For externally loaded fonts, you may have to wait for more than a second to get a reliable 17 * answer. Internal browser fonts can be detected immediately. 18 * 19 * // Determines which font in the font stack is being used for a given element. 20 * fontname = FontDetect.whichFont(element); // DOM element, or can be a $(expression) if jQuery is loaded 21 * 22 * @author Jennifer Simonds 23 * @copyright 2014 Jennifer Simonds 24 * @license MIT License http://opensource.org/licenses/MIT 25 */ 26FontDetect = function() 27{ 28 // The private parts 29 var _isInitialized = false; 30 var _aFallbackFonts = ['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy']; 31 var span = null; 32 var eLang = 'en'; 33 var aChars = { 34 'en': 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 35 'fa': 'Ø§Ø¨Ù¾ØªØ¬ÚØØ®Ø¯Ø°Ø±Ø²Ø³Ø´ØµØ¶Ø·Ø·Ø¹ØºÙÙÚ©Ú¯ÙÙ ÙÙÙÛ' 36 }; 37 38 function _init () 39 { 40 if (_isInitialized) 41 { return; 42 } 43 44 _isInitialized = true; 45 46 var body = document.body; 47 var firstChild = document.body.firstChild; 48 49 var div = document.createElement('div'); 50 div.id = 'fontdetectHelper'; 51 span = document.createElement('span'); 52 span.innerText = aChars[eLang]; 53 div.appendChild(span); 54 55 body.insertBefore(div,firstChild); 56 57 div.style.position = 'absolute'; 58 div.style.visibility = 'hidden'; 59 div.style.top = '-200px'; 60 div.style.left = '-100000px'; 61 div.style.width = '100000px'; 62 div.style.height = '200px'; 63 div.style.fontSize = '200px'; 64 } 65 66 67 function _getCss (p_element, p_cssStyle) 68 { 69 // First check if p_element is a DOM element. 70 if (p_element instanceof Element) 71 { return window.getComputedStyle(p_element).getPropertyValue(p_cssStyle); 72 } 73 74 // If jQuery's loaded, use that. 75 else if (window.jQuery) 76 { return $(p_element).css(p_cssStyle); 77 } 78 79 else // p_element might be a jQuery expression & caller was expecting jQuery to be loaded, 80 // or else some other parameter error... 81 { return ''; 82 } 83 } 84 85 86 // The public interface 87 return { 88 /** 89 * Polls 10 times/second until a font gets loaded or until it times out. (Default = 2 secs) It 90 * calls a callback on load, & optionally calls another function if it times out without loading. 91 * 92 * NOTE: You must specify at least one callback - for success or failure. 93 * 94 * @param string The font name to check for. 95 * @param function The function to call if it gets loaded within the timeout period. 96 * @param options An optional object with named parameters: 97 * @param eLang Which font language to use. Default = 'en'. 98 * @param onFail The function to call if the font doesn't load within the timeout period. 99 * @param msInterval How many milliseconds for the polling interval. Default = 100. 100 * @param msTimeout How many milliseconds until we time out & call onFail. Default = 2000. 101 */ 102 onFontLoaded: function (p_cssFontName, p_onLoad, p_onFail, p_options) 103 { 104 if (!p_cssFontName) 105 { return; 106 } 107 108 // Our hashtable of optional params. 109 var msInterval = (p_options && p_options.msInterval) ? p_options.msInterval : 100; 110 var msTimeout = (p_options && p_options.msTimeout) ? p_options.msTimeout : 2000; 111 var param1 = (p_options && p_options.param1) ? p_options.param1 : false; 112 var param2 = (p_options && p_options.param2) ? p_options.param2 : false; 113 // Since the language to use is an enum, check if the language they pass in is defined in aChars. 114 eLang = (p_options && p_options.eLang && p_options.eLang in aChars) ? p_options.eLang : 'en'; 115 116 if (!p_onLoad && !p_onFail) 117 { // Caller must specify at least one callback. 118 return; 119 } 120 121 if (!_isInitialized) 122 { _init (); 123 } 124 125 if (this.isFontLoaded(p_cssFontName)) 126 { // It's already here, so no need to poll. 127 if (p_onLoad) 128 { p_onLoad(p_cssFontName,param1,param2); 129 } 130 return; 131 } 132 133 // At this point we know the font hasn't loaded yet. Add it to the list of fonts to monitor. 134 135 // Set up an interval using msInterval. The callback calls isFontLoaded(), & if true
136 // it closes the interval & calls p_onLoad, else if the current time has timed out 137 // it closes the interval & calls onFail if there is one. 138 var outerThis = this; 139 var utStart = new Date().getTime(); 140 var idInterval = setInterval ( 141 function() 142 { 143 if (outerThis.isFontLoaded(p_cssFontName)) 144 { // It's now loaded. 145 clearInterval (idInterval); 146 if (p_onLoad) 147 { 148 p_onLoad(p_cssFontName,param1,param2); 149 } 150 return; 151 } 152 else 153 { // Still not loaded. 154 var utNow = new Date().getTime(); 155 if ((utNow - utStart) > msTimeout) 156 { 157 clearInterval (idInterval); 158 if (p_onFail) 159 { p_onFail(p_cssFontName); 160 } 161 } 162 } 163 }, 164 msInterval 165 ); 166 }, 167 168 169 /** 170 * Determines if a font has gotten loaded. 171 * 172 * @param string The font name to check for. 173 * 174 * @returns bool true if it's loaded, else false if the browser had to use a fallback font. 175 */ 176 isFontLoaded: function (p_cssFontName) 177 { 178 var wThisFont = 0; 179 var wPrevFont = 0; 180 181 if (!_isInitialized) 182 { _init (); 183 } 184 185 for(var ix = 0; ix < _aFallbackFonts.length; ++ix) 186 { 187 span.style.fontFamily = '"' + p_cssFontName + '",' + _aFallbackFonts[ix]; 188 wThisFont = span.offsetWidth; 189 if (ix > 0 && wThisFont != wPrevFont) 190 {// This iteration's font was different than the previous iteration's font, so it must 191 // have fallen back on a generic font. So our font must not exist. 192 return false; 193 } 194 195 wPrevFont = wThisFont; 196 } 197 198 // The widths were all the same, therefore the browser must have rendered the text in the same 199 // font every time. So unless all the generic fonts are identical widths (highly unlikely), it 200 // couldn't have fallen back to a generic font. It's our font. 201 return true; 202 }, 203 204 205 /** 206 * Determines which font is being used for a given element. 207 * 208 * @param string/object The element to examine. If it's a string, it's a jQuery selector. If it's 209 * an object, it's taken as a DOM element. 210 * 211 * @returns string The name of the font that's being used - either one of the fonts 212 * listed in the element's font-family css value, or null. 213 */ 214 whichFont: function (p_element) 215 { 216 var sStack = _getCss(p_element, 'font-family'); 217 var aStack = sStack.split(','); 218 219 var sFont = aStack.shift(); 220 while (sFont) 221 { 222 // Trim the fontname of any spaces or quotes. 223 sFont = sFont.replace(/^\s*['"]?\s*([^'"]*)\s*['"]?\s*$/, '$1'); 224 225 // If it's a default fallback font, trap it here. 226 for (var ix=0; ix < _aFallbackFonts.length; ix++) 227 { 228 if (sFont == _aFallbackFonts[ix]) 229 {return sFont; 230 } 231 } 232 233 // It must be a custom font name. Check it. 234 if (this.isFontLoaded(sFont)) 235 { return sFont; 236 } 237 238 sFont = aStack.shift(); 239 } 240 241 return null; 242 } 243 }; 244}();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.