UNDER CONSTRUCTION
At the end of part 2, we had a pretty functional forum going. But we're still missing a good way to discover the topic's originator (using page.author isn't reliable, since someone else other than the original author may have edited the page last.) And there's room for our topic pages to look nicer and more "forum-like". So let's get to it.
Finding the Topic's Originator
As we've said, the page.author field for a particular page only tells you the person who last edited the page, not the first. So we'll need to do a little digging to get the correct answer.
In general, just about any information you could ask for from Deki is available from the API, though it's not nearly as convenient to use from within Dekiscript as the built-in wiki variables. But it can be done (with some caveats, as we'll see).
So how do we find the originator? Well, we know that the wiki remembers all revisions to each page. Therefore, if we could find information about the first revision of a page, then its author should be the topic's originator. Browsing through the list of API functions (focusing on the "GET" calls), we find GET:pages/{pageid}/revisions. That sounds promising. Indeed, this call returns the revision history for a given page, which is exactly what we want. All we need to do is figure out how to get the author of the first revision.
It seems like we've solved our problem, but in fact there's a huge "gotcha" that completely pulls the rug out from under this approach. It concerns authorization.
If a wiki is private, or the page is restricted, then the page's API calls require authentication. Unfortunately (as of 8.08), Dekiscript is unable to provide this authentication, even though the viewer of the page might be fully authorized. As a result, the API call will return no data.
This means that our API code only works if the wiki is open and the page is public. That may be fine in some cases, but certainly not the general case, and if possible we'd prefer our code to be universal. So let's try again.
So we've learned that an API-based approach won't work for our application, but we know that the API is the best (and sometimes only) way to get complete information about a page. Are we stuck? Of course not!
One thing we definitely can do is access the page variable and the page contents (via wiki.page() or page.xml) of other pages; we're already doing that with no problems, even on private pages. We can exploit this capability to solve our problem by embedding our desired information in the page contents. It would be preferable to do this automatically, with no user intervention. Thus we introduce the ForumTopic template.
Our goals for the ForumTopic template will be two-fold:
In order to actually call this template whenever a new topic is created, we need to add it as an argument to the wiki.create() call in ForumTopicList:
{{wiki.create("Create New Topic",homepath,'ForumTopic',true,"Put Your Title Here")}}
We'd like to do this automatically, so it's not subject to user error. Dekiscript provides a means to insert data onto a page when the editor is opened, like this:
{{ edit: <dekiscript code goes here> }}
When the page is opened in the editor, the Dekiscript is evaluated, and then the results are inserted directly into the editor. The standard way to use this would be to put this code in a template, and then when wiki.create() is called with that template, the desired data will automagically appear.
In our case, we want to remember the originator, which is easy to figure out because it is the current user when the page is created and the editor is opened. It is also nice to see this on the topic page itself (last revision won't tell you who created it in the first place), so we'll kill two birds with one stone. So, we will put this code in the ForumTopic template:
{{ edit: web.link(user.uri, user.name) }}
Now the editor will open with a nice link to the user, and we'll grab this whole chunk of HTML for use in the topic list. How will we be able to fetch that from the page later? There are many possibilities, but in this case we'll wrap it in an easily findable <span> like this (we're in source view now):
<span id="originator">{{ edit: web.link(user.uri, user.name) }}</span>
To fetch this whole shebang and save it to the topiclist, we need only modify our foreach loop like this:
foreach (var p in homepage.subpages) {
var originator = wiki.page(topicPath)['//span[id=\'originator\']'];
...
let topiclist ..= [ { page:p, originator:originator, author:lastauthor, type:lasttype, date:date.format(lastupdate, 's') } ];
}
Note that we've encountered the need for a third level of quoting, so we've escaped the innermost single-quotes in the xpath up top.
Now, inside the "author" column of the ForumTopicList table, we simply put:
{{ t.originator }}
One other thing we'd like to store on the topic page is the creation date. By that, we mean the time when the page is saved. This time should be almost equal (or maybe exactly equal) to the timestamp of the first revision. How can we do this automatically?
Well, we could include a script that'd use the revisions API call to find the date of first revision, but we've already realized that won't work well (or at all) on restricted pages or wikis. Therefore, we'll find a way to insert this information directly onto the page.
What if we used the "edit:" modifier, as above, and put this in our template:
{{ edit: date.now }}
That's close, but it'll actually yield the time when the page is opened, not when it's saved. That may be satisfactory, but it's not what we're truly aiming for, so let's see if we can do better.
Deki provides another modifier for scripts: "save:". This is sort of like the "edit:" modifier, but it evaluates the code and substitutes the results when the page is saved from the editor. So, if you typed this into the editor:
{{ save: date.now }}
then when you hit the save button, the current time and date will be saved to the page. That sounds close to what we want. Making it work inside the ForumTopic template, however, requires a bit of trickery. The problem is, we want the above code to appear in the editor when a ForumTopic page is created. If we simply type that into our template, though, it'll execute the "save:" functionality right then and there (try it if this isn't clear). What we really want, then, is a way to generate the above code when our page is opened in the editor:
{{ edit: "{{ save: date.now }}" }}
We can safely create this code while editing the template, and it'll save it as-is. When a new page is created with the ForumTopic template, the "edit:" modifier will kick in, and the code to the right will be inserted into the editor. Then, when the page is saved, the "save:" modifier will activate, and you'll have the time the page is saved stored in the page. Voila!
This is a rather strange and special-purpose piece of code, but it is compact and effective, and shows how you can make Dekiscript do your bidding when you bring all its capabilities to bear.
There are a few other things we'll add to the ForumTopic template. First, some formatting to keep the automatically-generated content clearly separated from the user-generated content.
Next, when using a discussion forum it's nice to be able to track a particular topic. Deki gives the ability to get an RSS feed for each wiki page, but the link is not made available by default on the page. So we'll add this to our template:
{{ web.link(page.feed, "Track this page") }}
Finally, I have found that it is useful to provide instructions on structured pages so that novice users have an idea what to do. Deki provides as facility to make instructions appear only when the editor is opened:
<span class="comment"> ...everything in here will only appear in the editor...
</span>
My typical approach is to very clearly separate the instructions from everything else, so I put them in a big red box. One caveat: you want to make sure that the user doesn't inadvertently add his or her content inside the comment span, so always put an extra line break after the comment, and put in a placeholder for their content that they can overwrite.
We now have fully-functional forum code, which you can demo here. Everything works quite nicely, and we could easily stop here and be satisfied. Because there are more nooks and crannies in Dekiscript to explore, though, we'll add a few unnecessary-but-cool final features in part 4.
One glaring omission from this template is the ability to track the entire forum, either by feed or by email notification. As of version 8.08.1, Deki does not provide a tracking mechanism for a hierarchy of pages. There are three kinds of feeds available:
None of these does the job if, for example, I'd like to learn of any new activity on my forum, be it comments, new postings, or edits. Unfortunately, there is no clear solution right now, so if this capability is critical to your usage, then stick with a real forum.
For casual applications, though, you can get a lot of use out of these templates. In the future, when Deki adds better tracking capabilities, this will become a non-issue.