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","");