inNamespace( NS_GADGET_DEFINITION ); } /** * @return string */ protected function getContentClass() { return GadgetDefinitionContent::class; } public function makeEmptyContent() { $class = $this->getContentClass(); return new $class( FormatJson::encode( $this->getDefaultMetadata(), "\t" ) ); } public function getDefaultMetadata() { return [ 'settings' => [ 'rights' => [], 'default' => false, 'package' => false, 'hidden' => false, 'skins' => [], 'actions' => [], 'category' => '' ], 'module' => [ 'scripts' => [], 'styles' => [], 'datas' => [], 'peers' => [], 'dependencies' => [], 'messages' => [], 'type' => '', ], ]; } /** * @param Title $title The title of the page to supply the updates for. * @param string $role The role (slot) in which the content is being used. * @return DeferrableUpdate[] A list of DeferrableUpdate objects for putting information * about this content object somewhere. */ public function getDeletionUpdates( Title $title, $role ) { return array_merge( parent::getDeletionUpdates( $title, $role ), [ new GadgetDefinitionDeletionUpdate( $title ) ] ); } /** * @param Title $title The title of the page to supply the updates for. * @param Content $content The content to generate data updates for. * @param string $role The role (slot) in which the content is being used. * @param SlotRenderingProvider $slotOutput A provider that can be used to gain access to * a ParserOutput of $content by calling $slotOutput->getSlotParserOutput( $role, false ). * @return DeferrableUpdate[] A list of DeferrableUpdate objects for putting information * about this content object somewhere. */ public function getSecondaryDataUpdates( Title $title, Content $content, $role, SlotRenderingProvider $slotOutput ) { return array_merge( parent::getSecondaryDataUpdates( $title, $content, $role, $slotOutput ), [ new GadgetDefinitionSecondaryDataUpdate( $title ) ] ); } /** * @inheritDoc */ protected function fillParserOutput( Content $content, ContentParseParams $cpoParams, ParserOutput &$output ) { '@phan-var GadgetDefinitionContent $content'; // Create a deep clone. FIXME: unserialize(serialize()) is hacky. $data = unserialize( serialize( $content->getData()->getValue() ) ); if ( $data !== null ) { foreach ( [ 'scripts', 'styles', 'datas' ] as $type ) { if ( isset( $data->module->{$type} ) ) { foreach ( $data->module->{$type} as &$page ) { $title = Title::makeTitleSafe( NS_GADGET, $page ); $this->makeLink( $output, $page, $title ); } } } foreach ( $data->module->dependencies as &$dep ) { if ( str_starts_with( $dep, 'ext.gadget.' ) ) { $gadgetId = explode( 'ext.gadget.', $dep )[1]; $title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $gadgetId ); $this->makeLink( $output, $dep, $title ); } } foreach ( $data->module->peers as &$peer ) { $title = Title::makeTitleSafe( NS_GADGET_DEFINITION, $peer ); $this->makeLink( $output, $peer, $title ); } foreach ( $data->module->messages as &$msg ) { $title = Title::makeTitleSafe( NS_MEDIAWIKI, $msg ); $this->makeLink( $output, $msg, $title ); } if ( $data->settings->category ) { $this->makeLink( $output, $data->settings->category, Title::makeTitleSafe( NS_MEDIAWIKI, "gadget-section-" . $data->settings->category ) ); } } if ( !$cpoParams->getGenerateHtml() || !$content->isValid() ) { $output->setText( '' ); } else { $output->setText( $content->rootValueTable( $data ) ); $output->addModuleStyles( 'mediawiki.content.json' ); } } /** * Create a link on the page * @param ParserOutput $output * @param string &$text The text to link * @param Title|null $title Link target title * @return void */ private function makeLink( ParserOutput $output, string &$text, ?Title $title ) { if ( $title ) { $output->addLink( $title ); $text = new GadgetDefinitionContentArmor( Linker::link( $title, htmlspecialchars( '"' . $text . '"' ) ) ); } } }