Skip to content

Commit 5525722

Browse files
namedgraphclaude
andcommitted
Skip fetch and re-render when switching to a cached tab
Tab clicks, popstate, and close-tab fallback used to funnel through ldh:DocumentNavigate, which always re-fetches the RDF document and replaces the pane's document-body via XSLT. For a tab whose pane is already in the DOM and whose RDF document is already in LinkedDataHub.contents[$uri], this is wasted work and a visible latency hit on every tab swap. Add ldh:TabSwitch: aborts any in-flight DocumentNavigate, syncs the address bar, optionally pushes history state, applies ldh:ActivateTab (CSS toggle), refreshes the sidebar via ldh:NavigationUpdate, scrolls to top. No fetch, no XSLT re-render; block factories ran on first render and the rendered DOM (including map instances cached under LinkedDataHub.contents[$uri].map) stays intact. Gate on ixsl:contains(LinkedDataHub.contents, $uri). Cache presence implies a prior rdf-document-response populated both the entry and the pane DOM, so block.xsl mousemove handlers will find what they expect (the invariant f726423 was protecting). Server-rendered initial panes do not populate the cache, so the local tab on a ?uri=<external> initial load still falls through to DocumentNavigate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d414d7a commit 5525722

1 file changed

Lines changed: 95 additions & 15 deletions

File tree

  • src/main/webapp/static/com/atomgraph/linkeddatahub/xsl

src/main/webapp/static/com/atomgraph/linkeddatahub/xsl/client.xsl

Lines changed: 95 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,49 @@ WHERE
799799
<xsl:sequence select="ixsl:call(ixsl:window(), 'history.pushState', [ $state-obj, $title, $href ])[current-date() lt xs:date('2000-01-01')]"/>
800800
</xsl:template>
801801

802+
<!-- switch to a tab whose pane DOM and LinkedDataHub.contents[$uri] are already populated: no fetch, no re-render -->
803+
<xsl:template name="ldh:TabSwitch">
804+
<xsl:param name="uri" as="xs:anyURI"/>
805+
<xsl:param name="href" as="xs:anyURI"/>
806+
<xsl:param name="tab-li" as="element()"/>
807+
<xsl:param name="push-state" select="true()" as="xs:boolean"/>
808+
<xsl:param name="container" as="element()" select="id($body-id, ixsl:page())"/>
809+
810+
<!-- the user has switched intent; cancel any in-flight DocumentNavigate fetch so its response doesn't reactivate the previous tab -->
811+
<xsl:if test="ixsl:contains(ixsl:get(ixsl:window(), 'LinkedDataHub'), 'saxonController')">
812+
<xsl:sequence select="ixsl:call(ixsl:get(ixsl:window(), 'LinkedDataHub.saxonController'), 'abort', [])[current-date() lt xs:date('2000-01-01')]"/>
813+
</xsl:if>
814+
<ixsl:set-style name="cursor" select="'default'" object="ixsl:page()//body"/>
815+
816+
<!-- mirror ldh:DocumentNavigate: show external URI, clear for local -->
817+
<xsl:for-each select="id('uri', ixsl:page())">
818+
<xsl:choose>
819+
<xsl:when test="not(starts-with($uri, lapp:origin(ldh:request-uri()) || '/'))">
820+
<ixsl:set-property name="value" select="string($uri)" object="."/>
821+
</xsl:when>
822+
<xsl:otherwise>
823+
<ixsl:set-property name="value" select="''" object="."/>
824+
</xsl:otherwise>
825+
</xsl:choose>
826+
</xsl:for-each>
827+
828+
<xsl:if test="$push-state">
829+
<xsl:call-template name="ldh:PushState">
830+
<xsl:with-param name="href" select="$href"/>
831+
<xsl:with-param name="title" select="()"/>
832+
<xsl:with-param name="container" select="$container"/>
833+
</xsl:call-template>
834+
</xsl:if>
835+
836+
<xsl:apply-templates select="$tab-li" mode="ldh:ActivateTab"/>
837+
838+
<xsl:call-template name="ldh:NavigationUpdate">
839+
<xsl:with-param name="href" select="$href"/>
840+
</xsl:call-template>
841+
842+
<xsl:sequence select="ixsl:call(ixsl:window(), 'scrollTo', [ 0, 0 ])[current-date() lt xs:date('2000-01-01')]"/>
843+
</xsl:template>
844+
802845
<!-- document navigation: handles local/external branching -->
803846

804847
<xsl:template name="ldh:DocumentNavigate">
@@ -902,12 +945,25 @@ WHERE
902945
<!-- decode URI from the ?uri query param if the URI was proxied; otherwise strip the query string so the cache key matches document-body/@about -->
903946
<xsl:variable name="query-params" select="ldh:parse-query-params(substring-after($href, '?'))" as="map(xs:string, xs:string*)"/>
904947
<xsl:variable name="uri" select="if (map:contains($query-params, 'uri')) then xs:anyURI(map:get($query-params, 'uri')) else ac:absolute-path($href)" as="xs:anyURI"/>
948+
<xsl:variable name="tab-li" select="id('tab-bar-list', ixsl:page())/li[ixsl:get(., 'dataset.uri') = string($uri)]" as="element()?"/>
905949

