helma/modules/jala/util/XmlRpcClient/Global/Global.js

362 lines
10 KiB
JavaScript

//
// Jala Project [http://opensvn.csie.org/traccgi/jala]
//
// Copyright 2004 ORF Online und Teletext GmbH
//
// Licensed under the Apache License, Version 2.0 (the ``License'');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an ``AS IS'' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// $Revision$
// $LastChangedBy$
// $LastChangedDate$
// $HeadURL$
//
/**
* Dependencies
*/
app.addRepository("modules/core/String.js");
app.addRepository(getProperty("jala.dir", "modules/jala") +
"/code/XmlRpcRequest.js");
/**
* A safe eval method that uses a standard Javascript scope
* without any Helma specifics for evaluation. This method
* does a double evaluation: first it evaluates the code
* in a separate javascript scope without any Helma specifics, and only
* if that doesn't throw an exception it evaluates the expression in the
* application scope, so that objects constructed during evaluation
* belong to the correct scope (and eg. testing with instanceof returns
* the expected result). Keep in mind that due to the double
* evaluation using this method is quite costly.
* @param {String} code The code to evaluate
* @returns The result of the evaluated code
*/
var safeEval = function(code) {
var context = new Packages.org.mozilla.javascript.Context();
try {
context.enter();
// first evaluation in separate scope
context.evaluateString(safeEval.SCOPE, code, null, 0, null);
return eval(code);
} finally {
context.exit();
}
};
safeEval.SCOPE = Packages.org.mozilla.javascript.Context.getCurrentContext().initStandardObjects();
/**
* Returns true if the value passed as argument is a string. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is a string, false otherwise
*/
var isString = function(val) {
return typeof(val) == "string" ||
val instanceof java.lang.String ||
val instanceof String;
};
/**
* Returns true if the value passed as argument is a boolean. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is a boolean, false otherwise
*/
var isBoolean = function(val) {
return typeof(val) == "boolean" ||
val instanceof Boolean;
};
/**
* Returns true if the value passed as argument is a number. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is a number, false otherwise
*/
var isNumber = function(val) {
return typeof(val) == "number" ||
val instanceof java.lang.Integer ||
val instanceof Number;
};
/**
* Returns true if the value passed as argument is null.
* @param {Object} val The value to test
* @returns True if the value is null, false otherwise
*/
var isNull = function(val) {
return val === null;
};
/**
* Returns true if the value passed as argument is undefined.
* @param {Object} val The value to test
* @returns True if the value is undefined, false otherwise
*/
var isUndefined = function(val) {
return val === undefined;
};
/**
* Returns true if the value passed as argument is an array. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is an array, false otherwise
*/
var isArray = function(val) {
return val instanceof Array;
};
/**
* Returns true if the value passed as argument is a date. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is a date, false otherwise
*/
var isDate = function(val) {
return val instanceof Date ||
val instanceof java.util.Date;
};
/**
* Returns true if the value passed as argument is an object. Since
* this value might be constructed using the safeEval's scope
* this method tests both the application's scope and the safe one.
* @param {Object} val The value to test
* @returns True if the value is an object, false otherwise
*/
var isObject = function(val) {
return val instanceof Object ||
val instanceof java.lang.Object;
};
/**
* Parses the argument string passed into an array containing
* evaluated arguments. The string can contain object and array literals,
* strings, numbers and dates (using standard Javascript syntax).
* @param {String} str The string to parse
* @returns The parsed arguments
* @type Array
*/
var parseArguments = function(str) {
var result = [];
var c, literalLevel = 0;
var buf = new java.lang.StringBuffer();
for (var i=0;i<str.length;i++) {
c = str.charAt(i);
if (c == "," && literalLevel == 0) {
result.push(evalArgument(buf.toString()));
buf.setLength(0);
} else {
if (c == "[" || c == "{") {
literalLevel += 1;
} else if (c == "]" || c == "}") {
literalLevel -= 1;
}
buf.append(c);
}
}
if (buf.length() > 0) {
result.push(evalArgument(buf.toString()));
}
return result;
};
/**
* Parses a single argument string using the safeEval's method
* eval(). This way users can't do any harm since all they have is
* a plain Javascript environment without any Helma specifics.
* @param {String} str The string to evaluate
* @returns The evaluated argument
*/
var evalArgument = function(str) {
if (str) {
str = str.trim();
return safeEval("(" + str + ")");
}
return null;
};
/**
* Returns the object passed as argument as formatted JSOn compatible
* string.
* @param {Object} obj The object to format as string
* @returns The formatted string
*/
var prettyPrint = function(obj) {
var pad = function(str) {
return "&nbsp;".repeat((lvl) * 6) + str;
};
var printString = function(str) {
return '"' + encode(str) + '"';
};
var printInteger = function(nr) {
return nr.toString();
};
var printBoolean = function(bool) {
return bool.toString();
};
var printUndefined = function() {
return "undefined";
};
var printNull = function() {
return "null";
};
var printDate = function(date) {
return date.toString();
};
var printArray = function(arr) {
var buf = new java.lang.StringBuffer();
buf.append("[");
lvl += 1;
for (var i=0;i<arr.length;i++) {
if (i > 0) {
buf.append(",");
}
buf.append("\n");
buf.append(pad(printValue(arr[i])));
}
lvl -= 1;
buf.append("\n");
buf.append(pad("]"));
return buf.toString();
};
var printObject = function(obj) {
var buf = new java.lang.StringBuffer();
buf.append("{");
lvl += 1;
var first = true;
for (var i in obj) {
if (first) {
first = !first;
} else {
buf.append(",");
}
buf.append("\n");
buf.append(pad(printString(i) + ": "));
buf.append(printValue(obj[i]));
}
lvl -= 1;
buf.append("\n");
buf.append(pad("}"));
return buf.toString();
};
var printValue = function(val) {
if (isArray(val)) {
return printArray(val);
} else if (isDate(val)) {
return printDate(val);
} else if (isString(val)) {
return printString(val);
} else if (isNumber(val)) {
return printInteger(val);
} else if (isBoolean(val)) {
return printBoolean(val);
} else if (isNull(val)) {
return printNull();
} else if (isUndefined(val)) {
return printUndefined();
} else if (isObject(val)) {
return printObject(val);
} else if (val.toString != null) {
return val.toString();
}
return;
};
var lvl = 0;
return printValue(obj);
};
/**
* Returns the xml source passed as argument as readable string
* with appropriate linefeeds and indents. This method uses a
* regular expression instead of converting the xml source into
* a DOM tree to be able to format invalid xml which might be useful
* for debugging.
* @param {String} xmlSource The XML source for format
* @returns The formatted source
*/
var prettyPrintXml = function(xmlSource) {
var pad = function(str) {
res.write("&nbsp;".repeat((lvl) * 6) + encode(str));
};
// remove all linefeeds and carriage returns
var xml = xmlSource.replace(/\r\n|\n\r|\n|\r/g, "");
var re = /<(\/?)([^>]+)[^<]+(?=<|$)/gm;
var lvl = 0;
var match;
var tag, prevTag;
res.push();
while (match = re.exec(xml)) {
tag = match[2];
if (!match[1]) {
// opening or contentless tag
if (match.index > 0) {
res.write("\n");
lvl += 1;
}
pad(match[0]);
if (tag.indexOf("/") > -1) {
lvl -= 1;
}
} else {
// closing tag
if (tag == prevTag) {
lvl -= 1;
res.encode(match[0]);
} else {
res.write("\n");
pad(match[0]);
lvl -= 1;
}
}
prevTag = tag;
}
return res.pop();
};
/**
* Basic selection macro useable for checkboxes
* and select dropdowns. This macro checks if
* req.data[param.name] equals param.value, and if
* true it writes the specified param.attribute in
* the form 'attribute="attribute"' to response.
*/
var selection_macro = function(param) {
if (req.data[param.name] == param.value) {
res.write(" ");
res.write(param.attribute);
res.write('="');
res.write(param.attribute);
res.write('"');
}
return;
};