c5a326f3cc42beca0b59c284a2819763548c166a
max
Wed Jul 8 05:31:13 2026 -0700
Add top-right "Share a link" and "Login" links to the menu bar, refs #10138
New js/topLinks.js drives two links at the top-right of the menu bar on all pages:
- Login: links to the login page when logged out; when logged in it shows the
username and opens an account dialog (My Sessions / My Custom Tracks /
My Track Hubs, change password, sign out).
- Share a link: on hgTracks, one click saves the current view as a session and
shows a copyable short link, with an optional "Specify name" rename step; works
logged-in or anonymously (reserved user "l"). On hgTrackUi and the hgc/hgGene
item-details popup it instead shares the page URL with the hgsid stripped and
the db argument kept.
hgSession gains two JSON endpoints (hgS_doSaveSessionJson, hgS_doRenameSessionJson)
that reuse saveCartAsSession() and addSessionLink(). The menu bar is patched in
lib/web.c (CGI pages) and hgMenubar.c (static pages) via comment placeholders in
globalNavBar.inc. On narrow/phone screens the links collapse into a menu icon with
a dropdown so they no longer overlap the menu.
diff --git src/hg/lib/web.c src/hg/lib/web.c
index 76d43b490e4..f2cff7eb275 100644
--- src/hg/lib/web.c
+++ src/hg/lib/web.c
@@ -1607,30 +1607,31 @@
char *navBarFile = "inc/globalNavBar.inc";
struct stat statBuf;
char *scriptName = cgiScriptName();
if (cart)
safef(uiVars, sizeof(uiVars), "%s=%s", cartSessionVarName(), cartSessionId(cart));
else
uiVars[0] = 0;
if(docRoot == NULL)
// tolerate missing docRoot (i.e. don't bother with menu when running from command line)
return NULL;
jsIncludeFile("jquery.js", NULL);
jsIncludeFile("jquery.plugins.js", NULL);
jsIncludeFile("utils.js", NULL);
+jsIncludeFile("topLinks.js", NULL);
webIncludeResourceFile("nice_menu.css");
webIncludeLocalJs();
// Read in menu bar html
safef(buf, sizeof(buf), "%s/%s", docRoot, navBarFile);
fd = mustOpen(buf, "r");
fstat(fileno(fd), &statBuf);
int len = statBuf.st_size;
menuStr = needMem(len + 1);
mustRead(fd, menuStr, statBuf.st_size);
menuStr[len] = 0;
carefulClose(&fd);
if (cart)
@@ -1654,32 +1655,87 @@
{
struct trackDb *tdb = hTrackDbForTrack(db, track);
if (tdb)
{
struct trackDb *topLevel = trackDbTopLevelSelfOrParent(tdb);
char *undupedTrack = dupTrackSkipToSourceName(topLevel->track);
safef(hgTablesOptions, sizeof hgTablesOptions,
"../cgi-bin/hgTables?hgta_doMainPage=1&hgta_group=%s&hgta_track=%s&hgta_table=%s&",
topLevel->grp, undupedTrack, tdb->table);
menuStr = replaceChars(menuStr, "../cgi-bin/hgTables?", hgTablesOptions);
trackDbFree(&tdb);
}
}
}
-if(!loginSystemEnabled())
- stripRegEx(menuStr, "<\\!-- LOGIN_START -->.*<\\!-- LOGIN_END -->", REG_ICASE);
+// Fill in the top-right Login link (placeholder in globalNavBar.inc, inside
+// the #topRightLinks container). Logged out: a "Login" link to hgSession. Logged in: the
+// username, which opens an account dialog (handled in topLinks.js using the data-* attributes
+// below). No login system: removed.
+ {
+ char *loginLi = "";
+ if (loginSystemEnabled() || wikiLinkEnabled())
+ {
+ char *userName = wikiLinkUserName();
+ struct dyString *dy = dyStringNew(512);
+ if (userName == NULL)
+ {
+ // Link straight to the login page (same target hgSession's own Login link uses),
+ // rather than bouncing the user through hgSession first.
+ char *loginUrl = wikiLinkUserLoginUrl(cart ? cartSessionId(cart) : "");
+ dyStringPrintf(dy, "Login", loginUrl);
+ }
+ else
+ {
+ char *hgsid = cart ? cartSessionId(cart) : NULL;
+ char *logoutUrl = wikiLinkUserLogoutUrl(hgsid);
+ char *changePwUrl = wikiLinkChangePasswordUrl(hgsid);
+ dyStringPrintf(dy, "%s",
+ userName, logoutUrl, changePwUrl ? changePwUrl : "", userName);
+ }
+ loginLi = dyStringCannibalize(&dy);
+ }
+ menuStr = replaceChars(menuStr, "", loginLi);
+ }
+
+// Fill in the top-right "Share a link" link (placeholder ).
+// data-sharemode tells topLinks.js what to do:
+// "session" (hgTracks): save the current view as a session and show a short link; branches on
+// data-loggedin to either name a session (logged in) or make an anonymous link.
+// "url" (hgTrackUi): just show the current page URL with the hgsid stripped, for sharing.
+ {
+ char *shareLi = "";
+ boolean isHgTracks = (scriptName && endsWith(scriptName, "hgTracks"));
+ boolean isHgTrackUi = (scriptName && endsWith(scriptName, "hgTrackUi"));
+ if (isHgTracks || isHgTrackUi)
+ {
+ char *userName = (loginSystemEnabled() || wikiLinkEnabled()) ? wikiLinkUserName() : NULL;
+ char *shareMode = isHgTrackUi ? "url" : "session";
+ struct dyString *dy = dyStringNew(256);
+ dyStringPrintf(dy, "Share a link");
+ shareLi = dyStringCannibalize(&dy);
+ }
+ menuStr = replaceChars(menuStr, "", shareLi);
+ }
if(scriptName)
{ // Provide optional official mirror servers menu items
char *geoMenu = geoMirrorMenu();
char *pattern = "";
char *newMenuStr = replaceChars(menuStr, pattern, geoMenu);
freez(&menuStr);
menuStr = newMenuStr;
}
if(scriptName)
{
// Provide view menu for some CGIs.
struct dyString *viewItems = dyStringCreate("%s","");