$Source: /spark/Website/resources/downloads/afettes/draft.html,v $
$Revision: 1.2 $
$Date: 2004/04/23 02:09:04 $
**********************************************
** SVG Programmers Application Resource Kit **
**********************************************
INTRODUCTION: - todo
-------------
- Why is SPARK needed?
- Paper outline


BACKGROUND: - todo
-----------
- SVG
- Viewers (Adobe, Batik)


HISTORY: - todo
--------
- Philip and Chris L. start SPARK fall 2002
- Chris L.           - CGUI
- Chris Peto         - SVG editor
- Glenn MacDonald    - skinning example
- Alastair Fettes
- SVGOpen            - initial thoughts
- SchemaSoft project - spring 2004


GOALS: - todo
------
- a framework (not just a set of widgets)
- interoperability
- MVC
- modularity
- low coupling, high cohesion
- serialization
- easy to use


SPARK ARCHITECTURE:
-------------------
The SPARK framework describes a set of rules and techniques for creating
SVG user interface widgets.  The architecture describes the interfaces that
the differently widget types must follow in order for the interoperability 
of the widgets.

There are two main sides of the SPARK framework - SVG and Code (ECMAScript
and/or Java).  The SVG structure has been standardized to a certain extent
to ensure interoperability of widgets and for possible future applications
that use the framework outside of a application user interface context.  The
coding side of the framework is in place to ensure widgets are able to talk
each other successfully and to enforce certain pertinent paradigms.  Initially
most widgets will be written in ECMAScript but support for Java (and any other
Scripting/Programming language available for use in the future) is a design
goal of the project in the long term.

SPARK follows a number of well established programming paradigms.  These have
been used in order to enforce good design principles.  The paradigms include
Model-View-Controller separation, information hiding, Observer/Observable
paradigm.  It also describes the document object model to a certain degree
(visibility of widgets, widget base types, etc).  These are in place to 
enforce the afore mentioned paradigms and avoid dependency issues.


BASIC SPARK WIDGET STRUCTURE (SVG)
----------------------------------
<g id="uniqueID" class="SPARK widgetType widgetName [CSSClass]">
    <desc>...Widget Descriptive Information...</desc>           - required
    <metadata>...Widget State Information (Model)...</metadata> - optional
    ...contents...                                              - optional
</g>

All widgets must:
  - have a root SVGElement that contains all the widgets members
     - the suggested element type is a group (<g/>) element.
  - have a document wide unique ID.
  - have a class attribute that follows the following rule
    <g class="SPARK widgetType widgetName CSSClass"/> 
    where:
      - SPARK      - static identifier for application to recognize a widget
      - widgetType - "atom" or "container"
      - widgetName - the class name, can also used for CSS purposes
      - CSSClass   - optional use
  - have a <desc/> element that contains information relating to the widget
    (i.e. for accessibility, what the widget is for, etc)
  - optionally have a <metadata/> element that contains state information
    (i.e. for serialization).


OBSERVER PARADIGM
-----------------
SPARK widgets implement the Observer/Observable interface.  

    The "Observable" interface:
    <code>
        /**
         * Observable interface.
         *
         * @see org.SchemaSoft.dom.SPARK.Observer
         */
        
        package org.SchemaSoft.dom.SPARK;

        public interface Observable
        {
            /**
             * Add an observer to the set of listeners for this widget.
             * @param in_pObserver The observer to add.
             */
            public void addObserver( Observer in_pObserver );
            
            /**
             * Remove an observer from the set of listeners for this widget.
             * @param in_pObserver The observer to remove.
             */
            public void removeObserver( Observer in_pObserver );
        }
    </code>

    The "Observer" Interface:
    <code>    
        /**
         * Observer interface.
         */
        
        package org.SchemaSoft.dom.SPARK;

        public interface Observer
        {
            /**
             * Called by an observable when it handles an event.
             */
            public void notify( Observable in_pObservable);
        }
    </code>


SPARK CLASS DEFINITION
----------------------
Java Abstract Class:
   <code>
    /**
     * SPARK abstract class.  Defines basic SPARK widget structure
     * including member variables and public methods.
     *
     * @see org.SchemaSoft.dom.SPARK.Observer
     */
        
    package org.SchemaSoft.dom.SPARK;

    public abstract class SPARK
    {
        /**
         * The class attribute of the widget.
         */
        public static final string CLASS;
        
        /**
         * A regular expression that defines the class attribute 
         * of the widget.
         */
        public static final string REGEX;
        
        /**
         * The document-wide unique id of this widget.
         */
        public final string ID;
        
        /**
         * Retrieve the widget's state.
         * @return The widgets state value.
         */
        public Object getState();
        
        /**
         * Set the widgets state.
         * @param in_state The new state value.
         */
        public void setState( Object in_state );            
    }
    </code>

