Vanilla 1 Documentation Archive

 
 
vanilla:development:formatters
Table of Contents

Formatters

Click here to go back to the previous section: Order of Execution

Please note that this documentation relates to Vanilla 1

StringFormatters are used to parse user-entered comments in Vanilla. You can create custom StringFormatters for use in your installation of Vanilla so that your users can post their comments in a variety of ways. Some StringFormatters that have been written are HTML (allows some basic html to be written and rendered), Markdown, Textile, and BBCode.

The Context object contains a StringManipulator class that manages these StringFormatters. The StringFormatters are used to change the way that user comments are formatted for display on the screen, or for saving to the database.

By the time any extension is included in the page, the Context class has already been instantiated and created an instance of the StringManipulator class. The StringManipulator also has a TextFormatter class created, instantiated, and added to it’s Formatter collection. This TextFormatter is used as the default formatter in Vanilla. Through it’s parse method, the TextFormatter only performs some simple newline to html-line-break transformations.

The TextFormatter extends the StringFormatter class, which means that it inherits all the same properties and methods as the StringFormatter class. The TextFormatter can be found in library/Framework/Framework.Class.StringManipulator.php. Let’s take a look at the TextFormatter in detail:

TextFormatter Properties

Property Description
ChildFormatters Inherited from StringFormatter, this is an array of Formatter objects. Useless to the TextFormatter, but could be useful for extension writers if they wanted to add other formatters to their own formatter so they can pass strings through numerous formatters at the same time.

TextFormatter Methods

Method Description
Constructor Inherited from StringFormatter, this is a manual constructor - meant to be called from any class that extends StringFormatter from the actual constructor.
ParseChildren Inherited from StringFormatter. Again, this is useless to TextFormatter because it contains no other formatters, but this is the method that extension writers can call to execute the parse method on child formatters and return their resultant string.
Parse Inherited from StringFormatter and overridden to perform custom formatting methods.

In particular, let’s take a look at the Parse method, which is what the StringManipulator will pass user data into:

function Parse ($String, $Object, $FormatPurpose) {
	$sReturn = $String;
	// Only format plain text strings if they are being displayed (save in database as is)
	if ($FormatPurpose == FORMAT_STRING_FOR_DISPLAY) {
		$sReturn = htmlspecialchars($sReturn);
		$sReturn = str_replace("\r\n", '<br />', $sReturn);
	} else {
		// You'd think I should be formatting the string for safe database
		// input here, but I don't want to leave that in the hands of plugin
		// authors. So, I perform that in the validation call on the comment
		// object when it is being saved (CommentManager->SaveComment)
	}
	$sReturn = $this->ParseChildren($sReturn, $Object, $FormatPurpose);
	return $sReturn;
}
Parameter Description
String The string being passed in for formatting. Unless an extension author wants to use a Formatter for a different purpose, 99% of the time this will be a user comment. This comment may be coming from a form submission, or it may be coming directly out of the database - depending on the FormatPurpose supplied.
Object An object that an extension author may want to use when formatting the string. Again, 99% of the time this will be the Comment object. The comment object was chosen just in case an extension writer wanted access to any information about the comment (like the author’s name and UserID).
FormatPurpose There are two constants defined in the appg/settings.php file that describe FormatPurpose: FORMAT_STRING_FOR_DISPLAY and FORMAT_STRING_FOR_DATABASE. If this value of FormatPurpose is FORMAT_STRING_FOR_DISPLAY, then the string being passed into this method has already been saved to the database and now needs to be formatted for display on the screen. If the value of FormatPurpose is FORMAT_STRING_FOR_DATABASE, then the string being passed into this method has just come from a form-post and will be saved to the database next.

It is very important to understand the difference between FORMAT_STRING_FOR_DISPLAY and FORMAT_STRING_FOR_DATABASE. For example, In my TextFormatter I only do formatting on the string if the string is being formatted for display. If I were to perform this translation regardless of FormatPurpose, the next time a user went to edit their comment, they wouldn’t see what they had originally written, instead they’d see the formatted version.

It is also important to note (as I mentioned in the comments of the TextFormatter source) that although I call it FORMAT_STRING_FOR_DATABASE, you do not need to account for database insertion with addslashes. This formatting is purely for the purpose of changing the look and feel of user comments.

Making Your Own Formatter

One of the very first formatting requests I received was for John Gruber's Markdown. After doing a little research on the web, I came across Michel Fortin's PHP version of Markdown. So, I grabbed Michel’s version of PHP Markdown and copied it to an empty file. I renamed the file default.php and placed it in a Markdown folder within the extensions directory.

