Emerald Hand Wiki

Back to tutorials section


Edit

Introduction

This tutorial describes how to create a simplest type. Yet, even in simplicity there are some complex problems to consider. We will create a type to store rich text notes using HTML. It can be used in variety of places to store notes and comments.

I assume you have read New Type tutorial and are familiar with how to create a new blank type. So, I'm just going to provide details on how to customize a new type.

Edit

Analysis

In New Type tutorial I have mentioned importance of analysis. It doesn't have to be formal (and it shouldn't be in most cases) and its purpose is to improve picture of what you are about to spend several hours of your time on. If you have a good idea of what you are going to do, why, and what is the best way to do, you can easily skip this. However, if you are like me you would have only some ideas of what you need, but not well defined goals.

Edit

Why

The first step to understanding what you need to do is figure out why you are doing it. In most cases finding the answer is trivial. I mean, after all you wouldn't start working on something if you didn't think that you need to do it. Still, even in trivial cases it can be helpful to pause and take a moment to see if your reasons are good. It will help you to create and maintain a larger picture of how things (types and views in this case) fit together.

We are going to create this type for the following reasons:
  1. To learn (or get reminded on) how to extend Sider. I assume that's why you are reading this.
  2. To create a highly reusable type to store and work with rich text. I first created it when I wanted to organize my notes. However, it has much wider area of use.

Edit

Usage

The type is going to store rich text, but there are several ways to do it. First, we can use HTML (seems like a logical choice), since the view is shown in the browser. It's not the only choice. We could also use rich text form (RTF) or maybe even MS Word XML, but I think this will only complicate matters. There are no RTF editors for the browser that I know of and to use MS Word we would require user to have it installed. HTML is the simplest choice.

We have two alternatives on how to store it. First is to store HTML as XML nodes (text). This could be hard. A lot of HTML editors don't create valid XML form. Even if they would, they spit out string, which we would need to convert to XML nodes to insert to the document. It's just easier to store HTML as a string and decode it as we use it.

Edit

Structure prototype

Let's quickly create a document prototype to assist us with writing the type.


<document>
<htmlText> <![CDATA[<p>HTML code<br> is here<-p>]]></htmlText>
</document>

Notice that HTML text is inside another element in the document (inside htmlText). We are doing this because document can have other elements (document properties for example).

Edit

Descriptor

You now need to create type descriptor (type.xml):
id - Generate new GUID for the type
name - HtmlText
friendlyName - HTML text
version - 0.5.0.0
category - Embedded
prefix - siderHtml

Edit

Schema

Defining schema is straight forward. All we need is redefine document wrapper (pulling it into the current type namespace) and add an element with HTML text to it.

<xs:redefine schemaLocation="sider">
<xs:complexType name="DocumentContentType">
<xs:complexContent>
<xs:extension base="siderHtml:DocumentContentType">
<xs:sequence>
<xs:element name="htmlText" type="xs:string" />
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>


Edit

Constructor

Writing constructor is also straight forward. We only need a single template to copy document with all existing attributes and elements, and add HTML text in the process.

<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates />
<siderHtml:htmlText><![CDATA[<b><i>HTML<-i> goes here<-b>]]></siderHtml:htmlText>
</xsl:copy>
</xsl:template>

Edit

Script

Most complicated part of the type is probably script. Still, writing it is quite simple.


  1. Create constructor. We are going to declare qualified name for the single field in the type, htmlText

    /*
    Constructor: initializer
    Initializes a new instance of the <sider.types.html.0.5>.
    */
    initializer: function()
    {
    /*
    Variable: name.htmlText
    Element name to hold HTML.
    */
    this.name.htmlText = this.formQName( "htmlText" );
    }


  2. Next we will create HTML access methods. Actually, we don't have to. We could just force view developers to use setValue and getValue provided by the abstract type. But this type will be widely used so we are going to make it as accessible as possible and provide short-cut methods. They are nice, but not required.

    /*
    Function:setHtml
    Sets HTML of the specified HTML document.

    Parameters:
    path - Path to the HTML document.
    htmlText - HTML source to set.
    */
    setHtml: function( path, htmlText )
    {
    this.setValue( path, "htmlText", htmlText );
    },
    /*
    Function: getHtml
    Returns HTML from the specified document.

    Parameters:
    path - Path to the HTML document.

    Returns:
    HTML of the specified element. If node wasn't found or doesn't contain any HTML
    *null* is returned.

    Remarks:
    If path points to several elements, only first element from the list will be used.
    */
    getHtml: function( path )
    {
    return this.getValue( path, "htmlText" );
    }

    Notice that we are using "htmlText" as property name instead of this.name.htmlText. This is more for demonstration purposes. get/setValue methods automatically look up for the qualified field name in the name object. We added qualified field name in the constructor, so they should be able find it.

  3. Last thing we need to add is a method to create new HTML document at the specified path. Currently you need to manually write script has to do this. In the future we will use your XSLT constructor to simplify your job.

    /*
    Function: createDocument
    Creates HTML document as the child of the first element pointed by the *parentPath*.

    Parameters:
    parentPath - XPath referencing a parent of the node.

    Returns:
    Path to the new HTML element on success. *null* on failure.
    */
    createDocument: function( parentPath )
    {
    var docPath = this.inherited( "createDocument", [ parentPath ]);
    var newNodePath = this.addElement( docPath, this.name.htmlText );
    return docPath;
    }


Edit

Conclusion

By now you should have a good idea of what's involved in creating simple Sider extension, an atomic type. Writing more complex types or views will not be as straight-forward.

Copyright © 2006-2008 Emerald Hand, Inc. All rights reserved.
Powered by ScrewTurn Wiki version 2.0.34. Some of the icons created by FamFamFam.