ScrewTurn Wiki 4 Releases and News
Screwturn Compatible Hosting – Click Here for 3 Months Free!
G+ Twitter          Search: »
Amanuens
ScrewTurn Wiki
This page is a considered complete and accurate. However, if you find an error, please take the time report it.

In this short article we are going to learn how to write a simple formatter provider for ScrewTurn Wiki 3.0 (STW from now on). A formatter provider is a type of plugin that processes and alters page content.

For this article, we’ll use the Download Counter plugin (available in the standard distributions of STW) as an example.

Introduction to Formatter Providers

This brief section assumes you have already a general knowledge on STW providers.

The main task a formatter provider performs is processing the content that the wiki engine hands to it during one or more of the following phases, performed sequentially:

  • Phase 1: performed before the wiki engine formats the content with its own formatter.
    This phase is suitable to process custom tags, markup or other content that might be otherwise misinterpreted by the integrated formatter; overriding the behavior of existing tags is also possible.
  • Phase 2: performed after the wiki engine formats the content with its own formatter.
    This phase is suitable for processing custom tags that do not conflict with the built-in markup.
    Note: the result of Phase 1 + Phase 2 is cached: those phases are not executed again until the cache is refreshed.
  • Phase 3: performed before sending the content to the browser, at every web request.
    This phase is suitable to process tags whose output is dynamic and potentially changes at every request.

The formatter is allowed to declare which phase(s) it must execute, so that formatters execution is optimized. The formatter is also allowed to alter the title of pages before they are sent to the browser (in other words, title formatting is only performed in Phase 3). Last but not least, the formatter can declare its execution priority (0 to 100, 100 highest) that ultimately determines the execution order of all installed formatters.

Important note: all providers should be totally thread-safe.

Download Counter Mini Specification

The formatter is used for displaying the number of times a set of files and/or attachments has been downloaded.

Input

The formatter parses the page content during Phase 3, looking for pieces of XML formed like the following:

<countDownloads pattern="..."[ startDate="yyyy/mm/dd"]>
    <file name="..."[ provider="..."] />
    <attachment name="..." page="..."[ provider="..."] />
</countDownloads>

The pattern attribute determines the output text of the formatter. It can contain any string and any of the following placeholders (case insensitive):

  • #COUNT#: total download count
  • #DAILY#: downloads per day
  • #WEEKLY#: downloads per week
  • #MONTHLY#: downloads per month.

startDate is the date used for calculating the daily, weekly and monthly downloads values. If omitted, January 1st, 2009 is assumed.

The countDownloads root tag can contain one or more file and attachment elements. The name attribute is respectively the full name of the file or the name of the attachment. The optional provider attribute is the full type name of the files storage provider that manages the file or attachment. If omitted, the default provider is assumed. For attachment elements, the page attribute specifies the name of the page the attachment belongs to.

Output

The output of the formatter is determined by the pattern attribute. The pattern string will be rendered, replacing the placeholders with their respective calculated values.

For example, a pattern string formed as follows:

Downloads: #count# (#weekly# downloads per week)

Would generate an output like this:

Downloads: 1234 (45 downloads per week)

Input Error Handling and Configuration

If a specified file or attachment does not exist (or any other parameter is invalid), the element is ignored and a warning message logged for debugging purposes.

If the configuration string equals "nolog" (case insensitive), then no messages are logged.

Implementation

The implementation of the Download Counter plugin is relatively easy. The required steps are described in the following sections. To see the final result, you can download the source code package of STW.

Environment Setup

Assuming you have Visual Studio 2008 Standard or Professional installed on your development machine, download the source code of STW and unpack it on your hard drive.

  1. Open the solution in Visual Studio (ScrewTurnWiki.sln)
  2. add a new C# Class Library project, named MyPlugins
  3. for the new project, add a reference to the PluginFramework project, already part of the solution
  4. also add a reference to System.Xml (for processing XML) and to System.Web (required by the Plugin Framework).

Generating a Stub

