The Best of Both Worlds: - Browse Boxes on the Web

by Steve Parker and Vince Russo

Published 1999-02-01    Printer-friendly version

NOTE: Clarion Magazine was not able to obtain an archive of the original source code for this article. If you have the source, we'd very much appreciate it if you would email it to us so we can post it for other readers.

On the Internet, there are two things you can count on: graphics and lists (waiting doesn’t count because sometimes, though not often, the Web fools you and responds with alacrity).

Clarion Internet Connect, of course, supports lists. Not simply "lists," but list boxes as we are used to them. In fact, it supports them in multiple ways.

Falling off a log easy

By simply adding the Internet Connect extensions to your application, any existing browse procedures automatically work on the Web. Multiple columns are supported, as are navigation keys, scroll bars, toolbar navigation, double clicking, all forms of locators and, probably, a few more features we’ve forgotten about.

It doesn’t get much easier than this.

Of course, there is a price for this ease. Users must download the Java classes and scrolling can be slow (on the order of one or two seconds per line). Further, you are at the mercy of a multitude of bugs in the various Java Virtual Machines used by different browsers.

For an example, see:http://www.par2.com/cws/cwlaunch.dll/faqs/coolfaqs.exe.0

A little harder, but Java-free

(This subject was fully discussed in "Decaffeinating Forms and Browses," Clarion Online, 2, 1, August 1998 and "But it Doesn’t Look Like IC," Clarion Online, 2, 2, September 1998.)

IC allows you to override the default list box class (WebJavaListClass) with an HTML class (WebHtmlListClass), producing a non-Java list:

 Figure 1
Figure 1

While much faster and not requiring the Java classes, there is a price for this too. HTML lists are generated as HTML <select> structures. An HTML <select> only supports a single string per line. That is, you cannot get multi-column support.

Similarly, you lose all the features of Clarion list boxes you are used to: page-to-page navigation is not automatic, scroll bars don’t work, double clicking is gone, etc. But, HTML lists are fast and, combined with Tony Goldstein’s template modifications, the Java classes will never be downloaded.

For an example, see: http://www.par2.com/cws/cwlaunch.dll/faqs/faqs4.exe.0.

Tear off your shirt, pound your chest, roll your own

(This subject was fully discussed in "Dual-Dual-Mode Apps," Clarion Online, 2, 4, November 1998.)

No Java, multiple columns and a total Web look and feel are also possible.

It should be no surprise that there is a price, a heavy one, for the speed and aesthetics. Not only do you lose everything mentioned above, you also lose the ability to edit or delete records (at least, without substantial additional code, but that’s another story).

Because you create your own HTML, your code loses its connection to the queue from which the browse is built. This means that you have no way of knowing which record is highlighted and, therefore, which record to pass to the form.

Wouldn’t it be nice if …

we could have the best of both worlds?

Well, assuming you understand what the best of both actually is, you can.

The best of Clarion: A Clarion browse box is the result of a series of complex structures and interactions. The disk file is read into a View. The View is read to create a queue. This queue is what is actually displayed in the browse box (check the properties of a list box, then trace the label you find in the "From" prompt in the generated code). That is, the templates provide and maintain a queue for displaying records.

The queue is managed by ACCEPT, our event handler.

The browse-related events handled by ACCEPT include scrolling up and down, either one record or a page at a time, double clicking or pressing a button (like Insert, Change or Delete).

When the user presses a navigation key, ACCEPT determines whether or not the queue needs to be re-filled, doing so when required. If the window needs to be refreshed, it does so. For example, both re-filling the queue (which contains only as many entries as can fit in the list box) and refreshing the window are required by a page up or down.

This queue and its handling is the part that would be really nice to have while retaining …

The best of HTML: small, fast, easily delivered and displayed files (they’re just ASCII, after all) that look web-ish.

So, what would be nice would be to retain the template’s queue building and ACCEPT’s management of it but customize the HTML displayed instead of accepting the default HTML <select> or full Java list control.

HTML Style Pages with ACCEPT()

