e70152e44cc66cc599ff6b699eb8adc07f3e656a kent Sat May 24 21:09:34 2014 -0700 Adding Copyright NNNN Regents of the University of California to all files I believe with reasonable certainty were developed under UCSC employ or as part of Genome Browser copyright assignment. diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c index 7802961..a2d9b1a 100644 --- src/hg/lib/jsHelper.c +++ src/hg/lib/jsHelper.c @@ -1,671 +1,674 @@ // jsHelper.c - helper routines for interface between CGIs and client-side javascript +/* Copyright (C) 2014 The Regents of the University of California + * See README in this or parent directory for licensing information. */ + #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; /* 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", cartSidUrlString(cart), cgiScriptName(), cartSidUrlString(cart)); } static char *makeIndentBuf(int indentLevel) { if (indentLevel < 0) return ""; char *indentBuf; indentBuf = needMem(indentLevel + 1); memset(indentBuf, '\t', indentLevel); indentBuf[indentLevel] = 0; return indentBuf; } static void jsonPrintRecurse(struct jsonElement *ele, int indentLevel) { if (indentLevel >= -1) // Note that < -1 will result in no indenting indentLevel++; char *tab = "\t"; char *nl = "\n"; if (indentLevel < 0) { tab = ""; nl = ""; } char *indentBuf = makeIndentBuf(indentLevel); switch (ele->type) { case jsonObject: { hPrintf("{%s",nl); if(hashNumEntries(ele->val.jeHash)) { struct hashEl *el, *list = hashElListHash(ele->val.jeHash); slSort(&list, hashElCmp); for (el = list; el != NULL; el = el->next) { struct jsonElement *val = el->val; hPrintf("%s%s\"%s\": ", indentBuf, tab, el->name); jsonPrintRecurse(val, indentLevel); hPrintf("%s%s", el->next == NULL ? "" : ",",nl); } hashElFreeList(&list); } hPrintf("%s}", indentBuf); break; } case jsonList: { struct slRef *el; hPrintf("[%s",nl); if(ele->val.jeList) { for (el = ele->val.jeList; el != NULL; el = el->next) { struct jsonElement *val = el->val; hPrintf("%s%s", indentBuf,tab); jsonPrintRecurse(val, indentLevel); hPrintf("%s%s", el->next == NULL ? "" : ",",nl); } } hPrintf("%s]", indentBuf); break; } case jsonString: { hPrintf("\"%s\"", jsonStringEscape(ele->val.jeString)); break; } case jsonBoolean: { hPrintf("%s", ele->val.jeBoolean ? "true" : "false"); break; } case jsonNumber: { char buf[256]; safef(buf, sizeof(buf), "%ld", ele->val.jeNumber); hPrintf("%s", buf); break; } case jsonDouble: { char buf[256]; safef(buf, sizeof(buf), "%g", ele->val.jeDouble); hPrintf("%s", buf); break; } default: { errAbort("jsonPrintRecurse; invalid type: %d", ele->type); break; } } if (indentLevel >= 0) freez(&indentBuf); } void jsonPrint(struct jsonElement *json, char *name, int indentLevel) { // print out a jsonElement, indentLevel -1 means no indenting char *indentBuf = makeIndentBuf(indentLevel); if(name != NULL) { if (indentLevel >= 0 ) hPrintf("// START %s\n%s", name, indentBuf); hPrintf("var %s = ", name); } jsonPrintRecurse(json, (indentLevel - 1)); // will increment back to indentLevel if(name != NULL) { hPrintf("%s;\n", indentBuf); if (indentLevel >= 0 ) hPrintf("// END %s\n", name); } if (indentLevel >= 0) freez(&indentBuf); } 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); }