Index: trunk/phase3/skins/MonoBook.php |
— | — | @@ -204,10 +204,11 @@ |
205 | 205 | <?php $this->text( 'debug' ); ?> |
206 | 206 | |
207 | 207 | --> |
208 | | -<?php endif; ?> |
209 | | -</body></html> |
210 | | -<?php |
211 | | - wfRestoreWarnings(); |
| 208 | +<?php endif; |
| 209 | + |
| 210 | + echo Html::closeElement( 'body' ); |
| 211 | + echo Html::closeElement( 'html' ); |
| 212 | + wfRestoreWarnings(); |
212 | 213 | } // end of execute() method |
213 | 214 | |
214 | 215 | /*************************************************************************************************/ |
Index: trunk/phase3/includes/OutputPage.php |
— | — | @@ -2121,7 +2121,11 @@ |
2122 | 2122 | $ret .= "lang=\"$wgContLanguageCode\" dir=\"$dir\">\n"; |
2123 | 2123 | } |
2124 | 2124 | |
2125 | | - $ret .= "<head>\n"; |
| 2125 | + $openHead = Html::openElement( 'head' ); |
| 2126 | + if ( $openHead ) { |
| 2127 | + # Don't bother with the newline if $head == '' |
| 2128 | + $ret .= "$openHead\n"; |
| 2129 | + } |
2126 | 2130 | $ret .= "<title>" . htmlspecialchars( $this->getHTMLTitle() ) . "</title>\n"; |
2127 | 2131 | $ret .= implode( "\n", array( |
2128 | 2132 | $this->getHeadLinks(), |
— | — | @@ -2137,7 +2141,10 @@ |
2138 | 2142 | $ret .= $this->getTitle()->trackbackRDF(); |
2139 | 2143 | } |
2140 | 2144 | |
2141 | | - $ret .= "</head>\n"; |
| 2145 | + $closeHead = Html::closeElement( 'head' ); |
| 2146 | + if ( $closeHead ) { |
| 2147 | + $ret .= "$closeHead\n"; |
| 2148 | + } |
2142 | 2149 | |
2143 | 2150 | $bodyAttrs = array(); |
2144 | 2151 | |
Index: trunk/phase3/includes/Html.php |
— | — | @@ -117,7 +117,7 @@ |
118 | 118 | } |
119 | 119 | return $start; |
120 | 120 | } else { |
121 | | - return "$start$contents</$element>"; |
| 121 | + return "$start$contents" . self::closeElement( $element ); |
122 | 122 | } |
123 | 123 | } |
124 | 124 | |
— | — | @@ -136,15 +136,23 @@ |
137 | 137 | |
138 | 138 | /** |
139 | 139 | * Identical to rawElement(), but has no third parameter and omits the end |
140 | | - * tag (and the self-closing / in XML mode for empty elements). |
| 140 | + * tag (and the self-closing '/' in XML mode for empty elements). |
141 | 141 | */ |
142 | 142 | public static function openElement( $element, $attribs = array() ) { |
143 | | - global $wgHtml5; |
| 143 | + global $wgHtml5, $wgWellFormedXml; |
144 | 144 | $attribs = (array)$attribs; |
145 | 145 | # This is not required in HTML5, but let's do it anyway, for |
146 | 146 | # consistency and better compression. |
147 | 147 | $element = strtolower( $element ); |
148 | 148 | |
| 149 | + # In text/html, initial <html> and <head> tags can be omitted under |
| 150 | + # pretty much any sane circumstances, if they have no attributes. See: |
| 151 | + # <http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags> |
| 152 | + if ( !$wgWellFormedXml && !$attribs |
| 153 | + && in_array( $element, array( 'html', 'head' ) ) ) { |
| 154 | + return ''; |
| 155 | + } |
| 156 | + |
149 | 157 | # Remove HTML5-only attributes if we aren't doing HTML5 |
150 | 158 | if ( !$wgHtml5 ) { |
151 | 159 | if ( $element == 'input' ) { |
— | — | @@ -193,6 +201,36 @@ |
194 | 202 | } |
195 | 203 | |
196 | 204 | /** |
| 205 | + * Returns "</$element>", except if $wgWellFormedXml is off, in which case |
| 206 | + * it returns the empty string when that's guaranteed to be safe. |
| 207 | + * |
| 208 | + * @param $element string Name of the element, e.g., 'a' |
| 209 | + * @return string A closing tag, if required |
| 210 | + */ |
| 211 | + public static function closeElement( $element ) { |
| 212 | + global $wgWellFormedXml; |
| 213 | + |
| 214 | + $element = strtolower( $element ); |
| 215 | + |
| 216 | + # Reference: |
| 217 | + # http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags |
| 218 | + if ( !$wgWellFormedXml && in_array( $element, array( |
| 219 | + 'html', |
| 220 | + 'head', |
| 221 | + 'body', |
| 222 | + 'li', |
| 223 | + 'dt', |
| 224 | + 'dd', |
| 225 | + 'tr', |
| 226 | + 'td', |
| 227 | + 'th', |
| 228 | + ) ) ) { |
| 229 | + return ''; |
| 230 | + } |
| 231 | + return "</$element>"; |
| 232 | + } |
| 233 | + |
| 234 | + /** |
197 | 235 | * Given an element name and an associative array of element attributes, |
198 | 236 | * return an array that is functionally identical to the input array, but |
199 | 237 | * possibly smaller. In particular, attributes might be stripped if they |