Yurik has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/327445 )
Change subject: Cleanup tabular data HTML/CSS ...................................................................... Cleanup tabular data HTML/CSS Bug: T153290 Change-Id: I3ceb45a9feb1ec1daeb798f8bba1ce83276431ac --- M includes/JCTabularContentView.php M includes/JCUtils.php M modules/JsonConfig.css 3 files changed, 177 insertions(+), 72 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/JsonConfig refs/changes/45/327445/1 diff --git a/includes/JCTabularContentView.php b/includes/JCTabularContentView.php index 490a38f..cca860f 100644 --- a/includes/JCTabularContentView.php +++ b/includes/JCTabularContentView.php @@ -18,91 +18,114 @@ * Called from an override of AbstractContent::fillParserOutput() * * @param JCContent|JCTabularContent $content - * @param Title $title Context title for parsing + * @param Title $pageTitle Context title for parsing * @param int|null $revId Revision ID (for {{REVISIONID}}) * @param ParserOptions $options Parser options * @param bool $generateHtml Whether or not to generate HTML * @param ParserOutput &$output The output object to fill (reference). * @return string */ - public function valueToHtml( JCContent $content, Title $title, $revId, ParserOptions $options, - $generateHtml, ParserOutput &$output ) { + public function valueToHtml( JCContent $content, Title $pageTitle, $revId, + ParserOptions $options, $generateHtml, ParserOutput &$output ) { // Use user's language, and split parser cache. This should not have a big // impact because data namespace is rarely viewed, but viewing it localized // will be valuable $lang = $options->getUserLangObj(); - $okClass = [ ]; - $infoClass = [ 'class' => 'mw-jsonconfig-value-info' ]; - $errorClass = [ 'class' => 'mw-jsonconfig-error' ]; - $result = [ ]; + $infoClass = [ 'class' => 'mw-tabular-value-info' ]; + $titleHeaders = []; + $nameHeaders = []; + $typeHeaders = []; + $rows = []; + $headerAttributes = []; - $dataAttrs = [ 'class' => 'mw-jsonconfig sortable' ]; + // Helper to add a class value to an array of attributes + $addErr = function ( array $attrs, $isValid ) { + if ( !$isValid ) { + $attrs['class'] = 'mw-tabular-error'; + } + return $attrs; + }; + + // Helper to create a <tr> element out of an array of raw HTML values + $makeRow = function ( array $values, array $attrs = [] ) { + return Html::rawElement( 'tr', $attrs, implode( '', $values ) ); + }; + + $dataAttrs = [ 'class' => 'mw-tabular sortable' ]; if ( !$content->getValidationData() || $content->getValidationData()->error() ) { - $dataAttrs['class'] .= ' mw-jsonconfig-error'; + $dataAttrs['class'] .= ' mw-tabular-error'; } + $flds = $content->getField( [ 'schema', 'fields' ] ); if ( $flds && !$flds->error() ) { - $vals = [ ]; foreach ( $flds->getValue() as $fld ) { $name = $content->getField( 'name', $fld ); + $nameIsValid = $name && !$name->error(); + $name = $nameIsValid ? $name->getValue() : ''; + + $title = $content->getField( 'title', $fld ); + $titleIsValid = $title && !$title->error(); + $title = + $titleIsValid ? JCUtils::pickLocalizedString( $title->getValue(), $lang, $name ) + : ''; + $type = $content->getField( 'type', $fld ); - $label = $content->getField( 'title', $fld ); + $typeIsValid = $type && !$type->error(); + $type = $typeIsValid ? $type->getValue() : ''; - if ( $name && !$name->error() && $type && !$type->error() && - ( !$label || !$label->error() ) - ) { - $labelAttrs = $okClass; - } else { - $labelAttrs = $errorClass; + $thAttr = []; + if ( $nameIsValid ) { + $thAttr['data-name'] = $name; + } + if ( $typeIsValid ) { + $thAttr['data-type'] = $type; + $headerAttributes['data-type'] = $type; } - if ( $label && !$label->error() ) { - $label = JCUtils::pickLocalizedString( $label->getValue(), $lang ); - } elseif ( $name && !$name->error() ) { - $label = $name->getValue(); - } else { - $label = ''; - } + $nameHeaders[] = Html::element( 'th', $addErr( $thAttr, $nameIsValid ), $name ); - $type = !$type || $type->error() ? 'invalid' : $type->getValue(); - $typeAttrs = $infoClass; - $typeAttrs['title'] = wfMessage( 'jsonconfig-type-name-' . $type )->plain(); - $typeAbbr = wfMessage( 'jsonconfig-type-abbr-' . $type )->plain(); + $typeHeaders[] = + Html::element( 'th', $addErr( $thAttr, $typeIsValid ), + $typeIsValid ? wfMessage( 'jsonconfig-type-name-' . $type )->plain() : '' ); - $label = htmlspecialchars( $label ) . - Html::element( 'span', $typeAttrs, $typeAbbr ); - $vals[] = Html::rawElement( 'th', $labelAttrs, $label ); + $titleHeaders[] = Html::element( 'th', $addErr( $thAttr, $titleIsValid ), $title ); } - $result[] = Html::rawElement( 'tr', $okClass, implode( '', $vals ) ); } $data = $content->getField( 'data' ); if ( $data && !$data->error() ) { foreach ( $data->getValue() as $row ) { - list( $row, $rowAttrs ) = self::split( $row ); - $vals = [ ]; + $rowIsValid = $row && $row instanceof JCValue && !$row->error(); + $row = ( $row && $row instanceof JCValue ) ? $row->getValue() : $row; + if ( !is_array( $row ) ) { + continue; + } + $vals = []; foreach ( $row as $column ) { - list( $column, $columnAttrs ) = self::split( $column, 'mw-jsonconfig-value' ); + $colIsValid = $column && $column instanceof JCValue && !$column->error(); + $column = + ( $column && $column instanceof JCValue ) ? $column->getValue() : $column; + $header = $headerAttributes; + if ( !$colIsValid ) { + $header['class'] = 'mw-tabular-error'; + } + if ( is_object( $column ) ) { $valueSize = count( (array)$column ); - $column = htmlspecialchars( JCUtils::pickLocalizedString( $column, $lang ) ) . - Html::element( 'span', $infoClass, "($valueSize)" ); - $vals[] = Html::rawElement( 'td', $columnAttrs, $column ); - } else { - if ( is_bool( $column ) ) { - $column = $column ? '☑' : '☐'; - } elseif ( $column === null ) { - // TODO: Should we append the CSS class instead? - $columnAttrs['class'] = 'mw-jsonconfig-value-null'; - $column = ''; - } - // TODO: We should probably introduce one CSS class per type - $vals[] = Html::element( 'td', $columnAttrs, $column ); + $column = + htmlspecialchars( JCUtils::pickLocalizedString( $column, $lang ) ) . + Html::element( 'span', $infoClass, "($valueSize)" ); + } elseif ( is_bool( $column ) ) { + $column = $column ? '☑' : '☐'; + } elseif ( $column === null ) { + $header['class'] = 'mw-tabular-value-null'; + $column = ''; } + $vals[] = Html::rawElement( 'td', $header, $column ); } - $result[] = Html::rawElement( 'tr', $rowAttrs, implode( '', $vals ) ); + $rows[] = $makeRow( $vals, $rowIsValid ? [] : [ 'class' => 'mw-tabular-error' ] ); } } @@ -110,31 +133,15 @@ $html = $content->renderDescription( $lang ) . - Html::rawElement( 'table', $dataAttrs, - Html::rawElement( 'tbody', null, implode( "\n", $result ) ) ) . - $content->renderSources( $wgParser->getFreshParser(), $title, $revId, $options ) . + Html::rawElement( 'table', $dataAttrs, Html::rawElement( 'thead', null, implode( "\n", [ + $makeRow( $titleHeaders, [ 'class' => 'mw-tabular-row-name' ] ), + $makeRow( $nameHeaders, [ 'class' => 'mw-tabular-row-key' ] ), + $makeRow( $typeHeaders, [ 'class' => 'mw-tabular-row-type' ] ), + ] ) ) . Html::rawElement( 'tbody', null, implode( "\n", $rows ) ) ) . + $content->renderSources( $wgParser->getFreshParser(), $pageTitle, $revId, $options ) . $content->renderLicense(); return $html; - } - - /** - * Converts JCValue into a raw data + class string. In case of an error, adds error class - * @param JCValue|mixed $data - * @param string $class - * @return array - */ - private static function split( $data, $class = '' ) { - if ( $data instanceof JCValue ) { - if ( $data->error() ) { - if ( $class ) { - $class .= ' '; - } - $class .= 'mw-jsonconfig-error'; - } - $data = $data->getValue(); - } - return [ $data, $class ? [ 'class' => $class ] : null ]; } /** diff --git a/includes/JCUtils.php b/includes/JCUtils.php index 2ad3f86..83328a1 100644 --- a/includes/JCUtils.php +++ b/includes/JCUtils.php @@ -270,9 +270,10 @@ * or use language fallbacks if message is not defined. * @param stdClass $map Dictionary of languageCode => string * @param Language|StubUserLang $lang language object + * @param bool|string $defaultValue if non-false, use this value in case no fallback and no 'en' * @return string message from the dictionary or "" if nothing found */ - public static function pickLocalizedString( stdClass $map, $lang ) { + public static function pickLocalizedString( stdClass $map, $lang, $defaultValue = false ) { $langCode = $lang->getCode(); if ( property_exists( $map, $langCode ) ) { return $map->$langCode; @@ -286,6 +287,12 @@ if ( property_exists( $map, 'en' ) ) { return $map->en; } + + // We have a custom default, return that + if ( $defaultValue !== false ) { + return $defaultValue; + } + // Return first available value, or an empty string // There might be a better way to get the first value from an object $map = (array)$map; diff --git a/modules/JsonConfig.css b/modules/JsonConfig.css index 59b5815..f0c2418 100644 --- a/modules/JsonConfig.css +++ b/modules/JsonConfig.css @@ -101,3 +101,94 @@ padding: 1em; width: 30px; } + +.mw-tabular { + border-collapse: collapse; + border-spacing: 0; + font-family: 'Bitstream Vera Sans', 'DejaVu Sans', 'Lucida Sans', 'Lucida Grande', sans-serif; + font-style: normal; +} + +.mw-tabular th, +.mw-tabular td { + border: 1px solid gray; + padding: 0.5em 1em; +} + +.mw-tabular td { + background-color: #eee; + font-style: italic; +} + +.mw-tabular .mw-tabular-value { + font-family: 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Courier, monospace; + background-color: #dcfae3; +} + +.mw-tabular .mw-tabular-value-null { + background-color: #eaecf0; +} + +.mw-tabular-value-info { + float: right; + font-weight: bold; + font-size: 80%; + color: #800080; +} + +.mw-tabular tr { + margin-bottom: 0.5em; +} + +.mw-tabular th { + background-color: #fff; + font-weight: normal; +} + +.mw-tabular-default { + opacity: 0.3; +} + +.mw-tabular-same { + color: purple; + font-weight: bold; +} + +.mw-tabular-error { + color: red; + font-weight: bold; +} + +.mw-tabular-unknown { + color: #ffa100; + font-weight: bold; +} + +.mw-tabular caption { + /* For stylistic reasons, suppress the caption of the outermost table */ + display: none; +} + +.mw-tabular table caption { + color: gray; + display: inline-block; + font-size: 10px; + font-style: italic; + margin-bottom: 0.5em; + text-align: left; +} + +.mw-tabular-editnotice { + color: #000; + border: solid 1px #A8A8A8; + padding: 0.5em; + margin: 0.5em 0; + background-color: #FFF; + font-size: 95%; + vertical-align: middle; +} + +.mw-tabular-editnotice-icon { + padding: 1em; + width: 30px; +} -- To view, visit https://gerrit.wikimedia.org/r/327445 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I3ceb45a9feb1ec1daeb798f8bba1ce83276431ac Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/JsonConfig Gerrit-Branch: master Gerrit-Owner: Yurik <yu...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits