Příručka:Modely obsahu stránek

This page is a translated version of the page Manual:Page content models and the translation is 100% complete.
Pro content pages vs. non-content pages se podívejte na stránku: Manual:Using custom namespaces#Content namespaces.

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 ContentHandlerDefaultModelFor.

"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