906-
<xsl:call-template name="ldh:DocumentNavigate">
907-
<xsl:with-param name="uri" select="$uri"/>
908-
<xsl:with-param name="query-params" select="map:remove($query-params, 'uri')"/>
909-
<xsl:with-param name="push-state" select="false()"/>
910-
</xsl:call-template>
950+
<xsl:choose>
951+
<xsl:when test="exists($tab-li) and ixsl:contains(ixsl:get(ixsl:window(), 'LinkedDataHub.contents'), '`' || $uri || '`')">
952+
<xsl:call-template name="ldh:TabSwitch">
953+
<xsl:with-param name="uri" select="$uri"/>
954+
<xsl:with-param name="href" select="$href"/>
955+
<xsl:with-param name="tab-li" select="$tab-li"/>
956+
<xsl:with-param name="push-state" select="false()"/>
957+
</xsl:call-template>
958+
</xsl:when>
959+
<xsl:otherwise>
960+
<xsl:call-template name="ldh:DocumentNavigate">
961+
<xsl:with-param name="uri" select="$uri"/>
962+
<xsl:with-param name="query-params" select="map:remove($query-params, 'uri')"/>
963+
<xsl:with-param name="push-state" select="false()"/>
964+
</xsl:call-template>
965+
</xsl:otherwise>
966+
</xsl:choose>
911967
</xsl:if>
912968
</xsl:template>
913969

@@ -1032,11 +1088,24 @@ WHERE
10321088
<!-- proxied tab: $uri is the external target (?uri=…); local tab: $uri is the bare document URI (no query string) - matches data-uri / document-body/@about, so the cache key downstream stays consistent -->
10331089
<xsl:variable name="uri" select="if (map:contains($query-params, 'uri')) then xs:anyURI(map:get($query-params, 'uri')) else ac:absolute-path($href)" as="xs:anyURI"/>
10341090

1035-
<xsl:call-template name="ldh:DocumentNavigate">
1036-
<xsl:with-param name="uri" select="$uri"/>
1037-
<xsl:with-param name="query-params" select="map:remove($query-params, 'uri')"/>
1038-
<xsl:with-param name="container" select=".."/>
1039-
</xsl:call-template>
1091+
<xsl:choose>
1092+
<!-- pane already rendered for $uri and cache populated: pure CSS toggle, no fetch -->
1093+
<xsl:when test="ixsl:contains(ixsl:get(ixsl:window(), 'LinkedDataHub.contents'), '`' || $uri || '`')">
1094+
<xsl:call-template name="ldh:TabSwitch">
1095+
<xsl:with-param name="uri" select="$uri"/>
1096+
<xsl:with-param name="href" select="$href"/>
1097+
<xsl:with-param name="tab-li" select=".."/>
1098+
<xsl:with-param name="container" select=".."/>
1099+
</xsl:call-template>
1100+
</xsl:when>
1101+
<xsl:otherwise>
1102+
<xsl:call-template name="ldh:DocumentNavigate">
1103+
<xsl:with-param name="uri" select="$uri"/>
1104+
<xsl:with-param name="query-params" select="map:remove($query-params, 'uri')"/>
1105+
<xsl:with-param name="container" select=".."/>
1106+
</xsl:call-template>
1107+
</xsl:otherwise>
1108+
</xsl:choose>
10401109
</xsl:template>
10411110

10421111
<xsl:template match="ul[@id = 'tab-bar-list']/li/span[contains-token(@class, 'tab-close')]" mode="ixsl:onclick">
@@ -1055,16 +1124,27 @@ WHERE
10551124
<!-- remove the tab <li> from the DOM -->
10561125
<xsl:sequence select="ixsl:call($tab-li, 'remove', [])[current-date() lt xs:date('2000-01-01')]"/>
10571126

1058-
<!-- if the closed tab was active, navigate to the fallback's URI (ldh:RenderTab will activate after fetch) -->
1127+
<!-- if the closed tab was active, switch to the fallback's URI (ldh:TabSwitch if cached, otherwise ldh:DocumentNavigate -> RenderTab will activate after fetch) -->
10591128
<xsl:if test="$was-active and $fallback-li">
10601129
<xsl:variable name="fallback-href" select="xs:anyURI(resolve-uri($fallback-li/a/@href, ldh:base-uri(.)))" as="xs:anyURI"/>
10611130
<xsl:variable name="fallback-query-params" select="ldh:parse-query-params(substring-after($fallback-href, '?'))" as="map(xs:string, xs:string*)"/>
10621131
<xsl:variable name="fallback-uri" select="if (map:contains($fallback-query-params, 'uri')) then xs:anyURI(map:get($fallback-query-params, 'uri')) else ac:absolute-path($fallback-href)" as="xs:anyURI"/>
10631132

1064-
<xsl:call-template name="ldh:DocumentNavigate">
1065-
<xsl:with-param name="uri" select="$fallback-uri"/>
1066-
<xsl:with-param name="query-params" select="map:remove($fallback-query-params, 'uri')"/>
1067-
</xsl:call-template>
1133+
<xsl:choose>
1134+
<xsl:when test="ixsl:contains(ixsl:get(ixsl:window(), 'LinkedDataHub.contents'), '`' || $fallback-uri || '`')">
1135+
<xsl:call-template name="ldh:TabSwitch">
1136+
<xsl:with-param name="uri" select="$fallback-uri"/>
1137+
<xsl:with-param name="href" select="$fallback-href"/>
1138+
<xsl:with-param name="tab-li" select="$fallback-li"/>
1139+
</xsl:call-template>
1140+
</xsl:when>
1141+
<xsl:otherwise>
1142+
<xsl:call-template name="ldh:DocumentNavigate">
1143+
<xsl:with-param name="uri" select="$fallback-uri"/>
1144+
<xsl:with-param name="query-params" select="map:remove($fallback-query-params, 'uri')"/>
1145+
</xsl:call-template>
1146+
</xsl:otherwise>
1147+
</xsl:choose>
10681148
</xsl:if>
10691149

10701150
<!-- if only the base-uri tab is left, hide the whole tab-bar (mirror of ldh:AddTabNavBarListItem) -->

0 commit comments

Comments
 (0)