Modifying IC's Basic Page Formatting
By Chris Rybitski and Steve Parker (c) 1999
The template modifications and classes presented here are Chris work. A sample IC application that utilizes these modifications, is available at: http://www.charter-systems.com/COLsample
Internet Connect is really a quite remarkable product: true scrolling lists, real tabs, toolbars, the ability to create a fully Internet enabled application in anywhere from one to seven mouse clicks, tight integration of language, file access and the web UI. However, it is becoming increasingly obvious that IC, to reverse a cliche, suffers the defects of its virtues. Perhaps it is just showing its age (it went into public beta over two years ago).
The Problem with IC
The product appears (and this is entirely inferential our part) to be based on two key assumptions. First, and this seems obvious, is the assumption that client-side Java for Web applications would catch on much faster and be more widely employed/accepted than it has been. Second, and this is the major inference we are making, is the apparent assumption that it is desirable for Web applications to resemble Windows applications. Or, what is the same thing, it is assumed that Clarion developers would want Web applications that looked like Clarion Windows apps.
Happily, Topspeed developers are not locked into emulating Windows or even to using the Java classes. Thanks to pioneering work by Tony Goldstein, it is entirely possible to create applications using neither Java nor JavaScript. It is entirely possible to create applications using JavaScript but no Java. We can also create Java-free lists using only the built-in capabilities of the templates ("Decaffeinating Forms and Browses," Clarion Online, 2, 1, August 1998), HTML tables using Target.Writeln ("But It Doesnt Look Like IC!," Clarion Online, 2, 2, September 1998), even multi-column lists, without Java, using the standard listbox queue provided by the templates ("The Best of Both Worlds," Clarion Online, 2, 7, February 1999).
It does take additional work compared to using the standard IC templates. But all of these can be done.
What we cannot do is easily access the Internet Builder Classes (IBC), their properties and methods. And alternate list styles must be manually implemented each time they are required. In large measure this is because IC remains very much hybrid product.
This is because IC was first introduced when CW2.0 was the current product. IC was built using OOP but OOP had only been implemented in the core product as an add-on. That is, an OOP class structure was imposed on and combined with the legacy templates. Even when ABC was introduced, IBC remained an entire separate set of classes. No interface is provided into the classes as we have in C5 (see Figure 1) since IBC has yet to be integrated into ABC.

There simply is no convenient way to override the IC methods. The "override" capability we are given is limited to a single control or all controls of a given type (see Figure 2).

