Příručka:Modely obsahu stránek
ContentHandler představený v MediaWiki 1.21 vám umožňuje přidávat nové modely obsahu jiné než wikitext. Umožňuje, aby stránky wiki byly složeny z jiných dat než wikitext a byly reprezentovány jakýmkoli způsobem – například: Markdown, reStructuredText, icalendar nebo vlastní formát XML. Zobrazení a úpravy těchto modelů obsahu lze provádět vlastními způsoby (např. různé zvýraznění syntaxe nebo zcela nové formuláře pro zadávání dat).
Tato stránka popisuje, jak vytvořit nový model obsahu v rozšíření. Předpokládá určitou znalost obecných postupů vývoje rozšíření. Stručné shrnutí požadavků naleznete v sekci Souhrn ve spodní části této stránky.
Pro příklady bude použit nesmyslný obsahový model "Goat". Můžete také prozkoumat rozšíření DataPages, které je součástí Extension:Examples .
Registrace
Nejprve přidejte název modelu obsahu a třídu manipulátoru do svého extension.json:
"ContentHandlers": {
"goat": "MediaWiki\\Extension\\GoatExt\\Content\\GoatContentHandler"
}
- Hodnota vlevo je zde název typu obsahu, může to být libovolný jedinečný řetězec, který chcete, a existuje vedle pěti vestavěných typů obsahu: 'wikitext', 'JavaScript', 'CSS', 'plain text', 'JSON'. Tato hodnota je uživatelům vystavena na místech, jako jsou Special:ChangeContentModel a informace o stránce.
- Hodnota napravo je plně kvalifikovaný název třídy, která přesahuje MediaWiki\Content\ContentHandler.
To bude vyžadovat vytvoření dvou nových tříd, například \MediaWiki\Extension\GoatExt\Content\GoatContent
a \MediaWiki\Extension\GoatExt\Content\GoatContentHandler
(ujistěte se, že jejich jmenný prostor je registrován v AutoloadNamespaces).
Další informace o těchto třídách jsou uvedeny níže.
Volitelné konstanty modelu obsahu
Řetězec 'goat' výše je model obsahu IS (v kódu se obecně nazývá $modelId
) a je obvykle také definován jako konstanta.
Tyto konstanty jsou definovány pro všechny modely vestavěného obsahu a mnoho dokumentace odkazuje na konstanty "CONTENT_MODEL_XXX".
Pokud jste je nedefinovali, může to být trochu matoucí.
Definice by měla být provedena prostřednictvím položky zpětné volání v extension.json
. Například:
V extension.json
:
"callback": "MediaWiki\\Extension\\GoatExt\\Hooks::registrationCallback"
V src/Hooks.php
:
<?php
namespace MediaWiki\Extension\GoatExt;
class Hooks {
public static function registrationCallback() {
// Musí odpovídat názvu použitému v sekci 'ContentHandlers' souboru extension.json
define( 'CONTENT_MODEL_GOAT', 'goat' );
}
}
Nemusíte to dělat tímto způsobem a můžete použít pouze řetězec.
Přiřazení modelů obsahu ke stránkám
U stránek lze ručně změnit typ obsahu, ale je užitečné mít je jako výchozí na správný. Dva běžné způsoby, jak toho dosáhnout, jsou podle jmenného prostoru a podle přípony souboru.
Podle jmenného prostoru
Pokud chcete, aby měl celý jmenný prostor wiki výchozí model obsahu, můžete jej jako takový definovat v extension.json:
"namespaces": [
{
"id": 550,
"constant": "NS_GOAT",
"name": "Goat",
"subpages": false,
"content": true,
"defaultcontentmodel": "goat"
},
{
"id": 551,
"constant": "NS_GOAT_TALK",
"name": "Goat_talk",
"subpages": true,
"content": false,
"defaultcontentmodel": "wikitext"
}
]
Upozorňujeme, že publikovaná rozšíření by měla zaregistrovat ID jmenného prostoru, která používají (550
a 551
výše) na stránce Výchozí jmenné prostory rozšíření .
Podle přípony souboru
Pokud chcete určit typ obsahu přidáním přípony typu kvazi souboru k názvu stránky wiki, můžete použít háček ContentHandlerDefaultModelFor . Například:
<?php
namespace MediaWiki\Extension\GoatExt;
use MediaWiki\Revision\Hook\ContentHandlerDefaultModelForHook;
use MediaWiki\Title\Title;
class Hooks implements ContentHandlerDefaultModelForHook {
/**
* @param Title $title
* @param string &$model
*/
public function onContentHandlerDefaultModelFor( $title, &$model ) {
// Libovolný název stránky (v libovolném jmenném prostoru) končící na '.goat'.
$ext = '.goat';
if ( str_ends_with( $title->getText(), $ext ) ) {
// Toto je konstanta, kterou jste definovali dříve.
$model = CONTENT_MODEL_GOAT;
// Pokud změníte model obsahu, vraťte hodnotu false.
return false;
}
// Pokud to nezměníte, vraťte true.
return true;
}
}
ContentHandler
Další věcí, kterou je třeba definovat, je třída GoatContentHandler, kde také určujeme, v jakém formátu bude tento typ obsahu uložen (v tomto případě text). ContentHandlers nevědí nic o žádném konkrétním obsahu stránky, ale určují obecnou strukturu a uložení obsahu.
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\Content;
use MediaWiki\Content\ContentHandler;
class GoatContentHandler extends ContentHandler {
public function __construct( $modelId = 'goat' ) {
parent::__construct( $modelId, [ CONTENT_FORMAT_TEXT ] );
}
public function serializeContent( Content $content, $format = null ) {
}
public function unserializeContent( $blob, $format = null ) {
}
public function makeEmptyContent() {
return new GoatContent();
}
public function supportsDirectEditing() {
return true;
}
}
Obsah
Třída GoatContent
představuje data obsahu a neví nic o stránkách, revizích ani o tom, jak jsou uloženy v databázi.
Kromě požadovaných sedmi zděděných metod můžete přidat další veřejné metody, které jsou specifické pro doménu. V tomto případě chceme být schopni získat jméno Goat.
Notably, AbstractContent::getNativeData()
has been deprecated since 1.33.
If you're extending MediaWiki\Content\TextContent
instead, then you could use the getText()
method.
If you're extending MediaWiki\Content\JsonContent
, the parent class provides the getData()
method.
<?php
namespace MediaWiki\Extension\GoatExt;
use MediaWiki\Content\AbstractContent;
class GoatContent extends AbstractContent {
public function __construct( $modelId = 'goat' ) {
parent::__construct( $modelId );
}
public function getTextForSearchIndex() {
}
public function getWikitextForTransclusion() {
}
public function getTextForSummary( $maxLength = 250 ) {
}
public function getSize() {
}
public function copy() {
}
public function isCountable( $hasLinks = null ) {
}
public function getName() {
return 'Garry';
}
}
Úprava formuláře
Teď už máme kostru nastavenou, budeme chtít zkusit upravit Goat.
Za tímto účelem vytvoříme GoatContentHandler::getActionOverrides()
a určíme, jaké akce chceme mapovat na jaké třídy.
Pro začátek se budeme zabývat pouze 'edit' (což odpovídá ?action=edit
v URL).
public function getActionOverrides() {
return [
'edit' => GoatEditAction::class,
];
}
A vytvoříme naši novou třídu GoatEditAction
, v podstatě stejnou jako základní EditAction
, ale použijeme naše vlastní GoatEditPage
:
<?php
namespace MediaWiki\Extension\GoatExt\Action;
use MediaWiki\Actions\EditAction;
use MediaWiki\Extension\GoatExt\EditPage;
class GoatEditAction extends EditAction {
public function show() {
$this->useTransactionalTimeLimit();
$editPage = new GoatEditPage( $this->getArticle() );
$editPage->setContextTitle( $this->getTitle() );
$editPage->edit();
}
}
Naše nová třída GoatEditPage
je místem, kde se akce odehrává (omluvte slovní hříčku):
<?php
namespace MediaWiki\Extension\GoatExt;
use MediaWiki\EditPage\EditPage;
use OOUI\FieldLayout;
use OOUI\TextInputWidget;
class GoatEditPage extends EditPage {
protected function showContentForm() {
$out = $this->context->getOutput();
// Získejte data.
$name = $this->getCurrentContent()->getGoatName();
// Vytvořte formulář.
$nameField = new FieldLayout(
new TextInputWidget( [ 'name' => 'goat_name', 'value' => $name ] ),
[ 'label' => 'Name', 'align' => 'left' ]
);
$out->addHTML( $nameField );
}
}
Nyní byste měli být schopni upravit stránku a zobrazit svůj formulář. Ale když do něj vložíte data a stisknete 'náhled', uvidíte, že věci ještě nefungují plně a že nemáte žádný výstup, ani se váš odeslaný text znovu nezobrazuje ve formuláři.
Musíme tedy přepsat i akci 'odeslat' novou třídou GoatSubmitAction
a přidáním 'submit' => GoatSubmitAction::class,
k naší metodě GoatContentHandler::getActionOverrides()
.
Naše třída GoatSubmitAction
by měla být stejná jako třída core, ale dědit z našich GoatEditAction
.
Zobrazení
Model obsahu je odpovědný za vytváření jakéhokoli požadovaného výstupu pro zobrazení. To obvykle zahrnuje práci s jeho daty a vytváření HTML nějakým způsobem, který se přidá k výstupu analyzátoru.
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\ContentHandler;
use MediaWiki\Content\ContentParseParams;
use MediaWiki\Parser\ParserOutput;
class GoatContentHandler extends ContentHandler {
protected function fillParserOutput(
Content $content,
ContentParseParams $cpoParams,
ParserOutput &$output
) {
// define $html somewhere
// e.g. $output->setText( $html );
}
}
Zobrazení popis/dokumentace
Někdy můžete chtít zobrazit nějaké informace nebo dokumentaci pro stránku wiki, která má vlastní model obsahu, jako je JSON. Neexistují žádné systémové zprávy pro zobrazení textu nad takovými stránkami (kromě MediaWiki:Clearyourcache zobrazených pouze nad stránkami JavaScript a CSS). Možná budete chtít vidět phab:T355159 pro další podrobnosti.
Porovnání revizí
Extending DifferenceEngine (deprecated in 1.32)
Třída GoatDifferenceEngine
představuje rozdíl mezi obsahem Goat.
Přepíšeme výchozí metodu generateContentDiffBody
pro generování rozdílu.
<?php
namespace MediaWiki\Extension\GoatExt\Diff;
use DifferenceEngine;
use MediaWiki\Content\Content;
class GoatDifferenceEngine extends DifferenceEngine {
public function generateContentDiffBody( Content $oldContent, Content $newContent ) {
}
}
Abychom MediaWiki řekli, aby použila náš GoatDifferenceEngine
, přepíšeme getDiffEngineClass
na naše GoatContentHandler
.
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\ContentHandler;
use MediaWiki\Extension\GoatExt\Diff\GoatDifferenceEngine;
class GoatContentHandler extends ContentHandler {
public function getDiffEngineClass() {
return GoatDifferenceEngine::class;
}
}
Extending SlotDiffRenderer
Using the newer method, we can extend SlotDiffRenderer
instead. This follows the above pretty similarly:
<?php
namespace MediaWiki\Extension\GoatExt\Diff;
use MediaWiki\Content\Content;
use SlotDiffRenderer;
class GoatSlotDiffRenderer extends SlotDiffRenderer {
public function getDiff( ?Content $oldContent = null, ?Content $newContent = null ) {
}
}
Then, we tell our custom GoatContentHandler
to use our custom GoatSlotDiffRenderer
:
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\ContentHandler;
use MediaWiki\Context\IContextSource;
use MediaWiki\Extension\GoatExt\Diff\GoatSlotDiffRenderer;
class GoatContentHandler extends ContentHandler {
protected function getSlotDiffRendererWithOptions( IContextSource $context, $options = [] ) {
return new GoatSlotDiffRenderer();
}
}
Shrnutí
Chcete-li implementovat nový model obsahu s vlastním formulářem pro úpravy, vytvořte následující:
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\AbstractContent;
class GoatContent extends AbstractContent {
public function __construct( $modelId = 'goat' ) {
parent::__construct( $modelId );
}
public function getTextForSearchIndex() {}
public function getWikitextForTransclusion() {}
public function getTextForSummary( $maxLength = 250 ) {}
public function getSize() {}
public function copy() {}
public function isCountable( $hasLinks = null ) {}
}
<?php
namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\Content;
use MediaWiki\Content\ContentHandler;
use MediaWiki\Content\ContentParseParams;
class GoatContentHandler extends ContentHandler {
public function __construct( $modelId = CONTENT_MODEL_GOAT, $formats = ['text/x-goat'] ) {
parent::__construct($modelId, $formats);
}
protected function getContentClass() {}
public function supportsDirectEditing() {}
public function serializeContent( Content $content, $format = null ) {}
public function unserializeContent( $blob, $format = null ) {}
public function makeEmptyContent() {}
public function getActionOverrides() {}
protected function fillParserOutput(
Content $content,
ContentParseParams $cpoParams,
ParserOutput &$output
) {}
}
Checklist (kontrolní seznam)
Akce | Příklad | |
---|---|---|
Definujte ID modelu obsahu (a další typ obsahu) a konstantu modelu obsahu | goat CONTENT_MODEL_GOAT
| |
Vyberte si preferovaný mechanismus použití modelu obsahu: | ||
(a) Podle jmenného prostoru. Definujte konstanty jmenného prostoru, ID a jména za předpokladu, že žádné z nich ještě není obsazeno |
NS_GOAT (id: 550, name 'Goat')NS_GOAT_TALK (id: 551, name: 'Goat talk')
| |
(b) Podle přípony v názvu stránky | .goat
| |
(c) Ostatní | through 'Page information' interface (&action=info )
| |
extension.json
| ||
ContentHandlers - zaregistruje podtřídu ContentHandler pro nový model obsahu
|
"ContentHandlers": {
"goat": "MediaWiki\\Extension\\GoatExt\\Content\\GoatContentHandler"
}
|
↑ |
callback - pojmenuje svou metodu třídy pro zpětná volání, obvykle v souboru Hooks
|
"callback": "MediaWiki\Extension\\GoatExt\\Hooks::registrationCallback"
|
↑ |
Hooks , HookHandlers - poskytnout metodu háčku na ContentHandlerDefaultModelFor
|
"Hooks": {
"ContentHandlerDefaultModelFor": "main"
},
"HookHandlers": {
"main": {
"class": "MediaWiki\\Extension\\GoatExt\\Hooks"
}
}
| |
namespaces - definuje jmenné prostory s příslušnou hodnotou pro defaultcontentmodel .
Pro více možností použijte místo toho háček |
"namespaces": [
{
"id": 550,
"constant": "NS_GOAT",
"name": "Goat",
"subpages": false,
"content": false,
"defaultcontentmodel": "goat"
},
{
"id": 551,
"constant": "NS_GOAT_TALK",
"name": "Goat_talk",
"subpages": true,
"content": false,
"defaultcontentmodel": "wikitext"
}
]
|
↑ |
AutoloadNamespaces - načíst podtřídy Content a ContentHandler v podadresáři
|
"AutoloadNamespaces": {
"MediaWiki\\Extension\\GoatExt\\": "src/"
}
| |
AutoloadClasses - explicitně načíst podtřídy Content a ContentHandler
|
"AutoloadClasses": {
"MediaWiki\\Extension\\GoatExt\\Hooks": "src/Hooks.php",
"MediaWiki\\Extension\\GoatExt\\Content\\GoatContent": "src/Content/GoatContent.php",
"MediaWiki\\Extension\\GoatExt\\Content\\GoatContentHandler": "src/Content/GoatContentHandler.php"
}
| |
Soubor háčků | MediaWiki\\Extension\\GoatExt\\Hooks
| |
Přidat metodu pro zpětné volání | public static function registrationCallback() {
// Musí odpovídat názvu použitému v sekci 'ContentHandlers' souboru extension.json
define( 'CONTENT_MODEL_GOAT', 'goat' );
}
| |
Přidejte metodu pro háček ContentHandlerDefaultModelFor pro stránky wiki v zamýšleném jmenném prostoru
|
public function onContentHandlerDefaultModelFor( $title, &$model ) {
if ( $title->inNamespace( NS_GOAT ) {
$model = CONTENT_MODEL_GOAT;
return false;
}
return true;
}
|
|
Nebo přidejte metodu pro háček ContentHandlerDefaultModelFor pro stránky wiki se zamýšlenou příponou souboru
|
public function onContentHandlerDefaultModelFor( $title, &$model ) {
$ext = '.goat';
if ( str_ends_with( $title->getText(), $ext ) ) {
$model = CONTENT_MODEL_GOAT;
return false;
}
return true;
}
|
↑ |
Podtřídy Content a ContentHandler | ||
Přidejte podtřídu obsahu rozšířením AbstractContent nebo jedné z dostupných podtříd (např. TextContent ) | namespace MediaWiki\Extension\GoatExt\Content;
use MediaWiki\Content\AbstractContent;
class GoatContent extends AbstractContent {
public function __construct( $modelId = 'goat' ) {
parent::__construct( $modelId );
}
public function getTextForSearchIndex() {}
public function getWikitextForTransclusion() {}
public function getTextForSummary( $maxLength = 250 ) {}
public function getSize() {}
public function copy() {}
public function isCountable( $hasLinks = null ) {}
// atd. Podrobnosti viz dokumentace.
}
|
↑ |
Přidejte podtřídu ContentHandler rozšířením buď ContentHandler nebo jedné z jejích podtříd (např. TextContentHandler nebo CodeContentHandler ) | <?php
namespace MediaWiki\Extension\GoatExt;
use MediaWiki\Content\Content;
use MediaWiki\Content\ContentHandler;
class GoatContentHandler extends ContentHandler {
public function __construct( $modelId = 'goat' ) {
parent::__construct( $modelId, [ CONTENT_FORMAT_TEXT ] );
}
public function serializeContent( Content $content, $format = null ) {
}
public function unserializeContent( $blob, $format = null ) {
}
public function makeEmptyContent() {
return new GoatContent();
}
public function supportsDirectEditing() {
return true;
}
protected function fillParserOutput(
Content $content,
ContentParseParams $cpoParams,
ParserOutput &$output
) {
// define $html somewhere
// e.g. $output->setText( $html );
}
// atd. Podrobnosti viz dokumentace.
}
|
↑ |
Porovnejte revize | Buď přepíše ContentHandler::getDiffEngineClass() a DifferenceEngine::generateContentDiffBody() , nebo přepíše ContentHandler::getSlotDiffRendererWithOptions() a SlotDiffRenderer::getDiff
|
↑ |
Modify associated actions such as 'edit' | Přepíše ContentHandler::getActionOverrides() a EditAction::show()
|
↑ |
Související odkazy
- Manual:Hooks/ContentHandlerDefaultModelFor
- Nápověda:ChangeContentModel - pro dokumentaci pro koncového uživatele o změně modelu obsahu.
- Extension:Examples - pro příklad vlastního modelu obsahu (ale zatím ne pro vlastní editační formulář).