SVG Tiny 1.2 - 20060721

15 Scripting

Contents

15.1 Specifying the scripting language

15.1.1 Specifying the default scripting language

The 'contentScriptType' attribute on the 'svg' element specifies the default scripting language for the given document fragment.

15.1.2 Local declaration of a scripting language

It is also possible to specify the scripting language for each individual script or handler elements by specifying a type attribute on the script and handler elements.

15.2 The 'script' element

A script element may either contain or point to executable content (e.g., ECMAScript [ECMAScript] or Java [JAVA] JAR file). Executable content can come either in the form of a script (textual code) or in the form of compiled code. If the code is textual, it can either be placed inline in the script element (as character data) or as an external resource, referenced through xlink:href attribute. Compiled code must be an external resource. If a script element has both an xlink:href attribute and child character data, the executable content for the script is retrieved from the IRI of the xlink:href attribute, and the child content is not added to the scripting context.

When the executable content is inlined, it must be processed as described in Processing inline executable content.

Some scripting languages such as ECMAScript have a notion of a "global scope" or a "global object" such that a single global object must be associated with the document (unique for each uDOM Document node). This object is shared by all elements contained in that document. Thus, an ECMAScript function defined within any script element must be in the "global" scope of the entire document to which the script belongs. The global object must have all the methods and attributes from the SVGGlobal interface. It must be made available from an SVGDocument through the global attribute. Event listeners attached through event attributes and handler elements are also evaluated using the global scope of the document in which they are defined.

For compiled languages (such as Java) that don't have a notion of "global scope", each script element, in effect, provides a separate scope object. This scope object must perform an initialization as described in the uDOM chapter and serves as event listener factory for the handler element.

Any scripting logic associated with a given script element is executed at most once. Script execution happens just before the load event occurs for the given script element. Removing or altering script elements after script execution has taken place has no effect. Inserting a script element into the DOM tree will cause it to execute.

The processing model for scripting in SVG is that, before any fragment of script logic executes, the full document model must be fully updated, including any required positioning and sizing computations.

Exact details on how this element works depend on the executable content's type. SVG Tiny 1.2 does not require support for any particular programming language. However, SVG defines the behavior for two specific script types in the case where an implementation supports it:

application/ecmascript

This type of executable content must be source code for the ECMAScript programming language. This code must be executed in the context of this element's owner document's global scope as explained above.

SVG implementations that load external resources through protocols such as HTTP that support content coding must accept external script files that have been encoded using gzip compression (flagged using "Content-Encoding: gzip" for HTTP).

application/java-archive

This type of executable content must be an external resource that contains a Java JAR archive. The manifest file in the JAR archive must have an entry named SVG-Handler-Class. The entry's value must be a fully-qualified Java class name for a class contained in this archive. The user agent must instantiate the class from the JAR file and cast it to the EventListenerInitializer2 interface. Then the initializeEventListeners method must be called with the script element object itself as a parameter. If a class listed in SVG-Handler-Class does not implement EventListenerInitializer2, it is an error.

Note that the user agent may reuse classes loaded from the same URL, so the code must not assume that every script element or every document will create its own separate class object. Thus, one cannot assume, for instance, that static fields in the class are private to a document.

Implementations must also accept the script type "text/ecmascript" for backwards compatibility with SVG 1.1. However, this type is deprecated and should not be used by content authors.

Other language bindings are encouraged to adopt a similar approach to either of the two described above.

Example 18_01 defines a function circle_click which is called when the 'circle' element is being clicked. The drawing below on the left is the initial image. The drawing below on the right shows the result after clicking on the circle. The example uses the handler element which is described further down in this chapter.

Note that this example demonstrates the use of the click event for explanatory purposes. The example presupposes the presence of an input device with the same behavioral characteristics as a mouse, which will not always be the case. To support the widest range of users, the DOMActivate event attribute should be used instead of the click event attribute.

