// The Mochascript project.
// Copyright (c) 2000-2005 by Chris Zumbrunn Ventures (czv.com).
// Send your contributions, comments and questions to mochascript@czv.com.
// You may use this file only in compliance with the Original Contribution License
// OCL 1.0 available at http://ocl.czv.com/original-contribution-license/
/**
* Initializes the Mocha environment on startup or reset.
*/
function onPage() {
var X='';
initTagFunctionLibrary();
String.prototype.X = function(){ if (!X) Xwrite(this); else if (X != this) X+= this; else {Xwrite(X); X='';}};
String.prototype.lookup = lookupString;
}
function isAlien(a){if(methodOf(this))a=this;return isObject(a) && typeof a.constructor != 'function'}
function isArray(a){if(methodOf(this))a=this;return isObject(a) && a.constructor == Array}
function isBoolean(a){if(methodOf(this))a = this;return typeof a == 'boolean'}
function isEmpty(o){if(methodOf(this))o = this;var i,v;if(isObject(o)){for(var i in o){v=o[i];if(isUndefined(v) && isFunction(v)){return false}}}return true}
function isFunction(a){if(methodOf(this))a = this;return typeof a == 'function'}
function isNull(a){if(methodOf(this))a = this;return typeof a == 'object' && !a}
function isNumber(a){if(methodOf(this))a = this;return typeof a == 'number' && isFinite(a)}
function isObject(a){if(methodOf(this))a = this;return (a && typeof a == 'object') || isFunction(a)}
function isString(a){if(methodOf(this))a = this;return typeof a == 'string'}
function isUndefined(a){if(methodOf(this))a = this;return typeof a == 'undefined'}
/**
* Generates an MD5 hash in hexadecimal format based on this string.
* @param s - string for which the MD5 hash is calculated.
* @return MD5 hexadecimal hash of this string.
*/
function toMD5hex(s) {
if (methodOf(this)) s = this;
return Packages.helma.util.MD5Encoder.encode(s); // binl2hex(core_md5(str2binl(s), s.length * 8));
}
/**
* Returns an array of locations that this user is subscribed to.
* @param o - If mode is 'excluded' then a list of locations that this user has excluded from his subscriptions is returned.
* @return array of locations
*/
function substitute(o) {
var i, j, s = this, v;
for (;;) {
i = s.lastIndexOf('{');
if (i < 0) {
break;
}
j = s.indexOf('}', i);
if (i + 1 >= j) {
break;
}
v = o[s.substring(i + 1, j)];
if (!isString(v) && !isNumber(v)) {
break;
}
s = s.substring(0, i) + v + s.substring(j + 1);
}
return s;
}
function toQuoted(chunk) {
return '"' + chunk.replace(/(["\\])/g, '\\$1') + '"';
}
/**
* Returns this string with any whitespace removed from the beginning and the end.
* @param chunk - string to trim whitespace from, if not called as a string method
* @return string with leading and trailing whitespace trimmed
*/
function trim(chunk) {
if (methodOf(this)) chunk = this;
return chunk.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1");
}
function skip(item, amountToSkip){
var temp = new Array();
if(typeof item[0] == 'object'){
for(var i in item){
item[i].splice(0,amountToSkip);
temp.push(item[i]);
}
return temp;
}else{
item.splice(0,amountToSkip);
return item;
}
}
function makeButton(text,action,params) {
var side = checkEnvir().client ? 'client' : 'server';
if (!text) text = 'OK';
if (side == 'server') {
var loc = path[path.length-1];
action = action ? action : loc.href();
text = text ? text.toString().lookup() : 'OK';
if (session.data.makeButtonsUppercase) text = text.toUpperCase();
if (action == 'submit') {
if (!session.data.submitButtonTracker) session.data.submitButtonTracker = 2;
session.data.submitButtonTracker = Number(session.data.submitButtonTracker) + 1;
var submitButtonTracker = session.data.submitButtonTracker;
}
}
else {
var loc = '../';
action = action ? action : loc;
text = text ? text : 'OK';
// FIXME: if (session.data.makeButtonsUppercase) text = text.toUpperCase();
if (action == 'submit') {
if (!window.submitButtonTracker) window.submitButtonTracker = 2;
window.submitButtonTracker = Number(window.submitButtonTracker) + 1;
var submitButtonTracker = window.submitButtonTracker;
}
}
var X='';
if (action == 'submit') {
var submitname = (params && params.name) ? params.name : 'submitButtonTracker'+ submitButtonTracker;
X+= Tag.hidden({name:submitname,value:''});
var csjschunk = 'for (var ii=0; document.forms.length>ii; ii++) {for (var i=0; document.forms[ii].length>i; i++) {if (document.forms[ii][i].name==\''+ submitname +'\') {document.forms[ii][i].value=true;if (!self.checkFormFields || self.checkFormFields && checkFormFields(document.forms[ii])){document.forms[ii].submit();}}}}';
var urlchunk = 'javascript:' + csjschunk;
}
else var urlchunk = action;
if (params && params.small) {
buttonLinkStyle = 'buttonstylesmall';
buttonCellStyle = 'buttoncellsmall';
defaultheightchunk = 17;
}
else {
buttonLinkStyle = 'buttonstyle';
buttonCellStyle = 'buttoncell';
defaultheightchunk = 32;
}
var widthchunk = (params && params.widthchunk) ? params.widthchunk : 96;
var heightchunk = (params && params.heightchunk) ? params.heightchunk : defaultheightchunk;
X+= Tag.table() + Tag.tr({valign:'middle',align:'center'});
X+= '
' + text + '
';
if (action == 'submit') X+= Tag.image({src:'http://czv.com/zones/library/media/t.gif',width:1,height:heightchunk,border:0}).td();
else X+= makeSpace(1,heightchunk).td();
X+= Tag.tr('/')+Tag.table('/');
return X;
}
/**
* Looks up a translation or customization of this text string.
* @return String of the appropriate translation or customization or the unmodified string that was looked up.
*/
function lookupString() {
var loc = path[path.length-1];
var thisAudience = (session.data.audience == 'Draft' && session.data.lastaudience) ? session.data.lastaudience : session.data.audience;
if (methodOf(this)) {
var lookupResult = getPageProperty('translations.i'+toMD5hex(this)+'.'+thisAudience,root);
return lookupResult ? lookupResult : this;
}
else return '';
}
/**
* Looks up inherited property values from parent objects, respecting any disinheritance flags that may be set.
* @param propertyString - String representing the property name to lookup
* @param obj - Optional, alternative object from which to start the lookup. Default is this.
* @param mode - Optional, if 'node' then instead of the property the node where the property was found is returned.
* @return The nearest defined value of the property name in this object's backpath or the node where the property was found.
*/
function inheritPageProperty(propertyString,loc,mode) {
loc = loc ? loc : path[path.length-1];
var sourceParent = 'none';
var parents = getParents(loc); // FIXME: should probably use path object instead
for(var parent =0; parent < parents.length; parent++) {
if (verifyPageProperty(propertyString, parents[parent])) {
if (!verifyPageProperty(propertyString+'.disinherit', parents[parent])) {
sourceParent = parent;
break;
}
}
}
if (sourceParent != 'none') {
if (mode == 'node') return parents[sourceParent];
else return eval('parents[sourceParent].'+propertyString);
}
else return '';
}
/**
* Verfies if a certain property at the specified object exists.
* @param propertyString - String representing the property name to lookup
* @param loc - Optional, alternative object from which to start the lookup. Default is this.
* @return true or false
*/
function verifyPageProperty(propertyString, loc) {
loc = loc ? loc : path[path.length-1];
var propertyArray = (propertyString.search(/\./)) ? propertyString.split('.') : '';
var nextProperty = 0;
var propertyChunk = '';
if (propertyArray && !loc[propertyArray[0]] && loc[propertyArray[0]+'_json']) getPageProperty(propertyArray[0],loc);
while (nextProperty < propertyArray.length) {
propertyChunk += '["'+propertyArray[nextProperty]+'"]';
if (!eval('loc'+propertyChunk)) return false;
nextProperty++;
}
return true;
}
/**
* Returns the specified property if it exists at the specified object.
* @param propertyString - String representing the property name to lookup
* @param loc - Optional, alternative object from which to start the lookup. Default is this path.
* @return Retrieved property value or an empty string.
*/
function getPageProperty(propertyString, loc) {
loc = loc ? loc : path[path.length-1];
var propertyArray = (propertyString.search(/\./)) ? propertyString.split('.') : '';
var nextProperty = 0;
var propertyChunk = '';
var parentValue = '';
if (propertyArray && !loc[propertyArray[0]] && loc[propertyArray[0]+'_json']) {
eval('var jsonValue = '+ loc[propertyArray[0]+'_json']);
loc[propertyArray[0]] = jsonValue;
}
while (nextProperty < propertyArray.length) {
propertyChunk += '["'+propertyArray[nextProperty]+'"]';
propertyValue = eval('loc'+propertyChunk);
if (!propertyValue) return '';
nextProperty++;
}
return propertyValue ? propertyValue : '';
}
/**
* Sets the value of a property and makes sure that the specified object exists.
* @param propertyString - String representing the property name at which the value is to be stored at.
* @param value - The value that the property should be set to.
* @param loc - Optional, alternative object at which to store the value. Default is this.
* @return true or false
*/
function setPageProperty(propertyString, value, loc) {
loc = loc ? loc : path[path.length-1];
var propertyArray = (propertyString.search(/\./)) ? propertyString.split('.') : '';
var nextProperty = 0;
var propertyChunk = '';
if (propertyArray) getPageProperty(propertyArray[0],loc);
while (nextProperty < propertyArray.length) {
propertyChunk += '["'+propertyArray[nextProperty]+'"]';
if (!eval('loc'+propertyChunk)) {
eval('loc'+propertyChunk+'={}')
if (!eval('loc'+propertyChunk)) return false;
}
nextProperty++;
}
if (!propertyChunk) propertyChunk = propertyString;
eval('loc'+propertyChunk+'=value');
if (propertyChunk != propertyString) {
propertyChunk = '["'+propertyArray[0]+'_json"]';
var jsonString = toJson(getPageProperty(propertyArray[0],loc)).replace(/\n/g,"\\n").replace(/\r/g,"\\r");
eval('loc'+propertyChunk+'=jsonString');
}
return true;
}
/**
* Gets the value of a form property and constructs an object from multiple properties if appropriate.
* @param propertyString - String representing the property name to be looked up.
* @param obj - Object from which the property should be lokked up. Default is req.data.
* @return String of the requested property or an object of all matching properties.
*/
function getFormProperty(propertyString,obj){
obj = obj ? obj : req.data;
var i = 0;
var objArray = new Array();
for(var i in obj){
if(i == propertyString){
return obj[i];
}
else if(i.slice(0,propertyString.length + 1) == propertyString +'.'){
objArray.push([i.slice(propertyString.length + 1),obj[i]]);
}
}
if (objArray.length) return objArray;
}
/**
* Adds a carrage return and line feed to a string.
* @return String of the crlf, appended to this if this is a string.
*/
function crlf() {
if (methodOf(this)) return this +'\r\n';
else return '\r\n';
}
/**
* Space layout generator.
* @param width - amount of pixel that the layout spacing should be wide.
* @param height - amount of pixel that the layout spacing should be high.
* @return String of the html output generating the specified amount of layout spacing.
*/
function makeSpace(width,height) {
width = width ? width : 1;
height = height ? height : 1;
var side = checkEnvir().client ? 'client' : 'server';
if (side == 'server' && res.data.spaceImageUrl) var spaceImageUrl = res.data.spaceImageUrl;
else var spaceImageUrl = 'http://czv.com/zones/library/media/t.gif';
return Tag.img({src:spaceImageUrl,'width':width,'height':height,border:0})
}
/**
* Generates the select and option tags for a drop down menu.
* @param name - amount of pixel that the layout spacing should be wide.
* @param options - Array of options, each being an array containing the options value and the string to display .
* @param selectedItem - option which is selected by default.
* @return String of the html output generating the drop down menu.
*/
function makeSelectOptions(name,options,selectedItem,loc,size,param){
// makeSelectOptions('custom.property.name',[['','Who knows?'],['yes','For sure!'],['no','Certainly not!']],selectedItem);
loc = loc ? loc : path[path.length-1];
var sizechunk = size ? (' size="'+ size +'"') : '';
var paramchunk = param ? (' '+ param) : '';
var returnchunk = '';
return returnchunk
}
/**
* Core Mochascript html tag generator.
* @param tag - Name of html tag to be generated such as br, table, tr or td.
* @param specs - String or an object containing name:"value" pairs of html attributes to be inserted into tag.
* If '/' then a corresponding end tag will be generated.
* @return String of the start or end tag, or both wrapped around this if called as a method.
*/
function makeTag(tag,specs) {
if (!tag) return '';
var close = ''+tag+'>';
if (specs == '/') return close;
var open = '<'+ tag;
if (specs && typeof specs == 'object') {
for (var i in specs) {
open +=' '+ i +'="'+ specs[i] +'"';
}
}
else if (specs) open +=' '+ specs;
open +='>';
if (methodOf(this)) {
if (tag == 'br') return this + open;
return open + this + close;
}
else return open;
}
/**
* Checks context in which the current function is called and returns true if it was invoked as a method.
* @param The object on which this function may have been invoked as a method.
* @return true or false
*/
function methodOf(thisObj) {
if (typeof thisObj != 'object') return false;
if (!Function.apply) { // JScript older than 5.5
if (thisObj.toString() == '[object Window]') return false;
}
else var thisObjClass = Object.prototype.toString.apply(thisObj);
if (thisObjClass != '[object GlobalObject]'
&& thisObjClass != '[object Global]'
&& thisObjClass != '[object Window]') return true;
else return false;
}
/**
* Checks environment in which code is currently evaluated.
* @return Object with server and client properties, indicating the kind of server or client.
*/
function checkEnvir() {
var obj = this;
var r, x = '____apply';
obj[x] = Object.prototype.toString;
var thisObjClass = obj[x]();
delete obj[x];
var resultObj = {'server':'','client':''};
if (thisObjClass == '[object GlobalObject]') resultObj.server = 'hop';
else if (thisObjClass == '[object Global]') resultObj.server = 'webx';
//else if (thisObjClass == '[object Window]') resultObj.client = 'browser';
//else if (this.toString() == '[object Window]') resultObj.client = 'browser';
else resultObj.client = 'browser';
return resultObj;
}
/**
* Dynamically builds the individual tag functions.
* @param tag - The name of the html tag or the type of input tag. Use ibutton for the input tags of type button due to a name conflict with the button html tag. The content-based text style "var" is not a supported tag name.
* @param mode - input, if the tag is a form input tag; a, b or i if the tag id is link, bold or italic.
* @return Returns the function as a string ready for evaluation.
* @see initTagFunctionLibrary
*/
function buildTagFunction(tag,mode){
if (mode == 'input') {
var tagchunk = (tag == 'ibutton') ? 'button' : tag;
var specschunk = 'if (!specs) specs = new Object(); if (specs != "/") specs.type ="'+tagchunk+'"; '
}
else if (!mode) mode = tag;
if (!specschunk) specschunk = '';
var chunk = 'Tag.'+ tag +' = function(specs) {'+ specschunk +'if (methodOf(this) && this.makeTag) return this.makeTag("'+ mode +'",specs); else return makeTag("'+ mode +'",specs);}';
return chunk;
}
/**
* Dynamically builds the tag function library, called automatically in initialization routines.
*/
function initTagFunctionLibrary() {
Tag = new Object();
var tagArray = ['b','i','a','html','body','comment','frameset','frame','noframes','head'];
tagArray = tagArray.concat('base','basefont','isindex','link','meta','nextid','style','title');
tagArray = tagArray.concat('span','div','h1','h2','h3','h4','h5','h6');
tagArray = tagArray.concat('big','blink','s','small','strike','sub','sup','tt','u');
tagArray = tagArray.concat('abbr','acronym','cite','code','del','dfn','em','ins','kbd','samp','strong'); // 'var'
tagArray = tagArray.concat('form','button','fieldset','input','keygen','label','legend','select','option','optgroup','textarea');
tagArray = tagArray.concat('bgsound','img','map','area','marquee','dir','dl','menu','ol','ul','li');
tagArray = tagArray.concat('table','caption','colgroup','col','tbody','tfoot','thead','tr','td','th');
tagArray = tagArray.concat('applet','param','embed','noembed','noscript','object','script','server');
tagArray = tagArray.concat('address','bdo','blockquote','br','center','font','hn','hr','iframe','listing');
tagArray = tagArray.concat('nobr','p','plaintext','pre','q','span','wbr','xmp','layer','multicol','spacer');
for (var tag in tagArray) {
eval(buildTagFunction(tagArray[tag]));
}
eval(buildTagFunction('ibutton','input'));
eval(buildTagFunction('checkbox','input'));
eval(buildTagFunction('file','input'));
eval(buildTagFunction('hidden','input'));
eval(buildTagFunction('image','input'));
eval(buildTagFunction('password','input'));
eval(buildTagFunction('radio','input'));
eval(buildTagFunction('reset','input'));
eval(buildTagFunction('submit','input'));
eval(buildTagFunction('text','input'));
tagArray = tagArray.concat('ibutton','checkbox','file','hidden','image','password','radio','reset','submit','text');
for (var tag in tagArray) {
eval('String.prototype.'+ tagArray[tag] +' = Tag.'+ tagArray[tag] +';');
}
String.prototype.makeTag = makeTag;
}
/**
* Write output to the current runtime environment's appropriate default output object.
* @param chunk - String that should be appended to the response string buffer.
*/
function Xwrite(chunk) {
if (checkEnvir().server == 'hop') res.write(chunk);
else if (checkEnvir().server == 'webx') response.append(chunk);
else if (checkEnvir().client) document.write(chunk);
}
/**
* Converts a Javascript object to its serialized string representation, similar to JSON but also converts CR and LF.
* @param arg - Javascript object to be serialized.
* @return String of the serialized Javascript object.
*/
function toMocha(arg) {
if (methodOf(this)) arg = this;
return toJson(arg).replace(/\n/g,"\\n").replace(/\r/g,"\\r");
}
/**
* Converts a Javascript object to its serialized string representation.
* @param arg - Javascript object to be serialized.
* @return String of the serialized Javascript object.
*/
function toJson(arg) {
if (methodOf(this)) arg = this;
var i, o, v;
switch (typeof arg) {
case 'object':
if (arg) {
if (arg.constructor == Array) {
o = '[';
for (var i = 0; i < arg.length; ++i) {
v = toJson(arg[i]);
if (v != 'function' && !isUndefined(v)) {
o += (o != '[' ? ',' : '') + v;
}
else {
o += ',';
}
}
return o + ']';
}
else if (typeof arg.toString != 'undefined') {
o = '{';
for (var i in arg) {
v = toJson(arg[i]);
if (v != 'function' && !isUndefined(v)) {
o += (o != '{' ? ',' : '') +
toQuoted(i) + ':' + v;
}
}
return o + '}';
}
else {
return;
}
}
return 'null';
case 'unknown':
case 'undefined':
return;
case 'string':
return toQuoted(arg);
case 'function':
return 'function';
default:
return String(arg);
}
}
/**
* Converts a string to UTF8 Unicode encoding.
* @param rohtext - string to be UTF8-encoded.
* @return String in UTF8 encoding.
*/
function toUtf8(rohtext) {
if (methodOf(this)) rohtext = this;
// dient der Normalisierung des Zeilenumbruchs
rohtext = rohtext.replace(/\r\n/g,"\n");
var utftext = "";
for(var n=0; n 1byte
if (c<128) utftext += String.fromCharCode(c);
// alle Zeichen von 127 bis 2047 => 2byte
else if((c>127) && (c<2048)) {
utftext += String.fromCharCode((c>>6)|192);
utftext += String.fromCharCode((c&63)|128);
}
// alle Zeichen von 2048 bis 66536 => 3byte
else {
utftext += String.fromCharCode((c>>12)|224);
utftext += String.fromCharCode(((c>>6)&63)|128);
utftext += String.fromCharCode((c&63)|128);
}
}
return utftext;
}
/**
* Converts a string from UTF8 Unicode encoding.
* @param rohtext - string to be UTF8-decoded.
* @return String resulting from UTF8 decoding.
*/
function fromUtf8(utftext) {
if (methodOf(this)) utftext = this;
var plaintext = ""; var i=0; var c=c1=c2=0;
// while-Schleife, weil einige Zeichen uebersprungen werden
while(i191) && (c<224)) {
c2 = utftext.charCodeAt(i+1);
plaintext += String.fromCharCode(((c&31)<<6) | (c2&63));
i+=2;
}
else {
c2 = utftext.charCodeAt(i+1); c3 = utftext.charCodeAt(i+2);
plaintext += String.fromCharCode(((c&15)<<12) | ((c2&63)<<6) | (c3&63));
i+=3;
}
}
return plaintext;
}
/**
* This function takes in arguments that are arrays and filters out the dublicates.
* @param listToFilter - one or two dimensional array of objects to filter.
* @return single dimensional array of the objects with any duplicates removed.
*/
function filterDuplicates(listToFilter){
// This function takes in arguments that are arrays and filters out the dublicates
// and returns the array with no duplicates to the calling function.
var filteredList = new Array();
if(typeof listToFilter == 'string'){
var stringReturn = true;
listToFilter = listToFilter.split(' ');
}else{
var stringReturn = false;
}
filteredList[0] = listToFilter[0]; // first element of array inserted so that the for loop can take place
for(var i in listToFilter){
for(var index in filteredList){
if(filteredList[index] != listToFilter[i]){
duplicate = false;
}
else{
break;
}
if(index == filteredList.length - 1 && duplicate == false){
filteredList.push(listToFilter[i]);
}
}
}
if(stringReturn){
var filteredList = filteredList.join(' ');
return filteredList;
}else{
return filteredList;
}
}
function substitute(o) {
var i, j, s = this, v;
for (;;) {
i = s.lastIndexOf('{');
if (i < 0) {
break;
}
j = s.indexOf('}', i);
if (i + 1 >= j) {
break;
}
v = o[s.substring(i + 1, j)];
if (!isString(v) && !isNumber(v)) {
break;
}
s = s.substring(0, i) + v + s.substring(j + 1);
}
return s;
}