363 lines
10 KiB
JavaScript
363 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 " ".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(" ".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;
|
||
|
};
|