ECMAScript Abstract Prototype:
    <code>
    /**
      * Atom abstract class.
      */
    function SPARK(){}

    /**
     * The class attribute of the widget.
     */
    SPARK.CLASS;

    /**
     * A regular expression that defines the class attribute 
     * of the widget.
     */
    SPARK.REGEX;

    /**
     * The document-wide unique ID of this widget.
     */
    SPARK.ID;

    /**
     * Retrieve the widget's state.
     * @return The widgets state value.
     */
    SPARK.prototype.getState = function(){}

    /**
     * Set the widgets state.
     * @param in_state The new state value.
     */    
    SPARK.prototype.setState = function( in_state ){}
    </code>


WIDGET TYPES:
-------------
All widgets are of type "atom" or of type "container".  An atom is defined
by a widget that contains no other widget.  A container is defined by a 
widget that may contain a mixed, unordered set of "atom" and "container"
widgets.  This set may be entirely made of "atom" widgets or conversely of
entirely "container" widgets.  It may also be an empty set.


VISIBILITY STRUCTURE OF WIDGETS:
--------------------------------
- "atom" widgets only have knowledge of themselves.
- "container" widgets have knowledge of their own widget contents as well as 
  any "atom" or "container" widgets that they themselves contain (are the 
  direct container of).
  
The result of this visibility structure is one that enforces the paradigm of 
information hiding.  The one way visibility is a directed graph downwards 
through the SPARK DOM tree.  The only link that a lower widget (with respect
to the SPARK DOM tree) to a higher level widget is through the observer/
observable paradigm (described later).

The driving force behind this is the idea that a top level widget should 
not need to know about a bottom level widget.  If this information is 
required then the widget should be placed as an immediately childNode of the 
widget that requires the information.     


ATOM WIDGET DEFINITION
----------------------
All atomic widgets should provide:
  - A static factory method used to create a DOM version of the widget.

SVG:
    <g id="uniqueID" class="SPARK atom widgetName CSSClass">
        <desc/>     - required
        <metadata/> - optional
        ...view...  - optional
    </g>
    
    Example:
    <g id="abc123" class="SPARK atom MyAtom MyAtomCSS">
        <desc>This is MyAtom!</desc>
        <metadata>Hello World</metadata>
        <circle cx="100" cy="100" r="50" fill="red"/>
        <text>Click me!</text>
    </g>

Java Abstract Class:
    <code>        
        /**
         * Atom abstract class.
         *
         * @see org.SchemaSoft.dom.SPARK.Observer
         * @see org.SchemaSoft.dom.SPARK.SPARK
         */
            
        package org.SchemaSoft.dom.SPARK;
    
        public abstract class Atom extends SPARK implements Observerable
        {
            /**
             * Interface members.
             */
            public void addObserver( Observer in_pObserver );            
            public void removeObserver( Observer in_pObserver );
        }
    </code>

ECMAScript Abstract Prototype:
    <code>
        /**
         * Atom abstract class.
         */
        function Atom( in_node );
    
        /**
         * Interface members.
         */
        Atom.prototype.addObserver = function( in_pObserver );
        Atom.prototype.removeObserver = function( in_pObserver );
    </code>
  
    
CONTAINER WIDGET DEFINITION
---------------------------
All container widgets should provide:
  - A static factory method used to create a DOM version of the widget.
  - load any expected child widgets themselves during their constructor
    (using helper methods if needed).

SVG:
    <g id="uniqueID" class="SPARK container widgetName">
        <desc/>     - required
        <metadata/> - optional
        ...view...  - optional
        <g class="SPARK contents"/>
          - optional, zero to many
          - contains all member "atoms" and or "containers"
          - may be placed anywhere inside container; only container itself 
            must have advanced knowledge of location.
    </g>
    
    Example:
    <g id="abc123" class="SPARK container MyContainer">
        <desc>A container to hold widgets.</desc>
        <circle cx="100" cy="100" r="50" fill="red"/>
        <g class="SPARK contents">
            <desc>Buttons located near top of widget.</desc>
            <g id="abc456" class="SPARK atom MyAtom MyAtomCSS">
                <desc>This is a button.</desc>
                <circle cx="100" cy="100" r="50" fill="red"/>
            </g>
        </g>
        <g class="SPARK contents">
            <desc>Buttons located near bottom of widget.</desc>
            <g id="abc789" class="SPARK atom MyAtom MyAtomCSS">
                <desc>This is another button.</desc>
                <metadata>25</metadata>
                <circle cx="100" cy="100" r="50" fill="red"/>
            </g>
        </g>
    </g>

