Commit d21cd6c1 authored by Solly Ross's avatar Solly Ross

Cleanup: Util code

File: util.js
Tests Added: True (partial -- for logging and array push methods)
Changes:
- Fixed JSHint Errors (indentation, semicolons, global "use strict")
- Made browser detection methods more readable
- added some newline characters when appropriate for readability
- throw Errors not strings!
- Removed conf_defaults, and added make_properties and set_defaults
  instead (see below)

The removal of conf_defaults and switch to make_properties and
set_defaults is to facilitate the switch over to normal Javascript
constructors instead of Crockford-style constructors.  Now, methods
are added to the objects prototype (and thus make properties is called
outside the constructor).
parent fb64ed21
...@@ -6,9 +6,8 @@ ...@@ -6,9 +6,8 @@
* See README.md for usage and integration instructions. * See README.md for usage and integration instructions.
*/ */
"use strict"; /* jshint white: false, nonstandard: true */
/*jslint bitwise: false, white: false */ /*global window, console, document, navigator, ActiveXObject, INCLUDE_URI */
/*global window, console, document, navigator, ActiveXObject */
// Globals defined here // Globals defined here
var Util = {}; var Util = {};
...@@ -19,129 +18,161 @@ var Util = {}; ...@@ -19,129 +18,161 @@ var Util = {};
*/ */
Array.prototype.push8 = function (num) { Array.prototype.push8 = function (num) {
"use strict";
this.push(num & 0xFF); this.push(num & 0xFF);
}; };
Array.prototype.push16 = function (num) { Array.prototype.push16 = function (num) {
"use strict";
this.push((num >> 8) & 0xFF, this.push((num >> 8) & 0xFF,
(num ) & 0xFF ); num & 0xFF);
}; };
Array.prototype.push32 = function (num) { Array.prototype.push32 = function (num) {
"use strict";
this.push((num >> 24) & 0xFF, this.push((num >> 24) & 0xFF,
(num >> 16) & 0xFF, (num >> 16) & 0xFF,
(num >> 8) & 0xFF, (num >> 8) & 0xFF,
(num ) & 0xFF ); num & 0xFF);
}; };
// IE does not support map (even in IE9) // IE does not support map (even in IE9)
//This prototype is provided by the Mozilla foundation and //This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license. //is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.map) if (!Array.prototype.map) {
{ Array.prototype.map = function (fun /*, thisp*/) {
Array.prototype.map = function(fun /*, thisp*/) "use strict";
{ var len = this.length;
var len = this.length; if (typeof fun != "function") {
if (typeof fun != "function") throw new TypeError();
throw new TypeError(); }
var res = new Array(len);
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
res[i] = fun.call(thisp, this[i], i, this);
}
return res; var res = new Array(len);
}; var thisp = arguments[1];
for (var i = 0; i < len; i++) {
if (i in this) {
res[i] = fun.call(thisp, this[i], i, this);
}
}
return res;
};
} }
// IE <9 does not support indexOf // IE <9 does not support indexOf
//This prototype is provided by the Mozilla foundation and //This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license. //is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.indexOf) if (!Array.prototype.indexOf) {
{ Array.prototype.indexOf = function (elt /*, from*/) {
Array.prototype.indexOf = function(elt /*, from*/) "use strict";
{ var len = this.length >>> 0;
var len = this.length >>> 0;
var from = Number(arguments[1]) || 0;
var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from);
from = (from < 0) if (from < 0) {
? Math.ceil(from) from += len;
: Math.floor(from); }
if (from < 0)
from += len; for (; from < len; from++) {
if (from in this &&
for (; from < len; from++) this[from] === elt) {
{ return from;
if (from in this && }
this[from] === elt) }
return from; return -1;
} };
return -1;
};
} }
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) { if (!Object.keys) {
Object.keys = (function () { Object.keys = (function () {
'use strict'; 'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty, var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [ dontEnums = [
'toString', 'toString',
'toLocaleString', 'toLocaleString',
'valueOf', 'valueOf',
'hasOwnProperty', 'hasOwnProperty',
'isPrototypeOf', 'isPrototypeOf',
'propertyIsEnumerable', 'propertyIsEnumerable',
'constructor' 'constructor'
], ],
dontEnumsLength = dontEnums.length; dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
return function (obj) { var result = [], prop, i;
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i; for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
for (prop in obj) { if (hasDontEnumBug) {
if (hasOwnProperty.call(obj, prop)) { for (i = 0; i < dontEnumsLength; i++) {
result.push(prop); if (hasOwnProperty.call(obj, dontEnums[i])) {
} result.push(dontEnums[i]);
} }
}
}
return result;
};
})();
}
if (hasDontEnumBug) { // PhantomJS 1.x doesn't support bind,
for (i = 0; i < dontEnumsLength; i++) { // so leave this in until PhantomJS 2.0 is released
if (hasOwnProperty.call(obj, dontEnums[i])) { //This prototype is provided by the Mozilla foundation and
result.push(dontEnums[i]); //is distributed under the MIT license.
} //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError("Function.prototype.bind - " +
"what is trying to be bound is not callable");
} }
}
return result; var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis ? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
}; };
}());
} }
// //
// requestAnimationFrame shim with setTimeout fallback // requestAnimationFrame shim with setTimeout fallback
// //
window.requestAnimFrame = (function(){ window.requestAnimFrame = (function () {
return window.requestAnimationFrame || "use strict";
window.webkitRequestAnimationFrame || return window.requestAnimationFrame ||
window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
window.oRequestAnimationFrame || window.mozRequestAnimationFrame ||
window.msRequestAnimationFrame || window.oRequestAnimationFrame ||
function(callback){ window.msRequestAnimationFrame ||
function (callback) {
window.setTimeout(callback, 1000 / 60); window.setTimeout(callback, 1000 / 60);
}; };
})(); })();
/* /*
* ------------------------------------------------------ * ------------------------------------------------------
* Namespaced in Util * Namespaced in Util
* ------------------------------------------------------ * ------------------------------------------------------
...@@ -153,6 +184,7 @@ window.requestAnimFrame = (function(){ ...@@ -153,6 +184,7 @@ window.requestAnimFrame = (function(){
Util._log_level = 'warn'; Util._log_level = 'warn';
Util.init_logging = function (level) { Util.init_logging = function (level) {
"use strict";
if (typeof level === 'undefined') { if (typeof level === 'undefined') {
level = Util._log_level; level = Util._log_level;
} else { } else {
...@@ -163,26 +195,34 @@ Util.init_logging = function (level) { ...@@ -163,26 +195,34 @@ Util.init_logging = function (level) {
window.console = { window.console = {
'log' : window.opera.postError, 'log' : window.opera.postError,
'warn' : window.opera.postError, 'warn' : window.opera.postError,
'error': window.opera.postError }; 'error': window.opera.postError
};
} else { } else {
window.console = { window.console = {
'log' : function(m) {}, 'log' : function (m) {},
'warn' : function(m) {}, 'warn' : function (m) {},
'error': function(m) {}}; 'error': function (m) {}
};
} }
} }
Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {}; Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
/* jshint -W086 */
switch (level) { switch (level) {
case 'debug': Util.Debug = function (msg) { console.log(msg); }; case 'debug':
case 'info': Util.Info = function (msg) { console.log(msg); }; Util.Debug = function (msg) { console.log(msg); };
case 'warn': Util.Warn = function (msg) { console.warn(msg); }; case 'info':
case 'error': Util.Error = function (msg) { console.error(msg); }; Util.Info = function (msg) { console.log(msg); };
case 'warn':
Util.Warn = function (msg) { console.warn(msg); };
case 'error':
Util.Error = function (msg) { console.error(msg); };
case 'none': case 'none':
break; break;
default: default:
throw("invalid logging type '" + level + "'"); throw new Error("invalid logging type '" + level + "'");
} }
/* jshint +W086 */
}; };
Util.get_logging = function () { Util.get_logging = function () {
return Util._log_level; return Util._log_level;
...@@ -190,93 +230,133 @@ Util.get_logging = function () { ...@@ -190,93 +230,133 @@ Util.get_logging = function () {
// Initialize logging level // Initialize logging level
Util.init_logging(); Util.init_logging();
Util.make_property = function (proto, name, mode, type) {
"use strict";
// Set configuration default for Crockford style function namespaces var getter;
Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) { if (type === 'arr') {
var getter, setter; getter = function (idx) {
if (typeof idx !== 'undefined') {
return this['_' + name][idx];
} else {
return this['_' + name];
}
};
} else {
getter = function () {
return this['_' + name];
};
}
// Default getter function var make_setter = function (process_val) {
getter = function (idx) { if (process_val) {
if ((type in {'arr':1, 'array':1}) && return function (val, idx) {
(typeof idx !== 'undefined')) { if (typeof idx !== 'undefined') {
return cfg[v][idx]; this['_' + name][idx] = process_val(val);
} else {
this['_' + name] = process_val(val);
}
};
} else { } else {
return cfg[v]; return function (val, idx) {
if (typeof idx !== 'undefined') {
this['_' + name][idx] = val;
} else {
this['_' + name] = val;
}
};
} }
}; };
// Default setter function var setter;
setter = function (val, idx) { if (type === 'bool') {
if (type in {'boolean':1, 'bool':1}) { setter = make_setter(function (val) {
if ((!val) || (val in {'0':1, 'no':1, 'false':1})) { if (!val || (val in {'0': 1, 'no': 1, 'false': 1})) {
val = false; return false;
} else { } else {
val = true; return true;
} }
} else if (type in {'integer':1, 'int':1}) { });
val = parseInt(val, 10); } else if (type === 'int') {
} else if (type === 'str') { setter = make_setter(function (val) { return parseInt(val, 10); });
val = String(val); } else if (type === 'float') {
} else if (type === 'func') { setter = make_setter(parseFloat);
} else if (type === 'str') {
setter = make_setter(String);
} else if (type === 'func') {
setter = make_setter(function (val) {
if (!val) { if (!val) {
val = function () {}; return function () {};
} else {
return val;
} }
} });
if (typeof idx !== 'undefined') { } else if (type === 'arr' || type === 'dom' || type == 'raw') {
cfg[v][idx] = val; setter = make_setter();
} else { } else {
cfg[v] = val; throw new Error('Unknown property type ' + type); // some sanity checking
} }
};
// Set the description
api[v + '_description'] = desc;
// Set the getter function // set the getter
if (typeof api['get_' + v] === 'undefined') { if (typeof proto['get_' + name] === 'undefined') {
api['get_' + v] = getter; proto['get_' + name] = getter;
} }
// Set the setter function with extra sanity checks // set the setter if needed
if (typeof api['set_' + v] === 'undefined') { if (typeof proto['set_' + name] === 'undefined') {
api['set_' + v] = function (val, idx) { if (mode === 'rw') {
if (mode in {'RO':1, 'ro':1}) { proto['set_' + name] = setter;
throw(v + " is read-only"); } else if (mode === 'wo') {
} else if ((mode in {'WO':1, 'wo':1}) && proto['set_' + name] = function (val, idx) {
(typeof cfg[v] !== 'undefined')) { if (typeof this['_' + name] !== 'undefined') {
throw(v + " can only be set once"); throw new Error(name + " can only be set once");
} }
setter(val, idx); setter.call(this, val, idx);
}; };
}
} }
// Set the default value // make a special setter that we can use in set defaults
if (typeof defaults[v] !== 'undefined') { proto['_raw_set_' + name] = function (val, idx) {
defval = defaults[v]; setter.call(this, val, idx);
} else if ((type in {'arr':1, 'array':1}) && //delete this['_init_set_' + name]; // remove it after use
(! (defval instanceof Array))) { };
defval = []; };
Util.make_properties = function (constructor, arr) {
"use strict";
for (var i = 0; i < arr.length; i++) {
Util.make_property(constructor.prototype, arr[i][0], arr[i][1], arr[i][2]);
} }
// Coerce existing setting to the right type
//Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]);
setter(defval);
}; };
// Set group of configuration defaults Util.set_defaults = function (obj, conf, defaults) {
Util.conf_defaults = function(cfg, api, defaults, arr) { var defaults_keys = Object.keys(defaults);
var conf_keys = Object.keys(conf);
var keys_obj = {};
var i; var i;
for (i = 0; i < arr.length; i++) { for (i = 0; i < defaults_keys.length; i++) { keys_obj[defaults_keys[i]] = 1; }
Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1], for (i = 0; i < conf_keys.length; i++) { keys_obj[conf_keys[i]] = 1; }
arr[i][2], arr[i][3], arr[i][4]); var keys = Object.keys(keys_obj);
for (i = 0; i < keys.length; i++) {
var setter = obj['_raw_set_' + keys[i]];
if (conf[keys[i]]) {
setter.call(obj, conf[keys[i]]);
} else {
setter.call(obj, defaults[keys[i]]);
}
} }
}; };
/* /*
* Decode from UTF-8 * Decode from UTF-8
*/ */
Util.decodeUTF8 = function(utf8string) { Util.decodeUTF8 = function (utf8string) {
"use strict";
return decodeURIComponent(escape(utf8string)); return decodeURIComponent(escape(utf8string));
} };
...@@ -291,42 +371,46 @@ Util.decodeUTF8 = function(utf8string) { ...@@ -291,42 +371,46 @@ Util.decodeUTF8 = function(utf8string) {
// Handles the case where load_scripts is invoked from a script that // Handles the case where load_scripts is invoked from a script that
// itself is loaded via load_scripts. Once all scripts are loaded the // itself is loaded via load_scripts. Once all scripts are loaded the
// window.onscriptsloaded handler is called (if set). // window.onscriptsloaded handler is called (if set).
Util.get_include_uri = function() { Util.get_include_uri = function () {
return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/"; return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/";
} };
Util._loading_scripts = []; Util._loading_scripts = [];
Util._pending_scripts = []; Util._pending_scripts = [];
Util.load_scripts = function(files) { Util.load_scripts = function (files) {
"use strict";
var head = document.getElementsByTagName('head')[0], script, var head = document.getElementsByTagName('head')[0], script,
ls = Util._loading_scripts, ps = Util._pending_scripts; ls = Util._loading_scripts, ps = Util._pending_scripts;
for (var f=0; f<files.length; f++) {
var loadFunc = function (e) {
while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
ls[0].readyState === 'complete')) {
// For IE, append the script to trigger execution
var s = ls.shift();
//console.log("loaded script: " + s.src);
head.appendChild(s);
}
if (!this.readyState ||
(Util.Engine.presto && this.readyState === 'loaded') ||
this.readyState === 'complete') {
if (ps.indexOf(this) >= 0) {
this.onload = this.onreadystatechange = null;
//console.log("completed script: " + this.src);
ps.splice(ps.indexOf(this), 1);
// Call window.onscriptsload after last script loads
if (ps.length === 0 && window.onscriptsload) {
window.onscriptsload();
}
}
}
};
for (var f = 0; f < files.length; f++) {
script = document.createElement('script'); script = document.createElement('script');
script.type = 'text/javascript'; script.type = 'text/javascript';
script.src = Util.get_include_uri() + files[f]; script.src = Util.get_include_uri() + files[f];
//console.log("loading script: " + script.src); //console.log("loading script: " + script.src);
script.onload = script.onreadystatechange = function (e) { script.onload = script.onreadystatechange = loadFunc;
while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
ls[0].readyState === 'complete')) {
// For IE, append the script to trigger execution
var s = ls.shift();
//console.log("loaded script: " + s.src);
head.appendChild(s);
}
if (!this.readyState ||
(Util.Engine.presto && this.readyState === 'loaded') ||
this.readyState === 'complete') {
if (ps.indexOf(this) >= 0) {
this.onload = this.onreadystatechange = null;
//console.log("completed script: " + this.src);
ps.splice(ps.indexOf(this), 1);
// Call window.onscriptsload after last script loads
if (ps.length === 0 && window.onscriptsload) {
window.onscriptsload();
}
}
}
};
// In-order script execution tricks // In-order script execution tricks
if (Util.Engine.trident) { if (Util.Engine.trident) {
// For IE wait until readyState is 'loaded' before // For IE wait until readyState is 'loaded' before
...@@ -341,20 +425,22 @@ Util.load_scripts = function(files) { ...@@ -341,20 +425,22 @@ Util.load_scripts = function(files) {
} }
ps.push(script); ps.push(script);
} }
} };
// Get DOM element position on page // Get DOM element position on page
// This solution is based based on http://www.greywyvern.com/?post=331 // This solution is based based on http://www.greywyvern.com/?post=331
// Thanks to Brian Huisman AKA GreyWyvern! // Thanks to Brian Huisman AKA GreyWyvern!
Util.getPosition = (function() { Util.getPosition = (function () {
"use strict";
function getStyle(obj, styleProp) { function getStyle(obj, styleProp) {
var y;
if (obj.currentStyle) { if (obj.currentStyle) {
var y = obj.currentStyle[styleProp]; y = obj.currentStyle[styleProp];
} else if (window.getComputedStyle) } else if (window.getComputedStyle)
var y = window.getComputedStyle(obj, null)[styleProp]; y = window.getComputedStyle(obj, null)[styleProp];
return y; return y;
}; }
function scrollDist() { function scrollDist() {
var myScrollTop = 0, myScrollLeft = 0; var myScrollTop = 0, myScrollLeft = 0;
...@@ -383,7 +469,7 @@ Util.getPosition = (function() { ...@@ -383,7 +469,7 @@ Util.getPosition = (function() {
} }
return [myScrollLeft, myScrollTop]; return [myScrollLeft, myScrollTop];
}; }
return function (obj) { return function (obj) {
var curleft = 0, curtop = 0, scr = obj, fixed = false; var curleft = 0, curtop = 0, scr = obj, fixed = false;
...@@ -403,7 +489,7 @@ Util.getPosition = (function() { ...@@ -403,7 +489,7 @@ Util.getPosition = (function() {
do { do {
curleft += obj.offsetLeft; curleft += obj.offsetLeft;
curtop += obj.offsetTop; curtop += obj.offsetTop;
} while (obj = obj.offsetParent); } while ((obj = obj.offsetParent));
return {'x': curleft, 'y': curtop}; return {'x': curleft, 'y': curtop};
}; };
...@@ -412,6 +498,7 @@ Util.getPosition = (function() { ...@@ -412,6 +498,7 @@ Util.getPosition = (function() {
// Get mouse event position in DOM element // Get mouse event position in DOM element
Util.getEventPosition = function (e, obj, scale) { Util.getEventPosition = function (e, obj, scale) {
"use strict";
var evt, docX, docY, pos; var evt, docX, docY, pos;
//if (!e) evt = window.event; //if (!e) evt = window.event;
evt = (e ? e : window.event); evt = (e ? e : window.event);
...@@ -431,38 +518,41 @@ Util.getEventPosition = function (e, obj, scale) { ...@@ -431,38 +518,41 @@ Util.getEventPosition = function (e, obj, scale) {
} }
var realx = docX - pos.x; var realx = docX - pos.x;
var realy = docY - pos.y; var realy = docY - pos.y;
var x = Math.max(Math.min(realx, obj.width-1), 0); var x = Math.max(Math.min(realx, obj.width - 1), 0);
var y = Math.max(Math.min(realy, obj.height-1), 0); var y = Math.max(Math.min(realy, obj.height - 1), 0);
return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale}; return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale};
}; };
// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events // Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
Util.addEvent = function (obj, evType, fn){ Util.addEvent = function (obj, evType, fn) {
if (obj.attachEvent){ "use strict";
var r = obj.attachEvent("on"+evType, fn); if (obj.attachEvent) {
var r = obj.attachEvent("on" + evType, fn);
return r; return r;
} else if (obj.addEventListener){ } else if (obj.addEventListener) {
obj.addEventListener(evType, fn, false); obj.addEventListener(evType, fn, false);
return true; return true;
} else { } else {
throw("Handler could not be attached"); throw new Error("Handler could not be attached");
} }
}; };
Util.removeEvent = function(obj, evType, fn){ Util.removeEvent = function (obj, evType, fn) {
if (obj.detachEvent){ "use strict";
var r = obj.detachEvent("on"+evType, fn); if (obj.detachEvent) {
var r = obj.detachEvent("on" + evType, fn);
return r; return r;
} else if (obj.removeEventListener){ } else if (obj.removeEventListener) {
obj.removeEventListener(evType, fn, false); obj.removeEventListener(evType, fn, false);
return true; return true;
} else { } else {
throw("Handler could not be removed"); throw new Error("Handler could not be removed");
} }
}; };
Util.stopEvent = function(e) { Util.stopEvent = function (e) {
"use strict";
if (e.stopPropagation) { e.stopPropagation(); } if (e.stopPropagation) { e.stopPropagation(); }
else { e.cancelBubble = true; } else { e.cancelBubble = true; }
...@@ -474,41 +564,88 @@ Util.stopEvent = function(e) { ...@@ -474,41 +564,88 @@ Util.stopEvent = function(e) {
// Set browser engine versions. Based on mootools. // Set browser engine versions. Based on mootools.
Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)}; Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
Util.Engine = { (function () {
// Version detection break in Opera 11.60 (errors on arguments.callee.caller reference) "use strict";
//'presto': (function() { // 'presto': (function () { return (!window.opera) ? false : true; }()),
// return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()), var detectPresto = function () {
'presto': (function() { return (!window.opera) ? false : true; }()), return !!window.opera;
};
'trident': (function() {
return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()), // 'trident': (function () { return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
'webkit': (function() { var detectTrident = function () {
try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()), if (!window.ActiveXObject) {
//'webkit': (function() { return false;
// return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()), } else {
'gecko': (function() { if (window.XMLHttpRequest) {
return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }()) return (document.querySelectorAll) ? 6 : 5;
}; } else {
if (Util.Engine.webkit) { return 4;
// Extract actual webkit version if available }
Util.Engine.webkit = (function(v) { }
var re = new RegExp('WebKit/([0-9\.]*) '); };
v = (navigator.userAgent.match(re) || ['', v])[1];
return parseFloat(v, 10); // 'webkit': (function () { try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
})(Util.Engine.webkit); var detectInitialWebkit = function () {
} try {
if (navigator.taintEnabled) {
return false;
} else {
if (Util.Features.xpath) {
return (Util.Features.query) ? 525 : 420;
} else {
return 419;
}
}
} catch (e) {
return false;
}
};
var detectActualWebkit = function (initial_ver) {
var re = /WebKit\/([0-9\.]*) /;
var str_ver = (navigator.userAgent.match(re) || ['', initial_ver])[1];
return parseFloat(str_ver, 10);
};
// 'gecko': (function () { return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19ssName) ? 19 : 18 : 18); }())
var detectGecko = function () {
/* jshint -W041 */
if (!document.getBoxObjectFor && window.mozInnerScreenX == null) {
return false;
} else {
return (document.getElementsByClassName) ? 19 : 18;
}
/* jshint +W041 */
};
Util.Engine = {
// Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
//'presto': (function() {
// return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
'presto': detectPresto(),
'trident': detectTrident(),
'webkit': detectInitialWebkit(),
'gecko': detectGecko(),
};
if (Util.Engine.webkit) {
// Extract actual webkit version if available
Util.Engine.webkit = detectActualWebkit(Util.Engine.webkit);
}
})();
Util.Flash = (function(){ Util.Flash = (function () {
"use strict";
var v, version; var v, version;
try { try {
v = navigator.plugins['Shockwave Flash'].description; v = navigator.plugins['Shockwave Flash'].description;
} catch(err1) { } catch (err1) {
try { try {
v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
} catch(err2) { } catch (err2) {
v = '0 r0'; v = '0 r0';
} }
} }
version = v.match(/\d+/g); version = v.match(/\d+/g);
return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0}; return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
}()); }());
// requires local modules: util
/* jshint expr: true */
var assert = chai.assert;
var expect = chai.expect;
describe('Utils', function() {
"use strict";
describe('Array instance methods', function () {
describe('push8', function () {
it('should push a byte on to the array', function () {
var arr = [1];
arr.push8(128);
expect(arr).to.deep.equal([1, 128]);
});
it('should only use the least significant byte of any number passed in', function () {
var arr = [1];
arr.push8(0xABCD);
expect(arr).to.deep.equal([1, 0xCD]);
});
});
describe('push16', function () {
it('should push two bytes on to the array', function () {
var arr = [1];
arr.push16(0xABCD);
expect(arr).to.deep.equal([1, 0xAB, 0xCD]);
});
it('should only use the two least significant bytes of any number passed in', function () {
var arr = [1];
arr.push16(0xABCDEF);
expect(arr).to.deep.equal([1, 0xCD, 0xEF]);
});
});
describe('push32', function () {
it('should push four bytes on to the array', function () {
var arr = [1];
arr.push32(0xABCDEF12);
expect(arr).to.deep.equal([1, 0xAB, 0xCD, 0xEF, 0x12]);
});
it('should only use the four least significant bytes of any number passed in', function () {
var arr = [1];
arr.push32(0xABCDEF1234);
expect(arr).to.deep.equal([1, 0xCD, 0xEF, 0x12, 0x34]);
});
});
});
describe('logging functions', function () {
beforeEach(function () {
sinon.spy(console, 'log');
sinon.spy(console, 'warn');
sinon.spy(console, 'error');
});
afterEach(function () {
console.log.restore();
console.warn.restore();
console.error.restore();
});
it('should use noop for levels lower than the min level', function () {
Util.init_logging('warn');
Util.Debug('hi');
Util.Info('hello');
expect(console.log).to.not.have.been.called;
});
it('should use console.log for Debug and Info', function () {
Util.init_logging('debug');
Util.Debug('dbg');
Util.Info('inf');
expect(console.log).to.have.been.calledWith('dbg');
expect(console.log).to.have.been.calledWith('inf');
});
it('should use console.warn for Warn', function () {
Util.init_logging('warn');
Util.Warn('wrn');
expect(console.warn).to.have.been.called;
expect(console.warn).to.have.been.calledWith('wrn');
});
it('should use console.error for Error', function () {
Util.init_logging('error');
Util.Error('err');
expect(console.error).to.have.been.called;
expect(console.error).to.have.been.calledWith('err');
});
});
// TODO(directxman12): test the conf_default and conf_defaults methods
// TODO(directxman12): test decodeUTF8
// TODO(directxman12): test the event methods (addEvent, removeEvent, stopEvent)
// TODO(directxman12): figure out a good way to test getPosition and getEventPosition
// TODO(directxman12): figure out how to test the browser detection functions properly
// (we can't really test them against the browsers, except for Gecko
// via PhantomJS, the default test driver)
// TODO(directxman12): figure out how to test Util.Flash
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment