Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
86.96% |
20 / 23 |
|
66.67% |
2 / 3 |
CRAP | |
0.00% |
0 / 1 |
WikiLinkFixer | |
86.96% |
20 / 23 |
|
66.67% |
2 / 3 |
7.11 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getXPath | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
apply | |
85.71% |
18 / 21 |
|
0.00% |
0 / 1 |
5.07 |
1 | <?php |
2 | |
3 | namespace Flow\Parsoid\Fixer; |
4 | |
5 | use DOMElement; |
6 | use DOMNode; |
7 | use Flow\Conversion\Utils; |
8 | use Flow\Parsoid\Fixer; |
9 | use HtmlArmor; |
10 | use MediaWiki\Cache\LinkBatch; |
11 | use MediaWiki\MediaWikiServices; |
12 | use MediaWiki\Title\Title; |
13 | |
14 | /** |
15 | * Parsoid ignores red links. With good reason: redlinks should only be |
16 | * applied when rendering the content, not when it's created. |
17 | * |
18 | * This class updates HTML content from Parsoid with anchors generated by |
19 | * LinkRenderer. In addition to handling red links, this normalizes |
20 | * relative paths to start with a /, so the HTML renders correctly |
21 | * on any page. |
22 | */ |
23 | class WikiLinkFixer implements Fixer { |
24 | /** |
25 | * @var LinkBatch |
26 | */ |
27 | protected $batch; |
28 | |
29 | /** |
30 | * @param LinkBatch $batch |
31 | */ |
32 | public function __construct( LinkBatch $batch ) { |
33 | $this->batch = $batch; |
34 | } |
35 | |
36 | /** |
37 | * @return string |
38 | */ |
39 | public function getXPath() { |
40 | return '//a[contains(concat(" ",normalize-space(@rel)," ")," mw:WikiLink ")]'; |
41 | } |
42 | |
43 | /** |
44 | * Parsoid ignores red links. With good reason: redlinks should only be |
45 | * applied when rendering the content, not when it's created. |
46 | * |
47 | * This method will parse a given content, fetch all of its links & let MW's |
48 | * LinkRenderer build the link HTML (which will take redlinks into account.) |
49 | * It will then substitute original link HTML for the one LinkRenderer generated. |
50 | * |
51 | * This replaces both existing and non-existent anchors because the relative links |
52 | * output by parsoid are not usable when output within a subpage. |
53 | * |
54 | * @param DOMNode $node |
55 | * @param Title $title Title to resolve relative links against |
56 | * @throws \Flow\Exception\WikitextException |
57 | */ |
58 | public function apply( DOMNode $node, Title $title ) { |
59 | if ( !$node instanceof DOMElement ) { |
60 | return; |
61 | } |
62 | |
63 | $href = $node->getAttribute( 'href' ); |
64 | if ( $href === '' ) { |
65 | return; |
66 | } |
67 | |
68 | $title = Utils::createRelativeTitle( rawurldecode( $href ), $title ); |
69 | if ( $title === null ) { |
70 | return; |
71 | } |
72 | |
73 | // gather existing link attributes |
74 | $attributes = []; |
75 | foreach ( $node->attributes as $attribute ) { |
76 | $attributes[$attribute->name] = $attribute->value; |
77 | } |
78 | // let MW build link HTML based on Parsoid data |
79 | $html = MediaWikiServices::getInstance()->getLinkRenderer()->makeLink( |
80 | $title, |
81 | new HtmlArmor( Utils::getInnerHtml( $node ) ), |
82 | $attributes |
83 | ); |
84 | // create new DOM from this MW-built link |
85 | $replacementNode = Utils::createDOM( $html ) |
86 | ->getElementsByTagName( 'a' ) |
87 | ->item( 0 ); |
88 | // import MW-built link node into content DOM |
89 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal |
90 | $replacementNode = $node->ownerDocument->importNode( $replacementNode, true ); |
91 | // replace Parsoid link with MW-built link |
92 | $node->parentNode->replaceChild( $replacementNode, $node ); |
93 | } |
94 | } |