Java Abstract Class:
    <code>
    /**
     * Container abstract class.
     *
     * @see org.SchemaSoft.dom.SPARK.Observer
     * @see org.SchemaSoft.dom.SPARK.Observerable
     * @see org.SchemaSoft.dom.SPARK.Atom
     * @see org.SchemaSoft.dom.SPARK.SPARK
     */
    
    package org.SchemaSoft.dom.SPARK;
    
    public abstract class Container extends SPARK 
                                    implements Observer, Observable
    {
        /**
         * Add a container or atom to this container widget.
         * @param in_pContents The atom or container to add.
         */
        public void add( SPARK in_pContents );
        
        /**
         * Remove a container or atom from this container widget.
         * @param in_pContents The atom or container to remove.
         */
        public void remove( SPARK in_pContents );
        
        /**
         * Interface members.
         */
        public void notify( Observable in_pObservable );
        public void addObserver( Observer in_pObserver );            
        public void removeObserver( Observer in_pObserver );
    }
    </code>
    
ECMAScript Abstract Prototype:
    <code>
    /**
     * Constructor
     */
    function Container();

    /**
     * Add a container or atom to this container widget.
     * @param in_pContents The atom or container to add.
     */
    Container.prototype.add = function( in_pContents );

    /**
     * Remove a container or atom from this container widget.
     * @param in_pContents The atom or container to remove.
     */
    Container.prototype.remove = function( in_pContents );

    /**
     * Interface members.
     */
    Container.prototype.notify = function( in_pObservable );
    Container.prototype.addObserver = function( in_pObserver );
    Container.prototype.removeObserver = function( in_pObserver );
    </code>
  

DESIGN DECISIONS:
-----------------
1.  SVG 1.1 features supported
    Backwards compatible for most SVG viewers currently in use.

2.  SVG 1.2 features not supported
    To be added (when functionality is added to viewers) in SPARK v2.0

3.  No XUL or XForms
    These languages are too constrictive for the SPARK framework.  Therefore
    they have been ignored.  It is suggested however to look at these 
    languages as good examples of an initial widget set.

4.  No XBL
    See design decision 2.  XBL is a very interesting technology and is part 
    of the SVG 1.2 draft.  Careful thought will be given for implementing XBL 
    in SPARK 2.0.  Decision will be based primarily upon implementation in 
    the browser and relevance to SPARK.

5.  SVG Decisions
    
    5.1 <desc/> Element
        The reasons for the desc element are threefold:
        a.  Accessibility for UI.
        b.  Description of UI element invaluable.
        c.  Workaround for bug in Adobe SVG view.  ASVG will cause the 
            browser to crash if a pointer is kept to an SVG node and an 
            EventListener is added to it through script.  The desc element 
            ensures that the programmer may always retain an anchor to the 
            SVG node if required.
            
    5.2 <metadata/> Element
        A flexible storage container.  Any type of XML information may be 
        contained within.  This leaves it up to the programmer to decide how 
        their information is stored.  Also, model (state) information is 
        easily queried by retrieving the metadata element through the use of 
        the getElementByID function and retrieving the metadata node.
        
        This also enables MVC separation as the model is separated from the 
        View in the SVG structure.
    
    5.3 <g class="SPARK contents"/> Element
        This is used primarily for future applications that wish to create 
        SPARK based UI's using an interface similar to the Visual Basic 
        programming environment.  With a 'g' element that is specifically 
        used for containing other widgets then it is easy to decide where in 
        the SVG to insert the new member widget.
    
    5.3 @class="SPARK widgetType widgetName widgetClass"
        The first two classes are used to identify the SVG node as a SPARK 
        widget. In general the use of CSS classes are advised due to the ease 
        of skinning an application.
    
6.  Script generated SVG code
    It is definitely not advised to have a large amount of script generated 
    SVG code.    
    
    Reasons:
        - static representation of UI (if no script engine present)
        - XSLT created/modified UI
        - enable RAD applications to create UI (ex. Visual Basic
          drag and drop UI creation).
        - serialization of UI
        
