NOTE:
This project is no longer being maintained: it was developed for my masters thesis, which was completed in early 1997. I still, however, welcome any questions or comments that people may have.

[Home] [ToC] [Prev] [Next]


iHTML Python Language

Document Program Tutorial

A document program is one that executes in the context of the entire document. It is not normally seen by the user, but works in the background to help construct and manipulate the document's HTML tree, control the interactions between form elements and embedded programs, and track user events. The new HTML tag <OBJECT> with its CONTEXT attribute is used to insert these programs into an HTML document, as described in the introduction.

All Python document programs must export at least one symbol, ihMain, which is the program's main entry point. This symbol should be a callable object that is given a variable number of arguments and returns an instance of a Document class.

Example 1: The Simplest Document Program

The simplest document program possible is:

# Get standard document class definitions.
import ihDoc

# Our own document is a subclass of the iHTML-defined
# Document class.
class ihMain(ihDoc.Document):

    # Class initialization.
    def __init__(self,**args):

        # Just send control on up to the superclass.
        apply(ihDoc.Document.__init__,(self,),args)

        # Display the document.
        self.Reformat()

# Make our program externally visible.
__export__ = ['ihMain']

This class does almost nothing -- it just passes any arguments it finds on up to the top-level Document class, and then displays the current document. The HTML markup we can use to attach this program to document would be:

<OBJECT CONTEXT=DOCUMENT CLASSID="doc_simple.ipy">
</OBJECT>

If you have an iHTML-capable browser, you can take a look at the simple example.

Example 2: Editing Markup

This example does something a bit more interesting. Before displaying the HTML document, it uses the the interactive HTML markup interface and ihMarkup module to dynamically construct parts of the document.

A document program has access to its HTML document's parse tree. This allows it to easily examine and edit the document. The system also includes a very simple function, FillinMarkup(), that automatically performs string insertions of markup text. In this example, the HTML document has points where IDs are inserted in tags, indicating where some text should go. If a key matches the tag, the string associated with that key is itself parsed into an HTML tree, and inserted into the document at the point of the ID. Finally, the program displays the completed document.

# Dynamically insert text into an HTML document.

# Get standard document class definitions.
import ihDoc

# Get the markup interface module.
import ihMarkup

# Get other needed modules.
import sys,time,string
import ihBrowser, ihDoc, ihMarkup, ihURL

# Our own document is a subclass of the iHTML-defined
# Document class.
class ihMain(ihDoc.Document):

    # Convert a capability into a descriptive string.
    def get_cap(self,name):
	cap = getattr(self.Capabilities,name)
	if( cap ):
	    return "Yes"
	else:
	    return "No"

    # Class initialization.
    def __init__(self,**args):

        # Just send control on up to the superclass.
        apply(ihDoc.Document.__init__,(self,),args)

	# Get information about the user and host machine.
	user_name = ihBrowser.UserName
	host_name = ihBrowser.HostName

	# Get information about the display we are running on.
	if self.Capabilities.disp_color > 0:
	    color_disp = "Yes (" + `self.Capabilities.disp_color` \
			 + " distinct pens)"
	else:
	    color_disp = "No"
	if self.Capabilities.disp_true > 0:
	    true_disp = "Yes (" + `self.Capabilities.disp_true` + \
			" bits per pixel)"
	else:
	    true_disp = "No"

	# Insert the data into the document.
	ihMarkup.FillinMarkup(self.VisHTMLTree,
		    { "IH_VERSION": str(ihBrowser.IHVersion),
		      "IH_REVISION": str(ihBrowser.IHRevision),
		      "IH_SUBBUILD": str(ihBrowser.IHSubBuild),
		      "BR_NAME": str(ihBrowser.BRFullName),
		      "BUILDDATE": str(ihBrowser.BuildDate),
		      "USER_NAME": ihBrowser.UserName,
		      "USER_MACHINE": ihURL.GetHostName() + " (" \
		          + ihURL.GetHostByName(ihURL.GetHostName()) \
		          + ")",
		      "TEXT_DISP": self.get_cap("disp_text"),
		      "GFX_DISP": self.get_cap("disp_graphics"),
		      "COLOR_DISP": color_disp,
		      "TRUE_DISP": true_disp,
		      "VIEW_WIDTH": str(self.ViewWidth),
		      "VIEW_HEIGHT": str(self.ViewHeight),
		      } )

	# Clear progress line.
	self.ShowProgress()

	# Display the document.
	self.Reformat()

