r68230 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68229‎ | r68230 | r68231 >
Date:19:17, 18 June 2010
Author:daniel
Status:reverted (Comments)
Tags:
Comment:
let mode="grid" on a wiki table trigger output as div soup instead of a html table. this should get rid of "layout tables" that confuse screen readers etc. this is very experimental - feel free to revert, i just want to have this diff in the repository, to play with...
Modified paths:
  • /trunk/phase3/includes/Sanitizer.php (modified) (history)
  • /trunk/phase3/includes/parser/Parser.php (modified) (history)

Diff [purge]

Index: trunk/phase3/includes/parser/Parser.php
@@ -795,6 +795,18 @@
796796 $has_opened_tr = array(); # Did this table open a <tr> element?
797797 $indent_level = 0; # indent level of the table
798798
 799+ $table_tag = 'table';
 800+ $tr_tag = 'tr';
 801+ $th_tag = 'th';
 802+ $td_tag = 'td';
 803+ $caption_tag = 'caption';
 804+
 805+ $extra_table_attribs = null;
 806+ $extra_tr_attribs = null;
 807+ $extra_td_attribs = null;
 808+
 809+ $convert_style = false;
 810+
799811 foreach ( $lines as $outLine ) {
800812 $line = trim( $outLine );
801813
@@ -811,9 +823,31 @@
812824 $indent_level = strlen( $matches[1] );
813825
814826 $attributes = $this->mStripState->unstripBoth( $matches[2] );
815 - $attributes = Sanitizer::fixTagAttributes( $attributes , 'table' );
816827
817 - $outLine = str_repeat( '<dl><dd>' , $indent_level ) . "<table{$attributes}>";
 828+ $attr = Sanitizer::decodeTagAttributes( $attributes );
 829+
 830+ $mode = @$attr['mode'];
 831+ if ( !$mode ) $mode = 'data';
 832+
 833+ if ( $mode == 'grid' || $mode == 'layout' ) {
 834+ $table_tag = 'div';
 835+ $tr_tag = 'div';
 836+ $th_tag = 'div';
 837+ $td_tag = 'div';
 838+ $caption_tag = 'div';
 839+
 840+ $extra_table_attribs = array( 'class' => 'grid-table', 'style' => 'display:table;' );
 841+ $extra_tr_attribs = array( 'class' => 'grid-row', 'style' => 'display:table-row;' );
 842+ $extra_td_attribs = array( 'class' => 'grid-cell', 'style' => 'display:table-cell;' );
 843+
 844+ $convert_style = true;
 845+ }
 846+
 847+ if ($convert_style) $attr['style'] = Sanitizer::styleFromAttributes( $attr );
 848+ $attr = Sanitizer::validateTagAttributes( $attr, $table_tag );
 849+ $attributes = Sanitizer::collapseTagAttributes( $attr, $extra_table_attribs );
 850+
 851+ $outLine = str_repeat( '<dl><dd>' , $indent_level ) . "<$table_tag{$attributes}>";
818852 array_push( $td_history , false );
819853 array_push( $last_tag_history , '' );
820854 array_push( $tr_history , false );
@@ -825,15 +859,15 @@
826860 continue;
827861 } elseif ( substr( $line , 0 , 2 ) === '|}' ) {
828862 # We are ending a table
829 - $line = '</table>' . substr( $line , 2 );
 863+ $line = "</$table_tag>" . substr( $line , 2 );
830864 $last_tag = array_pop( $last_tag_history );
831865
832866 if ( !array_pop( $has_opened_tr ) ) {
833 - $line = "<tr><td></td></tr>{$line}";
 867+ $line = "<$tr_tag><$td_tag></$td_tag></$tr_tag>{$line}";
834868 }
835869
836870 if ( array_pop( $tr_history ) ) {
837 - $line = "</tr>{$line}";
 871+ $line = "</$tr_tag>{$line}";
838872 }
839873
840874 if ( array_pop( $td_history ) ) {
@@ -847,7 +881,12 @@
848882
849883 # Whats after the tag is now only attributes
850884 $attributes = $this->mStripState->unstripBoth( $line );
851 - $attributes = Sanitizer::fixTagAttributes( $attributes, 'tr' );
 885+
 886+ $attr = Sanitizer::decodeTagAttributes( $attributes );
 887+ if ($convert_style) $attr['style'] = Sanitizer::styleFromAttributes( $attr );
 888+ $attr = Sanitizer::validateTagAttributes( $attr, $tr_tag );
 889+ $attributes = Sanitizer::collapseTagAttributes( $attr, $extra_tr_attribs );
 890+
852891 array_pop( $tr_attributes );
853892 array_push( $tr_attributes, $attributes );
854893
@@ -857,7 +896,7 @@
858897 array_push( $has_opened_tr , true );
859898
860899 if ( array_pop( $tr_history ) ) {
861 - $line = '</tr>';
 900+ $line = "</$tr_tag>";
862901 }
863902
864903 if ( array_pop( $td_history ) ) {
@@ -895,7 +934,7 @@
896935 if ( $first_character !== '+' ) {
897936 $tr_after = array_pop( $tr_attributes );
898937 if ( !array_pop( $tr_history ) ) {
899 - $previous = "<tr{$tr_after}>\n";
 938+ $previous = "<$tr_tag{$tr_after}>\n";
900939 }
901940 array_push( $tr_history , true );
902941 array_push( $tr_attributes , '' );
@@ -910,11 +949,11 @@
911950 }
912951
913952 if ( $first_character === '|' ) {
914 - $last_tag = 'td';
 953+ $last_tag = $td_tag;
915954 } elseif ( $first_character === '!' ) {
916 - $last_tag = 'th';
 955+ $last_tag = $th_tag;
917956 } elseif ( $first_character === '+' ) {
918 - $last_tag = 'caption';
 957+ $last_tag = $caption_tag;
919958 } else {
920959 $last_tag = '';
921960 }
@@ -924,15 +963,24 @@
925964 # A cell could contain both parameters and data
926965 $cell_data = explode( '|' , $cell , 2 );
927966
 967+ $attributes = '';
 968+
928969 # Bug 553: Note that a '|' inside an invalid link should not
929970 # be mistaken as delimiting cell parameters
930971 if ( strpos( $cell_data[0], '[[' ) !== false ) {
931 - $cell = "{$previous}<{$last_tag}>{$cell}";
 972+ if ($extra_td_attribs) $attributes = Sanitizer::collapseTagAttributes( $extra_td_attribs );
 973+ $cell = "{$previous}<{$last_tag}{$attributes}>{$cell}";
932974 } elseif ( count( $cell_data ) == 1 ) {
933 - $cell = "{$previous}<{$last_tag}>{$cell_data[0]}";
 975+ if ($extra_td_attribs) $attributes = Sanitizer::collapseTagAttributes( $extra_td_attribs );
 976+ $cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[0]}";
934977 } else {
935978 $attributes = $this->mStripState->unstripBoth( $cell_data[0] );
936 - $attributes = Sanitizer::fixTagAttributes( $attributes , $last_tag );
 979+
 980+ $attr = Sanitizer::decodeTagAttributes( $attributes );
 981+ if ($convert_style) $attr['style'] = Sanitizer::styleFromAttributes( $attr );
 982+ $attr = Sanitizer::validateTagAttributes( $attr, $last_tag );
 983+ $attributes = Sanitizer::collapseTagAttributes( $attr, $extra_td_attribs );
 984+
937985 $cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[1]}";
938986 }
939987
@@ -946,16 +994,16 @@
947995 # Closing open td, tr && table
948996 while ( count( $td_history ) > 0 ) {
949997 if ( array_pop( $td_history ) ) {
950 - $out .= "</td>\n";
 998+ $out .= "</$td_tag>\n";
951999 }
9521000 if ( array_pop( $tr_history ) ) {
953 - $out .= "</tr>\n";
 1001+ $out .= "</$tr_tag>\n";
9541002 }
9551003 if ( !array_pop( $has_opened_tr ) ) {
956 - $out .= "<tr><td></td></tr>\n" ;
 1004+ $out .= "<$tr_tag><$td_tag></$td_tag></$tr_tag>\n" ;
9571005 }
9581006
959 - $out .= "</table>\n";
 1007+ $out .= "</$table_tag>\n";
9601008 }
9611009
9621010 # Remove trailing line-ending (b/c)
@@ -964,7 +1012,7 @@
9651013 }
9661014
9671015 # special case: don't return empty table
968 - if ( $out === "<table>\n<tr><td></td></tr>\n</table>" ) {
 1016+ if ( $out === "<$table_tag>\n<$tr_tag><$td_tag></$td_tag></$tr_tag>\n</$table_tag>" ) {
9691017 $out = '';
9701018 }
9711019
Index: trunk/phase3/includes/Sanitizer.php
@@ -793,6 +793,51 @@
794794 }
795795 }
796796
 797+ /**
 798+ * Take an associative array of attribute name/value pairs
 799+ * and generate a css style representing all the style-related
 800+ * attributes. If there already a style attribute in the array,
 801+ * it is also included in the value returned.
 802+ */
 803+ static function styleFromAttributes( $attributes ) {
 804+ $styles = array();
 805+
 806+ foreach ( $attributes as $attribute => $value ) {
 807+ if ( $attribute == 'bgcolor' ) {
 808+ $styles[] = "background-color: $value";
 809+ } else if ( $attribute == 'border' ) {
 810+ $styles[] = "border-width: $value";
 811+ } else if ( $attribute == 'align' ) {
 812+ $styles[] = "text-align: $value";
 813+ } else if ( $attribute == 'valign' ) {
 814+ $styles[] = "vertical-align: $value";
 815+ } else if ( $attribute == 'width' ) {
 816+ if ( preg_match( '/\d+/', $value ) === false ) {
 817+ $value .= 'px';
 818+ }
 819+
 820+ $styles[] = "width: $value";
 821+ } else if ( $attribute == 'height' ) {
 822+ if ( preg_match( '/\d+/', $value ) === false ) {
 823+ $value .= 'px';
 824+ }
 825+
 826+ $styles[] = "height: $value";
 827+ } else if ( $attribute == 'nowrap' ) {
 828+ if ( $value ) {
 829+ $styles[] = "white-space: nowrap";
 830+ }
 831+ }
 832+ }
 833+
 834+ if ( isset( $attributes[ 'style' ] ) ) {
 835+ $styles[] = $attributes[ 'style' ];
 836+ }
 837+
 838+ if ( !$styles ) return '';
 839+ else return implode( '; ', $styles );
 840+ }
 841+
