wiki:pyxpcom_idevices

Architecture of EXE2

Contents:

Anchor(importing_fields)?

Importing Fields into IDevices

IDevice writers can import fields using the special exe xml namespace.

  • In the xul <window> element or the xhtml <html> element, the name space is declared, eg:
    <window
      xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      xmlns:exe="http://www.exelearning.org/standards/exe/1"/>}}}
     * In the actual content, the field can be imported, using the same XML that the field uses to save and load itself, which is generally like this:
     {{{
    <exe:field class="..." title="...">
      <exe:param name="..." value="..."/>
      <exe:dataNode id="...">
      <![CDATA[
      ...
      ]]>
      </exe:dataNode>
    </exe:field>
    }}}
     * Of course not all elements (<param> and <data>) will always be needed. This is the minimum implementation, importing the staticText field with default settings:
     {{{
    <exe:field class="exestandardfields.staticText"/>}}}
     * Finally to make preview look good, any non-exe elements inside an exe: namespace element will be ignored, so this is perfectly valid. The inner xhtml code will be ignored when importing:
     {{{
    <exe:field class="exestandardfields.staticText">
      <xhtml:div style="background-color:red; width:100%; height:100px">
        <xhtml:h1>Static Text Goes Here</xhtml:h1>
      </xhtml:div>
    </exe:field>}}}
    Please check the idl file athttp://exelearning.org/svn/exe/branches/exe2/exeregistrar.idl
    
    [[Anchor(api)]]
    === API for IDevice Writers ===
    EXE will be a Mozilla package. It will provide a XPCOM service object with the following methods:
    
    {{{
    interface nsIExeRegistrationManager : nsISupports
    {
        // The version of eXe
        attribute wstring version;
        // Called by fields and idevices when their xul is imported to register
        // themselves with the global repository
        void register(in nsIExeElement element);
        // Returns a field/idevice renderer from an id
        nsIExeElementRenderer getFieldOrIdeviceRenderer(in string className);
    };
    }}}
    A package should provide Mozilla {{{<overlay>}}}'s that automatically install themselves in exe.xul. We'll call this overlay file "import.xul". It will contain a script that does something like this:
    
    {{{
    // Create our field definition
    var myFieldOrIdeviceDefinition = getDefinition()
    // Register it with the exe service
    var interface = Components.interfaces.nsIExeRegistrationManager;
    var service = Components.classes["@exe.registration-manager;1"].getService(interface);
    service.register(myFieldOrIdeviceDefinition);
    }}}
    In the above example myFieldOrIdeviceDefinition is an XPCOM object that implements the below intkerface called nsIExeElement:
    
    {{{
    // an ExeElement is either a field or an IDevice
    // When you create a field or idevice, you should provide an XPCOM object that
    // implements these interfaces
    [scriptable, uuid(10181ce1-82a4-419d-b36d-1ed541a9adf4)]
    interface nsIExeElement : nsISupports
    {
        // Wether this is an IDevice (as apposed to a field)
        attribute boolean isIDevice;
        // The human readable universally unique (amongst all eXeElements of the
        // same type) className of this idevice. Should be something like
        // author.idevicename or author.fieldname, e.g. it's ok (but not reccommended)
        // for a field to exist called 'matthewsherborne.cloze' and also an idevice to exist
        // with the same className. (should be all lowercase for consistency).
        attribute string className;
        // The name of the field or idevice, should really try to keep it unique but
        // won't kill the program if it isn't, it'll just confuse the user
        attribute wstring name;
        // The name of the individual or organisation that created the field/idevice
        attribute wstring author;
        // The version number
        attribute string version;
        // A short description to show in a tooltip window, from the idevice list pane
        // or the field list pane in the idevice editor
        attribute wstring description;
        // A URL to the XHTML help
        attribute string helpTextUrl;
        // The URL to the edit template
        attribute string editOverlayUrl;
        // The URL to the view template
        attribute string viewOverlayUrl;
        // This will be called when we want the field/idevice to show it's data
        // edit/teacher mode.
        // The 'data' is an XML node, that was earlier retrieved
        // from calling getData() and possibly saved and loaded.
        // 'content' is the edit XUL/XHTML/SVG/etc. imported from the field/idevice
        // editoverlay.xul, the node with the id=content
        nsIDOMNode fillInEditDOM(in nsIDOMNode content, in nsIDOMNode data);
        // This will be called when we want the field/idevice to show it's data
        // view/student mode.
        // The 'data' is an XML node, that was earlier retrieved
        // from calling getData() and possibly saved and loaded.
        // 'content' is the edit XUL/XHTML/SVG/etc. imported from the field/idevice
        // editoverlay.xul, the node with the id=content
        nsIDOMNode fillInViewDOM(in nsIDOMNode content, in nsIDOMNode data);
        // This will be called after render edit exits to get some XML data from the
        // field/idevice. This data can be in any format the author likes, but
        // simpler is better. It will be incorporated into the xlp file format when
        // the user saves the data.
        // 'content' is the node from the imported editoverlay.xul content node
        // 'data' is the XML DOM node, could be empty or have data. The implementor
        // should modify this.
        void getData(in nsIDOMNode content, in nsIDOMNode data);
    }
    }}}
    
    [[Anchor(file_layout)]]
    === File Layout ===
    We will use the mozilla plugin and import system to register fields and idevices and styles as plugins. This way you could get a mozilla package of fields and/or idevices and/or styles. More info on the mozilla plugin system can be found here: http://developer.mozilla.org/en/docs/Chrome_Registration
    
    There will be a Mozilla package for exe, (that will no contain any fields or idevices).
    
    Also there will be a package of standard fields and another Mozilla package of standard IDevices.
    
    A field or IDevice package will register an "import.xul" with Mozilla for each field or IDevice that it wishes to import. This will be registered as an overlay for the main exe.xul window. In this "import.xul" file is a script that will register an xpcom object with the big exe registration manager XPCOM service.
    
    Lets look at the “Static Text” field definition: It lives in the “fields/Static Text” directory.
    
    Each field and each idevice definition must provide two XUL overlay files, one
    for rendering in preview/view/export and one for rendering in edit/teacher mode.
    
    Also they will need to provide a {{{register.xul}}} file that will be
    referenced in the field/idevice packets manifest file.
        
    -- From experience and based on existing code some fields need different code for previewing as opposed to viewing (export) -- -- DavidMoore [[DateTime(2006-01-13T03:00:10Z)]]
    
    {{{
    edit.xul
    view.xul
    register.xul
    }}}
    
    Both of these will provide a function called render() which takes an optional Mozilla XML DOM node, which will be either an idevice or field node from the above XML file. This function will return a new mozilla Node object containing either the xul or html required for showing the node with the data.
    
    The idevices and fields, will have no knowledge/access to the package, other fields, or nodes etc. They will show their data only through with the data they have. There will however be a simple API xpcom component available to them, which will help them do things like get urls of other nodes, etc.
    
    [[Anchor(rendering)]]
    === Rendering ===
    How is xul and HTML rendering done for each field? although the implementation of the {{{render}}} functions matters little to the rest of the application, we do have a reccommended method:
    
    The field/idevice will have a xul html file and an html file containing example/default data. It will load this file into a mozilla DOM node and use the data from the XML to fill in/modify the contents of each sub element.
    
    [[Anchor(statictext)]]
    === Static Text Field File Layout Example ===
    The static field directory will look something like this:
    
    {{{
    exe
     |
     +-- fields
     |     |
     |     +-- Static Field
     |          |
     |          +-- renderView.py
     |          +-- renderEdit.py
     |          +-- view.html
     |          +-- edit.xul
     |          +-- viewScripts
     |          |     |
     |          |     +-- static.js
     |          |
     |          +-- editScripts
     |                |
     |                +-- static.py
     |
     +-- idevices
          |
          +-- Free Text
          |    |
          |    +-- fields.txt
          |          |
          |          +-- Static Field
          |
          +-- Cloze
               |
               +-- renderView.py
               |    |
               |    +-- def render(dataElement = None):
               |            node = document.createElementNS("...XHTML", "div")
               |            node.innerHTML = open('view.html').read()
               |            ...
               |            return node
               |
               +-- renderEdit.py
               +-- view.html
               +-- edit.xul
               +-- viewScripts
               |     |
               |     +-- cloze.js
               |
               +-- editScripts
                     |
                     +-- cloze.py
    }}}
    }}}
    }}}