Thursday, September 25, 2008

The HttpRequest class updated - Get cookie values

I've updated the HTTPRequest-class so that you also can use it to pick cookies of a request.

Example code:

Dim request As New HttpRequest()
Dim sessionCookie As String
sessionCookie = request.cookie( "DomAuthSessId" )
Print "I've got your cookie!"


Although I link to Jake's excellent demonstration of how simple it is to get the session cookie, I wrote the cookie-bit a couple of days before, in work relation.

>> HttpRequest Source code

Tuesday, September 23, 2008

Templating: Generating HTML from document collections

Sometimes it can be useful to render HTML from document collections. I believe one of the fastest ways to get values from Notes documents is using Evaluate. As a lazy person, I like to avoid writing formula code, as it's somewhat verbose compared to modern templating languages like PHP.

To avoid this, make your own template interpreter using simple formula code.

Example:
str := "Date: $#dayOfMonth#$. $?month?$.";
'"' + @ReplaceSubstring( str ;
"$?" : "?$" : "$#" : "#$" ;
'" + ' : ' + "' : '" + @Text( ' : ') + "'
) + '"'


Result: "Date: " + @Text( dayOfMonth) + ". " + month + "."

The result can be used in an evaluate statement.

A great thing about templating is that it is very maintainable/reusable. If you want to change the output, all you have to change is the template-string. To generate XML and HTML from the same collection, all you have to do is to have two different string templates. The conversion logic can be the same.

In the simple demoapp I've included, a collection of 300 documents is processed, extracting five fields. A HTML table row is generated per document. class="even"/class="odd" is added so that one can style odd/even rows. If you're somewhat familiar with LotusScript, it should not be hard to make a template-class to fit your needs.

On localhost (my laptop) it takes about 100 milliseconds to generate the HTML/write it to a PassTruHTML NotesRichTextItem.

>> Demoapp

If you want a sorted collection, you can use NotesView.AllEntries, and use NotesViewEntry.Document, to get to the document. Beware of categorized views. Test NotesViewEntry.isValid = True to be certain that the entry represents a NotesDocument. There may be other problems with using NotesViewEntry.Document as well. Proceed with caution/good error handling. :)

?OpenField - get HTML from a RichText-item

In case you missed it in Yellowcast, episode five. There's an undocumented feature in Lotus Domino that lets you pull HTML from a RichText field. This is a very useful feature for me at least.

Example url: http://www.notes.net/secrets/undocumented.nsf/documentation/easteregg?OpenField

I believe Carl Tyler was one of the first to blog about this.

Why not document such a great feature? Why, IBM?!

Friday, September 19, 2008

Processing documents by category in categorized views

Problem: How to process documents in a category (categorized view) in a simple way?

This is a problem I've heard a couple of times at work from the Notes-guys (I'm a Domino/Web-guy). I've tried a couple of approaches/googled, but found nothing. Therefore I archived this problem in my "experiment ideas"-folder.

Today I had a little time to play around, and found a very simple solution.

When you click an item in a view, a couple of properties is set in the NotesUIView. CaretNodeId points to the NoteId of the document that is selected. The gem is that when you click a category, an "invalid" NoteId is set. If you can't get a document from from the db using that NoteId, the item clicked is probably a category.

Now you know the user clicked a category.

Combining the ViewSelection-formula of the view, and the Formula-property of the first column (the column has to point to one field in the document for this to work), you have a valid search-formula for db.search.

Now you know which documents the user want.

Of course, the user don't want to modify documents by category each time they click the category. Add a button that sets an environment variable, and test for the value of that variable in the onSelect-event in the view. If you want to make available several types of action on the documents, use more values.

Now you know when/how the user wants to modify the documents

Problem solved..? :)

As always, blogposts like this are useless without a simple demoapp..
>> DemoApp

If you like/dislike this workaround/hack, please leave a comment.

Update: The onselect event is new in Notes 8. So if you're running on older versions, I guess there's no simple solution. Thanks to Theo for giving me a heads up!

Wednesday, September 17, 2008

