Feature #5142
openNew <ixsl:add-listener> instruction
0%
Description
Hi. I think there is a generic use case that shows up especially when integrating Saxon-JS with JS libraries. For example, with Google Maps one needs to use this to add an onlick
listener for a marker:
marker.addListener("click", () => {
infowindow.open({
anchor: marker,
map,
shouldFocus: false,
});
});
It requires a JS callback function, which is anonymous ()
in this case. I would like to use IXSL to handle the marker onclick
event instead.
The native IXSL way would be:
<xsl:template match="a[@class = 'marker']" mode="ixsl:onclick">
but the problem is that the DOM generated by Google Maps, including marker IDs or class names, cannot be relied upon. So the match pattern approach does not really work.
I propose a second, generalized mechanism to handle events using a new extension instruction <ixsl:add-listener>
. It could be used like this:
<ixsl:add-listener name="click" object="$marker">
<xsl:call-template name="onMarkerClick"/>
</ixsl:add-listener>
<xsl:template name="onMarkerClick" mode="ixsl:onclick">
<xsl:variable name="event" select="ixsl:event()"/> <!-- MapMouseEvent -->
<xsl:variable name="lat-lng" select="ixsl:get(ixsl:event(), 'latLng')"/>
...
</xsl:template>
If the native match
/mode
/ approach can be used instead, one could replace the name="onMarkerClick"
with mode="ixsl:onclick"
and the same template body should still work.
The <ixsl:add-listener>
call would translate to this pseudo-JS:
marker.addListener('click', (event) => { SaxonJS.callTemplate('onMarkerClick', event); });
Updated by Martynas Jusevicius about 3 years ago
I realized just now that Google Maps' google.maps.MVCObject.addListener()
is not the same as EventTarget.addEventListener()
, so maybe this approach is not generic after all...
Updated by Martynas Jusevicius about 3 years ago
So I got the following working, but I cannot see how it could be generalized since addListener()
is GMaps-specific :/
If the addGoogleMapsListener
could also be implemented in IXSL, it could at leaset be used to create a native GMaps API wrapper for Saxon-JS.
var addGoogleMapsListener = function(object, type, options, templateName, params)
{
object.addListener(type,
function (event)
{
SaxonJS.transform({
"stylesheetLocation": contextUri + "static/com/atomgraph/linkeddatahub/xsl/client.xsl.sef.json",
"initialTemplate": templateName,
"templateParams": Object.assign(params, { "event": event })
});
},
options);
};
<xsl:variable name="params" select="map{ 'url': string(@rdf:about) }" as="map(xs:string, xs:string)"/>
<xsl:variable name="params-obj" select="ixsl:call(ixsl:window(), 'JSON.parse', [ $params => serialize(map { 'method': 'json' }) ])"/>
<xsl:sequence select="ixsl:call(ixsl:window(), 'addGoogleMapsListener', [ $marker, 'click', (), 'onInfoWindowLoad', $params-obj ])[current-date() lt xs:date('2000-01-01')]"/>
<xsl:template name="onInfoWindowLoad">
<xsl:param name="event"/>
<xsl:param name="url" as="xs:string"/>
<xsl:sequence select="ixsl:call(ixsl:window(), 'alert', [ 'onInfoWindowLoad' ])"/>
</xsl:template>
Updated by Martynas Jusevicius about 3 years ago
onInfoWindowLoad
in all the examples should have been onMarkerClick
...
Updated by Norm Tovey-Walsh about 2 years ago
- Sprint/Milestone set to SaxonJS 3.0
- Fix Committed on JS Branch deleted (
2)
Updated by Martynas Jusevicius about 2 years ago
I think now I have a better idea of what I wanted to describe here. Not an instruction, but an IXSL function ixsl:template-call
that returns a JS function that calls an XSL template.
The body of ixsl:template-call
would be equivalent to:
function(stylesheetLocation, initialTemplate, stylesheetParams, templateParams, event)
{
// event is bound as ixsl:event() here
SaxonJS.transform({
"stylesheetLocation": stylesheetLocation,
"initialTemplate": initialTemplate,
"stylesheetParams": stylesheetParams,
"templateParams": templateParams
});
};
That would allow using templates for JS listener callbacks. Registration:
<ixsl:set-property name="map" select="$map" object="$template-params"/>
<xsl:variable name="map-marker-onclick" select="ixsl:template-call(static-base-uri(), 'onMapMarkerClick', $stylesheet-params, $template-params)"/>
<xsl:sequence select="ixsl:call($map, 'on', [ 'click', $map-marker-onclick ])[current-date() lt xs:date('2000-01-01')]"/>
Template body:
<xsl:template name="onMapMarkerClick">
<xsl:param name="event" select="ixsl:event()"/>
<xsl:param name="map"/>
...
</xsl:template>
Updated by Martynas Jusevicius about 2 years ago
This is how I use the JS function currently (called ixslTemplateListener
):
<xsl:variable name="map-marker-onclick" select="ixsl:call(ixsl:get(ixsl:window(), 'ixslTemplateListener'), 'bind', [ (), static-base-uri(), 'onMapMarkerClick', $stylesheet-params, $template-params ])"/>
<xsl:sequence select="ixsl:call($map, 'on', [ 'click', $map-marker-onclick ])[current-date() lt xs:date('2000-01-01')]"/>
Please register to edit this issue
Also available in: Atom PDF Tracking page