Bartosz Dziewoński has uploaded a new change for review.
https://gerrit.wikimedia.org/r/249452
Change subject: Implement <button> tag in wikitext for OOjs UI clickable buttons
......................................................................
Implement <button> tag in wikitext for OOjs UI clickable buttons
Bug: T101666
Change-Id: I91467297de4b7c532448a4c20b9a0dc8216c7200
---
M includes/parser/CoreTagHooks.php
M includes/parser/Parser.php
2 files changed, 140 insertions(+), 19 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/52/249452/1
diff --git a/includes/parser/CoreTagHooks.php b/includes/parser/CoreTagHooks.php
index 9755ea9..59b4391 100644
--- a/includes/parser/CoreTagHooks.php
+++ b/includes/parser/CoreTagHooks.php
@@ -36,6 +36,7 @@
$parser->setHook( 'nowiki', array( __CLASS__, 'nowiki' ) );
$parser->setHook( 'gallery', array( __CLASS__, 'gallery' ) );
$parser->setHook( 'indicator', array( __CLASS__, 'indicator' )
);
+ $parser->setHook( 'button', array( __CLASS__, 'button' ) );
if ( $wgRawHtml ) {
$parser->setHook( 'html', array( __CLASS__, 'html' ) );
}
@@ -146,4 +147,96 @@
return '';
}
+
+ /**
+ * XML-style tag for OOjs UI clickable button links.
+ *
+ * A button must have a valid `link` attribute, and content or valid
`icon` (or both).
+ * All other attributes are optional.
+ *
+ * @param string $content Button label
+ * @param array $attributes
+ * - `link`: any internal or external link target, treated like the
'link' parameter in image syntax
+ * - `title`: link tooltip, default is generated from `link`
+ * - `icon`: name of the icon to display next to button label
+ * - `flags`: space-separated list of flags to apply,
progressive/constructive/destructive/primary
+ * - `frameless`: whether to show a covert button that pretends not
to be one (boolean)
+ * @param Parser $parser
+ * @param PPFrame $frame
+ * @return string
+ * @since 1.27
+ */
+ public static function button( $content, array $attributes, Parser
$parser, PPFrame $frame ) {
+ $parser->enableOOUI();
+
+ $config = array();
+
+ if ( $content ) {
+ $parsed = $parser->recursiveTagParseFully( $content,
$frame );
+ $stripped = Parser::stripOuterParagraph( $parsed );
+ if ( $parsed === $stripped ) {
+ return '<span class="error">' .
+ wfMessage(
'tag-button-must-be-single-line' )->inContentLanguage()->parse() .
+ '</span>';
+ }
+ if ( strpos( $stripped, '<a ') !== false ) {
+ return '<span class="error">' .
+ wfMessage(
'tag-button-must-not-nest-links' )->inContentLanguage()->parse() .
+ '</span>';
+ }
+ $config['label'] = new OOUI\HtmlSnippet( $stripped );
+ }
+ if ( isset( $attributes['icon'] ) ) {
+ // TODO Validate and load required additional modules
+ $config['icon'] = $attributes['icon'];
+ }
+ if ( !isset( $config['label'] ) && !isset( $config['icon'] ) ) {
+ return '<span class="error">' .
+ wfMessage( 'tag-button-must-have-content'
)->inContentLanguage()->parse() .
+ '</span>';
+ }
+
+ if ( isset( $attributes['link'] ) ) {
+ list( $type, $target ) = $parser->parseLinkParameter(
$attributes['link'] );
+ // We intentionally do not add any classes like 'new'
or 'redirect' to button links
+ if ( $type === 'link-url' ) {
+ $config['href'] = $target;
+ if ( $parser->mOptions->getExternalLinkTarget()
) {
+ $config['target'] =
$parser->mOptions->getExternalLinkTarget();
+ }
+ $config['noFollow'] =
Parser::getExternalLinkRel( $target ) === 'nofollow';
+ } elseif ( $type === 'link-title' ) {
+ $config['href'] = $target->getLinkURL();
+ $config['title'] = $target->getPrefixedText();
+ $config['noFollow'] = false;
+ }
+ }
+ if ( !isset( $config['href'] ) ) {
+ return '<span class="error">' .
+ wfMessage( 'tag-button-must-have-link'
)->inContentLanguage()->parse() .
+ '</span>';
+ }
+ if ( isset( $attributes['title'] ) ) {
+ // Overwrites the default from 'link', if any
+ $config['title'] = $attributes['title'];
+ }
+
+ if ( isset( $attributes['frameless'] ) ) {
+ $config['framed'] = false;
+ }
+ if ( isset( $attributes['flags'] ) ) {
+ $config['flags'] = array_filter( array_map( 'trim',
explode( ' ', $attributes['flags'] ) ) );
+ }
+
+ $button = new OOUI\ButtonWidget( $config );
+ // Prevent paragraphs breaking on the <div> tag
+ $prop = new ReflectionProperty( 'OOUI\\ButtonWidget', 'tag' );
+ $prop->setAccessible( true );
+ $prop->setValue( $button, 'span' );
+ $button = $button->toString();
+ // Prevent Tidy from removing empty <span> tags (used to
display the icon)
+ $button = str_replace( '></span>', '><!-- --></span>', $button
);
+ // Prevent further parsing
+ return array( $button, 'markerType' => 'nowiki' );
+ }
}
diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php
index 9060756..fd02128 100644
--- a/includes/parser/Parser.php
+++ b/includes/parser/Parser.php
@@ -5610,29 +5610,16 @@
$value =
$this->stripAltText( $value, $holders );
break;
case 'link':
- $chars =
self::EXT_LINK_URL_CLASS;
- $addr =
self::EXT_LINK_ADDR;
- $prots =
$this->mUrlProtocols;
- if ( $value === '' ) {
- $paramName =
'no-link';
- $value = true;
+ list( $paramName,
$value ) = $this->parseLinkParameter( $value );
+ if ( $paramName ) {
$validated =
true;
- } elseif ( preg_match(
"/^((?i)$prots)/", $value ) ) {
- if (
preg_match( "/^((?i)$prots)$addr$chars*$/u", $value, $m ) ) {
-
$paramName = 'link-url';
-
$this->mOutput->addExternalLink( $value );
+ if ( $paramName
=== 'no-link' ) {
+ $value
= true;
+ }
+ if ( $paramName
=== 'link-url' ) {
if (
$this->mOptions->getExternalLinkTarget() ) {
$params[$type]['link-target'] = $this->mOptions->getExternalLinkTarget();
}
-
$validated = true;
- }
- } else {
- $linkTitle =
Title::newFromText( $value );
- if ( $linkTitle
) {
-
$paramName = 'link-title';
- $value
= $linkTitle;
-
$this->mOutput->addLink( $linkTitle );
-
$validated = true;
}
}
break;
@@ -5730,6 +5717,47 @@
}
/**
+ * Parse the value of 'link' parameter in image syntax
(`[[File:Foo.jpg|link=<val>]]`).
+ *
+ * Adds an entry to appropriate link tables.
+ *
+ * @return array `array( type, target )`, where:
+ * - `type` is one of:
+ * - `null`: Given value is not a valid link target, use default
+ * - `'no-link'`: Given value is empty, do not generate a link
+ * - `'link-url'`: Given value is a valid external link
+ * - `'link-title'`: Given value is a valid internal link
+ * - `target` is:
+ * - When `type` is `null` or `'no-link'`: `false`
+ * - When `type` is `'link-url'`: URL string corresponding to given
value
+ * - When `type` is `'link-title'`: Title object corresponding to
given value
+ */
+ public function parseLinkParameter( $value ) {
+ $chars = self::EXT_LINK_URL_CLASS;
+ $addr = self::EXT_LINK_ADDR;
+ $prots = $this->mUrlProtocols;
+ $type = null;
+ $target = false;
+ if ( $value === '' ) {
+ $type = 'no-link';
+ } elseif ( preg_match( "/^((?i)$prots)/", $value ) ) {
+ if ( preg_match( "/^((?i)$prots)$addr$chars*$/u",
$value, $m ) ) {
+ $this->mOutput->addExternalLink( $value );
+ $type = 'link-url';
+ $target = $value;
+ }
+ } else {
+ $linkTitle = Title::newFromText( $value );
+ if ( $linkTitle ) {
+ $this->mOutput->addLink( $linkTitle );
+ $type = 'link-title';
+ $target = $linkTitle;
+ }
+ }
+ return array( $type, $target );
+ }
+
+ /**
* @param string $caption
* @param LinkHolderArray|bool $holders
* @return mixed|string
--
To view, visit https://gerrit.wikimedia.org/r/249452
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I91467297de4b7c532448a4c20b9a0dc8216c7200
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits