Project

Profile

Help

Bug #1865

ixsl:prevent-default is not documented

Added by Michael Kay almost 3 years ago. Updated almost 3 years ago.

Status:
New
Priority:
Normal
Assignee:
Category:
-
Sprint/Milestone:
-
Start date:
2013-08-15
Due date:
% Done:

0%

Spent time:
-
Found in version:
1.1
Fixed in version:

Description

We support an attribute ixsl:prevent-default on the xsl:template element; its effect is to set event.preventDefault at the Javascript level, which causes the normal browser handling of events to be suppressed. It appears to be necessary to set this attribute when handling events on HTML forms controls, but the attribute appears to be undocumented.

History

#1 Updated by Michael Kay almost 3 years ago

Phil Fearon recalls:

Ah....yes, I do remember this was a rather thorny issue.

A number of HTML elements, including HTML forms controls have default
behaviours triggered by certain events, like onclick. If JavaScript
developers want to handle the event entirely themselves, they have to
call the preventDefault() method on the event object, but....as you
might suspect IE is different, for IE the custom JS event handler
function has to return false. Now, in Saxon-CE XSLT, If it weren't for
this IE difference one would only have to use something like (from
memory) ixsl:call(ixsl:event(), 'preventDefault').

At the time, I didn't know an equivalent call using ixsl that would
work for IE so I suggested to you the ixsl:preserve-default parameter
because I wanted the samples to be able to function properly under IE.
Your reaction was that this kind of low-level attribute was
undesirable, so I think the plan was to provide some top-level
declarative way of specifying which elements should have default
behaviours disabled. As there were other event-handling issues such as
iOS touch events conflicting with click events I think I decided to
shelve the issue until we could address all these low-level issues
together.

In the mean time, as a working proof of concept, I had coded the
ixsl:prevent-default solution and used the samples as a test case,
unfortunately I think I must have failed to remove the
ixsl:prevent-default attribute code and revert the samples (I'm a bit
hazy on what samples were affected) to their original form. So, the
reason why this attribute is undocumented is because it was not
intended to be used.

I now know that there is a way (I have some sample XSLT code
somewhere, but haven't got the details to hand) of acheiving the same
effect as ixsl:prevent-default (it was easiest to call a custom global
javascript function I think). So it may be preferred to leave
ixsl:prevent-default undocumented and recommend the alternative
workaround.

So far as defaulting certain element events to always have
default-behaviour disabled (if they have matching templates), I think
the only reason we didn't go this way is that I didn't know exactly
what element events to include and whether there were significant
differences between browsers. I think focusing just on forms controls
as suggested would have been easier.

Tomorrow (it's getting late) I will look for the sample code that
avoids the use of ixsl:prevent-default and forward it as soon as I
find it.

Regards

Phil

#2 Updated by Michael Kay almost 3 years ago

More from Phil:

Mike, here's the code that I used as a workaround for the
ixsl:prevent-default attribute:

XSLT
--------
:
<xsl:template match="*" mode="ixsl:onkeydown">
<xsl:variable name="activeElement" select="ixsl:get(ixsl:page(),
'activeElement')"/>
<xsl:variable name="activeElementName" select="name($activeElement)"/>
<xsl:variable name="activeElementId" select="$activeElement/@id"/>
<xsl:variable name="isCtrlKey"
select="ixsl:get(ixsl:event(),'ctrlKey')" as="xs:boolean"/>
<xsl:variable name="keycode" select="ixsl:get(ixsl:event(),'keyCode')"
as="xs:double"/>

<xsl:choose>
<xsl:when test="$keycode = 13">

<xsl:value-of select="js:preventDefault(ixsl:event())"/> <<<

</xsl:when>
...

JavaScript:
---------------

var preventDefault = function (inEvent) {
if (typeof inEvent.preventDefault == 'function') {
inEvent.preventDefault();
} else if (inEvent.returnValue) {
inEvent.returnValue = false;
}
}

There's another thing to note about the undocumented
ixsl:prevent-default property (yes, I'm afraid it get's worse), I
added a ixsl:event-property attribute to control the scope of a
template match to a set of values for a defined event property, as in
the following example:

<xsl:template match="p[@id eq 'xmlurl']" mode="ixsl:onkeydown"
ixsl:event-property="keyCode 13" ixsl:prevent-default="yes">
<xsl:result-document href="#xbody">
<p>Requesting document: <xsl:value-of select="."/> ...</p>
</xsl:result-document>
<xsl:value-of select="js:addFileFromURL(normalize-space(.))"/>
</xsl:template>

In the above sample this attribute was required to avoid
preventDefault being applied for all keydown events, when we only
wanted it applied for when the user pressed the <enter> key. This is a
common use case as it is useful to allow the user to tab between
controls and to accept values by pressing <enter> and also to use
short-cut keys - making the user experience feel more like an
application. The ixsl:event-property attribute allows that granularity
but feels awkward for a number of reasons - probably the reason why
this is undocumented also.

Ideally, there would be a high-level way to bind specific key down
events to templates, but I don't have any proposals for how this
should be done.

Summary
-------------

I would probably recommend to users to use the js:preventDefault
function call included above as this works cross-browser and should
provide all the control they need.

Also available in: Atom PDF