Example: 18_01.svg
<?xml version="1.0"?>
<svg width="6cm" height="5cm" viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
     xmlns:ev="http://www.w3.org/2001/xml-events">
  <desc>Example: invoke an ECMAScript function from an click event
  </desc>
  <!-- ECMAScript to change the radius with each click -->
  <script type="application/ecmascript"> <![CDATA[
    function circle_click(evt) {
      var circle = evt.target;
      var currentRadius = circle.getFloatTrait("r");
      if (currentRadius == 100)
        circle.setFloatTrait("r", currentRadius*2);
      else
        circle.setFloatTrait("r", currentRadius*0.5);
    }
  ]]> </script>
  
  <!-- Outline the drawing area with a blue line -->
  <rect x="1" y="1" width="598" height="498" fill="none" stroke="blue"/>
  <!-- Act on each click event -->
  <circle cx="300" cy="225" r="100" fill="red">
  <handler type="application/ecmascript" ev:event="click"> 
        circle_click(evt);
    </handler>
  </circle>  
  
  <text x="300" y="480" font-family="Verdana" font-size="35" text-anchor="middle">
    Click on circle to change its size
  </text>
</svg>
    
Example 18_01 - invoke an ECMAScript function from an onclick event - before first click     Example 18_01 - invoke an ECMAScript function from an onclick event - after first click

Here the same script is invoked, this time in an external file.

Example: 18_02.svg
<?xml version="1.0"?>
<svg width="6cm" height="5cm" viewBox="0 0 600 500"
     xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
     xmlns:ev="http://www.w3.org/2001/xml-events">
  <desc>Example: invoke an external ECMAScript function from an click event
  </desc>
  <!-- ECMAScript to change the radius with each click -->
  <script type="application/ecmascript" xlink:href="sample.es"/> 
  
  <!-- Outline the drawing area with a blue line -->
  <rect x="1" y="1" width="598" height="498" fill="none" stroke="blue"/>
  <!-- Act on each click event -->
  <circle cx="300" cy="225" r="100" fill="red">
  <handler type="application/ecmascript" ev:event="click"> 
        circle_click(evt);
    </handler>
  </circle>  
  
  <text x="300" y="480" font-family="Verdana" font-size="35" text-anchor="middle">
    Click on circle to change its size
  </text>
</svg>
    
Schema: script

    <define name='script'>
      <element name='script'>
        <ref name='script.AT'/>
        <ref name='script.ATCM'/>
      </element>
    </define>

    <define name='script.AT' combine='interleave'>
      <ref name='svg.CorePreserve.attr'/>
      <ref name='svg.External.attr'/>
      <ref name='svg.ContentType.attr'/>
    </define>

    <define name='script.ATCM'>
      <interleave>
        <choice>
          <group>
            <ref name='svg.XLinkRequired.attr'/>
          </group>
          <text/>
        </choice>
        <ref name='svg.Desc.group'/>
      </interleave>
    </define>
      

Attribute definitions:

type = "content-type"
Identifies the programming language for the given script element. The value content-type specifies a media type, per per Multipurpose Internet Mail Extensions (MIME) PartTwo [RFC2046]. If a 'type' is not provided, the value of 'contentScriptType' on the svg element shall be used, which in turn defaults to "application/ecmascript" [RFC4329].

Animatable: no.
xlink:href = "<XMLRI>"
An IRI reference to an external resource containing the script code.

Animatable: no.


15.3 XML Events

XML Events is an XML syntax for integrating event listeners and handlers with DOM 2 and DOM 3 Event interfaces. Declarative event handling in SVG 1.1 was hardwired into the language, in that the developer was required to embed the event handler in the element syntax (e.g. an element with an onclick attribute). SVG Tiny 1.2 does not support the event attributes (onload, onclick, onactivate, etc.). Instead SVG Tiny 1.2 uses XML Events to provide the ability to specify the event listener separately from the graphical content.

SVG Tiny 1.2 uses XML Events, available on the listener and handler elements.

The list of events supported by SVG Tiny 1.2 is given in the Interactivity chapter.

There are two ways to place a handler in SVG Tiny 1.2 content. The first method is most suitable for simple cases:

Example: simplehandler.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
       xmlns:ev="http://www.w3.org/2001/xml-events">
       
  <rect x="10" y="20" width="10" height="20" fill="red">
    <handler type="application/ecmascript" ev:event="click">
      var theRect = evt.target;
      var width = theRect.getFloatTrait("width");
      theRect.setFloatTrait("width", (width+10));
    </handler>
  </rect>
    
</svg>
    

In this method the handler element is a child element of the observer. For instance one can place a handler as a child of a rect element, which becomes the observer. This causes the handler element to be invoked whenever the event that it is interested in (e.g.: "click") occurs on the rect.