7.  Atom and Container Paradigm
    These are the lowest common denominators of all widgets.  Any widget is 
    able to be broken down into one of these two categories.  It also mimics 
    other well known applications storage structure (structured storage 
    libraries), object hierarchies and file structures.

8.  Observer/Observable Interface
    This paradigm enables information hiding, encapsulation and low coupling 
    of widgets all of which are good software engineering design principles.  
    This also enforces the one way visibility structure of the UI DOM tree.


FUTURE OF SPARK:
----------------
1.  SPARK 2.0
    Adjust for new features in the SVG 1.2 draft.  This version will not 
    necessarily be backwards compatible with SPARK 1.0 and SVG 1.1 *only* 
    viewers.  SPARK 1.0 will be depreciated once the majority of viewers are 
    SVG 1.2 enabled.  On particular update that will most likely be included 
    is the use of XBL.
    
2.  <metadata/>
    It is a possibility that there will be a suggested metadata structure.  
    In the end it is still up to the developer to use their own content 
    model.
    
3.  Widgets, widgets and more widgets
    The only way to ensure that SPARK is successful is to steadily increase 
    the number of widgets available.
    
4.  Call for feedback
    More suggestions, input and support are always welcome.  With more 
    community support the framework will become more robust and popular 
    throughout the SVG community.


REFERENCES: - todo
-----------
1.  SVG 1.1 and 1.2 draft
2.  Philip Mansfield
3.  Darryl Fuller
4.  SPARK presentation at SVGOpen 2003 (author list)
5.  Kevin Lindsey


ACKNOWLEDGEMENTS: - todo
-----------------
1.  Christoper Lewis
2.  Glenn MacDonald
3.  Chris Peto


APPENDIX:
---------  

1. SVG EXAMPLES:
----------------
1.1 Atom Examples:
    <g id="spark-5" transform="translate(50,0)" 
          class="SPARK atom Radiobutton">
        <desc>Radiobutton - red</desc>
        <metadata>red</metadata>
        <rect width="100" height="40"/>
        <text x="10" y="20">red</text>
    </g>

1.2 Container Examples:
    <g id="fillcolor" 
        transform="translate(350,50)" 
        class="SPARK container RadiobuttonGroup">
        <desc>RadioGroup for picking colors.</desc>
        <g id="spark-5" transform="translate(50,0)" 
            class="SPARK atom Radiobutton">
            <desc>Radiobutton - red</desc>
            <metadata>red</metadata>
            <rect width="100" height="40"/>
            <text x="10" y="20">red</text>
        </g>
        <g id="spark-6" transform="translate(50,100)" 
            class="SPARK atom Radiobutton">
            <desc>Radiobutton - blue</desc>
            <metadata>blue</metadata>
            <rect width="100" height="40"/>
            <text x="10" y="20">blue</text>
        </g>
        <g id="spark-7" transform="translate(50,200)" 
            class="SPARK atom Radiobutton">
            <desc>Radiobutton - green</desc>
            <metadata>green</metadata>
            <rect width="100" height="40"/>
            <text x="10" y="20">green</text>
        </g>
    </g>


