Eigene Auszeichnungen
Einführung
Die Auszeichnungsumwandlung wird bei PmWiki durch einen Satz von Regeln gesteuert. Jede Regel definiert eine bestimmte Zeichenkette, nach der der Wikitext durchsucht wird. Die gefundene Stelle wird durch einen anderen Text ersetzt. Intern wird dazu die PHP Funktion "preg_replace" verwendet.
Zusätzliche Regeln werden in PmWiki mit der PmWiki-Funktion Markup() oder Markup_e() bekannt gemacht. Diese sehen folgendermaßen aus:
Markup($name, $wann, $muster, $ersetzung); # ODER Markup_e($name, $wann, $muster, $ersetzung);
Wobei mit $name ein eindeutiger Name (Zeichenfolge) für die Regel festgelegt wird. $wann legt fest, wann die Regel im Vergleich zu den Anderen ausgeführt werden soll. $muster enthält das Suchmuster, nach dem im Wikitext gesucht wird und $ersetzung ist die Zeichenkette, die das gesuchte Muster ersetzen soll.
Als Beispiel hier der Programmcode, der die Regel für ''hervorgehobener Text'' (in scripts/stdmarkup.php) erzeugt:
Markup("em", "inline", "/''(.*?)''/", "<em>$1</em>");
Diese Anweisung erstellt eine Regel, die "em" heißt, welche zusammen mit anderen "inline" Auszeichnungen ausgeführt wird. Die Regel ersetzt den Text innerhalb zweier Paare einfacher Anführungszeichen durch eben diesen Text ($1), jedoch eingeschlossen von <em> und </em>.
Die ersten beiden Parameter von Markup() legen die Reihenfolge der Anwendung der Regeln fest. Der erste Parameter gibt der Regel einen Namen – "em" im obigen Beispiel. Man könnte einen beliebigen anderen Namen benutzen, etwa "''" oder sogar "zweieinfachehochkommata". Im Allgemeinen benutzt PmWiki das Markup selbst als Namen der Regel (d.h. PmWiki würde "''" und nicht "em" benutzen), aber im Interesse der Lesbarkeit im Folgenden benutzen wir hier einen mnemonischen Namen.
Der zweite Parameter sagt, dass die Regel zusammen mit anderen "inline" Auszeichnungen bearbeitet werden soll. PmWiki erledigt den Übersetzungsvorgang in mehreren Phasen:
_begin Beginn der Umwandlung fulltext Verarbeitung des gesamten Eingabetextes split Zerteilen des Eingabetextes in einzelne, zu verarbeitende Zeilen directives Verarbeitung von Direktiven inline Übersetzung von im Text auftauchenden Auszeichnungen links Übersetzung von Verweisen, Internetadressen und Wikiwörtern block Übersetzung von Block-Auszeichnungen style Umsetzung von Stilen _end Ende der Umwandlung
Dies Argument wird normalerweise als öffnende spitze Klammer ("vorher") oder schließende spitze Klammer ("nachher") angegeben, gefolgt vom Namen einer anderen Regel.
Die Angabe "inline" als zweiter Parameter bedeutet somit, dass die Regel zusammen mit anderen "inline" Regeln verarbeitet wird. Soll die Regel dagegen zusammen mit den Direktiven verarbeitet werden, d. h. bevor die inline-Regeln verarbeitet werden, müsste man "directives" oder "<inline" als zweiten Parameter angeben.
Der dritte Parameter ist ein Perl-kompatibler regulärer Ausdruck. Genau genommen ist es ein Schrägstrich, ein regulärer Ausdruck, ein weiterer Schrägstrich und (optional) einige Modifikatoren.
Das Beispiel verwendet das Suchmuster "/''(.*?)''/", das ''(.*?)'' als regulären Ausdruck ohne weitere Optionen enthält. (Der reguläre Ausdruck sagt "Finde zwei aufeinander folgende einfache Anführungszeichen, dann so wenig besondere Zeichen wie möglich, damit das Suchmuster zutrifft, danach wieder zwei aufeinander folgende einfache Anführungszeichen". Die Klammern "kopieren" einen Teil des Wikitextes für die spätere Verwendung in eine "Zwischenablage".)
Der vierte Parameter ist der Ersetzungstext, der anstatt des kompletten Suchmusters (Auszeichnung und Wikitext) angezeigt werden soll. Man kann $1, $2 usw. verwenden, um den Text aus dem ersten, zweiten usw. Bereich innerhalb des geklammerten Textes im regulären Ausdruck einzufügen.
In diesem Beispiel wird "<em>$1</em>" verwendet, das aus <em>, dem gefundenen Text innerhalb der ersten Klammer (d.h. den Teil .*? des Musters) und </em> besteht.
Beispiele
Hier die Regel für @@Schreibmaschinenschrift@@:
Markup("@@", "inline", "/@@(.*?)@@/", "<code>$1</code>");
und für eine [:comment ...:] Direktive, die einfach bei der Ausgabe entfernt wird:
Markup("comment", "directives", "/\\[:comment .*?:\\]/", '');
Aber wie funktioniert das bei der '''starken Hervorhebung'''? Hier muss man etwas vorsichtig sein. Zwar wird diese zusammen mit andere Inline-Auzeichnungen bearbeitet, aber es muss auch sichergestellt werden, dass die Regel ''' vor der Regel '' bearbeitet wird, da ''' auch '' enthält. Der zweite Parameter von Markup() kann auch benutzt werden, um die Beziehung einer Regel zu einer anderen festzulegen:
Markup("strong", "<em", "/'''(.*?)'''/", "<strong>$1</strong>");
Dies erzeugt eine Regel mit Namen "strong" und der zweite Parameter "<em" legt fest, dass die Regel vor der weiter oben gezeigten "em"-Regel verarbeitet werden soll. Um etwas nach der "em"-Regel auszuführen, würde man stattdessen ">em" verwenden. Damit ist es möglich, Erweiterungen an jeder Stelle der Umwandlung von Auszeichnungen vorzunehmen. (Genau genommen sind "inline", "block", "directives" usw. nur Platzhalter um den Gesamtablauf zu strukturieren, sodass andere Regeln an passender Stelle eingefügt werden können. So kann etwa "<inline" benutzt werden, damit eine Regel vor anderen "inline" Regeln angewendet wird.)
Wenn Sie verfügbare Auszeichnungen abschalten wollen, schreiben sie einfach z. B.:
DisableMarkup("strong");
Die vordefinierten Auszeichnungen von PmWiki sind in scripts/stdmarkup.php definiert. Um die gesamte Ersetzungstabelle während der Programmausführung auszugeben, gibt es das Modul scripts/diag.php das die Aktion "?action=ruleset" zur Verfügung stellt. Damit werden die festgelegten Regeln in der Reihenfolge angezeigt, in der sie verarbeitet werden. Man sieht dies z. B. in Eigene Auszeichnungen?action=ruleset.
Weitere gängige Beispiele
Definieren einer eigenen Funktion, die eine spezielle HTML- oder Javascript-Sequenz erzeugt
Angenommen, ein Admin möchte eine einfache "(:example:)"-Auszeichnung haben, die immer eine feste HTML-Zeichenkette in der Ausgabe erzeugt, etwa für einen Webring, Google-AdSense-Display oder Javascript. Der Markup()-Aufruf, der das bewirkt, wäre
Markup('example', 'directives',
'/\\(:example:\\)/',
Keep("<div class='example'><p>Here is a
<a target='_blank' href='http://www.example.com'>link</a> to
<em>example.com</em></p></div>") );
- Das erste Argument ist ein einzigartiger Name für die Auszeichnung ("example").
- Das zweite Argument sagt, führe diese Auszeichnung zusammen mit anderen Direktiven durch.
- Das dritte Argument ist das Suchmuster "(:example:)".
- Das vierte Argument ist die HTML-Zeichenkette, durch die das Suchmuster ersetzt wird. Wir benutzen hier die Keep()-Funktion, um die Ausgabe davor zu schützen, von nachfolgenden Regeln bearbeitet zu werden – im obigen Beispiel wollen wir nicht, dass der
http://www.example.com-URLwieder in einen Link verwandelt wird.
Aufruf einer eigenen Funktion, die etwas zurück liefert
Die Option 'e' beim Parameter $muster veranlasst PmWiki, den Parameter $ersetzung nicht als Ersetzungstext, sondern als PHP Ausdruck zu interpretieren, der den Ersetzungsausdruck zurückliefert.
Markup('random', 'directives',
'/\\(:random:\\)/e',
"rand(1, 100)");
Dies ruft die PHP-interne rand()-Funktion auf und ersetzt die Direktive mit dem Ergebnis. Jede Funktion kann aufgerufen werden, einschließlich der Funktionen, die in einer Datei für Lokale Anpassungen definiert wurden.
Argumente können auch übergeben werden, indem reguläre Ausdrücke einfangende Klammern benutzt werden, so bewirkt die Auszeichnung
Markup('randomargs', 'directives',
'/\\(:random (\\d+) (\\d+):\\)/e',
"rand('$1', '$2')");
dass die Direktive (:random 50 100:) eine Zufallszahl zwischen 50 und 100 erzeugt.
Wegen einer PmWiki-Funktion, die hilft, beliebige Sequenzen aus Schlüssel-Wert-Paaren zu parsen, siehe Cookbook:ParseArgs.
Migration zu PHP 5.5 und Markup_e()
Seit PHP Version 5.5 wird der /e-Auswertungs-Modifier missbilligt und einige Hoster erlauben seine Verwendung nicht mehr.
Jüngere Versionen des PmWiki-Kerns (2.2.58 und jünger) erlauben neue Wege, um Auszeichnungsregeln zu definieren, ohne auf den Modifier /e zurückgreifen zu müssen. Die historischen Wege, Auszeichnungsregeln zu definieren, wurden nicht entfernt und laufen weiterhin, aber sie könnten mit PHP-5.5-Installationen unverträglich sein.
Beachten Sie: Wenn ihr Ersatzmuster nicht ausgewertet werden muss, sollten Sie Markup() benutzen wie bisher und nicht Markup_e().
Das Folgende ist akzeptabel für PHP 5.5+ (verträglich mit PmWiki 2.2.58+, läuft auch mit PHP 5.4 und älter)
- Markup($name, $wann, $muster, $ersetzung);
- $muster darf keinen /e-Modifier mehr enthalten
- $ersetzung kann eine Zeichenkette mit Übereinstimmungen wie $1, $2 etc. sein,
- $ersetzung kann der Name einer Funktion sein (callback), die mit dem Array der Übereinstimmungen als Argument aufgerufen wird.
- Anstelle einer Zeichenkette kann der vierte Parameter auch eine anonyme Funktion sein (Beachten Sie: Sie können anonyme Funktionen auf diese Weise seit PHP 5.3.0+ benutzen)
- Für PHP 5.4 oder früher kann $muster einen /e-Modifier enthalten. Der existierende Weg funktioniert noch, aber unter PHP 5.5 löst er Warnungen wegen veralteter Features aus.
- Markup_e($name, $wann, $muster, $ersetzung);
- $muster darf keinen /e-Modifier enthalten
- $ersetzung kann eine Zeichenkette mit auszuwertendem Programmkode sein; beachten Sie, dass auf die Übereinstimmungen mit $m[1], $m[2] anstelle von '$1' , '$2' zugegriffen wird.
- $ersetzung kann der Name einer Funktion sein (callback), die mit dem Array der Übereinstimmungen als Argument aufgerufen wird (PmWiki 2.2.59+).
Beispiele:
- Für PHP 5.4 und älter ist dies akzeptabel:
Markup('randomargs', 'directives', '/\\(:random (\\d+) (\\d+):\\)/e', "rand('$1', '$2')" ); - Für PHP 5.5 und jünger, $ersetzung ist Kode, wir rufen markup_e() auf:
Markup_e('randomargs', 'directives', '/\\(:random (\\d+) (\\d+):\\)/', "rand(\$m[1], \$m[2])" );Das Array $m enthält die Übereinstimmungen in den Klammern des Musters. Die Übereinstimmungen \$m[1] haben einen Backslash vor dem $-Zeichen, damit die Variable in den doppelten Anführungszeichen nicht interpretiert wird. Das läuft auch unter PHP 5.4 und älter, erfordert aber PmWiki 2.2.58 oder jünger. - Für PHP5.5 und jünger, $ersetzung ist callback, wir rufen Markup() auf:
Markup('randomargs', 'directives', '/\\(:random (\\d+) (\\d+):\\)/', "MyRandom" ); function MyRandom($matches) { return rand($matches[1], $matches[2]); }
Ein weiteres Beispiel:
- PHP 5.4 oder älter:
Markup('Maxi:','<links', "/\\b([Mm]axi:)([^\\s\"\\|\\[\\]]+)(\"([^\"]*)\")?/e", "Keep(LinkMaxi(\$pagename,'$1','$2','$4','$1$2'),'L')" ); - PHP 5.5 oder neuer, PmWiki 2.2.58+, $ersetzung ist Programmkode, wir rufen Markup_e() auf:
Markup_e('Maxi:','<links', "/\\b([Mm]axi:)([^\\s\"\\|\\[\\]]+)(\"([^\"]*)\")?/", "Keep(LinkMaxi(\$pagename,\$m[1],\$m[2],\$m[4],\$m[1].\$m[2]),'L')" );Die '$1$2'-Zeichenkette in der alten Version wird ersetzt durch \$m[1].\$m[2], zwei aneinandergehängte Elemente des Arrays mit Übereinstimmungen. Das läuft auch unter PHP 5.4 und älter, erfordert aber PmWiki 2.2.58 oder jünger. - $ersetzung kann auch eine callback-Funktion sein, wir rufen Markup() auf:
Markup('Maxi:','<links', "/\\b([Mm]axi:)([^\\s\"\\|\\[\\]]+)(\"([^\"]*)\")?/", "CallbackMaxi" ); function CallbackMaxi($m) { extract($GLOBALS["MarkupToHTML"]); # to get $pagename return Keep(LinkMaxi($pagename,$m[1],$m[2],$m[4],$m[1].$m[2]),'L'); }
Offensichtlich kann die LinkMaxi-Funktion auch umgeschrieben werden, sodass sie das Übereinstimmungs-Array direkt akzeptiert. Das läuft auch unter PHP 5.4 und älter, erfordert aber PmWiki 2.2.58 oder jünger.
Das Obige mag kompliziert erscheinen, aber es ist tatsächlich einfacher, Sie benutzen ihre eigene callback-Funktion.
Markup('mykey', 'directives',
'/\\(:mydirective (.*?) (.*?):\\)/i',
'MyFunction'
);
function MyFunction($matches) {
extract($GLOBALS["MarkupToHTML"]);
# ... do stuff with $matches ...
return $out; # or return Keep($html);
}
Markup für beide, neue und alte, Versionen von PmWiki
Wenn Ihr Rezept mit PmWiki 2.2.58 und jünger unter PHP 5.5 und mit älteren PmWiki+PHP-Versionen laufen soll, können Sie etwa das Folgende benutzen:
if(function_exists('Markup_e')) { # new format, no /e
Markup_e('rnd', 'directives', '/\\(:random (\\d+) (\\d+):\\)/', "rand(\$m[1], \$m[2])");
}
else { # old format
Markup('rnd', 'directives', '/\\(:random (\\d+) (\\d+):\\)/e', "rand($1, $2)");
}
Wenn Sie Fragen bezüglich des neuen Weges haben, mit dem man eigene Markup-Funktionen definiert, fragen Sie uns auf der Talk-Seite? oder der Mailingliste.
FAQ
Wie kann ich JavaScript in die Ausgabe einer Seite einfügen?
Es gibt mehrere Wege, das zu erreichen. Das Cookbook:JavaScript-Rezept beschreibt ein einfaches Verfahren, um statisches JavaScript in eine Webseite einzufügen mit Hilfe von eigenen Auszeichnungen. Um JavaScript direkt in Wikiseiten zu schreiben (was verschiedene Sicherheitsrisiken öffnen kann), siehe das JavaScript-Editable-Rezept. Für JavaScript, das im Kopf- und Fußbereich von Seiten erscheinen soll, können Sie die skin-Vorlage direkt verändern, oder Sie fügen