09f26ed9a7dcc52b03b4d3e5b2f97c5177cd9334 max Mon Sep 21 06:00:40 2026 -0700 Drop the ${hgsid} trackDb variable; add session ids to links in the browser instead A description page's links can carry the session id without the page itself holding one. addHgsidToLinks() in utils.js walks the rendered page and appends hgsid to every that stays on this host and points into the same cgi-bin directory: a relative CGI link gets one, a static .html, a link to another host, a mailto and a plain #anchor do not, and a link that already names a session is left alone. hgc and hgTrackUi call it through a new jsAddHgsidToLinks(), and hgTracks.js calls it on the track description popup once the ajax content is in. A link written with a literal $hgsid is rewritten rather than skipped, so the description pages already deployed in the GenArk hubs work again. hVarSubst no longer knows about hgsid: it is out of the trackDb variable list, so hVarSubstTrackDbHtml is a hub-only pass again and needs no cart, and hVarSubstWithCart and webIncludeHelpFileSubst, which existed only to resolve it, are gone. The variable is taken out of the trackDb README and out of the twenty-odd description pages that used it. refs #38380 diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c index 6b3b5076c08..2c0210f244d 100644 --- src/hg/lib/jsHelper.c +++ src/hg/lib/jsHelper.c @@ -1,648 +1,663 @@ // jsHelper.c - helper routines for interface between CGIs and client-side javascript /* Copyright (C) 2014 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ 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 includes jsHelper.js. * Subsequent calls do nothing, so this can be called many times. */ { if (! jsInited) { // jsh_pageVertPos trick taken from // http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html puts(""); int pos = cgiOptionalInt("jsh_pageVertPos", 0); if (pos > 0) { jsInlineF("window.onload = function () { window.scrollTo(0, %d); }\n", pos); } jsInited = TRUE; jsIncludeFile("jsHelper.js", NULL); } } struct dyString *jsOnChangeStart() /* Start up an onChange string */ { struct dyString *dy = dyStringNew(1024); 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. */ { jsInlineF("var %s='%s';\n", jsVar, val); } void jsMakeTrackingRadioButtonExtraHtml(char *cgiVar, char *jsVar, char *val, char *selVal, char *extraHtml) /* Make a radio button with extra HTML attributes that also sets tracking variable * in javascript. */ { char id[256]; safef(id, sizeof id, "%s_%s", cgiVar, val); hPrintf(""); } void jsMakeTrackingRadioButton(char *cgiVar, char *jsVar, char *val, char *selVal) /* Make a radio button that also sets tracking variable * in javascript. */ { jsMakeTrackingRadioButtonExtraHtml(cgiVar, jsVar, val, selVal, NULL); } 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); jsInlineF("var %s=%d;\n", jsVar, oldVal); hPrintf(""); jsOnEventByIdF("click", cgiVar, "%s=(%s+1)%%2;", jsVar, jsVar); 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 * jsInit 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]; //TODO XSS filter safef(vertPosSet, sizeof(vertPosSet), "document.%s.jsh_pageVertPos.value = f_scrollTop(); ", form); return vertPosSet; } 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 id[256]; 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"); safef(id, sizeof id, "%s_grp%sBut", buttonVar, isSet ? "Set" : "Clr"); cgiMakeOnClickButton(id, javascript, isSet ? JS_SET_ALL_BUTTON_LABEL : JS_CLEAR_ALL_BUTTON_LABEL); } void jsMakeSetClearContainer() /* Begin a wrapper div with class setClearContainer, plus 'Set all' and 'Clear all' buttons. * This should be followed by a bunch of checkboxes, and then a call to jsEndContainer. */ { puts("
\n" "\n" "\n" "
" ); } void jsEndContainer() /* End a wrapper div. */ { puts("
"); } 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 *