// 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 = ''; 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; }