The following is an example of an SVG document using XML Events where the handler element can be reused on several objects. The listener element from XML Events is used to specify the observer and handler for a particular event.

Example: handler.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
     xmlns:ev="http://www.w3.org/2001/xml-events">
     
  <desc>An example of the handler element.</desc>

  <rect xml:id="theRect1" x="10" y="20" width="10" height="20" fill="red"/>
  <rect xml:id="theRect2" x="10" y="40" width="10" height="20" fill="green"/>

  <ev:listener event="click" observer="theRect1" handler="#theClickHandler"/>
  <ev:listener event="click" observer="theRect2" handler="#theClickHandler"/>
                 
  <handler xml:id="theClickHandler" type="application/ecmascript">
    var theRect = evt.target;
    var width = theRect.getFloatTrait("width");
    theRect.setFloatTrait("width", (width+10));
  </handler>

</svg>
    

In the above example, the ev:listener element registers that the theClickHandler element should be invoked whenever a click event happens on "theRect1" or "theRect2".

The combination of the XML Events syntax and the new handler element allows event handling to be more easily processed in a compiled language. Below is an example of an event handler using the Java language:

Example: javahandler.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny"
     xmlns:ev="http://www.w3.org/2001/xml-events"
     xmlns:foo="http://www.example.com/foo"
      xmlns:xlink="http://www.w3.org/1999/xlink">
     
  <desc>Example of a Java handler</desc>

  <rect xml:id="theRect" x="10" y="20" width="200" height="300" fill="red"/>

  <!-- reference a jar containing an EventListenerInitializer2 object -->
  <script type="application/java-archive" xml:id="init" xlink:href="http://example.com/theJar.jar"/>
  
  <!-- register a listener for a theRect.click event -->
  <ev:listener event="click" observer="theRect" handler="#theClickHandler" />

  <handler xml:id="theClickHandler" type="application/java-archive" xlink:href="#init" foo:offset="10"/>      

</svg>
    

In this case, the handler element specifies a reference to the script element that specifies the location of compiled code that conforms to the EventListenerInitializer2 interface. The user agent invokes the createEventListener method within the targeted interface.

In this case, the TheEventListenerInitializer2 referenced by the SVG-Handler-Class entry of the theJar.jar manifest has the following definition:

TheEventListenerInitializer2
package com.example;

import org.w3c.svg.EventListenerInitializer2;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;

public class TheEventListenerInitializer2 implements EventListenerInitializer2 {

   Document document;

    public void initializeEventListeners(Element scriptElement) {
        document = scriptElement.getOwnerDocument();
    }

    public EventListener createEventListener(final Element handlerElement) {
        return new EventListener() {
            public void handleEvent(Event event) {
                Element theRect = document.getElementById("theRect");
                float width = Float.parseFloat(theRect.getAttributeNS(null, "width"));
                float offset = Float.parseFloat(handlerElement.getAttributeNS("http://www.example.com/foo", "offset");
                theRect.setAttributeNS(null, "width", "" + (width + offset));
            }
        };
    }
}

The EventListenerInitializer2 interface is currently defined in the SVG package. Future specifications may move this package though it is guaranteed to always be available in the SVG package.

15.4 The listener element

The 'listener' element from XML Events [XML-EVENTS] must be supported. The definition for the 'listener' element is provided in [XML-EVENTS]. Any additional restrictions from this specification must also apply.

Whenever the attributes of a listener element are modified, the corresponding event listener is removed and a new one is created. When listener elements are added or removed, the event listener is added or removed respectively.

Please note that the 'listener' element must be specified in the XML Events namespace, and that an element in the SVG namespace with 'listener' as its local name must not be understood as being the element described in this chapter. Furthermore, the XML Events attributes that are available on other elements only when they are in the XML Events namespace, are only available on this element when they are in no namespace.

Schema: listener

    <define name='listener'>
      <element name='listener'>
        <ref name='listener.AT'/>
        <ref name='listener.CM'/>
      </element>
    </define>

