elements. * * @since 1.16 */ class Html { // List of void elements from HTML5, section 8.1.2 as of 2016-09-19 private static $voidElements = [ 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr', ]; // Boolean attributes, which may have the value omitted entirely. Manually // collected from the HTML5 spec as of 2011-08-12. private static $boolAttribs = [ 'async', 'autofocus', 'autoplay', 'checked', 'controls', 'default', 'defer', 'disabled', 'formnovalidate', 'hidden', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'novalidate', 'open', 'pubdate', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'truespeed', 'typemustmatch', // HTML5 Microdata 'itemscope', ]; /** * Modifies a set of attributes meant for button elements * and apply a set of default attributes when $wgUseMediaWikiUIEverywhere enabled. * @param array $attrs HTML attributes in an associative array * @param string[] $modifiers classes to add to the button * @see https://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return array $attrs A modified attribute array */ public static function buttonAttributes( array $attrs, array $modifiers = [] ) { global $wgUseMediaWikiUIEverywhere; if ( $wgUseMediaWikiUIEverywhere ) { if ( isset( $attrs['class'] ) ) { if ( is_array( $attrs['class'] ) ) { $attrs['class'][] = 'mw-ui-button'; $attrs['class'] = array_merge( $attrs['class'], $modifiers ); // ensure compatibility with Xml $attrs['class'] = implode( ' ', $attrs['class'] ); } else { $attrs['class'] .= ' mw-ui-button ' . implode( ' ', $modifiers ); } } else { // ensure compatibility with Xml $attrs['class'] = 'mw-ui-button ' . implode( ' ', $modifiers ); } } return $attrs; } /** * Modifies a set of attributes meant for text input elements * and apply a set of default attributes. * Removes size attribute when $wgUseMediaWikiUIEverywhere enabled. * @param array $attrs An attribute array. * @return array $attrs A modified attribute array */ public static function getTextInputAttributes( array $attrs ) { global $wgUseMediaWikiUIEverywhere; if ( $wgUseMediaWikiUIEverywhere ) { if ( isset( $attrs['class'] ) ) { if ( is_array( $attrs['class'] ) ) { $attrs['class'][] = 'mw-ui-input'; } else { $attrs['class'] .= ' mw-ui-input'; } } else { $attrs['class'] = 'mw-ui-input'; } } return $attrs; } /** * Returns an HTML link element in a string styled as a button * (when $wgUseMediaWikiUIEverywhere is enabled). * * @param string $contents The raw HTML contents of the element: *not* * escaped! * @param array $attrs Associative array of attributes, e.g., [ * 'href' => 'https://www.mediawiki.org/' ]. See expandAttributes() for * further documentation. * @param string[] $modifiers classes to add to the button * @see https://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return string Raw HTML */ public static function linkButton( $contents, array $attrs, array $modifiers = [] ) { return self::element( 'a', self::buttonAttributes( $attrs, $modifiers ), $contents ); } /** * Returns an HTML link element in a string styled as a button * (when $wgUseMediaWikiUIEverywhere is enabled). * * @param string $contents The raw HTML contents of the element: *not* * escaped! * @param array $attrs Associative array of attributes, e.g., [ * 'href' => 'https://www.mediawiki.org/' ]. See expandAttributes() for * further documentation. * @param string[] $modifiers classes to add to the button * @see https://tools.wmflabs.org/styleguide/desktop/index.html for guidance on available modifiers * @return string Raw HTML */ public static function submitButton( $contents, array $attrs, array $modifiers = [] ) { $attrs['type'] = 'submit'; $attrs['value'] = $contents; return self::element( 'input', self::buttonAttributes( $attrs, $modifiers ) ); } /** * Returns an HTML element in a string. The major advantage here over * manually typing out the HTML is that it will escape all attribute * values. * * This is quite similar to Xml::tags(), but it implements some useful * HTML-specific logic. For instance, there is no $allowShortTag * parameter: the closing tag is magically omitted if $element has an empty * content model. * * @param string $element The element's name, e.g., 'a' * @param array $attribs Associative array of attributes, e.g., [ * 'href' => 'https://www.mediawiki.org/' ]. See expandAttributes() for * further documentation. * @param string $contents The raw HTML contents of the element: *not* * escaped! * @return string Raw HTML */ public static function rawElement( $element, $attribs = [], $contents = '' ) { $start = self::openElement( $element, $attribs ); if ( in_array( $element, self::$voidElements ) ) { // Silly XML. return substr( $start, 0, -1 ) . '/>'; } else { return "$start$contents" . self::closeElement( $element ); } } /** * Identical to rawElement(), but HTML-escapes $contents (like * Xml::element()). * * @param string $element Name of the element, e.g., 'a' * @param array $attribs Associative array of attributes, e.g., [ * 'href' => 'https://www.mediawiki.org/' ]. See expandAttributes() for * further documentation. * @param string $contents * * @return string */ public static function element( $element, $attribs = [], $contents = '' ) { return self::rawElement( $element, $attribs, strtr( $contents, [ // There's no point in escaping quotes, >, etc. in the contents of // elements. '&' => '&', '<' => '<' ] ) ); } /** * Identical to rawElement(), but has no third parameter and omits the end * tag (and the self-closing '/' in XML mode for empty elements). * * @param string $element Name of the element, e.g., 'a' * @param array $attribs Associative array of attributes, e.g., [ * 'href' => 'https://www.mediawiki.org/' ]. See expandAttributes() for * further documentation. * * @return string */ public static function openElement( $element, $attribs = [] ) { $attribs = (array)$attribs; // This is not required in HTML5, but let's do it anyway, for // consistency and better compression. $element = strtolower( $element ); // Remove invalid input types if ( $element == 'input' ) { $validTypes = [ 'hidden', 'text', 'password', 'checkbox', 'radio', 'file', 'submit', 'image', 'reset', 'button', // HTML input types 'datetime', 'datetime-local', 'date', 'month', 'time', 'week', 'number', 'range', 'email', 'url', 'search', 'tel', 'color', ]; if ( isset( $attribs['type'] ) && !in_array( $attribs['type'], $validTypes ) ) { unset( $attribs['type'] ); } } // According to standard the default type for