__export__ = ['ihMain']

If you have an iHTML-capable browser, you can take a look at the markup editing example.

Example 3: User Interaction

Below is our final example, which shows how a document program can monitor the user's interaction with an HTML page. This can be useful to determine how much your pages are being used and help hunt down problems people may have in understanding them.

All events in iHTML trickle up through the user interface, eventually appearing at the top-level document object. This allows document programs to examine and react to any level of events they wish to, everything from responding to button presses in applets, to tracking and modifying forms as the user edits them, or keeping informed of when the user views and prints the document.

Since these events appear at one centralized place, there is no need to define explicit tags for each HTML element that produces them. This is very important because it allows general-purpose programs to be written. For example, one intelligent program can be written to track page usage in general, so all that is required to track a particular page is to add the link to the program in the head of the document.

This example also demonstrate the low-level network services provided by the ihURL module, and how it can be used to dynamically exchange data with the program's remote server.

# Report user interaction to a remote server.

# Get standard document class definitions.
import ihDoc

# Get some other needed modules.
import time,string
import ihURL

# This is the machine the server is located on.  If the program
# was retrieved from some other machine, an error will occur when
# trying to create the URL class.
DEFHOST = 'flapjack.cs.orst.edu'
DEFPORT = 55571

# This is the class that communicates with the server.  It is
# a subclasses of the LineURL class, and encapsulates a single
# tcp:// session.
class DocTracker(ihURL.LineURL):

    def __init__(self,doc,host,port):

	# Last document state that was sent to the server.
	self.last_clock = time.time()
	self.last_top = 0
	self.last_bottom = 0
	self.last_lines = 0
	self.doc = doc

	ihURL.LineURL.__init__(self,doc,'tcp://' + host + ':' + `port`)
	result = (self.GetStatus(),self.GetURL())
	self.sock_result = `result`
	self.sock_address = self.GetURL()

	self.Write("* send\n")

    def OnLine(self,lines):
	self.doc.ShowProgress(self.GetURL() + ' - ' + lines[-1])

    def OnError(self,error):
	addr = self.GetURL()
	if( not addr ): addr = '[tcp connection]'
	self.doc.ShowProgress(addr + ' - ' + error)

    # Global document event handler.  After instantiating this class,
    # this method can be attached to the document's list of handlers.
    def doc_handler(self,doc,event):
	self.send_scrollpos(doc,event.Code)

    # Send a new document state message to the server.
    def send_scrollpos(self,doc,action):
	if self.last_clock != 0:
	    new_clock = time.time()
	    elapsed = new_clock - self.last_clock
	    self.last_clock = new_clock
	    if(elapsed > 0.2):
		action = string.lower(action+"")
		txt = "* " + action + ": top=" \
		      + `self.last_top` \
		      + "; bot=" + `self.last_bottom` \
		      + "; total=" + `self.last_lines` \
		      + "; time=" + ("%.2f" % elapsed) + " secs\n"
		txt = "* " + action + " " + `self.last_top` + " " \
		      + `self.last_bottom` + " " + `self.last_lines` + " " \
		      + ("%.2f" % elapsed) + "\n"
		if( self.GetStatus() == ihURL.URL_INTERACTIVE ):
		    self.Write(txt)
	    else:
		self.last_clock = time.time()
	self.last_top = doc.ViewTop
	self.last_bottom = doc.ViewBottom
	self.last_lines = doc.DocHeight


# Our own document is a subclass of the iHTML-defined
# Document class.
class ihMain(ihDoc.Document):

    # Class initialization.
    def __init__(self,**args):

        # Just send control on up to the superclass.
	apply(ihDoc.Document.__init__,(self,),args)

	# Create the session with the server.
	self.tracker = DocTracker(self,DEFHOST,DEFPORT)

	# Clear progress line and display the document.
	self.ShowProgress()
	self.Reformat()

	# Send initial data and install handler
	self.tracker.send_scrollpos(self,"initpos")
	self.Handlers.append(self.tracker.doc_handler)

# Make our program externally visible.
__export__ = ['ihMain']

If you have an iHTML-capable browser, you can take a look at the complete user interaction example.


[Home] [ToC] [Prev] [Next]

_________.oo_Q_Q_oo.____________________________________________
Dianne Kyra Hackborn <hackbod@angryredplanet.com>
Last modified: Fri Oct 18 13:52:43 PDT 1996

This web page and all material contained herein is Copyright (c) 1997 Dianne Hackborn, unless otherwise noted. All rights reserved.