feat: identify focus and blur invocations with a command object - #25747
totally-not-ai[bot] wants to merge 1 commit into
Conversation
Focusable.focus() and blur() schedule their JavaScript through the new Element.executeJs(JsCommand), so the pending invocation carries a typed FocusCommand or BlurCommand. A driver of the client side that cannot run JavaScript recognizes the invocation by the type of its command instead of by matching the text of the generated expression, which is the framework's script wrapped by executeJs. The expression and the parameters sent to a browser are unchanged. Part of #25734
Type of changePrototype, kept as a draft on purpose: it is here to make the shape How to testNo integration test is added: the expressions and parameters that reach API changes
What a browserless driver gets out of it
Server-initiated focus and blur mark themselves for the client so the Relation to the alternatives in #25734This is ask 3 of that issue, but as a value object rather than a A Open questions
@Artur- @mcollovati — the queue side of #25734, small enough to judge from |
|
The invoker shape from #10759, as an alternative to this one on the same feature: #25749. It replaces the command records with a |
|
|
Dropped in favour of the invoker shape, which is now the single PR: #25749. It carries the queue-side identification this PR was about, plus the build and client sides that make a call need no |



Part of #25734
Related to vaadin/browserless-test#221
missing API · flow-server · external drivers of the client side, such
as browserless test frameworks
Background — the pending JavaScript queue. Server-initiated client
work is scheduled as
executeJsand queued per UI until the end of arequest, when
dumpPendingJavaScriptInvocations()hands the batch to theUIDL writer. A queued invocation carries an expression string and its
parameters, and nothing else.
A driver that plays the browser without running JavaScript can therefore
only recognise the invocations it should act on by substring-matching
generated script — today
expression.contains("this.focus("), against astring that is the framework's script wrapped by
executeJs. Thisprototype lets an invocation carry a typed description of what it does,
so focus and blur are identified by type instead. What a browser receives
is unchanged.
Risks:
JsCommand,FocusCommand,BlurCommand,Element.executeJs(JsCommand), and onJavaScriptInvocationa newconstructor plus
getCommand().Elementsubclass that overridesexecuteJs(String, Object...)no longer intercepts the script offocus()andblur(), which now take the command overload.getCommand()returns null for plain JavaScript,against the sentinel-over-null convention. A sentinel would allocate
per
executeJs, andcase null, defaultis needed regardless becauseJsCommandcannot be sealed across features.invocation.
protocol, threading or performance change.
Context.
Focusablebuilt its script inline, so the onlyserver-side trace of a focus was the text of that script. The
trigger/action model already describes client-side work as Java values
(
Action#toJs); this is the same idea for one-shotexecuteJs.JsCommand(new) is a typed, immutable description of a client-sideoperation together with the expression and parameters that perform it.
Element.executeJs(JsCommand)(new) schedules the command's script andkeeps the command on the queued invocation, where
JavaScriptInvocation.getCommand()returns it. The command neverleaves the server.
Focusable.focus(FocusOption...)andblur()scheduleFocusCommandand
BlurCommand; the scripts move into those records unchanged, andthe options travel as
FocusOptionvalues rather than only as JSON.Focusableonly.Page.executeJs,WebStorage,Page.fetchCurrentURL,HistoryandscrollIntoVieware thecandidates next in line and need no further API to adopt it.