MediaWiki  REL1_20
Html.php
Go to the documentation of this file.
00001 <?php
00050 class Html {
00051         # List of void elements from HTML5, section 8.1.2 as of 2011-08-12
00052         private static $voidElements = array(
00053                 'area',
00054                 'base',
00055                 'br',
00056                 'col',
00057                 'command',
00058                 'embed',
00059                 'hr',
00060                 'img',
00061                 'input',
00062                 'keygen',
00063                 'link',
00064                 'meta',
00065                 'param',
00066                 'source',
00067                 'track',
00068                 'wbr',
00069         );
00070 
00071         # Boolean attributes, which may have the value omitted entirely.  Manually
00072         # collected from the HTML5 spec as of 2011-08-12.
00073         private static $boolAttribs = array(
00074                 'async',
00075                 'autofocus',
00076                 'autoplay',
00077                 'checked',
00078                 'controls',
00079                 'default',
00080                 'defer',
00081                 'disabled',
00082                 'formnovalidate',
00083                 'hidden',
00084                 'ismap',
00085                 'itemscope',
00086                 'loop',
00087                 'multiple',
00088                 'muted',
00089                 'novalidate',
00090                 'open',
00091                 'pubdate',
00092                 'readonly',
00093                 'required',
00094                 'reversed',
00095                 'scoped',
00096                 'seamless',
00097                 'selected',
00098                 'truespeed',
00099                 'typemustmatch',
00100                 # HTML5 Microdata
00101                 'itemscope',
00102         );
00103 
00104         private static $HTMLFiveOnlyAttribs = array(
00105                 'autocomplete',
00106                 'autofocus',
00107                 'max',
00108                 'min',
00109                 'multiple',
00110                 'pattern',
00111                 'placeholder',
00112                 'required',
00113                 'step',
00114                 'spellcheck',
00115         );
00116 
00137         public static function rawElement( $element, $attribs = array(), $contents = '' ) {
00138                 global $wgWellFormedXml;
00139                 $start = self::openElement( $element, $attribs );
00140                 if ( in_array( $element, self::$voidElements ) ) {
00141                         if ( $wgWellFormedXml ) {
00142                                 # Silly XML.
00143                                 return substr( $start, 0, -1 ) . ' />';
00144                         }
00145                         return $start;
00146                 } else {
00147                         return "$start$contents" . self::closeElement( $element );
00148                 }
00149         }
00150 
00161         public static function element( $element, $attribs = array(), $contents = '' ) {
00162                 return self::rawElement( $element, $attribs, strtr( $contents, array(
00163                         # There's no point in escaping quotes, >, etc. in the contents of
00164                         # elements.
00165                         '&' => '&amp;',
00166                         '<' => '&lt;'
00167                 ) ) );
00168         }
00169 
00179         public static function openElement( $element, $attribs = array() ) {
00180                 global $wgHtml5, $wgWellFormedXml;
00181                 $attribs = (array)$attribs;
00182                 # This is not required in HTML5, but let's do it anyway, for
00183                 # consistency and better compression.
00184                 $element = strtolower( $element );
00185 
00186                 # In text/html, initial <html> and <head> tags can be omitted under
00187                 # pretty much any sane circumstances, if they have no attributes.  See:
00188                 # <http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags>
00189                 if ( !$wgWellFormedXml && !$attribs
00190                 && in_array( $element, array( 'html', 'head' ) ) ) {
00191                         return '';
00192                 }
00193 
00194                 # Remove HTML5-only attributes if we aren't doing HTML5, and disable
00195                 # form validation regardless (see bug 23769 and the more detailed
00196                 # comment in expandAttributes())
00197                 if ( $element == 'input' ) {
00198                         # Whitelist of types that don't cause validation.  All except
00199                         # 'search' are valid in XHTML1.
00200                         $validTypes = array(
00201                                 'hidden',
00202                                 'text',
00203                                 'password',
00204                                 'checkbox',
00205                                 'radio',
00206                                 'file',
00207                                 'submit',
00208                                 'image',
00209                                 'reset',
00210                                 'button',
00211                                 'search',
00212                         );
00213 
00214                         if( $wgHtml5 ) {
00215                                 $validTypes = array_merge( $validTypes, array(
00216                                         'datetime',
00217                                         'datetime-local',
00218                                         'date',
00219                                         'month',
00220                                         'time',
00221                                         'week',
00222                                         'number',
00223                                         'range',
00224                                         'email',
00225                                         'url',
00226                                         'search',
00227                                         'tel',
00228                                         'color',
00229                                 ) );
00230                         }
00231                         if ( isset( $attribs['type'] )
00232                         && !in_array( $attribs['type'], $validTypes ) ) {
00233                                 unset( $attribs['type'] );
00234                         }
00235 
00236                         if ( isset( $attribs['type'] ) && $attribs['type'] == 'search'
00237                         && !$wgHtml5 ) {
00238                                 unset( $attribs['type'] );
00239                         }
00240                 }
00241 
00242                 if ( !$wgHtml5 && $element == 'textarea' && isset( $attribs['maxlength'] ) ) {
00243                         unset( $attribs['maxlength'] );
00244                 }
00245 
00246                 return "<$element" . self::expandAttributes(
00247                         self::dropDefaults( $element, $attribs ) ) . '>';
00248         }
00249 
00258         public static function closeElement( $element ) {
00259                 global $wgWellFormedXml;
00260 
00261                 $element = strtolower( $element );
00262 
00263                 # Reference:
00264                 # http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#optional-tags
00265                 if ( !$wgWellFormedXml && in_array( $element, array(
00266                         'html',
00267                         'head',
00268                         'body',
00269                         'li',
00270                         'dt',
00271                         'dd',
00272                         'tr',
00273                         'td',
00274                         'th',
00275                 ) ) ) {
00276                         return '';
00277                 }
00278                 return "</$element>";
00279         }
00280 
00298         private static function dropDefaults( $element, $attribs ) {
00299                 # Don't bother doing anything if we aren't outputting HTML5; it's too
00300                 # much of a pain to maintain two sets of defaults.
00301                 global $wgHtml5;
00302                 if ( !$wgHtml5 ) {
00303                         return $attribs;
00304                 }
00305 
00306                 # Whenever altering this array, please provide a covering test case
00307                 # in HtmlTest::provideElementsWithAttributesHavingDefaultValues
00308                 static $attribDefaults = array(
00309                         'area' => array( 'shape' => 'rect' ),
00310                         'button' => array(
00311                                 'formaction' => 'GET',
00312                                 'formenctype' => 'application/x-www-form-urlencoded',
00313                                 'type' => 'submit',
00314                         ),
00315                         'canvas' => array(
00316                                 'height' => '150',
00317                                 'width' => '300',
00318                         ),
00319                         'command' => array( 'type' => 'command' ),
00320                         'form' => array(
00321                                 'action' => 'GET',
00322                                 'autocomplete' => 'on',
00323                                 'enctype' => 'application/x-www-form-urlencoded',
00324                         ),
00325                         'input' => array(
00326                                 'formaction' => 'GET',
00327                                 'type' => 'text',
00328                         ),
00329                         'keygen' => array( 'keytype' => 'rsa' ),
00330                         'link' => array( 'media' => 'all' ),
00331                         'menu' => array( 'type' => 'list' ),
00332                         # Note: the use of text/javascript here instead of other JavaScript
00333                         # MIME types follows the HTML5 spec.
00334                         'script' => array( 'type' => 'text/javascript' ),
00335                         'style' => array(
00336                                 'media' => 'all',
00337                                 'type' => 'text/css',
00338                         ),
00339                         'textarea' => array( 'wrap' => 'soft' ),
00340                 );
00341 
00342                 $element = strtolower( $element );
00343 
00344                 foreach ( $attribs as $attrib => $value ) {
00345                         $lcattrib = strtolower( $attrib );
00346                         if( is_array( $value ) ) {
00347                                 $value = implode( ' ', $value );
00348                         } else {
00349                                 $value = strval( $value );
00350                         }
00351 
00352                         # Simple checks using $attribDefaults
00353                         if ( isset( $attribDefaults[$element][$lcattrib] ) &&
00354                         $attribDefaults[$element][$lcattrib] == $value ) {
00355                                 unset( $attribs[$attrib] );
00356                         }
00357 
00358                         if ( $lcattrib == 'class' && $value == '' ) {
00359                                 unset( $attribs[$attrib] );
00360                         }
00361                 }
00362 
00363                 # More subtle checks
00364                 if ( $element === 'link' && isset( $attribs['type'] )
00365                 && strval( $attribs['type'] ) == 'text/css' ) {
00366                         unset( $attribs['type'] );
00367                 }
00368                 if ( $element === 'input' ) {
00369                         $type = isset( $attribs['type'] ) ? $attribs['type'] : null;
00370                         $value = isset( $attribs['value'] ) ? $attribs['value'] : null;
00371                         if ( $type === 'checkbox' || $type === 'radio' ) {
00372                                 // The default value for checkboxes and radio buttons is 'on'
00373                                 // not ''. By stripping value="" we break radio boxes that
00374                                 // actually wants empty values.
00375                                 if ( $value === 'on' ) {
00376                                         unset( $attribs['value'] );
00377                                 }
00378                         } elseif ( $type === 'submit' ) {
00379                                 // The default value for submit appears to be "Submit" but
00380                                 // let's not bother stripping out localized text that matches
00381                                 // that.
00382                         } else {
00383                                 // The default value for nearly every other field type is ''
00384                                 // The 'range' and 'color' types use different defaults but
00385                                 // stripping a value="" does not hurt them.
00386                                 if ( $value === '' ) {
00387                                         unset( $attribs['value'] );
00388                                 }
00389                         }
00390                 }
00391                 if ( $element === 'select' && isset( $attribs['size'] ) ) {
00392                         if ( in_array( 'multiple', $attribs )
00393                                 || ( isset( $attribs['multiple'] ) && $attribs['multiple'] !== false )
00394                         ) {
00395                                 # A multi-select
00396                                 if ( strval( $attribs['size'] ) == '4' ) {
00397                                         unset( $attribs['size'] );
00398                                 }
00399                         } else {
00400                                 # Single select
00401                                 if ( strval( $attribs['size'] ) == '1' ) {
00402                                         unset( $attribs['size'] );
00403                                 }
00404                         }
00405                 }
00406 
00407                 return $attribs;
00408         }
00409 
00449         public static function expandAttributes( $attribs ) {
00450                 global $wgHtml5, $wgWellFormedXml;
00451 
00452                 $ret = '';
00453                 $attribs = (array)$attribs;
00454                 foreach ( $attribs as $key => $value ) {
00455                         if ( $value === false || is_null( $value ) ) {
00456                                 continue;
00457                         }
00458 
00459                         # For boolean attributes, support array( 'foo' ) instead of
00460                         # requiring array( 'foo' => 'meaningless' ).
00461                         if ( is_int( $key )
00462                         && in_array( strtolower( $value ), self::$boolAttribs ) ) {
00463                                 $key = $value;
00464                         }
00465 
00466                         # Not technically required in HTML5, but required in XHTML 1.0,
00467                         # and we'd like consistency and better compression anyway.
00468                         $key = strtolower( $key );
00469 
00470                         # Here we're blacklisting some HTML5-only attributes...
00471                         if ( !$wgHtml5 && in_array( $key, self::$HTMLFiveOnlyAttribs )
00472                          ) {
00473                                 continue;
00474                         }
00475 
00476                         # Bug 23769: Blacklist all form validation attributes for now.  Current
00477                         # (June 2010) WebKit has no UI, so the form just refuses to submit
00478                         # without telling the user why, which is much worse than failing
00479                         # server-side validation.  Opera is the only other implementation at
00480                         # this time, and has ugly UI, so just kill the feature entirely until
00481                         # we have at least one good implementation.
00482 
00483                         # As the default value of "1" for "step" rejects decimal
00484                         # numbers to be entered in 'type="number"' fields, allow
00485                         # the special case 'step="any"'.
00486 
00487                         if ( in_array( $key, array( 'max', 'min', 'pattern', 'required' ) ) ||
00488                                  $key === 'step' && $value !== 'any' ) {
00489                                 continue;
00490                         }
00491 
00492                         // http://www.w3.org/TR/html401/index/attributes.html ("space-separated")
00493                         // http://www.w3.org/TR/html5/index.html#attributes-1 ("space-separated")
00494                         $spaceSeparatedListAttributes = array(
00495                                 'class', // html4, html5
00496                                 'accesskey', // as of html5, multiple space-separated values allowed
00497                                 // html4-spec doesn't document rel= as space-separated
00498                                 // but has been used like that and is now documented as such 
00499                                 // in the html5-spec.
00500                                 'rel',
00501                         );
00502 
00503                         # Specific features for attributes that allow a list of space-separated values
00504                         if ( in_array( $key, $spaceSeparatedListAttributes ) ) {
00505                                 // Apply some normalization and remove duplicates
00506 
00507                                 // Convert into correct array. Array can contain space-seperated
00508                                 // values. Implode/explode to get those into the main array as well.
00509                                 if ( is_array( $value ) ) {
00510                                         // If input wasn't an array, we can skip this step
00511                                         
00512                                         $newValue = array();
00513                                         foreach ( $value as $k => $v ) {
00514                                                 if ( is_string( $v ) ) {
00515                                                         // String values should be normal `array( 'foo' )`
00516                                                         // Just append them
00517                                                         if ( !isset( $value[$v] ) ) {
00518                                                                 // As a special case don't set 'foo' if a
00519                                                                 // separate 'foo' => true/false exists in the array
00520                                                                 // keys should be authoritive
00521                                                                 $newValue[] = $v;
00522                                                         }
00523                                                 } elseif ( $v ) {
00524                                                         // If the value is truthy but not a string this is likely
00525                                                         // an array( 'foo' => true ), falsy values don't add strings
00526                                                         $newValue[] = $k;
00527                                                 }
00528                                         }
00529                                         $value = implode( ' ', $newValue );
00530                                 }
00531                                 $value = explode( ' ', $value );
00532 
00533                                 // Normalize spacing by fixing up cases where people used
00534                                 // more than 1 space and/or a trailing/leading space
00535                                 $value = array_diff( $value, array( '', ' ' ) );
00536 
00537                                 // Remove duplicates and create the string
00538                                 $value = implode( ' ', array_unique( $value ) );
00539                         }
00540 
00541                         # See the "Attributes" section in the HTML syntax part of HTML5,
00542                         # 9.1.2.3 as of 2009-08-10.  Most attributes can have quotation
00543                         # marks omitted, but not all.  (Although a literal " is not
00544                         # permitted, we don't check for that, since it will be escaped
00545                         # anyway.)
00546                         #
00547                         # See also research done on further characters that need to be
00548                         # escaped: http://code.google.com/p/html5lib/issues/detail?id=93
00549                         $badChars = "\\x00- '=<>`/\x{00a0}\x{1680}\x{180e}\x{180F}\x{2000}\x{2001}"
00550                                 . "\x{2002}\x{2003}\x{2004}\x{2005}\x{2006}\x{2007}\x{2008}\x{2009}"
00551                                 . "\x{200A}\x{2028}\x{2029}\x{202F}\x{205F}\x{3000}";
00552                         if ( $wgWellFormedXml || $value === ''
00553                         || preg_match( "![$badChars]!u", $value ) ) {
00554                                 $quote = '"';
00555                         } else {
00556                                 $quote = '';
00557                         }
00558 
00559                         if ( in_array( $key, self::$boolAttribs ) ) {
00560                                 # In XHTML 1.0 Transitional, the value needs to be equal to the
00561                                 # key.  In HTML5, we can leave the value empty instead.  If we
00562                                 # don't need well-formed XML, we can omit the = entirely.
00563                                 if ( !$wgWellFormedXml ) {
00564                                         $ret .= " $key";
00565                                 } elseif ( $wgHtml5 ) {
00566                                         $ret .= " $key=\"\"";
00567                                 } else {
00568                                         $ret .= " $key=\"$key\"";
00569                                 }
00570                         } else {
00571                                 # Apparently we need to entity-encode \n, \r, \t, although the
00572                                 # spec doesn't mention that.  Since we're doing strtr() anyway,
00573                                 # and we don't need <> escaped here, we may as well not call
00574                                 # htmlspecialchars().
00575                                 # @todo FIXME: Verify that we actually need to
00576                                 # escape \n\r\t here, and explain why, exactly.
00577                                 #
00578                                 # We could call Sanitizer::encodeAttribute() for this, but we
00579                                 # don't because we're stubborn and like our marginal savings on
00580                                 # byte size from not having to encode unnecessary quotes.
00581                                 $map = array(
00582                                         '&' => '&amp;',
00583                                         '"' => '&quot;',
00584                                         "\n" => '&#10;',
00585                                         "\r" => '&#13;',
00586                                         "\t" => '&#9;'
00587                                 );
00588                                 if ( $wgWellFormedXml ) {
00589                                         # This is allowed per spec: <http://www.w3.org/TR/xml/#NT-AttValue>
00590                                         # But reportedly it breaks some XML tools?
00591                                         # @todo FIXME: Is this really true?
00592                                         $map['<'] = '&lt;';
00593                                 }
00594                                 
00595                                 $ret .= " $key=$quote" . strtr( $value, $map ) . $quote;
00596                         }
00597                 }
00598                 return $ret;
00599         }
00600 
00610         public static function inlineScript( $contents ) {
00611                 global $wgHtml5, $wgJsMimeType, $wgWellFormedXml;
00612 
00613                 $attrs = array();
00614 
00615                 if ( !$wgHtml5 ) {
00616                         $attrs['type'] = $wgJsMimeType;
00617                 }
00618 
00619                 if ( $wgWellFormedXml && preg_match( '/[<&]/', $contents ) ) {
00620                         $contents = "/*<![CDATA[*/$contents/*]]>*/";
00621                 }
00622 
00623                 return self::rawElement( 'script', $attrs, $contents );
00624         }
00625 
00633         public static function linkedScript( $url ) {
00634                 global $wgHtml5, $wgJsMimeType;
00635 
00636                 $attrs = array( 'src' => $url );
00637 
00638                 if ( !$wgHtml5 ) {
00639                         $attrs['type'] = $wgJsMimeType;
00640                 }
00641 
00642                 return self::element( 'script', $attrs );
00643         }
00644 
00654         public static function inlineStyle( $contents, $media = 'all' ) {
00655                 global $wgWellFormedXml;
00656 
00657                 if ( $wgWellFormedXml && preg_match( '/[<&]/', $contents ) ) {
00658                         $contents = "/*<![CDATA[*/$contents/*]]>*/";
00659                 }
00660 
00661                 return self::rawElement( 'style', array(
00662                         'type' => 'text/css',
00663                         'media' => $media,
00664                 ), $contents );
00665         }
00666 
00675         public static function linkedStyle( $url, $media = 'all' ) {
00676                 return self::element( 'link', array(
00677                         'rel' => 'stylesheet',
00678                         'href' => $url,
00679                         'type' => 'text/css',
00680                         'media' => $media,
00681                 ) );
00682         }
00683 
00696         public static function input( $name, $value = '', $type = 'text', $attribs = array() ) {
00697                 $attribs['type'] = $type;
00698                 $attribs['value'] = $value;
00699                 $attribs['name'] = $name;
00700 
00701                 return self::element( 'input', $attribs );
00702         }
00703 
00713         public static function hidden( $name, $value, $attribs = array() ) {
00714                 return self::input( $name, $value, 'hidden', $attribs );
00715         }
00716 
00731         public static function textarea( $name, $value = '', $attribs = array() ) {
00732                 global $wgHtml5;
00733 
00734                 $attribs['name'] = $name;
00735 
00736                 if ( !$wgHtml5 ) {
00737                         if ( !isset( $attribs['cols'] ) ) {
00738                                 $attribs['cols'] = "";
00739                         }
00740 
00741                         if ( !isset( $attribs['rows'] ) ) {
00742                                 $attribs['rows'] = "";
00743                         }
00744                 }
00745 
00746                 if (substr($value, 0, 1) == "\n") {
00747                         // Workaround for bug 12130: browsers eat the initial newline
00748                         // assuming that it's just for show, but they do keep the later
00749                         // newlines, which we may want to preserve during editing.
00750                         // Prepending a single newline
00751                         $spacedValue = "\n" . $value;
00752                 } else {
00753                         $spacedValue = $value;
00754                 }
00755                 return self::element( 'textarea', $attribs, $spacedValue );
00756         }
00771         public static function namespaceSelector( Array $params = array(), Array $selectAttribs = array() ) {
00772                 global $wgContLang;
00773 
00774                 ksort( $selectAttribs );
00775 
00776                 // Is a namespace selected?
00777                 if ( isset( $params['selected'] ) ) {
00778                         // If string only contains digits, convert to clean int. Selected could also
00779                         // be "all" or "" etc. which needs to be left untouched.
00780                         // PHP is_numeric() has issues with large strings, PHP ctype_digit has other issues
00781                         // and returns false for already clean ints. Use regex instead..
00782                         if ( preg_match( '/^\d+$/', $params['selected'] ) ) {
00783                                 $params['selected'] = intval( $params['selected'] );
00784                         }
00785                         // else: leaves it untouched for later processing
00786                 } else {
00787                         $params['selected'] = '';
00788                 }
00789 
00790                 if ( !isset( $params['exclude'] ) || !is_array( $params['exclude'] ) ) {
00791                         $params['exclude'] = array();
00792                 }
00793                 if ( !isset( $params['disable'] ) || !is_array( $params['disable'] ) ) {
00794                         $params['disable'] = array();
00795                 }
00796 
00797                 // Associative array between option-values and option-labels
00798                 $options = array();
00799 
00800                 if ( isset( $params['all'] ) ) {
00801                         // add an option that would let the user select all namespaces.
00802                         // Value is provided by user, the name shown is localized for the user.
00803                         $options[$params['all']] = wfMessage( 'namespacesall' )->text();
00804                 }
00805                 // Add all namespaces as options (in the content langauge)
00806                 $options += $wgContLang->getFormattedNamespaces();
00807 
00808                 // Convert $options to HTML and filter out namespaces below 0
00809                 $optionsHtml = array();
00810                 foreach ( $options as $nsId => $nsName ) {
00811                         if ( $nsId < NS_MAIN || in_array( $nsId, $params['exclude'] ) ) {
00812                                 continue;
00813                         }
00814                         if ( $nsId === 0 ) {
00815                                 // For other namespaces use use the namespace prefix as label, but for
00816                                 // main we don't use "" but the user message descripting it (e.g. "(Main)" or "(Article)")
00817                                 $nsName = wfMessage( 'blanknamespace' )->text();
00818                         }
00819                         $optionsHtml[] = Html::element(
00820                                 'option', array(
00821                                         'disabled' => in_array( $nsId, $params['disable'] ),
00822                                         'value' => $nsId,
00823                                         'selected' => $nsId === $params['selected'],
00824                                 ), $nsName
00825                         );
00826                 }
00827 
00828                 $ret = '';
00829                 if ( isset( $params['label'] ) ) {
00830                         $ret .= Html::element(
00831                                 'label', array(
00832                                         'for' => isset( $selectAttribs['id'] ) ? $selectAttribs['id'] : null,
00833                                 ), $params['label']
00834                         ) . '&#160;';
00835                 }
00836 
00837                 // Wrap options in a <select>
00838                 $ret .= Html::openElement( 'select', $selectAttribs )
00839                         . "\n"
00840                         . implode( "\n", $optionsHtml )
00841                         . "\n"
00842                         . Html::closeElement( 'select' );
00843 
00844                 return $ret;
00845         }
00846 
00855         public static function htmlHeader( $attribs = array() ) {
00856                 $ret = '';
00857 
00858                 global $wgMimeType;
00859 
00860                 if ( self::isXmlMimeType( $wgMimeType ) ) {
00861                         $ret .= "<?xml version=\"1.0\" encoding=\"UTF-8\" ?" . ">\n";
00862                 }
00863 
00864                 global $wgHtml5, $wgHtml5Version, $wgDocType, $wgDTD;
00865                 global $wgXhtmlNamespaces, $wgXhtmlDefaultNamespace;
00866 
00867                 if ( $wgHtml5 ) {
00868                         $ret .= "<!DOCTYPE html>\n";
00869 
00870                         if ( $wgHtml5Version ) {
00871                                 $attribs['version'] = $wgHtml5Version;
00872                         }
00873                 } else {
00874                         $ret .= "<!DOCTYPE html PUBLIC \"$wgDocType\" \"$wgDTD\">\n";
00875                         $attribs['xmlns'] = $wgXhtmlDefaultNamespace;
00876 
00877                         foreach ( $wgXhtmlNamespaces as $tag => $ns ) {
00878                                 $attribs["xmlns:$tag"] = $ns;
00879                         }
00880                 }
00881 
00882                 $html = Html::openElement( 'html', $attribs );
00883 
00884                 if ( $html ) {
00885                         $html .= "\n";
00886                 }
00887 
00888                 $ret .= $html;
00889 
00890                 return $ret;
00891         }
00892 
00899         public static function isXmlMimeType( $mimetype ) {
00900                 switch ( $mimetype ) {
00901                         case 'text/xml':
00902                         case 'application/xhtml+xml':
00903                         case 'application/xml':
00904                                 return true;
00905                         default:
00906                                 return false;
00907                 }
00908         }
00909 
00921         static function infoBox( $text, $icon, $alt, $class = false, $useStylePath = true ) {
00922                 global $wgStylePath;
00923 
00924                 if ( $useStylePath ) {
00925                         $icon = $wgStylePath.'/common/images/'.$icon;
00926                 }
00927 
00928                 $s  = Html::openElement( 'div', array( 'class' => "mw-infobox $class") );
00929 
00930                 $s .= Html::openElement( 'div', array( 'class' => 'mw-infobox-left' ) ).
00931                                 Html::element( 'img',
00932                                         array(
00933                                                 'src' => $icon,
00934                                                 'alt' => $alt,
00935                                         )
00936                                 ).
00937                                 Html::closeElement( 'div' );
00938 
00939                 $s .= Html::openElement( 'div', array( 'class' => 'mw-infobox-right' ) ).
00940                                 $text.
00941                                 Html::closeElement( 'div' );
00942                 $s .= Html::element( 'div', array( 'style' => 'clear: left;' ), ' ' );
00943 
00944                 $s .= Html::closeElement( 'div' );
00945 
00946                 $s .= Html::element( 'div', array( 'style' => 'clear: left;' ), ' ' );
00947 
00948                 return $s;
00949         }
00950 }