/*
* Common tools for JavaScript to support multiple browsers and languages.
*
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
js = {}
/** =======================================================================
* Logging API.
*
* Allows for sending debug info to a console window. Potentially,
* one for each of the different modes, along with a rendering hook for it.
* This way, some pages could define a particular section on their page for
* reporting errors.
*/
js.log = {}
/**
* public static void inlineConsole()
*/
js.log.inlineConsole = function() {
document.writeln(
"<div id='js-console-outer' class='js-console-outer'>" +
js.messages.console_title +
" <button class='js-console-button' onClick=" +
"'document.getElementById(\"js-console\").innerHTML = \"\";'>" +
js.messages.console_button +
"</button>" +
"<div id='js-console' class='js-console'></div>");
js.log.setDisplay(document.getElementById('js-console'));
js.log.DEBUG.format = '"<br /><span class=\'js-console-debug\'>[debug] {?1}</span>"';
js.log.WARN.format = '"<br /><span class=\'js-console-warn\'>Warning: {?1}</span>"';
js.log.ERROR.format = '"<br /><span class=\'js-console-error\'>Error: {?1}</span>"';
js.log.FAILURE.format = '"<br /><span class=\'js-console-failure\'>Failure: {?1}</span>"';
js.log.EXCEPT.format = '"<br /><span class=\'js-console-except\'>Exception: {?1}\nException {?2}:\n{?3}</span>"';
}
/**
* public static void setDisplay(domNode)
*/
js.log.setDisplay = function(display) {
for (var p in js.log) {
var x = js.log[p];
if (x['parseArgsFunc']) {
x['display'] = display;
}
}
}
js.log.LevelType = function(name, enabled, display, format, parseArgsFunc) {
if (enabled == null) {
enabled = true;
}
if (format == null) {
format = '"' + name + ': {1}"';
}
if (parseArgsFunc == null) {
parseArgsFunc = js.log.parseArgs_default;
}
this.name = name;
this.enabled = true;
this.display = display;
this.format = format;
this.parseArgsFunc = parseArgsFunc;
this.log = js.log.log;
}
js.log.log = function() {
if (this.enabled) {
// eval the format so that post-setup references can be altered
var fmt = '';
try {
fmt = eval(this.format);
} catch (e) {
alert(js.msg(js.messages.except,
js.msg(js.messages.bad_eval, this.format), e.name, e.message));
}
var args = new Array(fmt);
this.parseArgsFunc(args, arguments);
var msg = js.msg2(args);
if (this.display) {
this.display.innerHTML += msg;
} else {
alert(msg);
}
}
}
js.log.parseArgs_default = function(list, args) {
for (var i = 0; i < args.length; i++) {
list.push(args[i]);
}
}
js.log.parseArgs_except = function(list, args) {
if (args.length > 0) {
list.push(args[0]);
if (args.length > 1) {
var e = args[1];
if (e) {
list.push(ex.name);
list.push(ex.message);
}
}
}
}
/* List of log levels, and how they are displayed. These can be overridden
* by the implementation, or altered by the implementation.
*/
js.log.DEBUG = new js.log.LevelType('debug', false, null, null);
js.log.WARN = new js.log.LevelType('warn', false, null, 'js.messages.error');
js.log.ERROR = new js.log.LevelType('err', true, null, 'js.messages.error');
js.log.FAILURE = new js.log.LevelType('fail', true, null, 'js.messages.failure');
js.log.EXCEPT = new js.log.LevelType('except', true, null, 'js.messages.except',
js.log.parseArgs_except);
/**
* public void js.debug(String text)
*/
js.debug = function(text) {
js.log.DEBUG.log(text);
}
/**
* public void js.warn(String text)
*/
js.warn = function(text) {
js.log.WARN.log(text);
}
/**
* public void js.error(String text)
*/
js.error = function(text) {
js.log.ERROR.log(text);
}
/**
* public void js.failure(String text)
*/
js.failure = function(text) {
js.log.FAILURE.log(text);
}
/**
* public void js.except(String text, Exception ex)
*/
js.except = function(text, ex) {
js.log.EXCEPT.log(text, ex);
}
/** ========================================================================
* Message Formatting
*
* Allows for message objects and localization.
*/
/**
* String msg(String text, ...)
*
* Generates a computed message using {1}, {2}, ... style replacements.
* Used for generating language-specific messages. Argument indicies start
* at 1.
*/
js.msg = function() {
return js.msg2(arguments);
}
js.msg2 = function(args) {
if (args.length <= 0) {
return "";
}
var subs = args[0];
var a2 = new Array();
for (var i = 1; i < args.length; i++) {
a2[i-1] = args[i];
}
return js.__message.parse(subs, args, js.__message.parseIndex);
}
js.parseMsg = function(subs, context) {
if (context == null) {
context = window;
}
return js.__message.parse(subs, context, js.__message.parseContext);
}
js.__message = {}
js.__message.parse = function(subs, args, parseFunc) {
var ret = "";
var len = subs.length;
var start = 0;
while (start < len) {
var pos = subs.indexOf('{', start);
if (pos >= 0) {
var npos = subs.indexOf('}', pos+1);
if (npos >= 0) {
var replace = subs.substring(pos+1, npos);
var txt = '';
if (replace.length > 0 && replace.charAt(0) == '?') {
txt = js.escapeHtml(parseFunc(replace.substring(1), args));
} else {
txt = parseFunc(replace, args);
}
ret = ret + subs.substring(start, pos) + txt;
start = npos + 1;
} else {
ret = ret + subs.substring(start, pos + 1);
start = pos + 1;
}
} else {
// end of string
ret = ret + subs.substring(start, len);
start = len;
}
}
return ret;
}
js.__message.parseIndex = function(text, args) {
var index = parseInt(text);
if (index > 0 && index < args.length) {
return args[index];
} else {
return '{' + text + '}';
}
}
js.__message.parseContext = function(text, context) {
var seps = text.split('.');
var out = context;
var tc = 'context';
var txt = '';
for (var i = 0; i < seps.length; i++) {
if (out[seps[i]]) {
tc += '.' + seps[i];
out = out[seps[i]];
txt = '' + out;
} else {
txt = '{' + js.msg(js.messages.bad_eval_parse,
tc, seps[i]) + '}';
break;
}
}
return txt;
}
js.escapeHtml = function(txt) {
if (! txt) {
return 'null';
}
return txt.replace(/\&/g, '&').replace(/\</g, '<').
replace(/\>/g, '>').
replace(/"/g, '"');
}
js.isFunction = function(a) {
return typeof a == 'function';
}
/* ========================================================================
* Browser compatibility functions. For internal use only.
*/
js.__compat = {}
js.__compat.ie4_getElementById = function(elname) {
return js.__compat.generic_getElementById('all', elname);
}
js.__compat.nn4_getElementById = function(elname) {
return js.__compat.generic_getElementById('layers', elname);
}
js.__compat.generic_getElementById = function(key, elname) {
var expr = /^\\w[\\w\\d]*$/;
if (!expr.test(elname)) {
return null;
} else {
var ret = document[key][elname]);
if (ret) {
// if it returns an array, we only need the top element
if (ret[0]) {
return ret[0];
} else {
return ret;
}
}
}
// fall-through
return null;
}
js.__compat.Array_push = function(arg) {
this[this.length] = arg;
}
js.__compat.Array_pop = function() {
if (this.length <= 0) {
return null;
} else {
return this[this.length--];
}
}
js.__compat.Array_shift = function() {
if (this.length <= 0) {
return null;
} else {
var ret = this[0];
for (var i = 1; i < this.length; i++) {
this[i-1] = this[i];
}
this.length--;
}
}
js.__compat.Array_unshift = function(a) {
for (var i = this.length; i >= 1; i--) {
this[i] = this[i-1];
}
}
/**
* Initialization of the JavaScript environment, to ensure a viable platform
* for operation.
*/
js.__compat.check = function() {
// ie 4 DOM compatibility check
if (document.all && !document.getElementById) {
document.getElementById = js.__compat.ie4_getElementById;
}
else
// netscape 4 DOM compatibility check
if (document.layers && !document.getElementById) {
document.getElementById = js.__compat.nn4_getElementById;
}
// old API compatibility
// Array
if (! js.isFunction(Array.prototype['push'])) {
Array.prototype.push = js.__compat.Array_push;
}
if (! js.isFunction(Array.prototype['pop'])) {
Array.prototype.push = js.__compat.Array_pop;
}
if (! js.isFunction(Array.prototype['shift'])) {
Array.prototype.shift = js.__compat.Array_shift;
}
if (! js.isFunction(Array.prototype['unshift'])) {
Array.prototype.unshift = js.__compat.Array_unshift;
}
}
js.__compat.check();
/* =========================================================================
* DEFAULT MESSAGE TEXT
*
* Defaults to English.
*/
js.messages = {}
js.messages.language_code = "en";
js.messages.language = "US English";
js.messages.error = "Error: {1}";
js.messages.failure = "Failure: {1}";
js.messages.except = "{1}\nException {2}:\n{3}";
js.messages.bad_eval = "error in eval ({1})";
js.messages.bad_eval_parse = "error in expression ({1}.{2})";
js.messages.console_title = 'Console';
js.messages.console_button = 'Clear Console';