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.
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.
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.
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.
Dianne Kyra Hackborn <hackbod@angryredplanet.com> | Last modified: Fri Oct 18 13:52:43 PDT 1996 |