Examples

This page explains how CompareMyDocs.com works. CompareMyDocs is a simple mashup built to demonstrate how to use the TextFlow API.

The mashup consists of a simple HTML form to allow users to upload their Word documents, a back-end system that temporarily stores the word documents for use while comparing, and dynamically generated JavaScript code that controls how TextFlow behaves.

Screen shot of CompareMyDocs

Try out CompareMyDocs.com

CompareMyDocs.com Documentation

Note: some of the code segments below have been simplified for instructional purposes. The actual HTML source of CompareMyDocs.com are somewhat more complex in order to improve the appearance of the site.

index.html

First we define a helper function to unhide form elements so that we only show at most one free upload button at a time.

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html> <head>
<title></title>
<script  language="javascript">
<!--
function makeVisible( name ) {
  document.getElementsByName(name)[0].style.visibility="visible";
  document.getElementsByName(name)[0].style.height="25px";
}
-->
</script>
</head>

The body of index.html is a form element with 5 hard coded file upload buttons. The first button is for selecting the original document, and the other 4 are used to select versions to compare with the original. The form is submitted to a simple Python script that places the files into temporary storage and generates a new dynamic HTML page to load TextFlow.

<body>
<center>
<h1>CompareMyDocs.com</h1>

<form name="myform" action="submit.py" enctype="multipart/form-data" method="POST">
Original:<br>
<input type="file" name="base" onchange="makeVisible('diff1div'); makeVisible('msg'); "/>

<p>
<div name="msg" style="visibility:hidden;height:0px">
Versions to compare with:
</div>
<div name="diff1div" style="visibility:hidden;height:0px">
  <input type="file" name="diff1" onchange="makeVisible('diff2div'); makeVisible('compare'); " />
</div>
<div name="diff2div" style="visibility:hidden;height:0px">
  <input type="file" name="diff2" onchange="makeVisible('diff3div')" />
</div>
<div name="diff3div" style="visibility:hidden;height:0px">
  <input type="file" name="diff3" onchange="makeVisible('diff4div')" />
</div>
<div name="diff4div" style="visibility:hidden;height:0px">
  <input type="file" name="diff4" />
</div>

<div name="compare" style="visibility:hidden;height:0px">
  <input type="submit" value="Compare!" />
</div>
</form>

</center>


</body> </html>

submit.py

The source code for submit.py has also been slightly simplified.

This CGI script has two tasks. Firstly it stores the documents uploaded by the user in temporary storage and assigns them a GUID. Then it generates the HTML page used to load the TextFlow Flash object and interact with it via JavaScript.

import cgi
import uuid
# TFStore is a hidden class that handles the server storage of resources
import TFStore

import datetime, time

baseguid=""
diffguids=""

print "Content-type: text/html\n\n"

# Iterate through the files we recieved from the form, store them in
# temporary storage, and build up the TextFlow version list XML.

versionlist="<VersionList>"

form = cgi.FieldStorage()
for ff in ["base", "diff1", "diff2", "diff3", "diff4"]:
  if form.has_key(ff):
    fileitem = form[ff]
    if fileitem.filename!="" and fileitem.file:
      # generate a GUID to identify the file with
      guid = "%s" % uuid.uuid1()

      # store the GUID in either baseguid or as part of the diffguids 
      # comma separated list
      if ( baseguid=="" ):
        baseguid=guid
      elif ( diffguids == "" ):
        diffguids=guid
      else:
        diffguids+=","+guid

      # ask TFStore for a storage bin to put the document in
      outfile = TFStore.getStoredFile( guid+".doc" )
      fout = file( outfile, 'wb')

      # read the input file from CGI and write out to the storage bin
      while 1:
        chunk = fileitem.file.read(100000)
        if not chunk: break
        fout.write(chunk)
      fout.close()

      # finally generate the XML version entry needed by TextFlow
      versionlist+="  <Version id='%s' created='%s' name='%s' type='docurl' />"\
         % ( guid, datetime.datetime.now(), fileitem.filename )

versionlist+="</VersionList>"

# Ok, we now need to dynamically generate the HTML/JavaScript that will         
# act as the comparemydocs page.                                                
h = open( "TextFlowAPI.html" )
html = h.read()
h.close()
# For simplicity we just replace three hard coded values
html = html.replace( "TEXTFLOWBASE", baseguid )
html = html.replace( "TEXTFLOWDIFFS", diffguids )
html = html.replace( "TEXTFLOWVERSIONXML", versionlist )

# finally print the generated HTML
print html

TextFlowAPI.html

This file is based largely on the standard Flash HTML loader with two additions. Firstly we specify a <script> tag to implement the necessary JavaScript functions for controlling TextFlow. Secondly we need to provide a number of FlashVars to TextFlow to control which documents are pre-loaded.

Instead of standard Python string substitution in this example we are using the replace() function to swap three markers: TEXTFLOWBASE, TEXTFLOWDIFFS and TEXTFLOWVERSIONXML.

JavaScript Code:

<script language="JavaScript" type="text/javascript">
<!--
// the TextFlow API interface...                                                
function getVersionList( docid )                                                
{                                                                               
  return decode_utf8( "TEXTFLOWVERSIONXML" );                                   
};                                                                              
                                                                                
// getVersionData() uses verid to return a URL that the server can use
// to locate the document from local storage
function getVersionData( docid, verid )                                         
{                                                                               
  return "tfstore/"+verid+".doc"                                    
}
                                                                                
// Tell TextFlow to save the finished document as URL that can be
// downloaded by saveVersionData()
function getSaveFormat( docid ) 
{                                               
  return "docurl";                                                              
}                                                                               

function saveVersionData( docid, data )                                         
{                                                                               
// Here we just trigger a javascript download of the Word document:       
  window.open(data, "download window");

  // Then we need to return a new version entry for the version list            
  return decode_utf8( '<Version id="15" created="2009-01-05 01:10:42" '
                      +'name="Version5" type="docurl" />' ); 
}

// Helper functions 
function decode_utf8( s )
{                                                                               
  return decodeURIComponent( escape( s ) );                                     
}                                                                               

function onUnload() 
{  
  if ( TextFlowAPI.hasChanges() ) {    
    return "Warning: Your document has not been saved. To save first, please "
      +"select Cancel and pick the 'Close' button from the TextFlow toolbar.";  
  }                                                                             
}                                                                               
                                                                                
-->
</script>
   

FlashVars:

 AC_FL_RunContent(
        "src", "TextFlowAPI",                                   
        "FlashVars","TextFlowDocumentId=&TextFlowMode=API
                &TextFlowBaseVersionId=TEXTFLOWBASE&TextFlowCompareVersionIdList=TEXTFLOWDIFFS",      
        "width", "100%",                                        
        "height", "100%",                                       
        "align", "middle",                                      
        "id", "TextFlowAPI",                                    
        "quality", "high",                                      
        "bgcolor", "#869ca7",                                   
        "name", "TextFlowAPI",                                  
        "allowScriptAccess","sameDomain",                       
        "type", "application/x-shockwave-flash",                
        "pluginspage", "http://www.adobe.com/go/getflashplayer"
);