You can now add a class to the MyPlugins project, named DownloadCounter. The class should implement the IFormatterProviderV30 interface, defined in the ScrewTurn.Wiki.PluginFramework namespace:

public class DownloadCounter : IFormatterProviderV30 {
}

You can now use Visual Studio to automatically implement the interface with empty methods (omitted for brevity).

Filling in Required Information

As previously said, our formatter will work in Phase 3, so the PerformPhase1 and PerformPhase2 properties should both return false, while PerformPhase3 should return true.

Execution priority is not important in this case, thus the ExecutionPriority property should simply return 50 (midway between 0 and 100).

The Init method should set the enableLogging flag accordingly to the configuration string:

public void Init(IHostV30 host, string config) {
    this.host = host;
    this.config = config != null ? config : "";

    if(this.config.ToLowerInvariant() == "nolog") enableLogging = false;
}

The PrepareTitle method should simply return the title parameter unchanged because the formatter will not process titles.

You can set the ConfigHelpHtml property to return a brief help text such as:

"Specify <i>nolog</i> for disabling warning log messages for non-existent files or attachments."

Also, properly return an instance of ComponentInformation in the Information property.

Implementing the Formatter

The main formatter method, Format, can now be implemented as follows:

public string Format(string raw, ContextInformation context, FormattingPhase phase) {
    StringBuilder buffer = new StringBuilder(raw);

    KeyValuePair<int, string> block = FindAndRemoveFirstOccurrence(buffer);

    while(block.Key != -1) {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(block.Value);

        string pattern;
        DateTime startDate;
        GetRootAttributes(doc, out pattern, out startDate);

        double downloads = CountAllDownloads(doc);

        double timeSpanInDays = (DateTime.Now - startDate).TotalDays;
        int dailyDownloads = (int)Math.Round(downloads / timeSpanInDays);
        int weeklyDownloads = (int)Math.Round(downloads / (timeSpanInDays / 7D));
        int monthlyDownloads = (int)Math.Round(downloads / (timeSpanInDays / 30D));

        buffer.Insert(block.Key,
            BuildResult(pattern, (int)downloads, dailyDownloads, weeklyDownloads, monthlyDownloads));

        block = FindAndRemoveFirstOccurrence(buffer);
    }

    return buffer.ToString();
}

As you can see from the code, the Format method looks for countDownloads tag pairs and replaces them with the appropriate output string. Implementation details are not relevant for this article and are therefore omitted for brevity. It is however important to know how the plugin can interact with the wiki engine via the IHostV30 interface: in this case, the GetProvider method is used to retrieve an instance of the proper files storage provider as file or attachment elements are processed:

private IFilesStorageProviderV30 GetProvider(string provider) {
    if(string.IsNullOrEmpty(provider)) provider =
        host.GetSettingValue(SettingName.DefaultFilesStorageProvider);

    provider = provider.ToLowerInvariant();

    IFilesStorageProviderV30[] all = host.GetFilesStorageProviders(true);

    foreach(IFilesStorageProviderV30 prov in all) {
        if(prov.GetType().FullName.ToLowerInvariant() == provider) return prov;
    }

    LogWarning("Provider " + provider + " not found");

    return null;
}

The host class instance variable, set in the Init method, allows access to a number of methods and properties that, in this case, are used to get the existing files storage providers and the default one. For details about the IHostV30 interface, please take a look at the ScrewTurnWiki.chm file included in the source code distribution.

Deployment

Once compiled, the formatter is essentially a .NET class library file: MyPlugins.dll. You can upload it on your wiki using the administration interface, Plugins tab, and it will be immediately operational.

Side Projects

  • RESX Synchronizer allows to synchronize multi-language .resx files (used for the development of ScrewTurn Wiki).
  • Pixel Picker enables to pick the color of pixels on your screen — very handy for day-to-day graphics-related activities.

About

  • See our Privacy Policy.
  • Powered by ScrewTurn Wiki 3.0.5.613.
  • This namespace contains 11 pages.