While it is not strictly necessary, you will get maximum benefit by applying Tony Goldstein’s template modifications (http://www.cwsuperpage.com/kb).

If a list control template is populated, the queue building LOOP is present, by default. So, if we start with a standard browse or list control template on a window, the queue is taken care of.

The question, then, is, "How do we access the built-in routines that fill the browse queue?" If we can do this, ACCEPT will automatically manage the queue for us and we can create an HTML shadow of the queue.

In the Clarion templates, we need access to the FillQueue Routine. The ABC templates give us direct access to the method in which items are added to the browse queue: BRWx.SetQueueRecord (called from BRWx.FETCH, which initially fills the queue, and several of the RESET methods).

Of course, the answer is that there is an embed where we can create a list box element (which automatically means that it is in the queue filling LOOP). In the Clarion templates, within the FillQueue routine, is an embed, "Format an element of the browse queue." In ABC, the elements are added to the browse queue in Local Objects … BRWx … SetQueueRecord which takes us directly into BRWx.SetQueueRecord.

If you would rather have a single, long list of records and forego the need for navigation buttons, format your HTML in the ResetFromView method. Make sure your priority is set very low, 500 or under.

So, now we know where records are read into the queue and, by extension, where our alternate (HTML) formatting will go.

Other considerations:

To get an idea of what the HTML portion of your list will look like, you can use a visual HTML editor and "requisition" the code. If you wish to include column titles, don’t forget to format them in your editor.

You will also want a string to hold your HTML "shadow list" while looping through the queue. Note that the HTML characters required for formatting can add up to several hundred characters for each record. So, be sure you make your variable long enough. 5-10,000 characters is a good starting point.

By using HTML for the display list, the connection to the underlying queue (the real list) is broken. You will want to set your standard buttons (Change, Delete, etc.) to "Hide if launched from browser."

 Figure 2
Figure 2

These buttons, if displayed, will not work. So, there is no point in displaying them.

For the same reason, standard page navigation keys will not work. Therefore, we will need to supply our own page up and page down buttons. Optionally, you may add buttons for ScrollTop and ScrollBottom. While the standard keys will not work, we can post the relevant events and ACCEPT will recognize and act on them.

Next, we are going to substitute our own HTML for the standard list box. Therefore, we do not want to display the standard box. The temptation is to check "Hide if launched from browser" but this has undesirable consequences. If a control is hidden, no HTML will be generated, which is good. But, code in embeds related to the control will not be generated either, which is not good.

Instead, understanding that we want to substitute our HTML for the default HTML, use the option to omit default HTML generation. We do want HTML, just not that supplied by the templates.

 Figure 3
Figure 3

There is one important effect that the standard list box has, even though we will not use it. The height of the list box determines how many lines will be displayed. This, in turn, determines how many records will be in the queue. Therefore, the design height of the list box indirectly determines how many records will be read when formatting our substitute HTML <table>. (No such luck with width however.)

Implementation

(A sample app can be run from www.autohotline.com/cws/cwlaunch.dll/htmldemo/demo.exe.0, if you do not yet own Internet Connect.)

Declare a local variable to hold the HTML for displayed records, HTMLString.

"Hide if launched from browser" all controls that depend on knowing the selected queue record. These include the Change and Delete buttons. If you have a Select button, it, too, needs to be hidden. If you want a Java-free application, you will also need to hide Sheets and Tabs.

Create NextPage and PreviousPage buttons. The idea is to ensure that events normally associated with navigation keys will be posted to the list box.

Unfortunately, it is not quite as simple as posting the appropriate events in the buttons’ embeds:

?NextPage, Accepted:
  Clear(HTMLString)
  Post(Event:PageDown,?Browse:1)

or

?PreviousPage, Accepted:
  Clear(HTMLString)
  Post(Event:PageUp,?Browse:1)

While these events will post, they will not have the expected effect. To get the desired result, we must ensure that a queue entry is in memory (i.e., emulate "selecting" an item). This provides the starting point for the next queue fill.

Clarion Templates ABC Templates
Control Event Handling, before generated code. ?NextPage.Accepted

Clear(HTMLString)
Brw1::CurrentChoice = Brw1::ItemsToFill
Post(Event:PageDown,?Browse:1)

Control Event Handling, before generated code. ?PreviousPage.Accepted

Clear(HTMLString)
Brw1::CurrentChoice = 1
Post(Event:PageUp,?Browse:1)

Control Event Handling, before generated code. ?NextPage.Accepted

Clear(HTMLString)

Get(Queue:Browse:1,Records(Queue:Browse:1)

Free(Queue:Browse:1)

Post(Event:PageDown,?Browse:1)

Control Event Handling, before generated code. ?PreviousPage.Accepted

Clear(HTMLString)

Get(Queue:Browse:1,1)

Post(Event:PageUp,?Browse:1)

 

You may also want to consider defaulting these buttons to HIDE. Then, if you are running in a browser, unhiding them:

After Opening Window/end of ThisWindow.Init:

If WebServer.Active
  Unhide(?NextPage)
  Unhide(?PreviousPage)
  Enable(?NextPage)
  Enable(?PreviousPage)
End

ABC Caveats

Management of the required queue data is much more straightforward in the Clarion templates. Using the ABC templates, the Previous Page button tends to go back to the beginning of the file rather than a single page.

There are methods that appear to be ideally suited to the task, BRW1.ScrollPage() and BRW1.Fetch, for example, but they are protected. This means that they can only be called while the browse object is in scope (in simple English, this means from an embed within the browse object).

You can declare user defined events (401h and higher) and post those events to the browse in the Next and Previous buttons. Then, in BRW1.TakeEvent (within the browse object), you can call the ScrollPage or Fetch methods. But this is beyond the scope of this article.

Writing the HTML

There are two issues with the HTML. One is how to format it. The other is where to display it.

An important requirement of HTML is that you must have an opening tag and a closing tag. In the case of an HTML list, you can think of these as similar to header and footer bands in a report. While the HTML for each record will be created within the standard template loop, the header and footer need to be generated once (and only once) each.

Consider this table which displays three columns, with titles (line numbers added for reference):

1 <table border="0">
2     <tr>
3        <td>Last Name</td>
4        <td>First Name</td>
5        <td>Phone Number</td>
6     </tr>
7     <tr>
8        <td>pre:LastName</td>
9        <td>pre:FirstName</td>
10       <td>pre:PhoneNumber</td>
11    </tr>
12 </table>

Lines 1-6 are the table’s header and line 12 is its footer. Lines 7-11 need to be repeated for each record.

In the "Format an element of the browse queue" or BRWx.SetQueueRecord embed:

HTMLString = Clip(HTMLString) & '<<tr><<td>' & pre:LastName & '<</td> &|
             '<<td>' & pre:FirstName & '<</td>' &|
             '<<td> ' & pre:PhoneNumber & '<</td><</tr>'

handles formatting as records are read into the queue.

The final code will comprise three sections: writing the header HTML, writing HTMLString and writing the footer, in that order:

!Write the header

Target.WriteLN('<<table border="0"><<tr>' &|
               '<<td>Last Name</td>' &|
               '<<td>First Name</td>' &|
               '<<td>Phone Number</td></tr>')

!Write the list

Target.WriteLN(HTMLString)

!Write footer

Target.WriteLN(‘<</table>’)

But, where?

We are using the standard templates, with all their standard functionalities, and substituting our HTML for the standard HTML. Indeed, we told the template to retain the control but generate no HTML for it because we intend to provide our own. So, we continue to use the standard templates: Internet, After generating HTML for Control(Browse:1), ensuring our code will not be written out until after the LOOP has completed (any Internet embed after the queue filling LOOP will do).

Problem

When you press the Previous Page button, your list may be sorted backward (this is more likely to occur in the Clarion templates).

This is because the queue is being filled from the current position back toward the beginning of the queue. The appropriate routine or method is called with "Direction = Backward." That means that we may be formatting HTMLString in reverse order.

Pretty obvious after checking out the generated code (plant palm firmly on forehead).

Solution

Any of a number of ways of handling this is possible (typical Topspeeder cleverness is shown to its best advantage by this sort of glitch).

For example, instead of reading Queue:Browse:1 directly to HTMLString in the appropriate embed, you could read it to an intermediate queue. Afterwards you would sort the work queue and format the HTML from the work queue. Minimal work and no overhead to speak of (queue to queue is all but instantaneous).

In this case, you would probably use a different embed for processing the work queue because you’d need to FREE the queue and that can’t be done in the embeds we’ve been considering.

However, it is also possible to access the template’s queue directly, read it forward and format the HTML.

In the Internet, after generating HTML for control ... ?Browse:1, the queue has been completely filled. All we need to do is step through it and format our HTML there (i.e., immediately before writing the final HTML):

CLEAR(HTMLString)
Entries# = RECORDS(Queue:Browse:1)   !Determine number of entries
LOOP I# = 1 TO Entries#              !Loop through QUEUE
GET(Queue:Browse:1,I#)               !Get record from QUEUE
  IF ERRORCODE() THEN STOP(ERROR()).
  HTMLString = Clip(HTMLString) & '<<tr><<td>' & pre:LastName &|
                                  '<</td><<td>' & pre:FirstName & '<</td>' &|
                                  '<<td> ' & pre:PhoneNumber & '<</td><</tr>'
END                                  !Queue entries loop
! -------- Write HTML for display ---------
 !Write the header
Target.WriteLN('<<table border="0"><<tr>' &|
               '<<td>Last Name</td>' &|
               '<<td>First Name</td>' &|
               '<<td>Phone Number</td></tr>')
 !Write the list
Target.WriteLN(HTMLString)
 !Write footer
Target.WriteLN('<</table>')

Summary

Until now, we could have multi-column lists with Java or single column lists without the Java. To implement multi-column lists without Java meant forgoing Clarion’s built-in queue management and managing the queue by hand (not a lot of fun).

By creative use of existing embeds, we can take advantage of the standard listbox queue and ACCEPT’s event handling and still have multi-column, web-ish and Java-free lists.

Printer-friendly version

 
 

Search

 

Advanced Search
Topical Index

Related Articles

Subscribe to
ClarionMag

One year: $184

(includes all back issues since '99)

Renewals from $134

Two years: $274

Renewals from $224

More Info

Subscribe Now!

ClarionMag Blog

RSS Feeds

Updates via Email

Enter your Email


Powered by FeedBlitz

Quick Links