This means that the IC developer is bound by the decisions made by the IC class author (over two years ago at that).
For example, ClarionLoader.class always displays a 2x2 dot at the bottom of the generated page (see the highlighted code in Listing 1).
HtmlClass.WriteBasicAppletHeader PROCEDURE(STRING AppletName, STRING|
ClassName, SIGNED Width, SIGNED Height, BYTE Scale)
CODE IF (Scale) Width = SELF.GetPixelsX(Width) Height = SELF.GetPixelsY(Height) END IF (Width = 0) THEN Width = 2. IF (Height = 0) THEN Height = 2. |
Listing 1
When background colors or images are used, this dot is easily seen. The darker the background, the more obvious it is.
However, though many believe an applet must be displayed, displaying the ClarionLoader.class this way is not in fact required. Commenting these two lines out appears to have no adverse effect.
Similarly, images used as buttons, a built-in feature of the IC classes, always have a blue border (see Listing 2, the code in bold represents the modification required to produce an image map with no border).
WebHtmlImageClass.CreateCellContents PROCEDURE(*HtmlClass Target)
!code has been removed here
Target.Write(' WIDTH=' & Target.GetPixelsX(ImagePos.width))
Target.Write(' HEIGHT=' & Target.GetPixelsY(ImagePos.height))
Target.Writeln(' border="0">')
END
|
Listing 2
These two examples are aesthetic, not functional. Unfortunately there can be serious operational consequences of the HTML generated by the IC classes. For example, to fully accommodate users accessing the Web from behind firewalls and through proxy servers, additional code in the HTML <Head> tag to bypass incorrect caching of pages by proxy servers is required. Yes, these are bugs in the proxy server software (but Clarion does contribute its share by using non-unique HTML page names). So what? -Your customer cant get Novells or Microsofts attention but sure can get yours.
Similarly, it is often necessary to place additional code inside the <BODY> tag.
If you use the standard queue to manage your Java-free list box and also create hyperlinks from database fields, you may discover a peculiar behavior: If you click, say, the third item in the list, the third item on every subsequent page will appear as a "visited link." Minor issue? Confused users = angry users = you dont get paid = not a minor issue.
Unfortunately, there is no embed point nor is there an override within the templates available for these purposes. IC gives us the flexibility to embed custom HTML at many points. But the page header and the opening of the <BODY> tag are notable exceptions. And, this means that we have to hack the classes directly, really the only method open to us.
Preparing to Hack
Of course it is entirely possible, as in Listing 2 above, to hack the classes directly and hard code the desired changes. Of course, such a solution is not entirely general and may create HTML that functions no better than the unmodified base classes, due to its very inflexibility.
For example, color schemes change from page to page and from site to site. Link colors used on one page may be entirely out of place on a page with a different scheme.
There may be a JavaScript function you need in one app but not in another. (JavaScript functions often go in the header area.)
This makes an entirely general solution, i.e. a solution allowing us to insert variable strings into the generated HTML, desirable. Specifically, we need to prime a variable in the template interface and then, in the IC classes, insert the value of the variable (if any) into the generated HTML.
Fortunately, the IC classes make this fairly easy. Because the HTML <HEAD> and <BODY> tags are built up in small segments, not in a single, monolithic string, it is a straightforward matter to insert a new segment.
Both tags are created in WebWindowClass.CreatePageHeader (ICWINDOW.CLW), the relevant portion of which is shown in Listing 3:
WebWindowClass.CreatePageHeader PROCEDURE(*HtmlClass Target)
CODE
Target.Writeln('<<HTML>')
Target.Writeln('<<HEAD>') beginning of <HEAD> tag
Target.Write('<<TITLE>')
SELF.TitleContents(Target)
Target.Writeln('<</TITLE>')
Target.Writeln('<</HEAD>') ending of <HEAD> tag
Target.Write('<<BODY') beginning of <BODY> tag
IF (SELF.PageBackground = COLOR:None)
Target.Write(' BGCOLOR="' & IC:ColorText(COLOR:Silver) & '"')
ELSE
Target.Write(' BGCOLOR="' & IC:ColorText(SELF.PageBackground) & '"')
END
IF (SELF.PageImage)
Target.Write(' BACKGROUND="' & SELF.Files.GetAlias(SELF.PageImage) & '"')
END
IF (SELF.AllowJava)
Target.Write(' onLoad="setuptimer()" onUnload="killtimer()"')
END
Target.Writeln('>') ending of <BODY> tag
Listing 3
Notice how both tags are built up in small pieces, a single statement at a time, rather than in a single line. This is what will allow inserting an additional STRING containing HTML to be built into the tags, similar to the way background colors and images are handled.
To effect this, then, we need to do two things. First, we must provide a template interface to declare the required variables and to capture them.
This is the easy part.
Second, we have to get the template information into the WebWindow.CreatePageHeader method (WebWindow is how WebWindowClass is instantiated).
The problem is that while the templates know about the classes, the classes know nothing about the templates. Template symbols can access variables in the app but neither template symbols or app variables are available to the classes.
This means that the template variables containing our custom HTML cannot be read by methods in the WebWindowClass. To "make it so," we are going to have to create WebWindowClass properties that both the templates and the classes know about, containing the strings to be added to CreatePageHeader.
Why variables? The IC templates typically work by passing template options to the classes as parameters. The CreatePageHeader method accepts only its target as a variable. An alternate approach might be to change the CreatePageHeader method to accept additional, optional, parameters. If you think through what it would take to implement this alternative, you will see that the more linear method presented here is a bit easier.
Changes to ICONNECT.TPL
The first step is to create the template interface. To do this, we will add a Tab to the IC extension.
Find the #END which corresponds to #TAB ('C&lasses') in ICONNECT.TPL, making the new tab the last one.
Create a new tab by inserting (note, word wrapping may reformat this template code):
#TAB('Custom Control')
#BOXED('Custom HEAD/BODY tag control')
#DISPLAY()
#PROMPT('Insert dynamic text into HTML <<HEAD>|
Tag',CHECK),%AppOvrrdHeadTag,AT(10)
#ENABLE(%AppOvrrdHeadTag)
#PROMPT('<<HEAD> reference var:',FIELD),%AppOvrrdHeadVar,REQ
#ENDENABLE
#DISPLAY()
#PROMPT('Insert dynamic text into HTML <<BODY> Tag',CHECK),|
%AppOvrrdBodyTag,AT(10)
#ENABLE(%AppOvrrdBodyTag)
#PROMPT('<<BODY> reference var:',FIELD),%AppOvrrdBodyVar,REQ
#ENDENABLE
#ENDBOXED
#END
Listing 4
This creates a new Tab where we can indicate that we want to use custom HTML:
[
Notice that these template prompts expect a variable (the figure also shows additional customization that Chris will be discussing in a future article). This means we only need to prime these variables before the first window/page is displayed.
Of course, providing an initial value when declaring the variables avoids the need to prime. Moreover, the use of variables allows the flexibility of re-priming with new values at runtime.
To ensure that the WebWindow class knows about these variables, find the templates web window initialization code:
In C4IC or C5IC, search for:
!- Initialise the internet
classes
WebWindow.Init(WebServer, HtmlManager, %Window{PROP:text} & '
(%'Procedure)')
In C5aIC, search for:
!- Initialise the internet
classes
#IF (%WebWindowName='WebWindow')
%WebWindowName.Init(WebServer, HtmlManager, %Window{PROP:text}
& ' (%'Procedure)')
#ELSE
%WebWindowName.Init(WebServer, HtmlManager, 0{PROP:text} & '
(%'Procedure)')
#ENDIF
and after these lines, add:
#IF (%AppOvrrdHeadTag)
WebWindow.OvrrdHead = True
WebWindow.HeadTagText &= %AppOvrrdHeadVar !Reference new HEAD
tag text.
#END
#IF (%AppOvrrdBodyTag)
WebWindow.OvrrdBody = True
WebWindow.BodyTagText &= %AppOvrrdBodyVar !Reference new BODY
tag text.
#END
which tests whether customization is required and, if so, creates a reference in the classes (WebWindow.HeadTagText and WebWindow.BodyTagText) to the variables declared in the application (contained in the two template symbols).
The Carts a Bit Before the Horse
Two variables are being used but havent been declared. The declarations occur in a different file (see below). It seemed kinder to present all the modifications for a single file in one go. But since you noticed . . .
What is important is the use of reference variables in the assignments shown in Listing 5. Because we are still in the template file, both the variables and the template symbols are in scope.
The template variables actually contain the labels of the applications variable. So, the generated code will look like:
WebWindow.BodyTagText &= MyBodyVariable
By using a reference, WebWindow.BodyTagText is effectively MyBodyVariable. Thus, the class property is the application variable. Now both the application and the classes know not only about the variables but the contents of the strings to be integrated.
ICWINDOW.INC and ICWINDOW.CLW
The template interface is in place and so are the variables in the application. In the preceding code we also used two properties, WebWindow.HeadTagText and WebWindow.BodyTagText, to bridge from the templates to the classes. They dont exist. Bad form, that. They must be declared.
In ICWINDOW.INC, find WebWindowBaseClass. Add the following properties to the CLASS:
OvrrdHead BYTE
OvrrdBody BYTE
HeadTagText &CSTRING
BodyTagText &CSTRING
Listing 6
(a CSTRING is used to avoid the need to Clip().)
The Class now knows about our new properties.
To actually use them, open ICWINDOW.CLW and find WebWindowClass.CreatePageHeader. After the Target.Writeln('<</TITLE>') code statement, add:
IF (SELF.OvrrdHead)
IF SELF.HeadTagText
Target.Writeln(' ' & SELF.HeadTagText)
END
END
Listing 7
This inserts the variable, if used, containing our HTML into the <HEAD> tag.
For the <BODY> tag, scroll down to IF (SELF.PageImage) which is a few lines further down in the template. Note that this is just before the > which closes the tag.
After the corresponding END, add the following code:
IF (SELF.OvrrdBody)
IF SELF.BodyTagText
Target.Write(' ' & SELF.BodyTagText)
END
END
Listing 8
Cest tout! The next time you open the application, the template chain will re-register (you should have that option set) and the modifications will be available for consumption. Now, to avoid having users think theyve visited the third link on every page, you can simply set:
MyBodyVariable = link="#000000" vlink="#000000"
and no one will be any the wiser.
Similarly, you can force a proxy server to refresh the page (not using the one in its cache) by inserting the following metatags in the <HEAD> tag:
MyHeadVariable = <meta http-equiv="expires" content="Wed, 01 Jan 1997 00:00:01 GMT"> &|
<meta http-equiv="pragma" content="no-cache">
Summary
No one is real fond of the idea of hacking the IC classes or of adding properties to the distributed files. But there simply is no other way at this stage of ICs development.
At least, the majority of HTML is built up in small segments, allowing insertion of new variables and code without actually replacing the existing code. In this, the IC templates are in fact no more challenging to modify than the standard templates and easier than some.