Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
87.50% covered (warning)
87.50%
7 / 8
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
EmptyNodeFixer
87.50% covered (warning)
87.50%
7 / 8
50.00% covered (danger)
50.00%
1 / 2
3.02
0.00% covered (danger)
0.00%
0 / 1
 getXPath
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 apply
66.67% covered (warning)
66.67%
2 / 3
0.00% covered (danger)
0.00%
0 / 1
2.15
1<?php
2
3namespace Flow\Parsoid\Fixer;
4
5use Flow\Parsoid\Fixer;
6use MediaWiki\Title\Title;
7
8/**
9 * We use saveXML() instead of saveHTML() to serialize our HTML DOMs, to work around bugs
10 * in saveHTML(). However, saveXML() serializes all empty tags as self-closing tags.
11 * This is correct for some HTML tags (like <img>) but breaks for others (like <a>).
12 * We can pass LIBXML_NOEMPTYTAG to saveXML(), but then no self-closing tags will ever be
13 * generated, and we get output like <img></img>. We want self-closing tags for "void" elements
14 * (like <img />), but non-self-closing tags for other elements (like <a></a>).
15 *
16 * This fixer accomplishes this by inserting an empty text node into every childless non-void tag.
17 * It is not used to map Parsoid HTML to display HTML like the other fixers are; instead it's used
18 * whenever we serialize a DOM.
19 */
20class EmptyNodeFixer implements Fixer {
21    /**
22     * Returns XPath matching elements that need to be transformed
23     *
24     * @return string XPath of elements this acts on
25     */
26    public function getXPath() {
27        // List from https://www.w3.org/TR/2011/WD-html-markup-20110113/syntax.html#void-elements
28        $voidPattern = "self::area or self::base or self::br or self::col or self::command or " .
29            "self::embed or self::hr or self::img or self::input or self::keygen or self::link or " .
30            "self::meta or self::param or self::source or self::track or self::wbr";
31        // Find empty non-void elements
32        $pattern = "//*[not($voidPattern)][not(node())]";
33        return $pattern;
34    }
35
36    /**
37     * Adds an empty text node to an element.
38     *
39     * @param \DOMNode $node
40     * @param Title $title
41     */
42    public function apply( \DOMNode $node, Title $title ) {
43        if ( !$node instanceof \DOMElement ) {
44            return;
45        }
46
47        $node->appendChild( $node->ownerDocument->createTextNode( '' ) );
48    }
49}