5ede442a609630efb2eeda3682214948faf6d5c9 tdreszer Mon Jun 25 16:18:54 2012 -0700 Next batch of many checkins as dictated by Jim. Formatting space after if and limiting lines to 100 chars. Changes limited to lines last touched by tdreszer (git blame) so as not to ruin history. None of these changes should affect executables in any way. Only affect is to my sanity and Jim's. diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c index b9e29b9..4f392a7 100644 --- src/hg/lib/jsHelper.c +++ src/hg/lib/jsHelper.c @@ -1,956 +1,956 @@ // jsHelper.c - helper routines for interface between CGIs and client-side javascript #include "common.h" #include #include "dystring.h" #include "cheapcgi.h" #include "cart.h" #include "hPrint.h" #include "hash.h" #include "jsHelper.h" #include "web.h" #include "hui.h" #include "hgConfig.h" #include "portable.h" static boolean jsInited = FALSE; struct jsonElement *jsonGlobalsHash = NULL; /* mainForm/hiddenForm code supports the following: when the user selects * something from a pull-down, it will go hit the server to * figure out how to reload other control options based on the choice. * (For instance if they change the group, which items in the track * drop-down need to change). * * We accomplish this by maintaining two forms - a mainForm and a * hiddenForm. The hiddenForm maintains echo's of all the variables * in the main form, which get updated onChange of controls that need * to 'ripple' to other controls. The onChange also submits the * control. */ void jsInit() /* If this is the first call, set window.onload to the operations * performed upon loading a page and print supporting javascript. * Currently this just sets the page vertical position if specified on * CGI, and also calls jsWriteFunctions. * Subsequent calls do nothing, so this can be called many times. */ { if (! jsInited) { puts( "\n" "\n"); int pos = cgiOptionalInt("jsh_pageVertPos", 0); if (pos > 0) printf("\n\n", pos); jsWriteFunctions(); jsInited = TRUE; } } void jsWriteFunctions() /* Write out Javascript functions. */ { hPrintf("\n\n"); } struct dyString *jsOnChangeStart() /* Start up an onChange string */ { struct dyString *dy = dyStringNew(1024); dyStringAppend(dy, "onChange=\""); return dy; } char *jsOnChangeEnd(struct dyString **pDy) /* Finish up javascript onChange command. */ { dyStringAppend(*pDy, "document.hiddenForm.submit();\""); return dyStringCannibalize(pDy); } void jsDropDownCarryOver(struct dyString *dy, char *var) /* Add statement to carry-over drop-down item to dy. */ { dyStringPrintf(dy, "document.hiddenForm.%s.value=", var); dyStringPrintf(dy, "document.mainForm.%s.options", var); dyStringPrintf(dy, "[document.mainForm.%s.selectedIndex].value; ", var); } void jsTextCarryOver(struct dyString *dy, char *var) /* Add statement to carry-over text item to dy. */ { dyStringPrintf(dy, "document.hiddenForm.%s.value=document.mainForm.%s.value; ", var, var); } void jsTrackingVar(char *jsVar, char *val) /* Emit a little Javascript to keep track of a variable. * This helps especially with radio buttons. */ { hPrintf("\n"); } void jsMakeTrackingRadioButton(char *cgiVar, char *jsVar, char *val, char *selVal) /* Make a radio button that also sets tracking variable * in javascript. */ { hPrintf(""); } void jsMakeTrackingCheckBox(struct cart *cart, char *cgiVar, char *jsVar, boolean usualVal) /* Make a check box filling in with existing value and * putting a javascript tracking variable on it. */ { char buf[256]; boolean oldVal = cartUsualBoolean(cart, cgiVar, usualVal); hPrintf("\n", jsVar, oldVal); hPrintf(""); safef(buf, sizeof(buf), "%s%s", cgiBooleanShadowPrefix(), cgiVar); cgiMakeHiddenVar(buf, "0"); } void jsTrackedVarCarryOver(struct dyString *dy, char *cgiVar, char *jsVar) /* Carry over tracked variable (radio button?) to hidden form. */ { dyStringPrintf(dy, "document.hiddenForm.%s.value=%s; ", cgiVar, jsVar); } char *jsRadioUpdate(char *cgiVar, char *jsVar, char *val) /* Make a little javascript to check and uncheck radio buttons * according to new value. To use this you must have called * jsWriteFunctions somewhere, and also must use jsMakeTrackingRadioButton * to make the buttons. */ { static char buf[256]; safef(buf, sizeof(buf), "setRadioCheck('%s', '%s'); %s='%s'", cgiVar, val, jsVar, val); return buf; } void jsCreateHiddenForm(struct cart *cart, char *scriptName, char **vars, int varCount) /* Create a hidden form with the given variables */ { int i; hPrintf( "
\n", scriptName); cartSaveSession(cart); for (i=0; i\n", vars[i]); puts(""); } char *jsSetVerticalPosition(char *form) /* Returns a javascript statement for storing the vertical position of the * page; typically this would go just before a document submit. * jsInit must be called first. * Do not free return value! */ { if (! jsInited) errAbort("jsSetVerticalPosition: jsInit must be called first."); static char vertPosSet[2048]; safef(vertPosSet, sizeof(vertPosSet), "document.%s.jsh_pageVertPos.value = f_scrollTop(); ", form); return vertPosSet; } void jsMakeSetClearButton(struct cart *cart, char *form, char *buttonVar, char *buttonLabel, char *cartVarPrefix, struct slName *cartVarSuffixList, char *anchor, boolean currentPos, boolean isSet) /* Make a button for setting or clearing all of a list of boolean * cart variables (i.e. checkboxes). If this button was just pressed, * set or clear those cart variables. * Optional html anchor is appended to the form's action if given. * If currentPos, anchor is ignored and jsSetVerticalPosition is used so * that the new page gets the same vertical offset as the current page. */ { struct slName *suffix; char javascript[2048]; char *vertPosJs = ""; if (currentPos) { anchor = NULL; jsInit(); vertPosJs = jsSetVerticalPosition(form); } cgiMakeHiddenVar(buttonVar, ""); safef(javascript, sizeof javascript, "document.%s.action = '%s%s%s'; document.%s.%s.value='%s'; %s" "document.%s.submit();", form, cgiScriptName(), (isNotEmpty(anchor) ? "#" : ""), (isNotEmpty(anchor) ? anchor : ""), form, buttonVar, buttonLabel, vertPosJs, form); cgiMakeOnClickButton(javascript, buttonLabel); if (isNotEmpty(cgiOptionalString(buttonVar))) { char option[1024]; if (cartVarPrefix == NULL) cartVarPrefix = ""; for (suffix = cartVarSuffixList; suffix != NULL; suffix = suffix->next) { safef(option, sizeof(option), "%s%s", cartVarPrefix, suffix->name); cartSetBoolean(cart, option, isSet); } } } void jsMakeCheckboxGroupSetClearButton(char *buttonVar, boolean isSet) /* Make a button for setting or clearing a set of checkboxes with the same name. * Uses only javascript to change the checkboxes, no resubmit. */ { char javascript[256]; safef(javascript, sizeof(javascript), "var list = document.getElementsByName('%s'); " "for (var ix = 0; ix < list.length; ix++) {list[ix].checked = %s}", buttonVar, isSet ? "true" : "false"); cgiMakeOnClickButton(javascript, isSet ? JS_SET_ALL_BUTTON_LABEL : JS_CLEAR_ALL_BUTTON_LABEL); } char *jsPressOnEnter(char *button) /* Returns a javascript statement that clicks button when the Enter key * has been pressed; typically this would go in a text input. * jsInit must be called first. * Do not free return value! */ { if (! jsInited) errAbort("jsPressOnEnter: jsInit must be called first."); static char poe[2048]; safef(poe, sizeof(poe), "return pressOnEnter(event, %s);", button); return poe; } void jsIncludeFile(char *fileName, char *noScriptMsg) { /* Prints out html to include given javascript file from the js directory; suppresses redundant * \n"); } } void jsonErrPrintf(struct dyString *ds, char *format, ...) // Printf a json error to a dyString for communicating with ajax code; format is: // {"error": error message here} { va_list args; va_start(args, format); dyStringPrintf(ds, "{\"error\": \""); struct dyString *buf = newDyString(1000); dyStringVaPrintf(buf, format, args); dyStringAppend(ds, jsonStringEscape(dyStringCannibalize(&buf))); dyStringPrintf(ds, "\"}"); va_end(args); } static void skipLeadingSpacesWithPos(char *s, int *posPtr) /* skip leading white space. */ { for (;;) { char c = s[*posPtr]; if (!isspace(c)) return; (*posPtr)++; } } static void getSpecificChar(char c, char *str, int *posPtr) { // get specified char from string or errAbort if(str[*posPtr] != c) errAbort("Unexpected character '%c' (expected '%c') - string position %d\n", str[*posPtr], c, *posPtr); (*posPtr)++; } static char *getString(char *str, int *posPtr) { // read a double-quote delimited string; we handle backslash escaping. // returns allocated string. boolean escapeMode = FALSE; int i; struct dyString *ds = dyStringNew(1024); getSpecificChar('"', str, posPtr); for(i = 0;; i++) { char c = str[*posPtr + i]; if(!c) errAbort("Premature end of string (missing trailing double-quote); string position '%d'", *posPtr); else if(escapeMode) { // We support escape sequences listed in http://www.json.org, // except for Unicode which we cannot support in C-strings switch(c) { case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'u': errAbort("Unicode in JSON is unsupported"); break; default: // we don't need to convert \,/ or " break; } dyStringAppendC(ds, c); escapeMode = FALSE; } else if(c == '"') break; else if(c == '\\') escapeMode = TRUE; else { dyStringAppendC(ds, c); escapeMode = FALSE; } } *posPtr += i; getSpecificChar('"', str, posPtr); return dyStringCannibalize(&ds); } static struct jsonElement *jsonParseExpression(char *str, int *posPtr); static struct jsonElement *jsonParseObject(char *str, int *posPtr) { struct hash *h = newHash(0); getSpecificChar('{', str, posPtr); while(str[*posPtr] != '}') { // parse out a name : val pair skipLeadingSpacesWithPos(str, posPtr); char *name = getString(str, posPtr); skipLeadingSpacesWithPos(str, posPtr); getSpecificChar(':', str, posPtr); skipLeadingSpacesWithPos(str, posPtr); hashAdd(h, name, jsonParseExpression(str, posPtr)); skipLeadingSpacesWithPos(str, posPtr); if(str[*posPtr] == ',') (*posPtr)++; else break; } skipLeadingSpacesWithPos(str, posPtr); getSpecificChar('}', str, posPtr); return newJsonObject(h); } static struct jsonElement *jsonParseList(char *str, int *posPtr) { struct slRef *list = NULL; getSpecificChar('[', str, posPtr); while(str[*posPtr] != ']') { struct slRef *e; AllocVar(e); skipLeadingSpacesWithPos(str, posPtr); e->val = jsonParseExpression(str, posPtr); slAddHead(&list, e); skipLeadingSpacesWithPos(str, posPtr); if(str[*posPtr] == ',') (*posPtr)++; else break; } skipLeadingSpacesWithPos(str, posPtr); getSpecificChar(']', str, posPtr); slReverse(&list); return newJsonList(list); } static struct jsonElement *jsonParseString(char *str, int *posPtr) { return newJsonString(getString(str, posPtr)); } static struct jsonElement *jsonParseBoolean(char *str, int *posPtr) { struct jsonElement *ele = NULL; int i; for(i = 0; str[*posPtr + i] && isalpha(str[*posPtr + i]); i++); ; char *val = cloneStringZ(str + *posPtr, i); if(sameString(val, "true")) ele = newJsonBoolean(TRUE); else if(sameString(val, "false")) ele = newJsonBoolean(FALSE); else errAbort("Invalid boolean value '%s'; pos: %d", val, *posPtr); *posPtr += i; freez(&val); return ele; } static struct jsonElement *jsonParseNumber(char *str, int *posPtr) { int i; boolean integral = TRUE; struct jsonElement *retVal = NULL; for(i = 0;; i++) { char c = str[*posPtr + i]; if(c == 'e' || c == 'E' || c == '.') integral = FALSE; else if(!c || (!isdigit(c) && c != '-')) break; } char *val = cloneStringZ(str + *posPtr, i); *posPtr += i; if(integral) retVal = newJsonNumber(sqlLongLong(val)); else { double d; if(sscanf(val, "%lf", &d)) retVal = newJsonDouble(d); else errAbort("Invalid JSON Double: %s", val); } freez(&val); return retVal; } static struct jsonElement *jsonParseExpression(char *str, int *posPtr) { skipLeadingSpacesWithPos(str, posPtr); char c = str[*posPtr]; if(c == '{') return jsonParseObject(str, posPtr); else if (c == '[') return jsonParseList(str, posPtr); else if (c == '"') return jsonParseString(str, posPtr); else if (isdigit(c) || c == '-') return jsonParseNumber(str, posPtr); else return jsonParseBoolean(str, posPtr); // XXXX support null? } struct jsonElement *jsonParse(char *str) { // parse string into an in-memory json representation int pos = 0; struct jsonElement *ele = jsonParseExpression(str, &pos); skipLeadingSpacesWithPos(str, &pos); if(str[pos]) errAbort("Invalid JSON: unprocessed trailing string at position: %d: %s", pos, str + pos); return ele; } char *jsonStringEscape(char *inString) /* backslash escape a string for use in a double quoted json string. * More conservative than javaScriptLiteralEncode because * some json parsers complain if you escape & or ' */ { char c; int outSize = 0; char *outString, *out, *in; if (inString == NULL) return(cloneString("")); /* Count up how long it will be */ in = inString; while ((c = *in++) != 0) { switch(c) { case '\"': case '\\': case '/': case '\b': case '\f': case '\n': case '\r': case '\t': outSize += 2; break; default: outSize += 1; } } outString = needMem(outSize+1); /* Encode string */ in = inString; out = outString; while ((c = *in++) != 0) { switch(c) { case '\"': case '\\': case '/': case '\b': case '\f': case '\n': case '\r': case '\t': *out++ = '\\'; break; } *out++ = c; } *out++ = 0; return outString; }