    <define name='listener.AT' combine='interleave'>
      <ref name='svg.Core.attr'/>
      <optional>
        <attribute name='event' svg:animatable='false' svg:inheritable='false'>
          <ref name='XML-Name.datatype'/>
        </attribute>
      </optional>
      <optional>
        <attribute name='phase' svg:animatable='false' svg:inheritable='false'>
          <choice>
            <value>default</value>
            <value>capture</value>
          </choice>
        </attribute>
      </optional>
      <optional>
        <attribute name='propagate' svg:animatable='false' svg:inheritable='false'>
          <choice>
            <value>continue</value>
            <value>stop</value>
          </choice>
        </attribute>
      </optional>
      <optional>
        <attribute name='defaultAction' svg:animatable='false' svg:inheritable='false'>
          <choice>
            <value>perform</value>
            <value>cancel</value>
          </choice>
        </attribute>
      </optional>
      <optional>
        <attribute name='observer' svg:animatable='false' svg:inheritable='false'>
          <ref name='IDREF.datatype'/>
        </attribute>
      </optional>
      <optional>
        <attribute name='target' svg:animatable='false' svg:inheritable='false'>
          <ref name='IDREF.datatype'/>
        </attribute>
      </optional>
      <optional>
        <attribute name='handler' svg:animatable='false' svg:inheritable='false'>
          <ref name='IRI.datatype'/>
        </attribute>
      </optional>
    </define>


    <define name='listener.CM'>
      <empty/>
    </define>
      

Attribute definitions:

event = 'Event Identifier'
The 'event' attribute must be a valid SVG Tiny 1.2 'Event Identifier' as defined in the list of supported events..

Animatable: no.
observer = "<IDREF>"
The 'observer' attribute is defined in XML Events. This attribute is an IDREF as defined in XML Events. Note that if the 'observer' attribute is not present, the observer is the parent of the 'listener' element.

Animatable: no.
target = "<IDREF>"
The 'target' attribute is defined in XML Events. This attribute is an IDREF as defined in XML Events.

Animatable: no.
handler = "<XMLRI>"
The 'handler' attribute is defined in XML Events. This attribute is an IRI reference as defined in XML Events. Restrictions specified in this chapter as to which IRIs are acceptable must be a enforced.

Animatable: no.
phase = 'default'
The 'phase' attribute is defined in XML Events. Support for the capture phase is not required in SVG Tiny 1.2, implementations that do not support it must process this attribute as if it had not been specified.

Animatable: no.
propagate = 'stop'|'continue'
The 'propagate' attribute is defined in XML Events.

Animatable: no.
defaultAction = 'cancel'|'perform'
The 'defaultAction' attribute is defined in XML Events.

Animatable: no.

15.5 The handler element

The handler element is similar to the script element: its contents, either included inline or referenced, are code that is to be executed by the scripting engine(s) used by user agent.

However, where the script element executes its contents when it is loaded, the handler element must only execute its contents in response to an event. This means that SVG Tiny 1.2 uses handler to get the functionality equivalent to that provided by SVG Full event attributes.

When the executable content is inlined, it must be processed as described in Processing inline executable content.

For example, consider the following SVG 1.1 document:

Example: nohandler.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <rect id="theRect" x="10" y="20" width="200" height="300" fill="red"
        onclick="evt.target.width.baseVal.value += 10"/>
</svg>
    

The above example must be rewritten to use the handler element and XML Events (described below) as shown:

Example: handler2.svg
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.2"
     xmlns:ev="http://www.w3.org/2001/xml-events">
  <desc>handler element example</desc>
  <rect xml:id="theRect" x="10" y="20" width="200" height="300" fill="red">

    <handler type="application/ecmascript" ev:event="click">
        var theRect = evt.target;
        var width = theRect.getFloatTrait("width");
        theRect.setFloatTrait("width", (width+10));
    </handler>

  </rect>

</svg> 
    

Whenever the type or ev:event attributes of a handler element are modified, the corresponding event listener is removed and a new one is created. When the xlink:href attribute is modified or the content of the handler element is modified, the existing event listener is preserved, but the user agent must execute the updated handler logic. When handler elements are added or removed, the corresponding event listener is added or removed respectively.

In ECMAScript, the contents of the handler element behave as if they are the contents of a new Function object, created as shown:

function(evt) {

    //contents of handler

}
In ECMAScript, the element with which the event listener is registered ( the observer ) is pushed into the scope chain and is bound to the this keyword, as shown:
function(evt) {

    this.setFloatTrait( 'x', 10 );

}

Other interpreted languages should behave in a similar manner.

The 'evt' parameter shown above is an Event object corresponding to the event that has triggered the handler. An 'event' variable can be used instead of 'evt' ('event' is an alias to 'evt').

Schema: handler

