1// Copyright: Copyright Scott Lininger. 2// License: All Rights Reserved. 3 4/** 5 * @fileoverview Provide the c123 namespace and general functions. 6 */ 7 8 9 10/** 11 * Namespace where we'll hang everything off of. Note that at the end of this 12 * file we're making a number of things global. 13 * @namespace 14 */ 15var c123 = c123 || {}; 16 17 18/** 19 * Namespace where we'll store any localized strings. 20 * @namespace 21 */ 22c123.strings = c123.strings || {}; 23 24 25/** 26 * Maximum line width. 27 * @const 28 * @type {number} 29 */ 30c123.MAX_LINE_WIDTH = 40; 31 32/** 33 * Minimum line width. 34 * @const 35 * @type {number} 36 */ 37c123.MIN_LINE_WIDTH = 0; 38 39/** 40 * Default line width. 41 * @const 42 * @type {number} 43 */ 44c123.INITIAL_LINE_WIDTH = 2; 45 46var LEFT = 'left'; 47var DOWN = 'down'; 48var RIGHT = 'right'; 49var UP = 'up'; 50var NORTH = 'north'; 51var SOUTH = 'south'; 52var EAST = 'east'; 53var WEST = 'west'; 54var CENTER = 'center'; 55var NORTHEAST = 'northeast'; 56var SOUTHEAST = 'southeast'; 57var NORTHWEST = 'northwest'; 58var SOUTHWEST = 'southwest'; 59 60/** 61 * A list of valid fonts and their definitions. 62 */ 63c123.fontList = { 64 'impact': 'Impact, Charcoal, sans-serif', 65 'palatino': '"Palatino Linotype", "Book Antiqua", Palatino, serif', 66 'tahoma': 'Tahoma, Geneva, sans-serif', 67 'roboto': 'roboto', 68 'sans': 'sans-serif', 69 'sans-serif': 'sans-serif', 70 'serif': 'serif', 71 'hand': 'cursive', 72 'mono': 'monospace', 73 'century': 'Century Gothic, sans-serif', 74 'lucida': '"Lucida Sans Unicode", "Lucida Grande", sans-serif', 75 'gadget': '"Arial Black", Gadget, sans-serif', 76 'times': '"Times New Roman", Times, serif', 77 'narrow': '"Arial Narrow", sans-serif', 78 'verdana': 'Verdana, Geneva, sans-serif', 79 'console': '"Lucida Console", Monaco, monospace', 80 'gill': '"Gill Sans", "Gill Sans MT", sans-serif', 81 'trebuchet': '"Trebuchet MS", Helvetica, sans-serif', 82 'courier': '"Courier New", Courier, monospace', 83 'arial': 'Arial, Helvetica, sans-serif', 84 'georgia': 'Georgia, Serif' 85}; 86 87/** 88 * A collection of google fonts. This gets populated in the c123.Library 89 * constructor. 90 */ 91c123.googleFonts = {}; 92 93// TODO(jeff): Does this variable name make sense for up and down? 94var compassDirections = {'north': true, 'south': true, 'east': true, 95 'west': true, 'northeast': true, 'southeast': true, 96 'northwest': true, 'southwest': true, 'up': true, 97 'down': true}; 98 99 100 101/** 102 * Handy bind function. 103 * @param {Function} fn The function to be bound. 104 * @param {Object} selfObj The object to be bound as 'this'. 105 * @param {Array} var_args The arguments to be handed in to the bound function. 106 * @return {Function} The newly bound function. 107 */ 108c123.bind = function(fn, selfObj, var_args) { 109 var boundArgs = fn.boundArgs_; 110 if (arguments.length > 2) { 111 var args = Array.prototype.slice.call(arguments, 2); 112 if (boundArgs) { args.unshift.apply(args, boundArgs); } 113 boundArgs = args; 114 } 115 selfObj = fn.boundSelf_ || selfObj; 116 fn = fn.boundFn_ || fn; 117 var newfn; 118 var context = selfObj || goog.global; 119 if (boundArgs) { 120 newfn = function() { 121 var args = Array.prototype.slice.call(arguments); 122 args.unshift.apply(args, boundArgs); 123 return fn.apply(context, args); 124 }; 125 } else { 126 newfn = function() { 127 return fn.apply(context, arguments); 128 }; 129 } 130 newfn.boundArgs_ = boundArgs; 131 newfn.boundSelf_ = selfObj; 132 newfn.boundFn_ = fn; 133 return newfn; 134}; 135 136 137/** 138 * Handy inherits function. Here's what usage looks like. 139 * 140 * c123.Car = function(settings) { 141 * this.fuel = 'gas'; 142 * this.wheels = 4; 143 * } 144 * 145 * c123.Tesla = function(settings) { 146 * // Call the constructor code of the parent (optional). 147 * c123.base(this, settings); 148 * this.fuel = 'electric'; 149 * } 150 * c123.inherits(c123.Tesla, c123.Car); 151 * 152 * 153 * @param {function} childCtor The child constructor. 154 * @param {function} parentCtor The parent constructor we want to inherit from. 155 */ 156c123.inherits = function(childCtor, parentCtor) { 157 /** 158 * Temporary constructor for inherits. 159 */ 160 function TempCtor() { 161 } 162 TempCtor.prototype = parentCtor.prototype; 163 childCtor.superClass_ = parentCtor.prototype; 164 childCtor.prototype = new TempCtor(); 165 childCtor.prototype.constructor = childCtor; 166}; 167 168 169/** 170 * Handy base function. Call from within the a constructor of child class and 171 * it'll run the code inside the parent's class constructor. 172 * See the c123.inherits function for an example. 173 * @param {Object} a The parent object. 174 * @param {Object} b The child object. 175 * @return {Object} The newly based object. 176 */ 177c123.base = function(a, b) { 178 var c = arguments.callee.caller; 179 if (c.superClass_) { 180 return c.superClass_.constructor.apply( 181 a, Array.prototype.slice.call(arguments, 1)); 182 } 183 for (var d = Array.prototype.slice.call(arguments, 2), e = false, 184 f = a.constructor;f;f = f.superClass_ && f.superClass_.constructor) { 185 if (f.prototype[b] === c) { 186 e = true; 187 } else if (e) { 188 return f.prototype[b].apply(a, d); 189 } 190 } 191 if (a[b] === c) { 192 return a.constructor.prototype[b].apply(a, d); 193 } 194 throw Error('c123.base called from a method of one name ' + 195 'to a method of a different name.'); 196};
197 198/** 199 * Detects if the user's browser is IE of any kind, but not Edge. 200 * @param {string} opt_userAgent An optional user agent string. Useful for 201 * unit testing. 202 * @return {Boolean} True if the user's browser is IE. 203 */ 204c123.isIE = function(opt_userAgent) { 205 var userAgent = opt_userAgent || navigator.userAgent; 206 return userAgent.indexOf('MSIE ') > -1 || 207 userAgent.indexOf('Trident') > -1; 208}; 209 210/** 211 * Detects if the user's browser is MS Edge of any kind. 212 * @param {string} opt_userAgent An optional user agent string. Useful for 213 * unit testing. 214 * @return {Boolean} True if the user's browser is MS Edge. 215 */ 216c123.isEdge = function(opt_userAgent) { 217 var userAgent = opt_userAgent || navigator.userAgent; 218 return userAgent.indexOf('Edge') > -1; 219}; 220 221 222/** 223 * Detects if the user's browser is netscape/firefox of any kind. 224 * @param {string} opt_userAgent An optional user agent string. Useful for 225 * unit testing. 226 * @return {Boolean} True if the user's browser is firefox. 227 */ 228c123.isFirefox = function(opt_userAgent) { 229 var userAgent = opt_userAgent || navigator.userAgent; 230 return userAgent.toLowerCase().indexOf('firefox') > -1; 231}; 232 233 234/** 235 * Returns whether the code is able to access the top frame. 236 * @return {string} path The datastore path. 237 */ 238c123.canAccessTopFrame = function() { 239 try { 240 // This code will fail if we try to access a top frame that doesn't match 241 // the domain the library is running within. 242 var topDocument = top.document; 243 if (topDocument) { 244 return true; 245 } else { 246 return false; 247 } 248 } catch(e) { 249 return false; 250 } 251}; 252 253/** 254 * Returns true if the query string has offline=1 somewhere inside it. 255 * @return {boolean} Whether we're in offline mode. 256 */ 257c123.isOfflineMode = function() { 258 return ('' + top.location.href).indexOf('offline=1') > -1; 259}; 260 261 262/** 263 * Gets a query parameter value based on the variable name. 264 * @param {string} name The parameter's name. 265 * @return {string} The value, or undefined if there's no variable of that name. 266 */ 267c123.getQueryParameter = function(name) { 268 var queryString = window.location.search.substr(1); 269 var parts = queryString.split('&'); 270 for (var i = 0; i < parts.length; i++) { 271 var tuple = parts[i].split('='); 272 if (tuple[0] === name && tuple.length > 1) { 273 return decodeURIComponent(tuple[1]); 274 } 275 } 276 return undefined; 277}; 278 279 280/** 281 * Stores the current language code, as passed on the query string as hl=. 282 * @return {string} The current language code, or 'en' if none is set. 283 */ 284c123.language = (c123.getQueryParameter('hl') || 'en').toLowerCase(); 285 286 287/** 288 * If a language code was passed in, load the appropriate API aliases. 289 */ 290if (c123.language !== 'en' && codepops.createScriptTag) { 291 var base = 'l10n/' + c123.language + '/' + c123.language; 292 293 codepops.createScriptTag({'src': base + '_colors.js', async: true}); 294 codepops.createScriptTag({'src': base + '_fills.js', async: true}); 295 codepops.createScriptTag({'src': base + '_songs.js', async: true}); 296 codepops.createScriptTag({'src': base + '_sounds.js', async: true}); 297 codepops.createScriptTag({'src': base + '_stamps.js', async: true}); 298 codepops.createScriptTag({'src': base + '_ui.js', async: true}); 299 codepops.createScriptTag({'src': base + '_library-1.3.js', async: true}); 300} 301 302 303/** 304 * Make the Array forEach method be a bit more case insensitive. 305 */ 306Array.prototype.foreach = Array.prototype.forEach; 307 308 309/** 310 * Checks if a font is available to be used on a web page. 311 * @param {String} fontName The font to check. 312 * @return {Boolean} Whether the font is available. 313 * @license MIT 314 * @copyright Sam Clarke 2013 315 * @author Sam Clarke <[email protected]> 316 * 317 * See: https://www.samclarke.com/javascript-is-font-available/ 318 */ 319c123.isFontAvailable = function(fontName) { 320 var width; 321 var body = document.body; 322 323 var container = document.createElement('span'); 324 container.innerHTML = Array(100).join('wi'); 325 container.style.cssText = [ 326 'position:absolute', 327 'width:auto', 328 'font-size:128px', 329 'left:-99999px' 330 ].join(' !important;'); 331 332 var getWidth = function (fontFamily) { 333 container.style.fontFamily = fontFamily; 334 335 body.appendChild(container); 336 width = container.clientWidth; 337 body.removeChild(container); 338 339 return width; 340 }; 341 342 // Pre compute the widths of monospace, serif & sans-serif 343 // to improve performance. 344 var monoWidth = getWidth('monospace'); 345 var serifWidth = getWidth('serif'); 346 var sansWidth = getWidth('sans-serif'); 347
348 return monoWidth !== getWidth(fontName + ',monospace') || 349 sansWidth !== getWidth(fontName + ',sans-serif') || 350 serifWidth !== getWidth(fontName + ',serif'); 351};
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.