Bug #4843
closedjs:history.pushState() has no effect?
100%
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')]"/>
Updated by Martynas Jusevicius about 4 years ago
This could be relevant - my state object contained some XML nodes: https://stackoverflow.com/questions/50618225/uncaught-domexception-failed-to-execute-pushstate-on-history-function https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
Will check if removing them fixes the problem.
Updated by Michael Kay about 4 years ago
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]"/>
Updated by Martynas Jusevicius about 4 years ago
Using the open-source compiler.
I have double-checked and I don't think optimization is the cause. I've made a test-case: the [PUSH STATE]
button does not increment the history.length
but [PUSH STATE w/ JS]
does (it's printed to the console log):
https://namedgraph.github.io/saxon-js2-test/
Source code: https://github.com/namedgraph/saxon-js2-test/blob/gh-pages/client.xsl#L133
Updated by John Lumley about 4 years ago
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.
Updated by Martynas Jusevicius about 4 years ago
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
Updated by Norm Tovey-Walsh almost 4 years ago
- 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]"/>
Updated by Michael Kay almost 4 years ago
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.
Updated by Michael Kay almost 4 years ago
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.
Updated by Community Admin almost 4 years ago
- Applies to JS Branch 2 added
- Applies to JS Branch deleted (
2.0)
Updated by Norm Tovey-Walsh almost 4 years ago
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.
Updated by Norm Tovey-Walsh almost 4 years ago
- Status changed from In Progress to Resolved
Added note to change history for 2.1 docs.
Updated by Debbie Lockett almost 4 years ago
- Fix Committed on JS Branch 2 added
Updated by Debbie Lockett almost 4 years ago
- 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