summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Poem/Poem.class.php
blob: b366c97034dc971a2a586f92f9035095028a2b84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php
/**
 * This class handles formatting poems in WikiText, specifically anything within
 * <poem></poem> tags.
 */
class Poem {
	/**
	 * Bind the renderPoem function to the <poem> tag
	 * @param Parser &$parser
	 * @return bool true
	 */
	public static function init( &$parser ) {
		$parser->setHook( 'poem', [ 'Poem', 'renderPoem' ] );
		return true;
	}

	/**
	 * Parse the text into proper poem format
	 * @param string $in The text inside the poem tag
	 * @param array $param
	 * @param Parser $parser
	 * @param bool $frame
	 * @return string
	 */
	public static function renderPoem( $in, $param = [], $parser = null, $frame = false ) {
		// using newlines in the text will cause the parser to add <p> tags,
		// which may not be desired in some cases
		$newline = isset( $param['compact'] ) ? '' : "\n";

		$tag = $parser->insertStripItem( "<br />", $parser->mStripState );

		// replace colons with indented spans
		$text = preg_replace_callback( '/^(:+)(.+)$/m', [ 'Poem', 'indentVerse' ], $in );

		// replace newlines with <br /> tags unless they are at the beginning or end
		// of the poem
		$text = preg_replace(
			[ "/^\n/", "/\n$/D", "/\n/" ],
			[ "", "", "$tag\n" ],
			$text );

		// replace spaces at the beginning of a line with non-breaking spaces
		$text = preg_replace_callback( '/^( +)/m', [ 'Poem', 'replaceSpaces' ], $text );

		$text = $parser->recursiveTagParse( $text, $frame );

		$attribs = Sanitizer::validateTagAttributes( $param, 'div' );

		// Wrap output in a <div> with "poem" class.
		if ( isset( $attribs['class'] ) ) {
			$attribs['class'] = 'poem ' . $attribs['class'];
		} else {
			$attribs['class'] = 'poem';
		}

		return Html::rawElement( 'div', $attribs, $newline . trim( $text ) . $newline );
	}

	/**
	 * Callback for preg_replace_callback() that replaces spaces with non-breaking spaces
	 * @param array $m Matches from the regular expression
	 *   - $m[1] consists of 1 or more spaces
	 * @return mixed
	 */
	protected static function replaceSpaces( $m ) {
		return str_replace( ' ', '&#160;', $m[1] );
	}

	/**
	 * Callback for preg_replace_callback() that wraps content in an indented span
	 * @param array $m Matches from the regular expression
	 *   - $m[1] consists of 1 or more colons
	 *   - $m[2] consists of the text after the colons
	 * @return string
	 */
	protected static function indentVerse( $m ) {
		$attribs = [
			'class' => 'mw-poem-indented',
			'style' => 'display: inline-block; margin-left: ' . strlen( $m[1] ) . 'em;'
		];
		// @todo Should this really be raw?
		return Html::rawElement( 'span', $attribs, $m[2] );
	}
}