95433400da33b5bae4c4c8475f1305fc08510f66 jcasper Sat Jun 11 14:25:14 2016 -0700 Store the sort/filter state of jQuery-DataTables-enabled tables in hgSession and hgPublicSessions to the cart, without including that state in saved sessions. Block IE versions before 11 from seeing the DataTables table version, due to checkbox issues. Bonus: fix for a minor session deletion bug. refs #15312, #17509 diff --git src/hg/hgSession/hgSession.c src/hg/hgSession/hgSession.c index e31e3a4..175f633 100644 --- src/hg/hgSession/hgSession.c +++ src/hg/hgSession/hgSession.c @@ -27,64 +27,60 @@ #include "sessionThumbnail.h" #include "obscure.h" void usage() /* Explain usage and exit. */ { errAbort( "hgSession - Interface with wiki login and do session saving/loading.\n" "usage:\n" " hgSession <various CGI settings>\n" ); } /* Global variables. */ struct cart *cart; -char *excludeVars[] = {"Submit", "submit", NULL}; +char *excludeVars[] = {"Submit", + "submit", + hgSessionTableState, + hgPublicSessionsTableState, + NULL}; struct slName *existingSessionNames = NULL; /* Javascript to confirm that the user truly wants to delete a session. */ -#define confirmDeleteFormat "return confirm('Are you sure you want to delete %s?');" +#define confirmDeleteFormat "return confirm('Are you sure you want to delete ' + decodeURIComponent('%s') + '?');" char *cgiDecodeClone(char *encStr) /* Allocate and return a CGI-decoded copy of encStr. */ { size_t len = strlen(encStr); char *decStr = needMem(len+1); cgiDecode(encStr, decStr, len); return decStr; } void welcomeUser(char *wikiUserName) /* Tell the user they are not logged in to the wiki or other login * system and tell them how to do so. */ { char *wikiHost = wikiLinkHost(); cartWebStart(cart, NULL, "Welcome %s", wikiUserName); jsInit(); -/* Includes for the jquery datatables plugin. Clashes a bit with the jquery included - * by cartWebStart, unfortunately. Should resolve this ultimately (ideally by solving - * the issues preventing us from upgrading the global jquery include) */ -printf ("<link rel=\"stylesheet\" type=\"text/css\" " - "href=\"https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css\">\n"); -printf ("<script type=\"text/javascript\" " - "src=\"https://code.jquery.com/jquery-1.12.3.min.js\"></script>\n"); -printf ("<script type=\"text/javascript\" charset=\"utf8\" " - "src=\"https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js\"></script>\n"); +jsIncludeDataTablesLibs(); if (loginSystemEnabled()) /* Using the new hgLogin CGI for login? */ { printf("<h4 style=\"margin: 0pt 0pt 7px;\">Your Account Information</h4>" "<ul style=\"list-style: none outside none; margin: 0pt; padding: 0pt;\">" "<li>Username: %s</li>",wikiUserName); printf("<li><A HREF=\"%s\">Change password</A></li></ul>", wikiLinkChangePasswordUrl(cartSessionId(cart))); printf("<p><A HREF=\"%s\">Sign out</A></p>", wikiLinkUserLogoutUrl(cartSessionId(cart))); } else { printf("If you are not %s (on the wiki at " "<A HREF=\"http://%s/\" TARGET=_BLANK>%s</A>) " @@ -93,31 +89,31 @@ printf("<A HREF=\"%s\"><B>click here to sign out.</B></A>\n", wikiLinkUserLogoutUrl(cartSessionId(cart))); } } void offerLogin() /* Tell the user they are not logged in to the system and tell them how to * do so. */ { char *wikiHost = wikiLinkHost(); cartWebStart(cart, NULL, "Sign in to UCSC Genome Bioinformatics"); jsInit(); if (loginSystemEnabled()) { - printf("<ul style=\"list-style: none outside none; margin: 0pt; padding: 0pt;\"" + printf("<ul style=\"list-style: none outside none; margin: 0pt; padding: 0pt;\">" "<li><A HREF=\"%s\">Login</A></li>", wikiLinkUserLoginUrl(cartSessionId(cart))); printf("<li><A HREF=\"%s\">" "Create an account</A></li></ul>", wikiLinkUserSignupUrl(cartSessionId(cart))); printf("<P>Signing in enables you to save current settings into a " "named session, and then restore settings from the session later. <BR>" "If you wish, you can share named sessions with other users.</P>"); } else { printf("Signing in enables you to save current settings into a " "named session, and then restore settings from the session later.\n" "If you wish, you can share named sessions with other users.\n"); printf("<P>The sign-in page is handled by our " @@ -282,40 +278,45 @@ void showExistingSessions(char *userName) /* Print out a table with buttons for sharing/unsharing/loading/deleting * previously saved sessions. */ { struct sqlConnection *conn = hConnectCentral(); struct sqlResult *sr = NULL; char **row = NULL; char query[512]; boolean foundAny = FALSE; char *encUserName = cgiEncodeFull(userName); boolean gotSettings = (sqlFieldIndex(conn, namedSessionTable, "settings") >= 0); /* DataTables configuration: only allow ordering on session name, creation date, and database. * https://datatables.net/reference/option/columnDefs */ printf ("<script type=\"text/javascript\">" + "if (theClient.isIePre11() === false)\n{\n" "$(document).ready(function () {\n" " $('#sessionTable').DataTable({\"columnDefs\": [{\"orderable\":false, \"targets\":[0,4,5,6,7,8]}],\n" - " \"order\":[1,'asc']\n" + " \"order\":[1,'asc'],\n" + " \"stateSave\":true,\n" + " \"stateSaveCallback\": %s,\n" + " \"stateLoadCallback\": %s\n" " });\n" "} );\n" - "</script>\n"); + "}\n" + "</script>\n", jsDataTableStateSave(hgSessionPrefix), jsDataTableStateLoad(hgSessionPrefix, cart)); printf("<H3>My Sessions</H3>\n"); printf("<div style=\"max-width:1024px\">"); -printf("<table id=\"sessionTable\" class=\"display compact\" borderwidth=0>\n"); +printf("<table id=\"sessionTable\" class=\"sessionTable stripe hover row-border compact\" borderwidth=0>\n"); printf("<thead><tr>"); printf("<TH><TD><B>session name (click to load)</B></TD><TD><B>created on</B></TD><td><b>assembly</b></td>" "<TD align=center><B>view/edit <BR>details </B></TD>" "<TD align=center><B>delete this <BR>session </B></TD><TD align=center><B>share with <BR>others? </B></TD>" "<td align-center><b>post in <br><a href=\"../cgi-bin/hgPublicSessions?%s\">public listing</a>?</b></td>" "<TD align=center><B>send to<BR>mail</B></TD></TH>", cartSidUrlString(cart)); printf("</tr></thead>"); printf("<tbody>\n"); if (gotSettings) sqlSafef(query, sizeof(query), "SELECT sessionName, shared, firstUse, contents, settings from %s " "WHERE userName = '%s' ORDER BY sessionName;", namedSessionTable, encUserName); else @@ -366,36 +367,36 @@ printf("%s</td><td align=center>", db); } else printf("n/a</td><td align=center>"); if (gotSettings) { safef(buf, sizeof(buf), "%s%s", hgsEditPrefix, encSessionName); cgiMakeButton(buf, "details"); } else printf("unavailable"); printf("</TD><TD align=center>"); safef(buf, sizeof(buf), "%s%s", hgsDeletePrefix, encSessionName); char command[512]; - safef(command, sizeof(command), confirmDeleteFormat, sessionName); + safef(command, sizeof(command), confirmDeleteFormat, encSessionName); cgiMakeOnClickSubmitButton(command, buf, "delete"); printf("</TD><TD align=center>"); safef(buf, sizeof(buf), "%s%s", hgsSharePrefix, encSessionName); - cgiMakeCheckBoxJS(buf, shared>0, "onchange=\"document.mainForm.submit();\""); + cgiMakeCheckBoxJS(buf, shared>0, "onchange=\"console.log('new status' + this.checked); document.mainForm.submit();\""); printf("</TD><TD align=center>"); safef(buf, sizeof(buf), "%s%s", hgsGalleryPrefix, encSessionName); cgiMakeCheckBoxFourWay(buf, inGallery, shared>0, NULL, NULL, "onchange=\"document.mainForm.submit();\""); link = getSessionEmailLink(encUserName, encSessionName); printf("</td><td align=center>%s</td></tr>", link); freez(&link); foundAny = TRUE; struct slName *sn = slNameNew(sessionName); slAddHead(&existingSessionNames, sn); } if (!foundAny) printf("<TR><TD> </TD><TD>(none)</TD>" @@ -943,31 +944,31 @@ "<INPUT TYPE=HIDDEN NAME=\"%s\" VALUE=\"%s\">" "Session Name: " "<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=\"%s\" " "onChange=\"{%s}\" onKeypress=\"{%s}\">\n", sessionName, hgSessionName(), cartSessionVarName(cart), cartSessionId(cart), hgsOldSessionName, sessionName, hgsNewSessionName, 32, sessionName, highlightAccChanges, highlightAccChanges); dyStringPrintf(dyMessage, " <INPUT TYPE=SUBMIT NAME=\"%s%s\" VALUE=\"use\">" " <INPUT TYPE=SUBMIT NAME=\"%s%s\" VALUE=\"delete\" " "onClick=\"" confirmDeleteFormat "\">" " <INPUT TYPE=SUBMIT ID=\"%s\" NAME=\"%s\" VALUE=\"accept changes\">" " <INPUT TYPE=SUBMIT NAME=\"%s\" VALUE=\"cancel\"> " "<BR>\n", hgsLoadPrefix, encSessionName, hgsDeletePrefix, encSessionName, - sessionName, hgsDoSessionChange, hgsDoSessionChange, hgsCancel); + encSessionName, hgsDoSessionChange, hgsDoSessionChange, hgsCancel); dyStringPrintf(dyMessage, "Share with others? <INPUT TYPE=CHECKBOX NAME=\"%s%s\"%s VALUE=on " "onChange=\"{%s %s}\" onClick=\"{%s %s}\" id=\"detailsSharedCheckbox\">\n" "<INPUT TYPE=HIDDEN NAME=\"%s%s%s\" VALUE=0><BR>\n", hgsSharePrefix, encSessionName, (shared>0 ? " CHECKED" : ""), highlightAccChanges, toggleGalleryDisable, highlightAccChanges, toggleGalleryDisable, cgiBooleanShadowPrefix(), hgsSharePrefix, encSessionName); dyStringPrintf(dyMessage, "List in Public Sessions? <INPUT TYPE=CHECKBOX NAME=\"%s%s\"%s VALUE=on " "onChange=\"{%s}\" onClick=\"{%s}\" id=\"detailsGalleryCheckbox\">\n" "<INPUT TYPE=HIDDEN NAME=\"%s%s%s\" VALUE=0><BR>\n", hgsGalleryPrefix, encSessionName, (shared>=2 ? " CHECKED" : ""), highlightAccChanges, highlightAccChanges, cgiBooleanShadowPrefix(), hgsGalleryPrefix, encSessionName);