/** * @private Returns a prototype object suitable for extending the given class * f. Rather than constructing a new instance of f to serve as * the prototype (which unnecessarily runs the constructor on the created * prototype object, potentially polluting it), an anonymous function is * generated internally that shares the same prototype: * *
function g() {}
 * g.prototype = f.prototype;
 * return new g();
* * For more details, see Douglas Crockford's essay on prototypal inheritance. * * @param {function} f a constructor. * @returns a suitable prototype object. * @see Douglas Crockford's essay on prototypal * inheritance. */ pv.extend = function(f) { function g() {} g.prototype = f.prototype || f; return new g(); }; try { eval("pv.parse = function(x) x;"); // native support } catch (e) { /** * @private Parses a Protovis specification, which may use JavaScript 1.8 * function expresses, replacing those function expressions with proper * functions such that the code can be run by a JavaScript 1.6 interpreter. This * hack only supports function expressions (using clumsy regular expressions, no * less), and not other JavaScript 1.8 features such as let expressions. * * @param {string} s a Protovis specification (i.e., a string of JavaScript 1.8 * source code). * @returns {string} a conformant JavaScript 1.6 source code. */ pv.parse = function(js) { // hacky regex support var re = new RegExp("function\\s*(\\b\\w+)?\\s*\\([^)]*\\)\\s*", "mg"), m, d, i = 0, s = ""; while (m = re.exec(js)) { var j = m.index + m[0].length; if (js.charAt(j) != '{') { s += js.substring(i, j) + "{return "; i = j; for (var p = 0; p >= 0 && j < js.length; j++) { var c = js.charAt(j); switch (c) { case '"': case '\'': { while (++j < js.length && (d = js.charAt(j)) != c) { if (d == '\\') j++; } break; } case '[': case '(': p++; break; case ']': case ')': p--; break; case ';': case ',': if (p == 0) p--; break; } } s += pv.parse(js.substring(i, --j)) + ";}"; i = j; } re.lastIndex = j; } s += js.substring(i); return s; }; } /** * @private Computes the value of the specified CSS property p on the * specified element e. * * @param {string} p the name of the CSS property. * @param e the element on which to compute the CSS property. */ pv.css = function(e, p) { return window.getComputedStyle ? window.getComputedStyle(e, null).getPropertyValue(p) : e.currentStyle[p]; }; /** * @private Reports the specified error to the JavaScript console. Mozilla only * allows logging to the console for privileged code; if the console is * unavailable, the alert dialog box is used instead. * * @param e the exception that triggered the error. */ pv.error = function(e) { (typeof console == "undefined") ? alert(e) : console.error(e); }; /** * @private Registers the specified listener for events of the specified type on * the specified target. For standards-compliant browsers, this method uses * addEventListener; for Internet Explorer, attachEvent. * * @param target a DOM element. * @param {string} type the type of event, such as "click". * @param {function} the event handler callback. */ pv.listen = function(target, type, listener) { listener = pv.listener(listener); return target.addEventListener ? target.addEventListener(type, listener, false) : target.attachEvent("on" + type, listener); }; /** * @private Returns a wrapper for the specified listener function such that the * {@link pv.event} is set for the duration of the listener's invocation. The * wrapper is cached on the returned function, such that duplicate registrations * of the wrapped event handler are ignored. * * @param {function} f an event handler. * @returns {function} the wrapped event handler. */ pv.listener = function(f) { return f.$listener || (f.$listener = function(e) { try { pv.event = e; return f.call(this, e); } finally { delete pv.event; } }); }; /** * @private Returns true iff a is an ancestor of e. This is useful * for ignoring mouseout and mouseover events that are contained within the * target element. */ pv.ancestor = function(a, e) { while (e) { if (e == a) return true; e = e.parentNode; } return false; }; /** @private Returns a locally-unique positive id. */ pv.id = function() { var id = 1; return function() { return id++; }; }(); /** @private Returns a function wrapping the specified constant. */ pv.functor = function(v) { return typeof v == "function" ? v : function() { return v; }; };