|
The Gravy Framework | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||
Collection of general utility routines
Author: Bruce Wallace (PolyGlotInc.com)
Version: 1.0
| Class Summary | |
| Args | This singleton class parses ampersand-separated name=value argument pairs from the query string of the URL; It stores the name=value pairs as properties of "this" object; adapted from here. |
| OObject | the "abstract base class" OObject has no code, only
a design pattern followed by convention; Two utility
functions (Class,Extends) replace the "constructor"
Javascript function with a wrapper function and also
set up a proper inheritence mechanism; This mechanism
allows the pretty source whereby "methods" are declared
inline in the Javascript function, but the source code
of those methods are not copied into every object instance
as would otherwise be the case with simple Javascript; The wrapper function also sets up the "constructor" to use GLOBALS.ValidateArgs() to insure that the required parameters are passed to the constructor and throw an exception if not. The design pattern implemented by Class/Extends corrects several problems that occur with naive Class/Superclass mechanisms often used with Javascript;
The required "interface" for "OObject":
(1) the Object has its "class" declared via the utility
function GLOBALS.Class()
(2) the "superclass" (if any) is declared via the
utility function GLOBALS.Extends()
(3) the "constructor" logic for the class is placed
in a "method" named "konstructor"
(4) the konstructor method invokes the "super" constructor
via its class name [rather than super()]
|
| Method Summary | |
static Object
|
ArgsToString( args )
|
static Object
|
ArrayToString( a )
|
static Object
|
Break(msg)
|
static void
|
Breakpoint()
|
static void
|
busy()
set the cursor to the hourglass icon |
static void
|
BusyDo( <String> funcname, <String> funcargs, <int> optDelayMilliSecs )
generic utility function to queue up for future execution the specified function with the specified arguments after a specified amount of delay. |
static String
|
CallerName( <Arguments> argumentsObj )
This utility function returns the name of the function that called this routine. |
static Function
|
Class( <Function> theClass, <StringArray> optConstructorArgDescArray )
Declare a class and create the glue objects and code to allow "pretty" source; A mechanism is set up to insure that required constructor parameters each have a defined value; This function also defines the "name" attribute of the specified class and initializes it with the class name. |
static void
|
ClearGlobalVar( <String> varname )
static routine to dynamically undefine/delete a global variable |
static void
|
ClearGlobalVars()
static routine to dynamically undefine/delete ALL "...GlobalVars" variables |
static void
|
ClearPersistentVars()
static routine to dynamically undefine/delete ALL "...PersistentVars" variables |
static void
|
DebugWindow( <String> contents )
open debug window with contents in scrollable area |
static String
|
diamond(<boolean> optBlankFlag)
return the HTML to draw a diamond |
static boolean
|
dollarKeyFilter( <int> keyCode, <String> valueSoFar )
is the given character a legal addition to the given dollar string |
static Object
|
dollarStrFilter(s)
|
static String
|
dot()
return the HTML to draw a biggish dot |
static void
|
editElem( e, makeSelected, makeEdited, makeInvalid )
|
static void
|
editElemID( ID, makeSelected, makeEdited, makeInvalid )
|
static String
|
epsilon()
return the HTML to draw a smallish "E" |
static void
|
Error(msg)
|
static Function
|
Extends( <Function> superClass )
This utility function takes (via "THIS") a "class" and (re)sets its superClass. |
static Object
|
filterNum( str )
|
static String
|
format_dollar( <anyType> v, <boolean> optZeroAsBlankFlag )
format given value as $#,###.00 |
static String
|
format_dollar_not( v )
like format_dollar except empty string returned for zero |
static String
|
FuncName(<Function> f)
This function returns the name of a given function; It does this by converting the function to a string, then using a regular expression to extract the function name from the resulting code. |
static String
|
genHook( <String> hookID, <String> optInnerHTML )
generate a piece of HTML, identified by the given ID, that can safely have its innerHTML replaced at runtime. |
static Object
|
GetArg( argname )
|
static Object
|
GetGlobalVar( <String> varname )
static routine to return the value of persistent variable with given name |
static Object
|
getHook( hookID )
|
static Object
|
GetPersistentVar( <String> varname )
static routine to return the value of the persistent variable with given name |
static Object
|
getTodayAsMMDDYYYY()
|
static Object
|
getTodayAsXXDDYYYY(monthNames)
|
static void
|
highlightElem( e, makeSelected, selectColor )
|
static Object
|
isDate(dateStr)
return error message on invalid date or null if valid |
static Object
|
isDigit(c)
Returns true if character c is a digit (0 .. |
static Object
|
isEmpty(s)
Check whether string s is "empty". |
static Object
|
isFloat(s)
Returns true if string s is an unsigned floating point (real) number. |
static Object
|
isInteger(s)
Returns true if all characters in string s are numbers. |
static Object
|
isLetter(c)
Returns true if character c is an English letter (A .. |
static Object
|
isSignedFloat(s)
Returns true if string s is a signed or unsigned floating point (real) number. |
static Object
|
isZeroDollars(v)
|
static boolean
|
keyFilter( <int> keyCode, <String> allowedChars )
Is the given keyCode in the given list of allowed characters? |
static void
|
LoudThrow( exceptionObj )
|
static Object
|
MissingArgException( argDesc, funcName )
|
static boolean
|
noDuplicates( <String> s, <String> charList )
Is there no more than one occurance of each character in the given character list in the given string? |
static void
|
notbusy()
set the cursor to the default icon |
static Object
|
NullArgException( argDesc, funcName )
|
static Object
|
ObjectToInitializer( o )
|
static Object
|
ObjectToShortInitializer( o )
|
static Object
|
ObjectToString( o )
|
static Object
|
pleaseWait( <boolean> enableFlag, <String> msg, appId )
create and open a window (if enabled) with the specified message |
static void
|
selectElem( e, makeSelected )
|
static void
|
selectElemID( ID, makeSelected )
|
static void
|
SendStatusMessage( <String> msg )
send a message via the browser status bar |
static void
|
setBackgroundColor( ID, color )
|
static void
|
setElemBackgroundColor( e, color )
|
static void
|
setElemText( e, str )
|
static void
|
setElemVisibility( e, visibleFlag )
|
static void
|
SetGlobalVar( <String> varname, <Object> value )
static routine to dynamically define/update a global (to window/page but reloaded with page) variable with the given name and value. |
static void
|
SetPersistentVar( <String> varname, <Object> value )
static routine to dynamically define/update a persistent (across page loads) variable with the given name and value. |
static void
|
setText( ID, str )
|
static void
|
setVisibility( ID, visibleFlag )
|
static boolean
|
strFilter( s, <String> allowedChars )
Does the given string consist of only characters in the given list of allowed characters? |
static String
|
subitem( isInValid )
return the HTML to draw a subitem bullet |
static Object
|
timestamp()
return the current time in milliseconds since start of epoc |
static Object
|
TooFewArgsException( funcName, required, passed )
|
static Object
|
Trace(flag,msg)
|
static Object
|
TraceEvt(msg)
|
static Object
|
TraceMsg(msg)
|
static Object
|
TraceMVC(msg)
|
static String
|
trimStr(sInString)
strip leading and trailing whitespace |
static void
|
UNWAIT(appId)
close the "please wait" window if it exists otherwise no effect |
static String
|
URLDecode( <String> encoded )
This decodes URL-encoded strings because the Javascript function "unescape" only does part of the job; adapted from here. |
static void
|
ValidateArgs( <StringArray> optArgDescArray )
generic utility function to verify that required args (of the caller of this function) have been passed; The given array of descriptions defines how many arguments should be found with a defined value; Therefore, the caller of this routine should place its optional arguments at the end of its parameter list with no description specified in "optArgDescArray". |
static void
|
validateDate( hookID )
|
static void
|
validateDollar( hookID )
|
static void
|
validateFloat( hookID )
|
static void
|
validateInteger( hookID )
|
static void
|
WAIT(appId)
Create an idempotent "wait a minute" window, if one doesn't exist, and squirrel away a reference to it that survives window reloads |
static Object
|
WaitWindowName(appId)
|
static void
|
warnInvalid(theField, s)
Notify user that contents of field theField are invalid. |
// This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ] /** * @file utils.js * @fileoverview Collection of general utility routines * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ /** * open debug window with contents in scrollable area * @param {String} contents what to put into this debug window */ function DebugWindow( contents ) { window.open("","","").document.write ("<textarea cols=150 rows=40>"+ contents + "</textarea>" ); } function Breakpoint() { //open window with current dynamic HTML displayed DebugWindow( document.body.parentNode.innerHTML ); //cause Javascript debugger to kick in on undefined object reference //OR, comment out the next line and pre-set a breakpoint here via debugger // UNDEFINED(); } function Break(msg) { if (msg.length>200) { DebugWindow( msg ); msg="(see window)"; } if (confirm(msg+"\nBreak here?")) Breakpoint(); else return true; } function Error(msg){ if (Break("ERROR:"+msg)) alert("It is recommended that you close this window and try again."); } //global debug flags to enable verbose event tracing var gTraceMVC = false; //MVC setup tracing var gTraceEvt = false; //Event processing tracing var gTraceMsg = false; //message broadcast tracing function Trace(flag,msg){ if (flag) return Break(msg); else return true; } function TraceMVC(msg){ return Trace(gTraceMVC,msg); } function TraceEvt(msg){ return Trace(gTraceEvt,msg); } function TraceMsg(msg){ return Trace(gTraceMsg,msg); } /** return the current time in milliseconds since start of epoc */ function timestamp(){ return (new Date()).getTime(); } // ---------------------------------------------------------------------------- // Utility routines for Formatting Data // ---------------------------------------------------------------------------- /** return the HTML to draw a biggish dot @type String */ function dot (){ return '<font face="Symbol">·</font>'; } /** return the HTML to draw a smallish "E" @type String */ function epsilon(){ return '<font face="Symbol">e</font>'; } /** return the HTML to draw a diamond * @param {boolean} optBlankFlag if true, says generate blanks of same size as 1 diamond * @type String */ function diamond(optBlankFlag){ return optBlankFlag ? " " : "♦"; } /** return the HTML to draw a subitem bullet @type String */ function subitem( isInValid ){ return isInValid ? "ε" : "⇒" } /** Is the given keyCode in the given list of allowed characters? * @param {int} keyCode the charCode of the character to validate * @param {String} allowedChars the list of characters that are allowed * @return true iff keyCode is legal * @type boolean */ function keyFilter( keyCode, allowedChars ){ return allowedChars.indexOf(String.fromCharCode(keyCode)) >= 0; } /** Does the given string consist of only characters in the given * list of allowed characters? * @param {int} keyCode the charCode of the character to validate * @param {String} allowedChars the list of characters that are allowed * @return true iff keyCode is legal * @type boolean */ function strFilter( s, allowedChars ){ var q = ""; for (var i=0; i<s.length; ++i) { var c = s.charAt(i); if (allowedChars.indexOf(c) >= 0) q += c; } return q; } /** Is there no more than one occurance of each * character in the given character list in the given string? * @param {String} s string to check * @param {String} charList list of characters that should occur only once * @return true if there are no duplicates * @type boolean */ function noDuplicates( s, charList ) { for (var i=0; i<charList.length; ++i) { var c = charList.charAt(i); var first = s.indexOf(c); if (first!=-1 && first!=s.lastIndexOf(c)) return false; } return true; } var kDigitChars = "0123456789"; var kFloatChars = "+-."; /** is the given character a legal addition to the given dollar string * @param {int} keyCode the proposed new character * @param {String} valueSoFar the value so far * @return true iff character is legal * @type boolean */ function dollarKeyFilter( keyCode, valueSoFar ) { return keyFilter( keyCode, kDigitChars+kFloatChars+"$," ) // && noDuplicates( valueSoFar+String.fromCharCode(keyCode), "$"+kFloatChars ); } function dollarStrFilter(s){ return strFilter(s,kDigitChars+kFloatChars); } function isZeroDollars(v){ return Math.abs(parseFloat(v))<0.01; } /** format given value as $#,###.00 * @type String * @param {anyType} v value to format * @param {boolean} optZeroAsBlankFlag optional flag to make zero format as blank * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function format_dollar( v, optZeroAsBlankFlag ) { if ( v==null || v=="null" ) return dot(); if ( isZeroDollars(v) ) v = 0; //get rid of microcents and negative zeroes if ( optZeroAsBlankFlag && v==0 ) return " "; // Do the equivalent to XSL::format-number($v,'$#,###.00') var x = parseFloat(v).toFixed(2); var sign = ''; if (x < 0){ sign = '-'; x = x.substr(1); } var C = x.split(""); var n = C.length-4; var s = x.substring(n+1,n+4); for (var i=n; i>=0; --i) s = (((C.length-i)%3==0 && i!=0) ? "," : "") + C[i] + s; return sign + "$" + s; } /** like format_dollar except empty string returned for zero @type String */ function format_dollar_not( v ){ return format_dollar( v, true ); } /** strip leading and trailing whitespace @type String */ function trimStr(sInString) { sInString = sInString.replace( /^\s+/g, "" );// strip leading return sInString.replace( /\s+$/g, "" );// strip trailing } /** generate a piece of HTML, identified by the given ID, * that can safely have its innerHTML replaced at runtime. * @param {String} hookID name of the HTML to be generated * @param {String} optInnerHTML optional HTML to be inserted * into the generated HTML * @return generated HTML * @type String * @see #getHook * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function genHook( hookID, optInnerHTML ){ return '<span id="'+hookID+'">' + (optInnerHTML?optInnerHTML:"") + '</span>'; } function getHook( hookID ){ var e = document.getElementById( hookID ); if (e==null) TraceMVC("cant find hook["+hookID+"]"); return e; } function setElemBackgroundColor( e, color ){ if (!e) {Break("null setElemBackgroundColor!"); return;} e.style.backgroundColor = color; } function setBackgroundColor( ID, color ){ setElemBackgroundColor( document.getElementById(ID), color ); } function setElemText( e, str ){ if (!e) {Break("null setElemText!"); return;} e.innerHTML = str; } function setText( ID, str ){ setElemText( getHook(ID), str ); } //TODO implement these via CSS instead var kInValidColor = '#FF9900'; var kEditedColor = '#99CCCC';//'#FFCC99'; var kSelectedColor = '#FFFFCC'; var kUnSelectedColor = '#FFFAF0'; function highlightElem( e, makeSelected, selectColor ){ setElemBackgroundColor( e, makeSelected?selectColor:kUnSelectedColor ); } /*ALTERNATE COLOR SCHEME... //set the background color of the given element based on //whether it is selected, dirty, and valid. function editElem( e, makeSelected, makeEdited, makeInvalid ){ var useColor = makeSelected || makeEdited || makeInvalid; highlightElem( e, useColor, makeInvalid ? kInValidColor : makeEdited ? kEditedColor : kSelectedColor ); } */ //set the background color of the given element based on //whether it is selected, dirty, and valid. function editElem( e, makeSelected, makeEdited, makeInvalid ){ var useColor = makeSelected || makeEdited; highlightElem( e, useColor, makeEdited ? kEditedColor : kSelectedColor ); } function editElemID( ID, makeSelected, makeEdited, makeInvalid ){ editElem( getHook(ID), makeSelected, makeEdited, makeInvalid ); } function selectElem( e, makeSelected ){ highlightElem( e, makeSelected, kSelectedColor ); } function selectElemID( ID, makeSelected ){ selectElem( getHook(ID), makeSelected ); } function setElemVisibility( e, visibleFlag ) { if (!e) {if (TraceMVC("null setElemVisibility!")) return;} e.style.visibility = visibleFlag ? "visible" : "hidden"; e.style.position = visibleFlag ? "relative" : "absolute"; } function setVisibility( ID, visibleFlag ){ setElemVisibility( getHook(ID), visibleFlag ); } var kMonthNames = new Array( "January","February","March","April","May","June","July", "August","September","October","November","December"); var kMonthNums = new Array( "01","02","03","04","05","06","07", "08","09","10","11","12"); function getTodayAsXXDDYYYY(monthNames) { var now = new Date(); return monthNames[ now.getMonth() ] + "/" + now.getDate() + "/" + now.getFullYear(); } function getTodayAsMMDDYYYY(){ return getTodayAsXXDDYYYY( kMonthNums ); } // ---------------------------------------------------------------------------- // Utility routines for Exception Handling // ---------------------------------------------------------------------------- function LoudThrow( exceptionObj ) { Break(exceptionObj); throw exceptionObj; } function MissingArgException( argDesc, funcName ) { return "Error: "+argDesc+" wasnt passed to "+funcName; } function NullArgException( argDesc, funcName ) { return "Illegal null "+argDesc+" passed to "+funcName; } function TooFewArgsException( funcName, required, passed ) { return funcName + " requires "+ required +" arguments, but was passed " + passed; } /** * This function returns the name of a given function; It does this by * converting the function to a string, then using a regular expression * to extract the function name from the resulting code. * @param {Function} f reference to a function * @return name of given function * @type String * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function FuncName(f) { var s = f.toString().split( new RegExp("[ \(]"), 2)[1]; if ((s == null) || (s.length == 0)) return "anonymous"; return s; } /** * This utility function returns the name of the function that * called this routine. * @param {Arguments} argumentsObj the Javascript arguments object * @return the caller's function name * @type String * @see #FuncName * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function CallerName( argumentsObj ){ return FuncName( argumentsObj.caller.callee ) } /** * This utility function takes (via "THIS") a "class" and * (re)sets its superClass. * @param {Function} superClass the "superclass constructor" function * @return a reference to the "class object" * @type Function * @see #Class * @see OObject * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function Extends( superClass ) { this.baseClass.prototype = superClass ? superClass.prototype : null; this.prototype = new this.baseClass(); this.prototype.name = this.name;//default value this.prototype[this.name] = this.prototype.konstructor;//so people can call super return this; } /** * Declare a class and create the glue objects and code * to allow "pretty" source; A mechanism is set up to insure * that required constructor parameters each have a defined value; * This function also defines the "name" attribute of the specified * class and initializes it with the class name. * @param {Function} theClass the "class constructor" function * @param {StringArray} optConstructorArgDescArray optional array * of strings describing required parameters for this class' * "constructor"; Note: Optional constructor parameters should * not be included in this array. * @return the "class object" (an extended Function object) * @type Function * @see #Extends * @see #ValidateArgs * @see OObject * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function Class( theClass, optConstructorArgDescArray ) { // The "class" as passed in will really be an abstract base class. We // will squirrel that away and replace theClass with a wrapper function // so that method source code is not copied into each object instance // as would otherwise be the case. var baseClass = theClass; // create the new wrapper function to replace theClass var className = FuncName( theClass ); self[className] = theClass = function(){ ValidateArgs( theClass.required ); theClass.prototype.konstructor.apply( this, arguments ); } theClass.required = optConstructorArgDescArray; theClass.name = className; theClass.baseClass= baseClass; theClass.Extends = Extends;//so we can call Extends as a method return theClass.Extends();//needed, even tho no superclass specified } /** * @class the "abstract base class" OObject has no code, only * a design pattern followed by convention; Two utility * functions (Class,Extends) replace the "constructor" * Javascript function with a wrapper function and also * set up a proper inheritence mechanism; This mechanism * allows the pretty source whereby "methods" are declared * inline in the Javascript function, but the source code * of those methods are not copied into every object instance * as would otherwise be the case with simple Javascript;<p> * The wrapper function also sets up the "constructor" * to use {@link GLOBALS#ValidateArgs} to insure that the required * parameters are passed to the constructor and throw an * exception if not.<p> * The design pattern implemented by Class/Extends * corrects several problems that occur with naive * Class/Superclass mechanisms often used with Javascript; *<pre> * The required "interface" for "OObject": * (1) the Object has its "class" declared via the utility * function {@link GLOBALS#Class} * (2) the "superclass" (if any) is declared via the * utility function {@link GLOBALS#Extends} * (3) the "constructor" logic for the class is placed * in a "method" named "konstructor" * (4) the konstructor method invokes the "super" constructor * via its class name [rather than super()] *</pre> * @throws MissingArgException thrown by constructor wrapper * @see GLOBALS#Class * @see GLOBALS#Extends * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function OObject(){/* this function exists only for JsDoc purposes.*/} /** * generic utility function to verify that required args * (of the caller of this function) have been passed; The given * array of descriptions defines how many arguments should be * found with a defined value; Therefore, the caller of this * routine should place its optional arguments at the end of its * parameter list with no description specified in "optArgDescArray". * @param {StringArray} optArgDescArray optional array of strings * describing required parameters; Note: Optional constructor parameters should * not be included in this array. * @throws MissingArgException * @see #Class * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function ValidateArgs( optArgDescArray ) { if (optArgDescArray==null || optArgDescArray.length==0) return; // arguments.caller.callee is the Function object that called us. // Its arity property is the number of arguments that were expected. //var expected = arguments.caller.callee.arity; // arguments.caller is the arguments object of the function that // called us. Its length property is the number of actual args passed. var passed = arguments.caller.length; // argDescArray should be an array of arg names of args that musnt be null var required = optArgDescArray==null ? 0 : optArgDescArray.length; if (passed < required) LoudThrow( TooFewArgsException( CallerName(arguments), required, passed ) ); for (var i=0; i<required; ++i) //robust test for "undefined" //see http://pt.withy.org/ptalk/archives/2005/06/dont_assume_undefined_is_undefined.html if (arguments.caller[i] === void 0) LoudThrow( MissingArgException( optArgDescArray[i], CallerName(arguments) ) ); } // ---------------------------------------------------------------------------- // Utility routines for "please wait" indicators // ---------------------------------------------------------------------------- function WaitWindowName(appId){ return "gWaitWindow" + appId; } /** Create an idempotent "wait a minute" window, if one doesn't exist, * and squirrel away a reference to it that survives window reloads */ function WAIT(appId) { var winName = WaitWindowName(appId); if (navigator[ winName ]==null) navigator[ winName ]= pleaseWait( true, "Loading data.", appId ); } /** close the "please wait" window if it exists otherwise no effect */ function UNWAIT(appId) { var winName = WaitWindowName(appId); if (navigator[ winName ]==null) return; navigator[ winName ].close(); navigator[ winName ] = null; } /** create and open a window (if enabled) with the specified message * @param {boolean} enableFlag iff true then create window * @param {String} msg message to place in window * @return the created window or null if not enabled * @type Object */ function pleaseWait( enableFlag, msg, appId ) { var theWindow = null; if ( enableFlag ) { var xMax = screen.width, yMax = screen.height; var xOffset = (xMax - 220)/2, yOffset = (yMax - 100)/2; theWindow = window.open("", 'pleaseWait', 'width=250 height=100 toolbar=no scrollbars=no menubar=no resizable=yes top='+yOffset+' left='+xOffset+''); theWindow.document.write("<BODY BGCOLOR=#6eaba1>"); theWindow.document.write("<TITLE>" +appId+ " Processing...</TITLE>"); theWindow.document.write('<FONT FACE="Arial" SIZE=2><layer id="c"><left><B>'+msg+'<br/>Please Wait.</left></layer></font><br>'); } return theWindow; } /** set the cursor to the hourglass icon */ function busy() { document.body.style.cursor='wait'; } /** set the cursor to the default icon */ function notbusy() { document.body.style.cursor='default'; } /** * generic utility function to queue up for future execution the specified * function with the specified arguments after a specified amount of delay. * THIS function returns immediately, and the specified function will execute * later (in potentially a different thread). If this is called with the same * function specified as was specified earlier, and that function has not * executed yet, then the scheduled execute time is updated, rather than the * function being executed twice. * @param {String} funcname the name of the function to call * @param {String} funcargs a string image of the parameters to be passed * @param {int} optDelayMilliSecs optional delay amount (default 5 milliSeconds) * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function BusyDo( funcname, funcargs, optDelayMilliSecs ) { var timedelay = optDelayMilliSecs || 5; // busy(); var globalVarName = "gTimeout"+funcname; if (navigator[ globalVarName ]==null) navigator[globalVarName] = null; if (navigator[ globalVarName ]!=null) clearTimeout( navigator[globalVarName] ); navigator[ globalVarName ] = setTimeout( funcname+funcargs, timedelay ); } // ---------------------------------------------------------------------------- // Utility routines for URL Handling // ---------------------------------------------------------------------------- /** This decodes URL-encoded strings because the Javascript * function "unescape" only does part of the job; adapted from * <a target="_blank" href="http://www.albionresearch.com/misc/urlencode.php">here.</a> * @param {String} encoded the URL-encoded string to translate * @return decoded version of given encoded string * @type String * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 */ function URLDecode( encoded ) { // Replace + with space // Replace %xx with equivalent character // Put [ERROR] in output if %xx is invalid. var HEXCHARS = "0123456789ABCDEFabcdef"; var plaintext = ""; var i = 0; while (i < encoded.length) { var ch = encoded.charAt(i); if (ch == "+") { plaintext += " "; i++; } else if (ch == "%") { if (i < (encoded.length-2) && HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 && HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) { plaintext += unescape( encoded.substr(i,3) ); i += 3; } else { throw 'Bad escape combination near ...' + encoded.substr(i); i++; } } else { plaintext += ch; i++; } } return plaintext; } var gArgs = null; //global singleton object reference /** * @class This singleton class parses ampersand-separated name=value * argument pairs from the query string of the URL; It stores the * name=value pairs as properties of "this" object; adapted from * <a target="_blank" href="http://www.oreilly.com/catalog/jscript3/chapter/ch13.html#ch13_08.htm">here.</a> * @author Bruce Wallace (PolyGlotInc.com) * @version 1.0 * @todo refactor this into a proper object now that I know how to */ function Args() //lazy singleton factory { if (gArgs!=null) return gArgs; //use singleton gArgs = new Object; //create singleton gArgs.get = function(argname){ return eval("this."+argname); }; // todo someday see if above eval can be replaced with "this[argname]" var query = location.search.substring(1); // Get query string. var pairs = query.split("&"); // Break at ampersand. for (var i=0; i<pairs.length; ++i) { var pos = pairs[i].indexOf('='); // Look for "name=value". if (pos == -1) continue; // If not found, skip. var argname = pairs[i].substring(0,pos); // Extract the name. var value = pairs[i].substring(pos+1); // Extract the value. gArgs[argname] = URLDecode(value); // Store as a property. } return gArgs; // Return the singleton. } function GetArg( argname ) { return Args().get( argname ); } /** send a message via the browser status bar * @param {String} msg the message to send. */ function SendStatusMessage( msg ) { window.status = msg; TraceMsg(msg); window.status = ""; } // ---------------------------------------------------------------------------- // Utility routines to convert entities into strings // ---------------------------------------------------------------------------- function ObjectToString( o ) { var s = ""; for (var property in o)// iterate over all properties s += "Property [" + property + "] is [" + o[property] +"]\n"; return s; } function ObjectToInitializer( o ) { var s = "{\n"; for (var property in o)// iterate over all properties { var q = (o[property] instanceof Function) ? '' : '"'; s += property + ':'+q + o[property] +q+',\n'; } return s.substring(0,s.length-2)+"\n}";//get rid of dangling comma } function ObjectToShortInitializer( o ) { var s = "{\n"; for (var property in o)// iterate over all properties { var P = o[ property ]; if (!(P instanceof Function)) s += property + ':"' + P + '",\n'; // else s += property + ': function,\n'; } return s.substring(0,s.length-2)+"\n}";//get rid of dangling comma } function ArrayToString( a ) { var s = ""; for (var i in a)// iterate over all array items s += "["+ i +"] is ["+ a[i] +"]\n"; return s; } function ArgsToString( args ) { var s = ""; for (var i=0; i<args.length; ++i)// iterate over all function args s += "["+ i +"] is ["+ args[i] +"]\n"; return s; } ///// GLOBAL-PERSISTENCE VARIABLES ROUTINES ///// /** static routine to dynamically define/update a persistent (across page loads) * variable with the given name and value. * @param {String} varname name of "persistent" variable * @param {Object} value value to set variable to */ function SetPersistentVar( varname, value ) //persisted across page loads { if (navigator.gGlobalMap==null) navigator.gGlobalMap = new Object(); navigator.gGlobalMap[varname] = value; } /** static routine to return the value of the persistent variable with given name * @param {String} varname name of "persistent" variable * @return {Object} value of variable (empty object if not previously defined) * @type Object */ function GetPersistentVar( varname ) { if (navigator.gGlobalMap==null) navigator.gGlobalMap = new Object(); return navigator.gGlobalMap[varname]; } /** static routine to dynamically undefine/delete ALL "...PersistentVars" variables */ function ClearPersistentVars(){ navigator.gGlobalMap = null; } /** static routine to dynamically define/update a global (to window/page * but reloaded with page) variable with the given name and value. * @param {String} varname name of "persistent" variable * @param {Object} value value to set variable to */ function SetGlobalVar( varname, value ) { if (window.gGlobalMap==null) window.gGlobalMap = new Object(); window.gGlobalMap[ varname ] = value; } /** static routine to return the value of persistent variable with given name * @param {String} varname name of "global" i.e. "static" variable * @return {Object} value of variable (empty object if not previously defined) * @type Object */ function GetGlobalVar( varname ) { if (window.gGlobalMap==null) window.gGlobalMap = new Object(); return window.gGlobalMap[ varname ]; } /** static routine to dynamically undefine/delete ALL "...GlobalVars" variables */ function ClearGlobalVars(){ window.gGlobalMap = null; } /** static routine to dynamically undefine/delete a global variable * @param {String} varname name of "persistent" variable */ function ClearGlobalVar( varname ){ delete window.gGlobalMap[ varname ]; } ///// BASIC DATA VALIDATION ROUTINES ///// /** Check whether string s is "empty". */ function isEmpty(s) { return ((s == null) || (s.length == 0)) } /** Returns true if character c is an English letter (A .. Z, a..z). */ function isLetter(c) { return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) ) } /** Returns true if character c is a digit (0 .. 9). */ function isDigit(c) { return (c >= "0") && (c <= "9"); } /** * Returns true if all characters in string s are numbers. * Accepts non-signed integers only. Does not accept floating * point, exponential notation, etc. * We don't use parseInt() because that would accept a string * with trailing non-numeric characters. */ function isInteger(s) { if (isEmpty(s)) return true; for (i = 0; i < s.length; i++) if (!isDigit(s.charAt(i))) return false; return true; } /** * Returns true if string s is an unsigned floating point (real) number. * Does not accept exponential notation. */ function isFloat(s) { if (isEmpty(s)) return true; var seenDecimalPoint = false; var decimalPointDelimiter = "."; if (s == decimalPointDelimiter) return false; for (i = 0; i < s.length; i++) { var c = s.charAt(i); if ((c == decimalPointDelimiter) && !seenDecimalPoint) seenDecimalPoint = true; else if (!isDigit(c)) return false; } return true; } /** * Returns true if string s is a signed or unsigned floating point * (real) number. First character is allowed to be + or -. * Does not accept exponential notation. */ function isSignedFloat(s) { if (isEmpty(s)) return true; var startPos = 0; // skip leading + or - if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") ) startPos = 1; return (isFloat(s.substring(startPos, s.length))); } /** * Notify user that contents of field theField are invalid. * String s describes expected contents of theField.value. */ function warnInvalid(theField, s) { if (isEmpty(s)) return; theField.focus(); theField.select(); alert(s); } /** return error message on invalid date or null if valid */ function isDate(dateStr) { if (isEmpty(dateStr)) return null; var datePat = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/; var matchArray = dateStr.match(datePat); // is format OK? if (matchArray == null) return "Please enter date as either mm/dd/yyyy or mm-dd-yyyy."; // parse date into variables month = matchArray[1]; day = matchArray[3]; year = matchArray[5]; if (month < 1 || month > 12) return("Month must be between 1 and 12."); if (day < 1 || day > 31) return("Day must be between 1 and 31."); if ((month==4 || month==6 || month==9 || month==11) && day==31) return("Month " + month + " doesn't have 31 days!"); if (month == 2) { // check for february 29th var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); if (day > 29 || (day==29 && !isleap)) return("February " + year + " doesn't have " + day + " days!"); } return null; // date is valid } function filterNum( str ) { var re = /\$|,/g; // remove "$" and "," return str.replace(re, ""); } function validateDollar( hookID ) { var field = getHook( hookID ); field.value = filterNum( field.value ); if ( ! isSignedFloat(field.value) ) warnInvalid( field, "Please enter a valid dollar amount" ); } function validateInteger( hookID ) { var field = getHook( hookID ); field.value = filterNum(field.value); if (!isInteger(field.value)) warnInvalid( field, "Please enter a valid integer" ); } function validateFloat( hookID ) { var field = getHook( hookID ); //field.value = filterNum(field.value); if (!isSignedFloat(field.value)) warnInvalid( field, "Please enter a valid number" ); } function validateDate( hookID ) { var field = getHook( hookID ); warnInvalid( field, isDate(field.value) ); }
|
The Gravy Framework | |||||||
| PREV NEXT | FRAMES NO FRAMES | |||||||