Building a wiki - Part 2

In part 1, we have built the foundation of our application by creating the basic wiki page. In this part, we will improve the wiki by adding some new features.

Formatting

Right now, our wiki is pretty basic. If we want any formatting to be performed, we would have to write the HTML into the edit box, which will cause it to be rendered.

Textile

In order to facilitate wiki style formatting, we will use a custom control. This control will use Textile (http://textile.thresholdstate.com) to output HTML based on simple text formatting. Luckely, a control which integrates Textile with QCubed already exists: http://www.qcodocoder.com/node/2 In order to install it, we need to

  • download textile and put the into our includes directory
  • download the QTextileLabel.class.php and put it into our includes/qcodo/qform directory.

Let's do so...

QTextileLabel.class.php:

include __INCLUDES__ . "/textile/classTextile.php";


class QTextileLabel extends QLabel {
 
  protected $blnHtmlEntities = false;
  protected $blnTextileText = true;
 
  protected function GetControlHtml() {
    $strStyle = $this->GetStyleAttributes();
 
    if ($strStyle)
    $strStyle = sprintf('style="%s"', $strStyle);
 
    if ($this->strFormat)
    $strText = sprintf($this->strFormat, $this->strText);
    else
    $strText = $this->strText;
 
    if ($this->blnTextileText) {
      $textile = new Textile();
      $strText = $textile->TextileThis($strText);
    }
 
    $strTemplateEvaluated = '';
    if ($this->strTemplate) {
      global $_CONTROL;
      $objCurrentControl = $_CONTROL;
      $_CONTROL = $this;
      $strTemplateEvaluated = $this->objForm->EvaluateTemplate($this->strTemplate);
      $_CONTROL = $objCurrentControl;
    }
 
    $strToReturn = sprintf('<%s id="%s" %s%s>%s%s%s</%s>',
    $this->strTagName,
    $this->strControlId,
    $this->GetAttributes(),
    $strStyle,
    ($this->blnHtmlEntities) ? QApplication::HtmlEntities($strText) : $strText,
    $strTemplateEvaluated,
    ($this->blnAutoRenderChildren) ? $this->RenderChildren(false) : '',
    $this->strTagName);
 
    return $strToReturn;
  }
 
  public function __get($strName) {
    switch ($strName) {
      case "TextileText": return $this->blnTextileText;
      default:
        try {
          return parent::__get($strName);
        } catch (QCallerException $objExc) {
          $objExc->IncrementOffset();
          throw $objExc;
        }
    }
  }
 
 
  public function __set($strName, $mixValue) {
    $this->blnModified = true;
    switch ($strName) {
      // APPEARANCE
      case "TextileText":
        try {
          $this->blnTextileText = QType::Cast($mixValue, QType::Boolean);
          break;
        } catch (QInvalidCastException $objExc) {
          $objExc->IncrementOffset();
          throw $objExc;
        }
 
      default:
        try {
          parent::__set($strName, $mixValue);
        } catch (QCallerException $objExc) {
          $objExc->IncrementOffset();
          throw $objExc;
        }
        break;
    }
 
  }
 
}

When both classTextile.php and QTextileLabel.class.php have been put in their proper location, we can use the Label.

For our wiki, we want the Label lblContents to be a QTextileLabel, as this is where the conversion of the database contents (text) to HTML occurs. To do this, simply replace the object of the lblContents from QLabel to QTextileLabel:

$this->lblContents = new QTextileLabel($this);

After this, any textile formatting will be converted to proper HTML. Let's try: Go to the wiki, and edit the contents of the start page to something like:

h1. *Welcome to our Wiki*
_this text should be cursive_
+underlined+

This should display the text "welcome to our wiki" in bold, the next line cursive and the text underlined should be underlined .

Layout

CSS

Our wiki currently uses the default css file that was provided with QCubed. We can change the layout of our wiki to fit our needs by changing the styles defined in the css file, or by applying a complete new CSS. To easy the implementation of the CSS, we have retrieved a basic version from the open wiki project (http://www.openwiki.com/). The css for the openwiki project is release under BSD license, and can be found at http://www.openwiki.com/ow.css?3 . We shall put this file (ow.css) into our assets/css folder. To load the CSS, we change the template to load the ow.css instead of the default style.css:

<style type="text/css">@import url("<?php _p(__VIRTUAL_DIRECTORY__ . __CSS_ASSETS__); ?>/ow.css");</style>

Some little fine tuning may be needed later, but for now, let's take this CSS as it is. As a result of changing the CSS, the layout of the textbox where we edit the wiki contents changed: it now has fixed font (which is actually better), the backgroundcolor is gone and the height and width are adjusted. Except for the height of the textbox, everything is acceptable as a change. To modify the height of the textbox, we will tell the textbox to render 20 rows by adding the following line in the Form_Create:

$this->txtEditContents->Rows = 20;

Some simple navigation will help the usability of the wiki. We shoud add at least the possibility to go back to the "home" page, as well as to the previous page. We can do this by simply adding the required HTML to the template file wiki.tpl.php, just below the current

<? $this->RenderBegin(); ?>:

<a href="wiki.php?page=WikiStart">Home</a> | <a href="javascript:history.back();">Back to previous page</a>  
<hr>

Adding Ajax

Another feature of our wiki would be to not have to perform a page refresh when we edit and save our wiki page. To enable ajax, simply change all "QServerAction" occurances into "QAjaxAction":

$this->btnEditPage->AddAction(new QClickEvent(), new QAjaxAction('btnEditPage_Click'));
...
		  $this->btnSavePage->AddAction(new QClickEvent(), new QAjaxAction('btnSavePage_Click'));
...
		  $this->btnCancelEdit->AddAction(new QClickEvent(), new QAjaxAction('btnCancelEdit_Click'));

This will cause the whole application to support Ajax!

We also should have some kind of an indication that the ajax request is being processed when we perform an action. QCubed forms already have a "default" wait icon member variable. The only thin we need to do is initialize it. Add this to your Form_Create() function of wiki.php:

$this->objDefaultWaitIcon = new QWaitIcon($this);

Next, render the control in the template at the location you want, for example:

<? $this->lblTitle->Render(); ?> <? $this->objDefaultWaitIcon->Render() ?><br>

Putting the wiki to test

To test this wiki, we will... well, insert this tutorial into the wiki! Let's see how it goes, and find my remarks in the next tutorial...