More wiki 07 May 2004
Ah yes, my “train project”… well, I have become somewhat disheartened twiddling around in BeeWiki, and may have to knock it on the head. The database has some nice pages and functionality, but one potential show-stopper — which initially I thought I could overcome — has kicked me in the nadgers:
The key issue with BeeWiki is that it uses a Java agent to render its content. This agent in turn uses the gnu.regexp package (java.util.regexp comes with J2SE 1.4.x so no joy there for Notes 5 / 6), and as a result, any code using said package is classed as Java that needs signing by an ID capable of running unrestricted agents. This makes it impractical for most Domino shops, even though regexp processing is a pretty benign activity. I tell you, it’s at times like this I find myself going off Domino…!
Anyway, back to wiki-style regexp processing. I have cobbled together a load of Javascript, invoked via onLoad(), which renders wiki markup to HTML. So far my fledgeling Javascript can do the following:
- Convert text tagged ~some text~ to <em>some text</em>
- Convert text tagged #some text# to <strong>some text</strong>
- Convert text tagged _some text_ to an <h3> header
- Convert URLs into links
- Convert so-called WikiText (i.e. two or more proper case words mashed-together) to links
- Wrap text tagged *some text thus: <li>some text</li> tags
The more problematic element of all this is converting line feed and carriage return characters to paragraph tags in the appropriate places, especially when combined with my list tag. Ho hum, I may soldier on for a bit more with that — or p’raps implement it all in @formula!
One of the pieces of code I’m more proud of is a computed (using @formula) Javascript onLoad() event in a $$ReturnGeneralError form, to intercept clicks on WikiLinks which haven’t yet been created.
What do I mean by that? Well, in a wiki, WikiLinks get created automagically, but there aren’t necessarily underlying pages for those links at the time of their creation. The wiki deals with this by making the link either an actual link to the page, or a link to create said page. For on-the-fly rendering in Domino (without Java) this is a little tricky, because working with WikiLinks means that a URL fragment like this:
http://server/path.nsf/Pages/WikiPage?Open
gives a 404 if that page hasn’t yet been created. So, my Javascript routine intercepts this, and changes the window.location to something like this:
http://server/path.nsf/WikiFormName?OpenForm&Title=WikiPage
It works really well, although there is of course one caveat: ideally the system shouldn’t try to re-direct to a page creation URL like this when the 404 error generated is for something entirely unrelated!
Crikey, this post is rambling stream of consciousness. I doubt it’s even remotely useful. Oh well. I will be posting the relevant code snippets somewhere on this site soon. In fact, I have quite a few things to post here — my LinkedArray and FormValidator classes, plus an article I wrote for the soon-to-be-gone e-Pro Magazine for example. Sigh. A wee wiki would be perfect for all of that… Bah!
I guess the next train project is a regular expression class for Lotusscript… or has someone already done it? LOL!
Further reading: Mike Golding: Processing HTML using Regular Expressions.
:-)
Jason Bell#
In the meantime, because of the security restriction with Java in Domino, I have switched the rendering engine to one based upon Jen-Christian Fischer’s (http://blog.invisible.ch) NotesWiki.
Wiki markup conversion in Lotusscript?!? Yes, it really is possible, and not bad on the performance front either, which surprised me. In fact, the template is shaping up quite nicely, and I’ll release it soon.Ben Poole#
I decided to use the old version.
The ORO Matcher is the way to go. After testing I found it was quicker of free regular expression libraries so I decided to use it as the basis for my own tag templating system for Domino.
I adore regular expressions and use the following for testing them:
"The Regulator"
http://royo.is-a-geek.com/iserializable/regulator/
It integrates with a web service at http://www.regexplib.com/ which is a reasonable source of regular expression examples some need a little tweaking though.
Ben, what do you mean by "train project" ?
John Marshall#
http://www.regular-expressions.info
Now then, “train project”: my job involves a 45 minute commute into London, so occasionally I code on the train in lieu of reading a book or sleeping :-) Ben Poole#
Recently (as part of the ZAPPATA Personal Groupware project), I have coded a Textile parser / renderer in Java. Even with the power of RegExps, it *is* difficult to decide where to put the break and the paragraph tags.
ZTextile (as we call it) may be released unter the LGPL … If we find time to clean it up etc…Jens-Christian Fischer#
Option Public
Option Explicit
Class RegExp
''' RegExp -- use VBScript RegExp object to provide regular expressions
'
' 2004-06-03 David Phillips, rfdinc.com First version.
Public matches As Variant
Public oRegExp As Variant
' VBScript RegExp properties
Public Pattern As String
Public IgnoreCase As Boolean ' default = False
Public Global As Boolean ' default = False
Sub new ()
Set oRegExp = CreateObject ("VBScript.RegExp")
End Sub
Public Function Match (source As String, pattern As String, matches As Variant) As Boolean
' RegEx.Match -- scan source for pattern, set matches collection and return true if any
' (Can't call it Execute as that collides with LotusScript built-in function and statement.)
With oRegExp
.Pattern = pattern ' regular expression to match
.IgnoreCase = IgnoreCase
.Global = Global
Set matches = .Execute (source) ' do match
Match = (Not 0 = matches.count)
End With
End Function
Public Function Replaces (source As String, pattern As String, replacement As String) As String
' RegEx.Replaces -- scan source for pattern, if found substitute replacement, return result
' (Can't call it Replace as that collides with LotusScript built-in function.)
With oRegExp
.Pattern = pattern
.IgnoreCase = IgnoreCase
.Global = Global
Replaces = .Replace (source, replacement) ' do replace
End With
End Function
Public Function Test (source As String, pattern As String) As Boolean
' RegEx.Test -- scan source for pattern, return true if found
With oRegExp
.Pattern = pattern
.IgnoreCase = IgnoreCase
Test = .Test (source)
End With
End Function
End Class
Sub test_RegExp
' Include Use "RegExp" in Options section to refer to an external script library.
Dim re As New RegExp
' Pattern matching defaults to case sensitive.
Dim test As Boolean
test = re.Test ("ABC", "b")
msgbox "'ABC' contains 'b' (case sensitive) = " & test
re.IgnoreCase = True
test = re.Test ("ABC", "b")
msgbox "'ABC' contains 'b' (case insensitive) = " & test
' Match returns success indication.
test = re.Match ("xyz", "a")
msgbox "'xyz' has a match for 'a' = " & test
' Global defaults to False; = return first match only.
Dim count As Integer
test = re.Match ("them these theirs", "e")
' Match returns successful matches as a collection property.
count = re.matches.count
msgbox "'them these theirs' with Global = false matches 'e' " & count & " time."
re.Global = True
test = re.Match ("them these theirs", "the[a-z]+")
Dim position As Integer
Dim length As Integer
Dim s As String
dim msg as string
Forall m In re.matches
position = m.FirstIndex ' zero-based
length = m.Length
s = m.Value
msg = msg & "Match at position " & position & ". " & length & " character string = " & s & chr (10)
End Forall
msgbox msg
' Replaces returns source string with any successful replacement.
s = re.Replaces (s1, "([a-z]*)\W(\w*)\s(\S*)", "$3 $2 $1")
msgbox "Change 'them these theirs' to '" & s & "'."
End Sub
Keywords: RegEx, regular expression, Perl, PCRE (Perl Compatible Regular Expression), POSIX 1002.3, VBScript, LotusScript.David Phillips#