type = $type; $this->language = $language; } /** * @since 1.9 * * @param string|int $type * @param string|null $language * * @return Highlighter */ public static function factory( $type, $language = null ) { if ( $type === '' || !is_int( $type ) ) { $type = self::getTypeId( $type ); } return new Highlighter( $type, $language ); } /** * @since 3.0 * * @param string $text * @param string|null $type * * @return booelan */ public static function hasHighlighterClass( $text, $type = null ) { if ( strpos( $text, 'smw-highlighter' ) === false ) { return false; } if ( $type !== null ) { return strpos( $text, 'data-type="' . self::getTypeId( $type ) . '"' ) !== false; } return true; } /** * @since 3.0 * * @param string $text * * @return string */ public static function decode( $text ) { // #2347, '[' is handled by the MediaWiki parser/sanitizer itself return str_replace( [ '&', '<', '>', ' ', '', '' ], [ '&', '<', '>', ' ', '', '' ], $text ); } /** * Returns html output * * @since 1.9 * * @return string */ public function getHtml() { SMWOutputs::requireResource( 'ext.smw.tooltips' ); return $this->getContainer(); } /** * Set content * * An external class that invokes content via setContent has to ensure * that all data are appropriately escaped. * * @since 1.9 * * @param array $content * * @return array */ public function setContent( array $content ) { /** * @var $content * $content['caption'] = a text or null * $content['context'] = a text or null */ return $this->options = array_merge( $this->getTypeConfiguration( $this->type ), $content ); } /** * Returns type id * * @since 1.9 * * @param string $type * * @return integer */ public static function getTypeId( $type ) { // TODO: why do we have a htmlspecialchars here?! switch ( strtolower ( htmlspecialchars ( $type ) ) ) { case 'property': return self::TYPE_PROPERTY; case 'text': return self::TYPE_TEXT; case 'quantity': return self::TYPE_QUANTITY; case 'warning': return self::TYPE_WARNING; case 'error': return self::TYPE_ERROR; case 'info': return self::TYPE_INFO; case 'help': return self::TYPE_HELP; case 'note': return self::TYPE_NOTE; case 'service': return self::TYPE_SERVICE; case 'reference': return self::TYPE_REFERENCE; default: return self::TYPE_NOTYPE; } } /** * Builds Html container * * Content that is being invoked has to be escaped * @see Highlighter::setContent * * @since 1.9 * * @return string */ private function getContainer() { $captionclass = $this->options['captionclass']; // 2.4+ can display context for user-defined properties, here we ensure // to keep the style otherwise it displays italic which is by convention // reserved for predefined properties if ( $this->type === self::TYPE_PROPERTY && isset( $this->options['userDefined'] ) ) { $captionclass = $this->options['userDefined'] ? 'smwtext' : $captionclass; } $language = is_string( $this->language ) ? $this->language : Message::USER_LANGUAGE; $style = []; if ( isset( $this->options['style'] ) ) { $style = [ 'style' => $this->options['style'] ]; } // #1875 // title attribute contains stripped content to allow for a display in // no-js environments, the tooltip will remove the element once it is // loaded $title = $this->title( $this->options['content'], $language ); $html = Html::rawElement( 'span', [ 'class' => 'smw-highlighter', 'data-type' => $this->options['type'], 'data-content' => isset( $this->options['data-content'] ) ? $this->options['data-content'] : null, 'data-state' => $this->options['state'], 'data-title' => Message::get( $this->options['title'], Message::TEXT, $language ), 'title' => $title ] + $style, Html::rawElement( 'span', [ 'class' => $captionclass ], $this->options['caption'] ) . Html::rawElement( 'span', [ 'class' => 'smwttcontent' ], htmlspecialchars_decode( $this->options['content'] ) ) ); return $html; } /** * Returns initial configuration settings * * @note You could create a class per entity type but does this * really make sense just to get some configuration parameters? * * @since 1.9 * * @param string $type * * @return array */ private function getTypeConfiguration( $type ) { $settings = []; $settings['type'] = $type; $settings['caption'] = ''; $settings['content'] = ''; switch ( $type ) { case self::TYPE_PROPERTY: $settings['state'] = 'inline'; $settings['title'] = 'smw-ui-tooltip-title-property'; $settings['captionclass'] = 'smwbuiltin'; break; case self::TYPE_TEXT: $settings['state'] = 'persistent'; $settings['title'] = 'smw-ui-tooltip-title-info'; $settings['captionclass'] = 'smwtext'; break; case self::TYPE_QUANTITY: $settings['state'] = 'inline'; $settings['title'] = 'smw-ui-tooltip-title-quantity'; $settings['captionclass'] = 'smwtext'; break; case self::TYPE_NOTE: $settings['state'] = 'inline'; $settings['title'] = 'smw-ui-tooltip-title-note'; $settings['captionclass'] = 'smwtticon note'; break; case self::TYPE_WARNING: $settings['state'] = 'inline'; $settings['title'] = 'smw-ui-tooltip-title-warning'; $settings['captionclass'] = 'smwtticon warning'; break; case self::TYPE_ERROR: $settings['state'] = 'inline'; $settings['title'] = 'smw-ui-tooltip-title-error'; $settings['captionclass'] = 'smwtticon error'; break; case self::TYPE_SERVICE: $settings['state'] = 'persistent'; $settings['title'] = 'smw-ui-tooltip-title-service'; $settings['captionclass'] = 'smwtticon service'; break; case self::TYPE_REFERENCE: $settings['state'] = 'persistent'; $settings['title'] = 'smw-ui-tooltip-title-reference'; $settings['captionclass'] = 'smwtext'; break; case self::TYPE_HELP: case self::TYPE_INFO: $settings['state'] = 'persistent'; $settings['title'] = 'smw-ui-tooltip-title-info'; $settings['captionclass'] = 'smwtticon info'; break; case self::TYPE_NOTYPE: default: $settings['state'] = 'persistent'; $settings['title'] = 'smw-ui-tooltip-title-info'; $settings['captionclass'] = 'smwbuiltin'; }; return $settings; } private function title( $content, $language ) { // Pre-process the content when used as title to avoid breaking elements // (URLs etc.) if ( strpos( $content, '[' ) !== false || strpos( $content, '//' ) !== false ) { $content = Message::get( [ 'smw-parse', $content ], Message::PARSE, $language ); } return strip_tags( htmlspecialchars_decode( str_replace( [ "[", ' ' ], [ "[", ' ' ], $content ) ) ); } }