Bug #4843
closed
js:history.pushState() has no effect?
Fix Committed on JS Branch:
2
Description
Using Saxon-JS to call history.pushState()
does not seem to have any effect - window.history.length
does not increment and window.history.state
does not change:
<xsl:variable name="js-statement" as="element()">
<root statement="{{ 'state': 'smth' }}"/>
</xsl:variable>
<xsl:variable name="json-state" select="ixsl:eval(string($js-statement/@statement))"/>
<ixsl:sequence select="js:history.pushState($json-state, '')[current-date() lt xs:date('2000-01-01')]"/>
I've also tried ixsl:call(ixsl:get(ixsl:window(), 'history'), 'pushState', [ $json-state, '' ])
, with same result.
Evaluating JS does increment the window.history.length
and change the window.history.state
:
<xsl:variable name="js-statement" as="element()">
<root statement="history.pushState({{ 'state': 'smth' }}, '')"/>
</xsl:variable>
<xsl:sequence select="ixsl:eval(string($js-statement/@statement))[current-date() lt xs:date('2000-01-01')]"/>
Which compiler are you using? Are you sure that the call on pushState()
is actually being executed, and not optimised away? The always-false predicate here looks suspicious; although its value isn't statically known, it IS statically known that it doesn't depend on the focus, so the expression could get rewritten as
<xsl:if test="current-date() lt xs:date('2000-01-01'" select="ixsl:eval(string($js-statement/@statement))[)]"/>
If you want to be sure that the ixsl:eval() is evaluated for its side-effects, but the result is discarded, then a focus-dependent predicate might be better:
<xsl:sequence select="ixsl:eval(string($js-statement/@statement))[9999999999]"/>
The reason the [PUSH STATE] doesn't increment the history state length is from a typo I fear:
<xsl:variable name="json-state" select="ixsl:eval(string($js-statement/@statement))"/>
<ixsl:sequence select="js:history.pushState($json-state, '')[9999999999]"/>
and whilst some ixsl:
instructions are defined, at least in the XX compiler, and it appears also in the XJ compiler, the namespace http://saxonica.com/ns/interactiveXSLT
isn't 'reserved'. So <ixsl:sequence.../>
is a perfectly legitimate result tree element, whose @select
has no special processing. Looking at the SEF confirms this. (I wonder whether there is a case for at least warning in such circumstances, especially when there is a local-name alias to an xsl:
instruction.)
This doesn't help the overall issue, which, seemingly involving ixsl:schedule-action
with http requests, is not an area I've tackled at all.
My bad! I fixed the typo, but now I get
SaxonJS2.rt.js:892 Uncaught TypeError: Illegal invocation
Uncaught TypeError: Illegal invocation
at l (SaxonJS2.rt.js:892)
at Object.call (SaxonJS2.rt.js:893)
at d (SaxonJS2.rt.js:899)
at a (SaxonJS2.rt.js:886)
at SaxonJS2.rt.js:642
at SaxonJS2.rt.js:664
at b (SaxonJS2.rt.js:375)
at SaxonJS2.rt.js:375
at Array.forEach (<anonymous>)
at SaxonJS2.rt.js:375
at SaxonJS2.rt.js:401
at SaxonJS2.rt.js:401
at Object.push (SaxonJS2.rt.js:404)
at d.sj (SaxonJS2.rt.js:918)
at SaxonJS2.rt.js:915
at t.sa (SaxonJS2.rt.js:238)
at d.Uc (SaxonJS2.rt.js:915)
at HTMLDocument.d (SaxonJS2.rt.js:937)
l @ SaxonJS2.rt.js:892
call @ SaxonJS2.rt.js:893
d @ SaxonJS2.rt.js:899
a @ SaxonJS2.rt.js:886
(anonymous) @ SaxonJS2.rt.js:642
(anonymous) @ SaxonJS2.rt.js:664
b @ SaxonJS2.rt.js:375
(anonymous) @ SaxonJS2.rt.js:375
(anonymous) @ SaxonJS2.rt.js:375
(anonymous) @ SaxonJS2.rt.js:401
(anonymous) @ SaxonJS2.rt.js:401
push @ SaxonJS2.rt.js:404
sj @ SaxonJS2.rt.js:918
(anonymous) @ SaxonJS2.rt.js:915
sa @ SaxonJS2.rt.js:238
Uc @ SaxonJS2.rt.js:915
d @ SaxonJS2.rt.js:937
- Status changed from New to In Progress
- Assignee set to Norm Tovey-Walsh
There is a bug that prevents js:history.pushState()
from working. In the meantime, you can work around the bug by isolating the history object and executing the call to pushState
against that object explicitly:
<xsl:variable name="json-state" select="ixsl:eval(string($js-statement/@statement))"/>
<xsl:variable name="history" select="ixsl:get(ixsl:window(), 'history')"/>
<xsl:sequence select="ixsl:call($history, 'pushState', [ $json-state, ''])[9999]"/>
The XJ compiler optimises the expression EXPR[NN]
to ()
if NN is a numeric literal other than a whole number in the range 1 to 2^31. That's because position()
will never be equal to any numeric value other than a whole number in that range.
Arguably it should avoid this optimisation if EXPR is known to have side-effects. However, the optimiser isn't very systematic about checking whether subexpressions have side-effects, even in cases where we have enough information to work it out.
So how DO you discard the results of an expression that you want to be evaluated for its side effects?
One way is to do
<xsl:param name="dummySubscript" select="-1"/>
<xsl:sequence select="EXPR[$dummySubscript]"/>
But even that isn't 100% reliable: with JIT compilation we sometimes compile code after the values of parameters are known, so this is just the same as using a literal subscript. However, JIT compilation doesn't happen when generating a SEF.
I introduced saxon:do for this purpose, but I'm not sure it works with Saxon-JS.
- Applies to JS Branch 2 added
- Applies to JS Branch deleted (
2.0)
In addition to the previously mentioned workaround, the bug has also been fixed. Basically, methods on subordinate objects (like history) weren't being handled correctly.
- Status changed from In Progress to Resolved
Added note to change history for 2.1 docs.
- Fix Committed on JS Branch 2 added
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in JS Release set to Saxon-JS 2.1
Bug fix applied in the Saxon-JS 2.1 maintenance release.
Please register to edit this issue
Also available in: Atom
PDF
Tracking page