Json-search on Domino views

Domino (at least pre 8.5) doesn't let you use $$SearchTemplate forms as anything other than vanilla Domino-generated html forms.

This makes it somewhat difficult to search/getting Json-data in return.

The simplest workaround I've found is to make a view with one column. The data is formatted as Json, with a trailing comma. In the search-template, I wrap the $$ViewBody-field like this:
<div id="result">[|$$ViewBody-field|,""]</div>

When I want to search, I use a temporary iframe, added to the DOM using Javascript. To make it as simple as possible, browser compatibility-wise (events), I add a the iframe inside a temporary div using innerHTML. The iframe has an onload-event. When that triggers, I know that the Json is loaded.

I'm terrible at explaining code (terrible at explaining anything), so I've made a simple demo-app you can try. Remember to create a full-text index on the demo-db before trying it out.

Flash demonstration of the app (I parse the Json to HTML):




>> Demoapp

The app is tested, and works in Opera 9.5, FF3 and IE7 on Vista x64.

Wednesday, September 10, 2008

Fun with the WebBrowserControl - DemoApp release

I think I've cleaned up the demo-app good enough now.

I added another demo, showing the browser on the onHelp event in Notes/offline Mootools accordion.

Apart from that, I've changed the way I store JS. I now store it in a page, and use the NotesNoteCollection of the db to fetch it (look in the code). This makes it easier to implement in a Template-context.

If you test the app on something else than Notes 8, I'd appreciate feedback (preferably in the comments) on the stability of the demoapp.

To test out making friends, edit a document in the DiscworldCharacters-view (make sure the HTTP-task is running). If you're running the demo on a server, edit the Add friend-button, so that the domain is correct.

The other demos are in the BrowserDemo-form.

>> The WebBrowserControl demoapp

The flash-demos are here

Update: Martin tested the app in N6.53. That makes it at least compatible with N6.5 to N8.02.

Tuesday, September 9, 2008

Fun with the WebBrowser Control - Finishing up

I'm more or less satisfied with what I've accomplished with my experiments.

I'm now able to "bootstrap" (in lack of a better term) a JS-library/HTML to a WebBrowser control. This enables you to write truly offline widgets (no HTTP-task involved) for your notes-apps.

I'm also able to bind LS-functions to the events available in the WebBrowser-control using environment variables and Execute.

I won't be able to clean up the demo-app today. Hopefully I'll be done tomorrow if nothing else comes up.

Until then, I've made another flash showing a youtube-movie inside Notes (for instruction videos/etc.), and logging of navigation (for tracking of online wizards inside Notes/etc.) in the webbrowser using the BeforeNavigate2-event.

If you want me to do make another example of integration with the WebBrowser-control, leave a comment, and I'll see what I can do.

All the flash-demos:
Demo 1 - simple usage
Demo 2 - Web autocomplete to Notes
Demo 3 - Offline Mootools-demo
Demo 4 - Web Autocomplete - Add friends
Demo 5 - Loading Youtube-movies/logging navigation

Monday, September 8, 2008

Fun with the WebBrowser Control - Making friends

The demoapp has gone through serious a serious rewrite to make the code more reusable/flexible. I've also worked a little bit on dynamically binding events through environment variables and execute. Sadly I haven't found a way of truly dynamically binding events (On Event..).

Some of the methods for the browser-class I use are now also chainable. E.g.
Dim browser As New Browser
Call browser.setSize(300, 400).openUrl("http://google.com")


Todays flash shows a little friend-making:



The document being edited has a hidden multi-value field that holds ID's to other "Discworld Characters". When a character is selected in the lookup, the id of that document is put inside a hidden field in the browser document.

When the browser is closed, the values is picked out of the browser document and added to the "friends-list". Then the document is refreshed/a lookup is run to update the list of friends (a computed for display field). This is achieved by binding a function-call to the windowclosing-event of the control.

I'm still not ready to release the demoapp. If I do that, I'm probably going to stop experimenting on the WebBrowser, and start mucking with XPages..