From 6fecdb89027f82b48ce670e9d645f40e7da00d24 Mon Sep 17 00:00:00 2001 From: Franciskid Date: Wed, 8 Jul 2026 02:09:49 +0200 Subject: [PATCH] fix series share navigation and menu placement Three problems reported on series shares. The ShareLink action landed at the bottom of the series menu because the fallback injector cloned the last item and appended; it now clones the first item and inserts at the top, matching where it sits for movies. Guests could not open season or episode pages because guest mode disabled pointer events on all cards; cards are clickable again, since the server-verified route check and the tag policy already control where a guest can actually go. The injected item also inherited the template's data-id, which could shadow a real menu command like Informations; it is stripped now. --- Jellyfin.Plugin.ShareLinks/Web/sharelinks.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Jellyfin.Plugin.ShareLinks/Web/sharelinks.js b/Jellyfin.Plugin.ShareLinks/Web/sharelinks.js index 5b8c010..d7c1b6d 100644 --- a/Jellyfin.Plugin.ShareLinks/Web/sharelinks.js +++ b/Jellyfin.Plugin.ShareLinks/Web/sharelinks.js @@ -2,7 +2,7 @@ var pluginId = '68540b76-ee74-436d-85ff-2abc884bbea6'; var copyLabel = 'Copy Stream URL'; var actionLabel = 'ShareLink'; - var clientVersion = '1.0.1-ui-1'; + var clientVersion = '1.0.1-ui-2'; var allowedItemStorageKey = 'sharelinks.allowedItemId'; var guestClassName = 'sharelinks-guest'; var hiddenAttr = 'data-sharelinks-hidden'; @@ -352,7 +352,8 @@ + ' body.' + guestClassName + ' [data-action="addtocollection"],' + ' body.' + guestClassName + ' [data-id="playlist"],' + ' body.' + guestClassName + ' [data-id="addtocollection"] { display: none !important; }' - + ' body.' + guestClassName + ' .card,' + // Cards stay clickable so guests can navigate season/episode cards on a shared series; + // checkAllowedLocation() verifies the destination server-side and redirects if disallowed. + ' body.' + guestClassName + ' #castCollapsible a,' + ' body.' + guestClassName + ' .detailsGroupItem a,' + ' body.' + guestClassName + ' .genresGroup a,' @@ -541,14 +542,14 @@ } } - return actions.length ? actions[actions.length - 1] : null; + return actions.length ? actions[0] : null; } function isVisible(node) { return !!(node && (node.offsetWidth || node.offsetHeight || node.getClientRects().length)); } - function insertActionAfter(copyNode, explicitItemId, appendToParent) { + function insertActionAfter(copyNode, explicitItemId, insertAtTop) { var parent = copyNode.parentElement; if (!parent || parent.querySelector('[' + injectedAttr + '="1"]')) { return; @@ -568,6 +569,9 @@ injected.removeAttribute('onclick'); injected.removeAttribute('target'); injected.removeAttribute('download'); + // The clone inherits the template's data-id (e.g. 'moreinfo'), which would duplicate + // an existing menu item's id and could shadow/trigger its command; strip it. + injected.removeAttribute('data-id'); injected.setAttribute('aria-label', actionLabel); injected.setAttribute('title', actionLabel); injected.dataset.sharelinksItemId = itemId; @@ -588,8 +592,8 @@ injected.textContent = actionLabel; } - if (appendToParent) { - parent.appendChild(injected); + if (insertAtTop) { + copyNode.insertAdjacentElement('beforebegin', injected); } else { copyNode.insertAdjacentElement('afterend', injected); }