All extensions need to be identified so that Vanilla knows what they are, I do this with simple PHP comments at the top of the file. Any extension MUST contain this information at the top of the file:

<?php
/*
Extension Name: Your Extension Name Here
Extension Url: The url to where this extension can be downloaded
Description: A description of your extension
Version: The current version of your extension
Author: Your Name
Author Url: Your personal url
*/

For my purposes with the MarkdownFormatter, I added the following to the top of my extension file:

<?php
/*
Extension Name: Markdown
Extension Url: http://www.michelf.com/projects/php-markdown/
Description: A text-to-HTML conversion tool for discussion comments
Version: 1.0.1a
Author: Michel Fortin (PHP Version), John Gruber (Original Markdown)
Author Url: http://www.michelf.com/
 
I've altered the original markdown a wee bit to fit into Vanilla. Many thanks to John Gruber and Michel Fortin.
- Mark O'Sullivan 2005-06-04
*/

Please Note: The MarkdownFormatter can be found in extensions/Markdown/default.php

From that point forward, it got really easy. I began by implementing a new extended StringFormatter called MarkdownFormatter:

// Create a simple interface for the markdown plugin
class MarkdownFormatter extends StringFormatter {

Up next I wanted to override the StringFormatter’s default Parse method with a Parse method of my own that accessed Michel Fortin’s Markdown function, like this:

function Parse($String, $Object, $FormatPurpose) {
	if ($FormatPurpose == FORMAT_STRING_FOR_DISPLAY) {
		return Markdown($String);
	} else {
		return $String;
	}
}

You’ll again note that I didn’t do any transformation on the string if it is being saved to the database. I actually think it will be very rare that anyone will ever want to perform any manipulations on comments before they go to the database, but I wanted to leave the option there for extension authors because you never know what people will want to do.

Once that code was in place, I closed my class definition with a trailing curly brace and I was done. However, I quickly discovered that Markdown allows straight HTML. I guess this is because it makes the assumption that whoever is using it will not want to muck things up. But on a forum of any kind, leaving straight HTML in comments is a very dangerous thing. It allows hackers to add in all kinds of malicious code to do things like get at your cookies. So, I created a new method to handle stripping html out of the string and altered my parse method a little bit. In the end my entire MarkdownFormatter looked like this:

class MarkdownFormatter extends StringFormatter {
	function Parse($String, $Object, $FormatPurpose) {
		if ($FormatPurpose == FORMAT_STRING_FOR_DISPLAY) {
			$String = $this->ProtectString($String);
			return Markdown($String);
		} else {
			return $String;
		}
	}
	function ProtectString ($String) {
		$String = str_replace("<", "&lt;", $String);
		return $String;
	}
}

Now that I had my MarkdownFormatter class ready to go, I needed to get it into the StringManipulator object so that it would be added to the page and referenced properly whenever required. I did it with the following code:

// Instantiate the MarkdownFormatter class
$MarkdownFormatter = $Context->ObjectFactory->NewObject($Context, "MarkdownFormatter");
// Add the MarkdownFormatter object to the StringManipulator Formatters array
$Context->StringManipulator->AddManipulator("Markdown", $MarkdownFormatter);

There are a couple of things to note about the StringManipulator’s AddManipulator method. First of all, notice that I specify a plain-text “Markdown” string as the first value. This string is what the StringManipulator will store in the database as the FormatMethod. So, when the application pulls the saved comment from the database, it will again know to use the Markdown formatter on the comments. If the Markdown formatter has since been disabled, the StringManipulator will default to using the TextFormatter on the comments.

This “Markdown” parameter is also used by the language dictionary as the code to be translated. Since Markdown in English is simply Markdown, I didn’t add any code to the English language definitions file. If someone else comes along and uses the Markdown extension in a non-English version of Vanilla, they can add a custom definition of the “Markdown” code to their conf/language.php file.

Finally, below my extension description, and below my MarkdownFormatter, and below the code where I instantiated my MarkdownFormatter and added it to the Context object’s StringManipulator, I included Michel Fortin’s Markdown code.

Then I signed into Vanilla, found Markdown in the extension list at Settings > Manage Extensions, and enabled it. Ta-Da: Markdown support for Vanilla.


Click here to read the next section on developing new extensions: The Panel

 
 
 
 
vanilla/development/formatters.txt · Last modified: 2009/03/28 14:19
Vanilla 1 Documentation archive (Wiki by DokuWiki)