store = $store; $this->parserData = $parserData; $this->applicationFactory = ApplicationFactory::getInstance(); $this->dataValueFactory = DataValueFactory::getInstance(); } /** * @since 3.0 * * @param integer $featureSet */ public function setFeatureSet( $featureSet ) { $this->featureSet = $featureSet; } /** * @note contains information about wpPreview * * @since 2.1 * * @param boolean $previewFlag */ public function setPreviewFlag( $previewFlag ) { $this->previewFlag = $previewFlag; } /** * Builds content suitable for rendering a Factbox and * updating the ParserOutput accordingly * * @since 1.9 * * @return Factbox */ public function doBuild() { $this->content = $this->fetchContent( $this->getMagicWords() ); if ( $this->content !== '' ) { $this->parserData->getOutput()->addModules( $this->getModules() ); $this->parserData->pushSemanticDataToParserOutput(); $this->isVisible = true; } return $this; } /** * Returns Title object * * @since 1.9 * * @return string|null */ public function getTitle() { return $this->parserData->getTitle(); } /** * Returns content * * @since 1.9 * * @return string|null */ public function getContent() { return $this->content; } /** * Returns if content is visible * * @since 1.9 * * @return boolean */ public function isVisible() { return $this->isVisible; } /** * @since 3.0 * * @param string $rendered * @param string $derived * * @return string */ public static function tabs( $rendered, $derived = '' ) { $htmlTabs = new HtmlTabs(); $htmlTabs->setActiveTab( 'facts-rendered' ); $htmlTabs->tab( 'facts-rendered', Message::get( 'smw-factbox-facts' , Message::TEXT, Message::USER_LANGUAGE ), [ 'title' => Message::get( 'smw-factbox-facts-help' , Message::TEXT, Message::USER_LANGUAGE ) ] ); $htmlTabs->content( 'facts-rendered', $rendered ); $htmlTabs->tab( 'facts-derived', Message::get( 'smw-factbox-derived' , Message::TEXT, Message::USER_LANGUAGE ), [ 'hide' => $derived === '' ? true : false ] ); $htmlTabs->content( 'facts-derived', $derived ); return $htmlTabs->buildHTML( [ 'class' => 'smw-factbox' ] ); } /** * Returns magic words attached to the ParserOutput object * * @since 1.9 * * @return string|null */ protected function getMagicWords() { $settings = $this->applicationFactory->getSettings(); $parserOutput = $this->parserData->getOutput(); // Prior MW 1.21 mSMWMagicWords is used (see SMW\ParserTextProcessor) if ( method_exists( $parserOutput, 'getExtensionData' ) ) { $smwMagicWords = $parserOutput->getExtensionData( 'smwmagicwords' ); $mws = $smwMagicWords === null ? [] : $smwMagicWords; } else { // @codeCoverageIgnoreStart $mws = isset( $parserOutput->mSMWMagicWords ) ? $parserOutput->mSMWMagicWords : []; // @codeCoverageIgnoreEnd } if ( in_array( 'SMW_SHOWFACTBOX', $mws ) ) { $showfactbox = SMW_FACTBOX_NONEMPTY; } elseif ( in_array( 'SMW_NOFACTBOX', $mws ) ) { $showfactbox = SMW_FACTBOX_HIDDEN; } elseif ( $this->previewFlag ) { $showfactbox = $settings->get( 'smwgShowFactboxEdit' ); } else { $showfactbox = $settings->get( 'smwgShowFactbox' ); } return $showfactbox; } /** * Returns required resource modules * * @since 1.9 * * @return array */ protected function getModules() { return [ 'ext.smw.style', 'ext.smw.table.styles' ]; } /** * Returns content found for a given ParserOutput object and if the required * custom data was not available then semantic data are retrieved from * the store for a given subject. * * The method checks whether the given setting of $showfactbox requires * displaying the given data at all. * * @since 1.9 * * @return integer $showFactbox * * @return string|null */ protected function fetchContent( $showFactbox = SMW_FACTBOX_NONEMPTY ) { if ( $showFactbox === SMW_FACTBOX_HIDDEN ) { return ''; } $semanticData = $this->parserData->getSemanticData(); if ( $semanticData === null || $semanticData->stubObject || $this->isEmpty( $semanticData ) ) { $semanticData = $this->store->getSemanticData( $this->parserData->getSubject() ); } if ( $showFactbox === SMW_FACTBOX_SPECIAL && !$semanticData->hasVisibleSpecialProperties() ) { // show only if there are special properties return ''; } elseif ( $showFactbox === SMW_FACTBOX_NONEMPTY && !$semanticData->hasVisibleProperties() ) { // show only if non-empty return ''; } return $this->createTable( $semanticData ); } /** * Returns a formatted factbox table * * @since 1.9 * * @param SMWSemanticData $semanticData * * @return string|null */ protected function createTable( SemanticData $semanticData ) { $html = ''; // Hook deprecated with SMW 1.9 and will vanish with SMW 1.11 \Hooks::run( 'smwShowFactbox', [ &$html, $semanticData ] ); // Hook since 1.9 if ( \Hooks::run( 'SMW::Factbox::BeforeContentGeneration', [ &$html, $semanticData ] ) ) { $header = $this->createHeader( $semanticData->getSubject() ); $rows = $this->createRows( $semanticData ); $html .= Html::rawElement( 'div', [ 'class' => 'smwfact', 'style' => 'display:block;' ], $header . HtmlDivTable::table( $rows, [ 'class' => 'smwfacttable' ] ) ); } return $html; } private function createHeader( DIWikiPage $subject ) { $dataValue = $this->dataValueFactory->newDataValueByItem( $subject, null ); $browselink = SMWInfolink::newBrowsingLink( $dataValue->getPreferredCaption(), $dataValue->getWikiValue(), '' ); $header = Html::rawElement( 'div', [ 'class' => 'smwfactboxhead' ], Message::get( [ 'smw-factbox-head', $browselink->getWikiText() ], Message::TEXT, Message::USER_LANGUAGE ) ); $rdflink = SMWInfolink::newInternalLink( Message::get( 'smw_viewasrdf', Message::TEXT, Message::USER_LANGUAGE ), Localizer::getInstance()->getNamespaceTextById( NS_SPECIAL ) . ':ExportRDF/' . $dataValue->getWikiValue(), 'rdflink' ); $header .= Html::rawElement( 'div', [ 'class' => 'smwrdflink' ], $rdflink->getWikiText() ); return $header; } private function createRows( SemanticData $semanticData ) { $rows = ''; $attributes = []; $comma = Message::get( 'comma-separator', Message::ESCAPED, Message::USER_LANGUAGE ); $and = Message::get( 'and', Message::ESCAPED, Message::USER_LANGUAGE ); foreach ( $semanticData->getProperties() as $property ) { if ( $property->getKey() === '_SOBJ' && !$this->hasFeature( SMW_FACTBOX_DISPLAY_SUBOBJECT ) ) { continue; } $propertyDv = $this->dataValueFactory->newDataValueByItem( $property, null ); $row = ''; if ( !$property->isShown() ) { // showing this is not desired, hide continue; } elseif ( $property->isUserDefined() ) { $propertyDv->setCaption( $propertyDv->getWikiValue() ); $attributes['property'] = [ 'class' => 'smwpropname' ]; $attributes['values'] = [ 'class' => 'smwprops' ]; } elseif ( $propertyDv->isVisible() ) { // Predefined property $attributes['property'] = [ 'class' => 'smwspecname' ]; $attributes['values'] = [ 'class' => 'smwspecs' ]; } else { // predefined, internal property // @codeCoverageIgnoreStart continue; // @codeCoverageIgnoreEnd } $list = []; $html = ''; foreach ( $semanticData->getPropertyValues( $property ) as $dataItem ) { $dataValue = $this->dataValueFactory->newDataValueByItem( $dataItem, $property ); $outputFormat = $dataValue->getOutputFormat(); $dataValue->setOutputFormat( $outputFormat ? $outputFormat : 'LOCL' ); $dataValue->setOption( $dataValue::OPT_DISABLE_SERVICELINKS, true ); if ( $dataValue->isValid() ) { $list[] = $dataValue->getLongWikiText( true ) . $dataValue->getInfolinkText( SMW_OUTPUT_WIKI ); } } if ( $list !== [] ) { $last = array_pop( $list ); if ( $list === [] ) { $html = $last; } else { $html = implode( $comma, $list ) . ' ' . $and . ' ' . $last; } } $row .= HtmlDivTable::cell( $propertyDv->getShortWikiText( true ), $attributes['property'] ); $row .= HtmlDivTable::cell( $html, $attributes['values'] ); $rows .= HtmlDivTable::row( $row ); } return $rows; } private function isEmpty( SemanticData $semanticData ) { // MW's internal Parser does iterate the ParserOutput object several times // which can leave a '_SKEY' property while in fact the container is empty. $semanticData->removeProperty( new DIProperty( '_SKEY' ) ); return $semanticData->isEmpty(); } private function hasFeature( $feature ) { return ( (int)$this->featureSet & $feature ) != 0; } }