2. ECMAScript EXAMPLES: - current out of date; update needed
-----------------------
2.1 Atom Examples:

    MyWidget.js (ECMAScript):
    <code>
        /**
         * Regular expression defining the class attribute for a MyWidget
         * SVGElement root element.
         */
        MyWidget.REGEX = /^SPARK atom MyWidget/;
        
        /**
         * String expression defining the class attribute for a MyWidget
         * SVGElement root element.
         */
        MyWidget.CLASS = "SPARK atom MyWidget";
        
        /**
         * Create a new MyWidget instance using an existing SVGElement
         * as the root.
         * @param in_node The root SVGElement.
         */
        function MyWidget( in_node )
        {
            this.id = in_node.getAttribute( "id" );
        };
        
        /**
         * Interface member.
         * @param in_observer The observer to add to the list of observers.
         * 
        MyWidget.prototype.addObserver = function( in_observer )
        {
            this.observers.push( in_observer );
        };        
        
        /**
         * Interface member.
         * @param in_observer The observer to remove from the observers list.
         **/
        MyWidget.prototype.removeObserver = function( in_observer )
        {
            var bFound = false;
    
            for( var i = 0; i < this.observers.length; i++ )
            {
                if( this.observers[i] == in_observer )
                {
                    this.observers[i] = null;
                    bNotFound         = false;
                    break;
                }
            }
            
            if( bFound )
            {
                for( var i = 0; i < this.widgets.length-1; i++ )
                {
                    if( this.observers[i] == null )
                    {
                        this.observers[i]   = this.widgets[i+1];
                        this.observers[i+1] = null;
                    }
                }
            }
        };
        
        /**
         * This widget was selected.
         */     
        MyWidget.prototype.select = function()
        {
            for( var i = 0; i < this.observers.length; i++ )
            {
                if( this.observers[i] != null )
                {
                    var observer = this.observers[i];
                    observer.notify( this );
                }
            }
        };
        
        /**
         * Factory function for creating a new MyWidget.
         * @param in_parent The parent SVGElement to this widget.
         * @return The new MyWidget.
         */
        MyWidget.createWidget = function( in_parent )
        {
            var SVGDoc = in_parent.ownerDocument;
            var node   = SVGDoc.createElement( "g" );
            node.setAttribute( "id", "abc123" );
            node.setAttribute( "class", MyWidget.CLASS );
            
            in_parent.appendChild( node );
            
            var widget = new MyWidget( node );
            
            return( widget );
        };
    </code>

2.2 Container Examples:
    MyContainer.js (ECMAScript)
    <code>
        /**
         * Regular expression defining the class attribute for a MyContainer
         * SVGElement root element.
         */
        MyContainer.REGEX = /^SPARK container MyContainer/;
        
        /**
         * String expression defining the class attribute for a MyContainer
         * SVGElement root element.
         */
        MyContainer.CLASS = "SPARK container MyContainer";
        
        /**
         * Create a new MyContainer instance using an existing SVGElement
         * as the root.
         * @param in_node The root SVGElement.
         */
        function MyContainer( in_node )
        {
            this.id         = in_node.getAttribute( "id" );
            this.atoms      = new Array();
            this.containers = new Array();
        };
        
        /**
         * Add an atom.
         * @param in_atom The atom to add.
         * 
        MyContainer.prototype.addAtom = function( in_atom )
        {
            this.atoms.push( in_atom );
        };        
        
        /**
         * Remove an atom.
         * @param in_atom The atom to remove.
         **/
        MyContainer.prototype.removeAtom = function( in_atom )
        {
            var bFound = false;
    
            for( var i = 0; i < this.atoms.length; i++ )
            {
                if( this.atoms[i] == in_atom )
                {
                    this.atoms[i] = null;
                    bNotFound     = false;
                    break;
                }
            }
            
            if( bFound )
            {
                for( var i = 0; i < this.atoms.length-1; i++ )
                {
                    if( this.atoms[i] == null )
                    {
                        this.atoms[i]   = this.atoms[i+1];
                        this.atoms[i+1] = null;
                    }
                }
            }
        };
        
        /**
         * Add a container.
         * @param in_container The container to add.
         * 
        MyContainer.prototype.addContainer = function( in_container )
        {
            this.containers.push( in_container );
        };        
        
        /**
         * Remove a container.
         * @param in_container The container to remove.
         **/
        MyContainer.prototype.removeContainer = function( in_container )
        {
            var bFound = false;
    
            for( var i = 0; i < this.containers.length; i++ )
            {
                if( this.containers[i] == in_container )
                {
                    this.containers[i] = null;
                    bNotFound          = false;
                    break;
                }
            }
            
            if( bFound )
            {
                for( var i = 0; i < this.containers.length-1; i++ )
                {
                    if( this.containers[i] == null )
                    {
                        this.containers[i]   = this.containers[i+1];
                        this.containers[i+1] = null;
                    }
                }
            }
        };
        
        /**
         * Interface member.
         */     
        MyContainer.prototype.notify = function( in_atom )
        {
            // do state change
        };
        
        /**
         * Factory function for creating a new MyContainer.
         * @param in_parent The parent SVGElement to this widget.
         * @return The new MyContainer.
         */
        MyContainer.createWidget = function( in_parent )
        {
            var SVGDoc = in_parent.ownerDocument;
            var node   = SVGDoc.createElement( "g" );
            node.setAttribute( "id", "abc123" );
            node.setAttribute( "class", MyContainer.CLASS );
            
            in_parent.appendChild( node );
            
            var widget = new MyContainer( node );
            
            return( widget );
        };
    </code>