Welcome Guest, you are in: Login

Search:
This page is a considered complete and accurate. However, if you find an error, please take the time Contact Us report it.


In this short article we are going to learn how to write a simple formatter provider for ScrewTurn Wiki v.5 (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.

Common Methods and Properties

SignatureDescription
bool PerformPhase1 { get; }Specifies whether or not to execute Phase 1
bool PerformPhase2 { get; }Specifies whether or not to execute Phase 2
bool PerformPhase3 { get; }Specifies whether or not to execute Phase 3
int ExecutionPriority { get; }Gets the execution priority of the provider (0 lowest, 100 highest)
string Format(string raw, ContextInformation context, FormattingPhase phase)Performs a Formatting phase
string PrepareTitle(string title, ContextInformation context)Prepares the title of an item for display (always during phase 3)
bool HandleRequest(HttpContext context, Match urlMatch)Method called when the plugin must handle a HTTP request

Visual editor for plugins

The visual editor is built on CKEditor and is realised in the form of its plugins. It connects dynamically during the loading of editing page. The Visual plugin files are stored as resources in the wiki-plugin and their path replicates the actual structure of the CKEditor plugins.
To implement the editor in IFormatterProviderV40 interface, there is a number of methods and properties.

SignatureDescription
bool EnablePluginsEditor { get; }The availability of visual editor  is determined by EnablePluginsEditor option. If it is set as true, then the actual plagin will be connected to visual editor. It is important that all the other properties and methods concerned were properly implemented, otherwise it can break both pages and plagin as whole.
bool GetEditorsFile(string name, Stream destinationStream)Returns the file of the plugin in the CKEditor format. The parameter stores the name of the file and the virtual path of the folder of the plugin CKEditor. For example: rating/dialogs/rating.js or rating/images/image.gif. The method should recognize the path and return the desired file. Virtual path to the files of CKEditor plugin should replicate the real one
List PluginsEditroNames { get; }Returns the list of of supported visual plugins of CKEditor format
string WysiwygFormat(string raw, ContextInformation context, FormattingPhase phase)Implements direct (from wiki markup into html) page formatting for Wysiwyg-editor. This is the html format, but with some limitations connected with the work of the editor, simple control and editing. For example, picture in Wysiwyg-editor is displayed by img tag, whereas formatting the final page, this tag will be framed by several div and supplemented by other tags. When forming, the tags of the current plugin are determined by the presence of the  pluginid attribute, which stores the value of the property PluginId converted to the lower case.
bool WysiwygReverseFormat(XmlNode node, StringBuilder sb)Implements the reverse formatting - from html into formatting language of wiki. Calling this method occurs whenever in attribute pluginid of div element,  the code is met coinciding with the code from PluginId property. That is why it is very important that the plugin tags were marked with the pluginid attribute, which stores the value of the PluginId  property converted to lower case. The result of formatting is placed in the parameter sb.

The following global java script variables are created on the editing page for plugin's functioning:
CurrentPage –  the full name of the editing page
CurrentNamespace – current namespace
PageExtension – page extension
ServicePath – a path to service
IsInWYSIWYG – flag is set as true, if the current editor is Wysiwyg-editor
RootNamespaceName - name of root namespace

WikiService

For  java scripts functioning, there is WikiService implementing the  following methods:

SignatureDescription
string[] GetNamespaces()Return the array of  namespaces
string[] GetPages(string selectedNs)Return the array of pages names of the given namespace. The fully encoded name of the page is stored in the odd positions of the array, while the name of the page  - in  even ones
string[] GetFilesStorageProviders()Return the array of files storage providers. The full name of the provider type is stored in the odd positions of the array, while the name of the provider  -  in  even ones
string[] GetPageImages(string provider, string page)Return the array of images names attached to the given page through the selected provider
string[] GetPageAttachments(string page)Return the array of files names attached to the given page
string[] GetSnippets()Return the array of  snippets
string[] GetDirectories(string path)Return the array of subdirectories in selected directory
string[] GetFiles(string path)Return the array of files
string[] GetImages(string path)Return the array of images


Examples of call method of service

The examples of call method of service from java script plugins are indicated below:

1. The call method without parameters is realized as stated below.  In this example, the call is initiated in the method of the  CKEditor component, the result is applied to it.
$.ajax({
context: this,
type: "POST",
url: ServicePath + 'GetNamespaces',
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
  var t = this;
  t.clear();
  for (var ii = 0; ii < response.d.length; ii += 2) {
   t.add(response.d[ii + 1], response.d[ii]);
  }
  t.setValue(curNs);
},
async: false,
error: function (data) {
  var message = "Error";
  if (typeof data !== "undefined")
   message += ": " + data.message;
  alert(message);
},
});

2. The call method with parameters is realized in the following way. In this case, the selected value of the CKEditor current component is used as a parameter. The result is filled in another component of the CKEditor.
$.ajax({
context: this,
type: "POST",
url: ServicePath + 'GetPages',
data: "{ selectedNs: '" + this.getValue() + "' }",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
  var t = this.getDialog().getContentElement('info', 'wikiPages');
  t.clear();
  for (var ii = 0; ii < response.d.length; ii += 2) {
   t.add(response.d[ii + 1], response.d[ii]);
  }
  if (page && page.length > 0) {
   t.setValue(page);
  }
},
async: false,
error: function (data) {
  var message = "Error";
  if (typeof data !== "undefined")
   message += ": " + data.message;
  alert(message);
},
});

 

Examples

Example of Formatter's Plugin

Example of Formatter's Plugin with visual-editor

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