    <define name='handler'>
      <element name='handler'>
        <ref name='handler.AT'/>
        <ref name='handler.ATCM'/>
      </element>
    </define>

    <define name='handler.AT' combine='interleave'>
      <ref name='svg.CorePreserve.attr'/>
      <ref name='svg.External.attr'/>
      <optional>
        <attribute name='ev:event' svg:animatable='false' svg:inheritable='false'>
          <ref name='XML-Name.datatype'/>
        </attribute>
      </optional>
      <ref name='svg.ContentType.attr'/>
    </define>

    <define name='handler.ATCM'>
      <interleave>
        <choice>
          <group>
            <ref name='svg.XLinkRequired.attr'/>
          </group>
          <text/>
        </choice>
        <ref name='svg.Desc.group'/>
      </interleave>
    </define>
      

Attribute definitions:

type = "content-type"
Identifies the language used for the handler element. The value specifies a media type, per RFC2045. If a 'type' is not provided, the value of 'contentScriptType' on the 'svg' element shall be used.

Animatable: no.
xlink:href = "<XMLRI>"
If this attribute is present, then the script content of the handler element must be loaded from this resource and what content the handler element may have must not be executable.

Animatable: no.
ev:event = "<string>"
The name of the event to handle. This attribute is in the XML Events namespace. See event list for a list of all supported events and [XML-Events] for the definition of the ev:event attribute.

Animatable: no.

For compiled languages, the xlink:href attribute must reference a script element that itself references a JAR archive holding a manifest with an SVG-Handler-Class entry pointing to an EventListenerInitializer2 implementation.

15.5.1 Parameters to handler elements

In many situations, the script author uses the handler as a template for calling other functions, using the content of the handler element to pass parameters. However, for compiled languages the handler element does not have any executable content.

In this case, the author should embed the parameters into the handler as custom content under the form of element children in a foreign namespace, or attributes on the handler element also in foreign namespaces.

Below is an example of using parameters on the handler element:

Example: handlerparam.svg
<svg xmlns="http://www.w3.org/2000/svg" version="1.2"
     xmlns:ev="http://www.w3.org/2001/xml-events"
     xmlns:foo="http://www.example.com/foo"
   xmlns:xlink="http://www.w3.org/1999/xlink">
  <desc>An example of parameters on the handler element.</desc>

  <rect xml:id="theRect" x="10" y="20" width="200" height="300" fill="red"/>               

  <!-- reference a jar containing an EventListenerInitializer2 object -->
  <script type="application/java-archive" xml:id="init" xlink:href="http://example.com/theJar.jar"/>

  <!-- register a listener for a theRect.click event -->
  <ev:listener event="click" observer="theRect" handler="#theClickHandler" />

  <handler xml:id="theClickHandler" type="application/java-archive" xlink:href="#init">
      <foo:offset value="10"/>
      <foo:person>
         <foo:name>Victor Vector</foo:name>
         <foo:age>42</foo:age>
      </foo:person>
  </handler>

</svg>
    

In this case, the object referenced by the SVG-Handler-Class entry of the theJar.jar manifest has its createEventListener method called and the returning EventListener registered. Whenever a click event on the 'theRect' object is observed, the handleEvent method of the listener is called. The object can then access of the handler element in order to obtain its parameters from elements in the "foo" namespace.

15.6 Event handling

Events must cause scripts to execute when either of the following has occurred:

Related sections of the spec:

15.7 Processing inline executable content

When executable content is inlined inside an executable element such as script or handler elements, it must be processed as follows before it is parsed and executed.

If the type of the content, obtained either through the type attribute, the 'contentScriptType' attribute, or the default is not known by the user-agent, then the content must ignored and no further processing takes place.

If the type of the content is an XML media type [RFC3023], then the entire subtree of the executable element must be passed on untouched to the script engine.

Otherwise, the content that the user-agent's script engine obtains must be that which is obtained through the following steps:

  1. remove all descendant elements of the executable element
  2. then use the textContent of the executable element