You want to create a new rule, to convert from a specific wiki syntax to another syntax markup. In summary, here what you should do:
WikiRendererConfig
(or from one of an existing rule).Don't hesitate to open a rule file, to see how it is organized.
In a wiki syntax, or in other markup language such HTML, we have two type of tag:
display:block;
. We will
call them, "block tags".To summary, inline tags are used inside sentences, and block tags are use outside sentence, to specify the type of the content.
To implement a converter, we will inherit from a different class, depending
of the type of tag: WikiTag
for inline tags, and WikiRendererBloc
for block tags.
There are also objects call "line handlers". This objects are responsible to process text content which are outside inline tags in a line of text.
A WikiTag
object represents a specific wiki tag. An inline tag
has a markup to indicate the begin of the tag, an other markup for the end of the tag.
Some of wiki tag contain often different parts, separated by a specific character.
For example, for a link, the writer can indicate an URL and a title:
[[http://foo.bar|my link]]
We have here the delimiters of the tag : [[
and ]]
.
And we have a separator, |
. So we have two parts, we call them "attributes".
The first attribute is the URL, the second is the title of the link.
To create a handler for your wiki tag, you should create a class which inherits
from WikiTag
, and set some properties with the delimiters of your
tag, attributes list, and the separator. For our link tag:
class my_link extends WikiTag {
// the left delimiter of our tag
public $beginTag='[[';
// the right delimiter of our tag
public $endTag=']]';
// the name of attributes
protected $attribute=array('href', '$$');
// the separator
public $separators=array('|');
}
In the $attribute
property, you have to indicate the name you give
for each attribute allowed in your wiki tag. You can give any name. However, there is
one name which have a special meaning: "$$"
. This name
indicates to the parser that the content of the attribute can contain other wiki
tags.
In the $separators
property, you give the list of separators. In
most of time, you use only one type of separator to separate attributes. But some time
it is not the case, so you will indicate all different separators, in the same
order of attributes. For example, you have 4 attributes on your wiki tag, and the
separator between the third and the fourth is different (%
for
example) than the others (|
for example), you will indicate:
public $separators=array('|','|','%');
If this is the first which is different, you don't have to list all the next separators:
public $separators=array('%','|');
// is equivalent to
public $separators=array('%','|', '|');
Our previous class is not finished. We still have to indicate
how the corresponding content for the target markup should be generated.
For that, we have to redefine the getContent()
method. We
assume that we want to generate XHTML:
public function getContent(){
if($this->separatorCount == 0){
// only the URL is given
$href = $this->wikiContentArr[0];
$title = htmlspecialchars($href);
}else{
$href = $this->wikiContentArr[0];
$title = $this->contents[1];
}
return '<a href="'.htmlspecialchars($href).'">'.$title.'</a>';
}
$separatorCount
contains the number of separators
that the parser has found. So if it is equals to 0, there is only
one attribute given in the text, if it is equal to 1, there are two
attributes etc.$wikiContentArr
: contains the value of each
attributes, as it is wrote in the text.$contents
: contains the value of each
attributes, after the original values have been
converted to the target markup. In fact, values of $wikiContentArr
and of $contents
are differents, only for attributes named '$$'.
For example, if in our wiki syntax, **bla**
means an emphasis,
and we write [[http://foo.bar|my **super** link]]
,
the value of $this->wikiContentArr[1]
will be
my **super** link
, and the value of $this->contents[1]
will be my <strong>super</strong> link
.
Note that in the case of a link for example, you will have to check the URL, to avoid javascript code for example, or you may have to generate a different URL if the syntax of the URL has a special meaning. This is often the case in a wiki CMS. For example in Dokuwiki, we can indicate "URL" like "foo:bar", and then the URL in the generated content should be "http://mysite.local/wiki/index.php?page=foo/bar" or something like that.
To generate XHTML markup or any other XML markup, there is
a child class of WikiTag
, named WikiTagXhtml
,
which have a generic getContent()
method to generate XML markup.
So in most of case, you don't have to create a getContent()
.
Just inherits from WikiTagXhtml
, indicate the name of the
X(HT)ML element in the $name
property. And in the $attribute
property, indicate names which will be names of the X(HT)ML attributes on the
element ('$$' indicate that the wiki attribute will be the content of the element).
For example, to implement a generator for the <strong>
markup, this class is enough:
class wr3xhtml_strong extends WikiTagXhtml {
protected $name='strong';
public $beginTag='**';
public $endTag='**';
}
For a wiki tag with attributes, here an example to generate the
<acronym>
XHTML element:
class wr3xhtml_acronym extends WikiTagXhtml {
protected $name='acronym';
public $beginTag='??';
public $endTag='??';
protected $attribute=array('$$','title');
public $separators=array('|');
}
With this handler, we can write in the wiki content
a standard: ??CSS|Cascading Style Sheets??
, and this will be converted
to a standard: <acronym title="Cascading Style Sheets">CSS</acronym>
.
There are other possibilities on WikiTag
, and other methods
you can redefine. It is too long to explain all of them. If features explained
above are not enough to implement your wiki tag, see the implementation
of wiki tags in the existing rules. You will discover that almost everything is possible :-)
Once you create the class, you have to declare it in the configuration. Just add its name into the inline tags list of one ore more line handler. See below.
A line handler is a class which handle the text on a line, which is outside wiki inline tags.
There is a default line handler (which does nothing), WikiTextLine
. There is an other,
WikiHtmlTextLine
, which escapes the content with htmlspecialhars
.
And in some rules, you have some specific line handlers to parse complex line of text,
like a wiki line which defines a table row, because on such lines, all contents are separated
by a specific caracters, to define values in each columns.
A line handler is in fact a class which inherits from WikiTag
,
with the property public $isTextLineTag=true;
.
See examples in some rules, for table row.
To declare a line handler, you have two properties on the configuration class:
$defaultTextLineContainer
$textLineContainers
Note that you must declare at least one line handler in the configuration. Example
public $defaultTextLineContainer = 'WikiHtmlTextLine';
public $textLineContainers = array(
'WikiHtmlTextLine'=>array( 'dkxhtml_strong','dkxhtml_emphasis','dkxhtml_underlined','dkxhtml_monospaced',
'dkxhtml_subscript', 'dkxhtml_superscript', 'dkxhtml_del', 'dkxhtml_link', 'dkxhtml_footnote', 'dkxhtml_image',
'dkxhtml_nowiki_inline',),
'dkxhtml_table_row'=>array( 'dkxhtml_strong','dkxhtml_emphasis','dkxhtml_underlined','dkxhtml_monospaced',
'dkxhtml_subscript', 'dkxhtml_superscript', 'dkxhtml_del', 'dkxhtml_link', 'dkxhtml_footnote', 'dkxhtml_image',
'dkxhtml_nowiki_inline',)
);
Tag for blocks in a wiki syntax is a tag which starts at the begining of the line, and which defines the type of the block of text. For some tags, you should repeat it at the begining of each lines of the block, and sometimes, you have only to write a delimiter at the start and at the end of the block of lines.
To create a block tag handler, create a class which inherits from
WikiRendererBloc
. It should have a property, $type
which contains a type identifer. Each blocks should have a unique name.
Then you have to specify how the parser will detect the begin and the end of the block.
You have two ways.
$regexp
property with a regular expression
which will be applied on each lines given by the parser.
Note that if the regular expression captures some part
of the string, this parts are stored in the $_detectMatch
properties. So you can use it in some redefined methods,
in particularly getRenderedLine()
.detect($line)
method. It should
return true if the line belongs to the block.If the block is always only on one line, set the $_closeNow
property to true
.
During the parsing, some methods on your class are called:
open()
detect()
method) that the block starts, this method is called. You can
redefine it to do some additionnal process. It can return a string
which will be added to the generated content. By default, it returns
the value of the property $_openTag
(you can set it
if you don't want to redefine the method).close()
detect()
method) that the block ends, this method is called. You can
redefine it to do some additionnal process at this step.
It can return a string which will be added to the generated content.
By default, it returns
the value of the property $_closeTag
(you can set it
if you don't want to redefine the method).closeNow()
$_closeNow
property.getRenderedLine()
$this->engine->inlineParser->parse($string);
,
where $string
is the part of the line (or the entire, it depends
of your syntax), which should be parsed.Just add its name into the list of the $bloctags
property of the
configuration class.
To know more about how to create such of classes, don't hesitate to read the source of the existing rules.