Omit some start/end tags if not well-formed XML
authorAryeh Gregor <simetrical@users.mediawiki.org>
Sun, 21 Mar 2010 05:12:02 +0000 (05:12 +0000)
committerAryeh Gregor <simetrical@users.mediawiki.org>
Sun, 21 Mar 2010 05:12:02 +0000 (05:12 +0000)
includes/Html.php
includes/OutputPage.php
skins/MonoBook.php

index 84acf31..b56a6d0 100644 (file)
@@ -117,7 +117,7 @@ class Html {
                        }
                        return $start;
                } else {
-                       return "$start$contents</$element>";
+                       return "$start$contents" . self::closeElement( $element );
                }
        }
 
@@ -136,15 +136,23 @@ class Html {
 
        /**
         * Identical to rawElement(), but has no third parameter and omits the end
-        * tag (and the self-closing / in XML mode for empty elements).
+        * tag (and the self-closing '/' in XML mode for empty elements).
         */
        public static function openElement( $element, $attribs = array() ) {
-               global $wgHtml5;
+               global $wgHtml5, $wgWellFormedXml;
                $attribs = (array)$attribs;
                # This is not required in HTML5, but let's do it anyway, for
                # consistency and better compression.
                $element = strtolower( $element );
 
+               # In text/html, initial <html> and <head> tags can be omitted under
+               # pretty much any sane circumstances, if they have no attributes.  See:
+               # <http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags>
+               if ( !$wgWellFormedXml && !$attribs
+               && in_array( $element, array( 'html', 'head' ) ) ) {
+                       return '';
+               }
+
                # Remove HTML5-only attributes if we aren't doing HTML5
                if ( !$wgHtml5 ) {
                        if ( $element == 'input' ) {
@@ -192,6 +200,36 @@ class Html {
                        self::dropDefaults( $element, $attribs ) ) . '>';
        }
 
+       /**
+        * Returns "</$element>", except if $wgWellFormedXml is off, in which case
+        * it returns the empty string when that's guaranteed to be safe.
+        *
+        * @param $element string Name of the element, e.g., 'a'
+        * @return string A closing tag, if required
+        */
+       public static function closeElement( $element ) {
+               global $wgWellFormedXml;
+
+               $element = strtolower( $element );
+
+               # Reference:
+               # http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags
+               if ( !$wgWellFormedXml && in_array( $element, array(
+                       'html',
+                       'head',
+                       'body',
+                       'li',
+                       'dt',
+                       'dd',
+                       'tr',
+                       'td',
+                       'th',
+               ) ) ) {
+                       return '';
+               }
+               return "</$element>";
+       }
+
        /**
         * Given an element name and an associative array of element attributes,
         * return an array that is functionally identical to the input array, but
index 8a80cc3..facd93f 100644 (file)
@@ -2121,7 +2121,11 @@ class OutputPage {
                        $ret .= "lang=\"$wgContLanguageCode\" dir=\"$dir\">\n";
                }
 
-               $ret .= "<head>\n";
+               $openHead = Html::openElement( 'head' );
+               if ( $openHead ) {
+                       # Don't bother with the newline if $head == ''
+                       $ret .= "$openHead\n";
+               }
                $ret .= "<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n";
                $ret .= implode( "\n", array(
                        $this->getHeadLinks(),
@@ -2137,7 +2141,10 @@ class OutputPage {
                        $ret .= $this->getTitle()->trackbackRDF();
                }
 
-               $ret .= "</head>\n";
+               $closeHead = Html::closeElement( 'head' );
+               if ( $closeHead ) {
+                       $ret .= "$closeHead\n";
+               }
 
                $bodyAttrs = array();
 
index fdc1684..68aa2f9 100644 (file)
@@ -204,10 +204,11 @@ if($this->data['copyrightico']) { ?>
 <?php $this->text( 'debug' ); ?>
 
 -->
-<?php endif; ?>
-</body></html>
-<?php
-       wfRestoreWarnings();
+<?php endif;
+
+               echo Html::closeElement( 'body' );
+               echo Html::closeElement( 'html' );
+               wfRestoreWarnings();
        } // end of execute() method
 
        /*************************************************************************************************/