797842 /**
798843 * Take a tag soup fragment listing an HTML element's attributes
799844 * and normalize it to well-formed XML, discarding unwanted attributes.
@@ -810,24 +855,66 @@
811856 *
812857 * @param $text String
813858 * @param $element String
 859+ * @param $defaults Array (optional) associative array of default attributes to splice in.
 860+ * class and style attributes are combined. Otherwise, values from
 861+ * $attributes take precedence over values from $defaults.
814862 * @return String
815863 */
816 - static function fixTagAttributes( $text, $element ) {
 864+ static function fixTagAttributes( $text, $element, $defaults = null ) {
817865 if( trim( $text ) == '' ) {
818866 return '';
819867 }
820868
821 - $stripped = Sanitizer::validateTagAttributes(
822 - Sanitizer::decodeTagAttributes( $text ), $element );
 869+ $decoded = Sanitizer::decodeTagAttributes( $text );
 870+ $stripped = Sanitizer::validateTagAttributes( $decoded, $element );
 871+ $attribs = Sanitizer::collapseTagAttributes( $stripped, $defaults );
823872
824 - $attribs = array();
825 - foreach( $stripped as $attribute => $value ) {
 873+ return $attribs;
 874+ }
 875+
 876+ /**
 877+ * Take an associative array or attribute name/value pairs
 878+ * and collapses it to well-formed XML.
 879+ * Does not filter attributes.
 880+ * Output is safe for further wikitext processing, with escaping of
 881+ * values that could trigger problems.
 882+ *
 883+ * - Double-quotes all attribute values
 884+ * - Prepends space if there are attributes.
 885+ *
 886+ * @param $attributes Array is an associative array of attribute name/value pairs.
 887+ * Assumed to be sanitized already.
 888+ * @param $defaults Array (optional) associative array of default attributes to splice in.
 889+ * class and style attributes are combined. Otherwise, values from
 890+ * $attributes take precedence over values from $defaults.
 891+ * @return String
 892+ */
 893+ static function collapseTagAttributes( $attributes, $defaults = null ) {
 894+ if ( $defaults ) {
 895+ foreach( $defaults as $attribute => $value ) {
 896+ if ( isset( $attributes[ $attribute ] ) ) {
 897+ if ( $attribute == 'class' ) {
 898+ $value .= ' '. $attributes[ $attribute ];
 899+ } else if ( $attribute == 'style' ) {
 900+ $value .= '; ' . $attributes[ $attribute ];
 901+ } else {
 902+ continue;
 903+ }
 904+ }
 905+
 906+ $attributes[ $attribute ] = $value;
 907+ }
 908+ }
 909+
 910+ $chunks = array();
 911+
 912+ foreach( $attributes as $attribute => $value ) {
826913 $encAttribute = htmlspecialchars( $attribute );
827914 $encValue = Sanitizer::safeEncodeAttribute( $value );
828915
829 - $attribs[] = "$encAttribute=\"$encValue\"";
 916+ $chunks[] = "$encAttribute=\"$encValue\"";
830917 }
831 - return count( $attribs ) ? ' ' . implode( ' ', $attribs ) : '';
 918+ return count( $chunks ) ? ' ' . implode( ' ', $chunks ) : '';
832919 }
833920
834921 /**

Follow-up revisions

RevisionCommit summaryAuthorDate
r781771.17: Back out r68230 (mode="grid" on wiki table triggers div soup instead of...catrope12:10, 10 December 2010
r78196Revert r68230, r68231 (mode="grid" on tables) per CR. It's in the history if ...demon16:03, 10 December 2010

Comments

#Comment by Bryan (talk | contribs)   19:21, 18 June 2010

Don't use @, use $mode = isset( $attrs['mode'] ) ? $attrs['mode'] : 'data';

#Comment by MaxSem (talk | contribs)   07:37, 19 June 2010

This definitely needs some tests.

#Comment by Platonides (talk | contribs)   22:38, 15 October 2010

Styles added in r68231

#Comment by MaxSem (talk | contribs)   20:25, 7 December 2010

Ping.

#Comment by Platonides (talk | contribs)   00:03, 8 December 2010

Should be reverted in 1.17. Probably also in trunk since there doesn't seem to be any work on it. It can be readded later if needed.

Status & tagging log