Jeśli posiadamy własną encyklopedię na silniku MediaWiki to zapewne chcemy aby naszym redaktorom pisanie stron sprawiało jak najmniej problemów ale jednocześnie aby tworzona przez nas wiki wyglądała jak najładniej. Pchanie htmla w kod stron mija się z celem. Szablony? Sprawdzą się. Ale co jeśli chcemy dać więcej możliwości edytującym np. automatyczne generowanie obrazka? Składnia MW na to nie pozwala ale PHP już tak. Musimy wiec dodać własne tagi do składni wiki za pomocą rozszerzenia!
Przygotowanie
Na początek ustalmy jaki mamy cel w naszej pracy. W tym poradniku chciałbym pokazać jak dodać tag <ramka> który pozwoli na szybkie tworzenie rameczek z obrazkowym tłem i treścią w środku. Jako tło będzie można ustawić dowolną grafikę spośród zuploadowanych na serwer wpisując jej nazwę jako wartość atrybutu grafika.
Teraz czas na napisanie rozszerzenia. Zaczniemy od stworzenia pliku z rozszerzeniem php. Musimy ten plik umieścić w folderze extensions naszej instalacji MW. U mnie będzie to extensions/nowetagi.php. Tak przygotowany plik musimy podpiąć do skryptu. W tym celu otwieramy plik LocalSettings i mniej więcej po środku dopisujemy linijkę:
require_once("extensions/nowetagi.php");
Włączanie parsowania
Kolejnym krokiem w naszej pracy będzie otwarcie pliku nowetagi.php i dodanie odpowiedniego zdarzenia wewnątrz znaczników php:
$wgHooks['ParserFirstCallInit'][] = 'mojParser';
Powyższa linijka spowoduje, że w momencie jak MediaWiki będzie parsował artykuł to wywoła funkcję mojParser by dowiedzieć się jak parsować tagi obsługiwane przez nasze rozszerzenie. Poniżej tej linijki umieszczamy ciało wspomnianej funkcji:
function mojParser( &$parser ) {
$parser->setHook( 'ramka', 'parsowanieRamka');
return true;
}
W podanym przykładzie poinformowaliśmy parser, że tag <ramka> ma być obsługiwany za pomocą funkcji parsowanieRamka(). W obrębie jednej funkcji mojParser możemy dodać nielimitowaną liczbę nowych tagów. Ważne jest tylko aby na końcu zwrócić true.
Funkcja parsująca
Teraz zdefiniujmy funkcję parsowanieRamka().
function parsowanieRamka( $input, $args, $parser, $frame ) {
}
Póki co ciało funkcji jest puste. Musimy bowiem najpierw wyjaśnić co zawierają przekazane argumenty. Jak wiadomo tagi dzielą się na dwuelementowe (<ramka></ramka>) i jednoelementowe (<cytat />). Jeśli parsowany tag składa się z otwarcia i zamknięcia to zmienna $input będzie zawierała to co znajduje się pomiędzy czyli inaczej mówiąc zawartość tagu. Zmienna $args jest zaś tablicą o indeksach identycznych jak atrybuty parsowanego tagu i z wartościami równymi wartościom tych atrybutów. Dla przykładu tag <ramka grafika=”tlo.jpg”>Dowolny tekst</ramka> zostanie podzielony na zmienną $input o wartości Dowolny tekst oraz na jednoelementową tablicę $args gdzie $args['grafika']=’tlo.jpg’. Pozostałe argumenty przekazane funkcji parsowanieRamka() nie są dla nas istotne.
Uzbrojeni w powyższą wiedzę możemy zacząć pisać skrypt który zwróci kod html w miejsce tagu w artykule. Musimy jeszcze tylko pobrać adres URL do grafiki której nazwa została przekazana w atrybucie grafika.
if(!empty($args['grafika'])){
$file = wfFindFile($args['grafika']);
$url = $file->getFullUrl();
}
Powyższa instrukcja sprawi, że jeśli zdefiniowano wartość atrybutu grafika to zmienna $url będzie przechowywała bezwzględny adres do tego pliku. Możemy ją teraz użyć przy generowaniu pierwszej części kodu wynikowegoi ustawić obrazek jako tło bloku:
$output = '<div class="ramka" style="background-image: url('.$url.');">';
Teraz trzeba dołączyć do tego treść spomiędzy znaczników. Ale tu należy pamiętać o jednej rzeczy, że tam również może zostać użyta składania wiki i inne tagi. Dlatego też zmienną $input należy jeszcze raz przepuścić przez parser za pomocą specjalnej funkcji:
$output .= $parser->recursiveTagParse( $input, $frame );
Argumentami tej funkcji jest treść do ponownego sparsowania oraz zmienna $frame którą otrzymaliśmy wcześniej jako czwarty argument funkcji parsowanieRamka. Gdy to już mamy możemy zamknąć blok i zwrócić gotowy kod html:
$output .= '</div>'; return $output;
Pełny kod naszego rozszerzenia wygląda tak:
<?php
$wgHooks['ParserFirstCallInit'][] = 'mojParser';
function mojParser( &$parser ) {
$parser->setHook( 'ramka', 'parsowanieRamka');
return true;
}
function parsowanieRamka( $input, $args, $parser, $frame ) {
if(!empty($args['grafika'])){
$file = wfFindFile($args['grafika']);
$url = $file->getFullUrl();
}
$output = '<div class="ramka" style="background-image: url('.$url.');">';
$output .= $parser->recursiveTagParse( $input, $frame );
$output .= '</div>';
return $output;
}
?>
Nieco więcej o parsowaniu
W powyższym przykładowym rozszerzeniu użyliśmy funkcji $parser->recursiveTagParse();. Jak już pisałem służy ona do tego by sparsować składnię wiki i dodatkowe tagi wewnątrz jakiegoś tekstu. Należy jednak pamiętać, że nie zostaną wtedy podmienione podpisy (~~~~). Tym zajmuję się tzw parser wstępny ale on także w tym wypadku nam nie pomoże. Jest to związane z tym, że tekst wewnątrz tagów dodawanych przez rozszerzenia jest parsowany przy każdym wyświetleniu strony na nowo a w bazie danych ląduje niezmieniony. Z tego też powodu własne tagi nie sprawdzą się w miejscach gdzie użytkownicy będą się podpisywać za pomoca 4 tyld.
Inną sprawą jest to, że należy uważać by nie parsować znaczników html które nie działają na stronach MediaWiki. Np. próba sparsowania tekstu <img src=”adres.png”> spowoduje, że ten kod pojawi się na stronie w formie tekstu a nie obrazka. Można jednak bezpiecznie parsować kod obrazka zapisany w wikiskładni tzn [[Grafika:Plik.png]]. Identyczna sytuacja zachodzi przy odnośnikach. Dlatego należy uważać by nie wrzucać do parsera przypadkowego kodu html a jedynie parsować to co można.
Inny przykład: tag <cytat>
Na koniec zamieszczę jeszcze jeden kod parsowania tagu. Jego składnia wygląda tak: <cytat autor=”Imię Nazwisko”></cytat> a skrypt który go parsuje przedstawia się następująco:
function parsowanieCytat($input, $args, $parser, $frame ) {
$output = '<blockquote>'.$input.'<div>'.$args['autor'].'</div></blockquote><br style="clear: left;" />';
return $parser->recursiveTagParse( $output, $frame );
}
Do tego dochodzi jeszcze krótki kod CSS:
blockquote{
padding-left: 50px;
background: url('quote.png') left 5px no-repeat;
margin: 0px 20px 10px 0px;
font-family: Georgia;
font-style: italic;
min-height: 27px;
float: left;
color: #333;
max-width: 500px;
}
blockquote div{
text-align: right;
color: #666;
font-style: normal;
font-size: 10px;
font-family: Arial;
margin-right: 10px;
}
Całość w akcji można zobaczyć na górze tej strony.




Brak komentarzy do tego artykułu