Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F2581
last.diff
Public
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
•
bzimport
Nov 21 2014, 9:02 PM
2014-11-21 21:02:26 (UTC+0)
Size
14 KB
Referenced Files
None
Subscribers
None
last.diff
View Options
Index: skins/common/wikibits.js
===================================================================
--- skins/common/wikibits.js (revision 78317)
+++ skins/common/wikibits.js (working copy)
@@ -604,14 +604,7 @@
};
window.ts_makeSortable = function( table ) {
- var firstRow;
- if ( table.rows && table.rows.length > 0 ) {
- if ( table.tHead && table.tHead.rows.length > 0 ) {
- firstRow = table.tHead.rows[table.tHead.rows.length-1];
- } else {
- firstRow = table.rows[0];
- }
- }
+ var firstRow = table.rows[0];
if ( !firstRow ) {
return;
}
Index: includes/parser/Parser.php
===================================================================
--- includes/parser/Parser.php (revision 78317)
+++ includes/parser/Parser.php (working copy)
@@ -825,189 +825,269 @@
$lines = StringUtils::explode( "\n", $text );
$out = '';
- $td_history = array(); # Is currently a td tag open?
- $last_tag_history = array(); # Save history of last lag activated (td, th or caption)
- $tr_history = array(); # Is currently a tr tag open?
- $tr_attributes = array(); # history of tr attributes
- $has_opened_tr = array(); # Did this table open a <tr> element?
- $indent_level = 0; # indent level of the table
+ $output =& $out;
foreach ( $lines as $outLine ) {
$line = trim( $outLine );
- if ( $line === '' ) { # empty line, go to next line
+ if ( $line === '' && !isset($tables[0])) { # empty line, go to next line
$out .= $outLine."\n";
continue;
}
-
- $first_character = $line[0];
+ $first_chars = $line[0];
+ if ( strlen($line) > 1) {
+ $first_chars .= in_array($line[1], array('}', '+', '-')) ? $line[1] : '';
+ }
$matches = array();
if ( preg_match( '/^(:*)\{\|(.*)$/', $line , $matches ) ) {
- # First check if we are starting a new table
- $indent_level = strlen( $matches[1] );
+ $tables[] = array();
+ $table =& $this->last($tables);
+ $table[0] = array(); //first row
+ $current_row =& $table[0];
+ $table['indent'] = strlen( $matches[1] );
+
$attributes = $this->mStripState->unstripBoth( $matches[2] );
$attributes = Sanitizer::fixTagAttributes( $attributes , 'table' );
- $outLine = str_repeat( '<dl><dd>' , $indent_level ) . "<table{$attributes}>";
- array_push( $td_history , false );
- array_push( $last_tag_history , '' );
- array_push( $tr_history , false );
- array_push( $tr_attributes , '' );
- array_push( $has_opened_tr , false );
- } elseif ( count( $td_history ) == 0 ) {
- # Don't do any of the following
+ if ( $attributes !== '' ) {
+ $table['attributes'] = $attributes;
+ }
+ } else if ( !isset($tables[0]) ) {
+ // we're outside the table
+
$out .= $outLine."\n";
- continue;
- } elseif ( substr( $line , 0 , 2 ) === '|}' ) {
- # We are ending a table
- $line = '</table>' . substr( $line , 2 );
- $last_tag = array_pop( $last_tag_history );
+ } else if ( $first_chars === '|}' ) {
+ // trim the |} code from the line
+ $line = substr ( $line , 2 );
- if ( !array_pop( $has_opened_tr ) ) {
- $line = "<tr><td></td></tr>{$line}";
+ // Shorthand for last row
+ $last_row =& $this->last($table);
+
+ // a thead at the end becomes a tfoot, unless there is only one row
+ // Do this before deleting empty last lines to allow headers at the bottom of tables
+ if ( isset($last_row['type'] ) && $last_row['type'] == 'thead' && isset($table[1])) {
+ $last_row['type'] = 'tfoot';
+ for($i = 0; isset($last_row[$i]); $i++ ) {
+ $last_row[$i]['type'] = 'td';
+ }
}
- if ( array_pop( $tr_history ) ) {
- $line = "</tr>{$line}";
+ // Delete empty last lines
+ if ( empty($last_row) ) {
+ $last_row = NULL;
}
+ $o = $this->printTableHtml( array_pop($tables) ) . $line;
- if ( array_pop( $td_history ) ) {
- $line = "</{$last_tag}>{$line}";
+ if ( count($tables) > 0 ) {
+ $table =& $this->last($tables);
+ $current_row =& $this->last($table);
+ $current_element =& $this->last($current_row);
+
+ $output =& $current_element['content'];
+ } else {
+ $output =& $out;
}
- array_pop( $tr_attributes );
- $outLine = $line . str_repeat( '</dd></dl>' , $indent_level );
- } elseif ( substr( $line , 0 , 2 ) === '|-' ) {
- # Now we have a table row
- $line = preg_replace( '#^\|-+#', '', $line );
- # Whats after the tag is now only attributes
+ $output .= $o;
+
+ } else if ( $first_chars === '|-' ) {
+ // start a new row element
+ // but only when we haven't started one already
+ if( count($current_row) != 0 ) {
+ $table[] = array();
+ $current_row =& $this->last($table);
+ }
+ // Get the attributes, there's nothing else useful in $line now
+ $line = substr ( $line , 2 );
$attributes = $this->mStripState->unstripBoth( $line );
$attributes = Sanitizer::fixTagAttributes( $attributes, 'tr' );
- array_pop( $tr_attributes );
- array_push( $tr_attributes, $attributes );
+ if( $attributes !== '') {
+ $current_row['attributes'] = $attributes;
+ }
+
+ } else if ( $first_chars === '|+' ) {
+ // a table caption
+ $line = substr ( $line , 2 );
+
+ $c = $this->getCellAttr($line , 'caption');
+ $table['caption'] = array();
+ $table['caption']['content'] = $c[0];
+ if(isset($c[1])) $table['caption']['attributes'] = $c[1];
+ unset($c);
- $line = '';
- $last_tag = array_pop( $last_tag_history );
- array_pop( $has_opened_tr );
- array_push( $has_opened_tr , true );
+ $output =& $table['caption'];
+ } else if ( $first_chars === '|' || $first_chars === '!' || $first_chars === '!+' ) {
+ // Which kind of cells are we dealing with
+ $this_tag = 'td';
+ $line = substr ( $line , 1 );
- if ( array_pop( $tr_history ) ) {
- $line = '</tr>';
+ if ( $first_chars === '!' || $first_chars === '!+' ) {
+ $line = str_replace ( '!!' , '||' , $line );
+ $this_tag = 'th';
}
- if ( array_pop( $td_history ) ) {
- $line = "</{$last_tag}>{$line}";
- }
+ // Split up multiple cells on the same line.
+ $cells = StringUtils::explodeMarkup( '||' , $line );
+ $line = ''; // save memory
- $outLine = $line;
- array_push( $tr_history , false );
- array_push( $td_history , false );
- array_push( $last_tag_history , '' );
- } elseif ( $first_character === '|' || $first_character === '!' || substr( $line , 0 , 2 ) === '|+' ) {
- # This might be cell elements, td, th or captions
- if ( substr( $line , 0 , 2 ) === '|+' ) {
- $first_character = '+';
- $line = substr( $line , 1 );
+ // decide whether thead to tbody
+ if ( !array_key_exists('type', $current_row) ) {
+ $current_row['type'] = ( $first_chars === '!' ) ? 'thead' : 'tbody' ;
+ } else if( $first_chars === '|' ) {
+ $current_row['type'] = 'tbody';
}
- $line = substr( $line , 1 );
+ // Loop through each table cell
+ foreach ( $cells as $cell ) {
+ // a new cell
+ $current_row[] = array();
+ $current_element =& $this->last($current_row);
- if ( $first_character === '!' ) {
- $line = str_replace( '!!' , '||' , $line );
+ $current_element['type'] = $this_tag;
+
+ $c = $this->getCellAttr($cell , $this_tag);
+ $current_element['content'] = $c[0];
+ if(isset($c[1])) $current_element['attributes'] = $c[1];
+ unset($c);
}
+ $output =& $current_element['content'];
+
+ } else {
+ $output .= $outLine."\n";
+ }
+ }
+
+ # Remove trailing line-ending (b/c)
+ if ( substr( $out, -1 ) === "\n" ) {
+ $out = substr( $out, 0, -1 );
+ }
+
+ #Close any unclosed tables
+ if ( count($tables) > 0 ) {
+ for ($i = 0; $i < count($tables); $i++) {
+ $out .= $this->printTableHtml( array_pop($tables) );
+ }
+ }
+
+ wfProfileOut( __METHOD__ );
- # Split up multiple cells on the same line.
- # FIXME : This can result in improper nesting of tags processed
- # by earlier parser steps, but should avoid splitting up eg
- # attribute values containing literal "||".
- $cells = StringUtils::explodeMarkup( '||' , $line );
+ return $out;
+ }
- $outLine = '';
- # Loop through each table cell
- foreach ( $cells as $cell ) {
- $previous = '';
- if ( $first_character !== '+' ) {
- $tr_after = array_pop( $tr_attributes );
- if ( !array_pop( $tr_history ) ) {
- $previous = "<tr{$tr_after}>\n";
- }
- array_push( $tr_history , true );
- array_push( $tr_attributes , '' );
- array_pop( $has_opened_tr );
- array_push( $has_opened_tr , true );
- }
+ /**
+ * Helper function for doTableStuff() separating the contents of cells from
+ * attributes. Particularly useful as there's a possible bug and this action
+ * is repeated twice.
+ *
+ * @private
+ */
+ function getCellAttr ($cell , $tag_name) {
+ $content = null;
+ $attributes = null;
- $last_tag = array_pop( $last_tag_history );
+ $cell = trim ( $cell );
- if ( array_pop( $td_history ) ) {
- $previous = "</{$last_tag}>\n{$previous}";
- }
+ // A cell could contain both parameters and data
+ $cell_data = explode ( '|' , $cell , 2 );
- if ( $first_character === '|' ) {
- $last_tag = 'td';
- } elseif ( $first_character === '!' ) {
- $last_tag = 'th';
- } elseif ( $first_character === '+' ) {
- $last_tag = 'caption';
- } else {
- $last_tag = '';
- }
+ // Bug 553: Note that a '|' inside an invalid link should not
+ // be mistaken as delimiting cell parameters
+ if ( strpos( $cell_data[0], '[[' ) !== false ) {
+ $content = trim ( $cell );
+ }
+ else if ( count ( $cell_data ) == 1 ) {
+ $content = trim ( $cell_data[0] );
+ }
+ else {
+ $attributes = $this->mStripState->unstripBoth( $cell_data[0] );
+ $attributes = Sanitizer::fixTagAttributes( $attributes , $tag_name );
- array_push( $last_tag_history , $last_tag );
+ $content = trim ( $cell_data[1] );
+ }
+ return array($content, $attributes);
+ }
- # A cell could contain both parameters and data
- $cell_data = explode( '|' , $cell , 2 );
- # Bug 553: Note that a '|' inside an invalid link should not
- # be mistaken as delimiting cell parameters
- if ( strpos( $cell_data[0], '[[' ) !== false ) {
- $cell = "{$previous}<{$last_tag}>{$cell}";
- } elseif ( count( $cell_data ) == 1 ) {
- $cell = "{$previous}<{$last_tag}>{$cell_data[0]}";
- } else {
- $attributes = $this->mStripState->unstripBoth( $cell_data[0] );
- $attributes = Sanitizer::fixTagAttributes( $attributes , $last_tag );
- $cell = "{$previous}<{$last_tag}{$attributes}>{$cell_data[1]}";
- }
+ /**
+ * Helper function for doTableStuff(). This converts the structured array into html.
+ *
+ * @private
+ */
+ function printTableHtml (&$t) {
+ $r = "\n";
+ $r .= str_repeat( '<dl><dd>' , $t['indent'] );
+ $r .= '<table';
+ $r .= isset($t['attributes']) ? $t['attributes'] : '';
+ $r .= '>';
+ unset($t['attributes']);
- $outLine .= $cell;
- array_push( $td_history , true );
- }
+ if ( isset($t['caption']) ) {
+ $r .= "\n<caption";
+ $r .= isset($t['caption']['attributes']) ? $t['caption']['attributes'] : '';
+ $r .= '>';
+ $r .= $t['caption']['content'];
+ $r .= '</caption>';
+ }
+ $last_section = '';
+ $empty = true;
+ for($i = 0; isset($t[$i]); $i++ ) {
+ #Check for empty tables
+ if ( count( $t[$i]) ) {
+ $empty=false;
}
- $out .= $outLine . "\n";
- }
- # Closing open td, tr && table
- while ( count( $td_history ) > 0 ) {
- if ( array_pop( $td_history ) ) {
- $out .= "</td>\n";
+ if( $t[$i]['type'] != $last_section ) {
+ $r .= "\n<" . $t[$i]['type'] . '>';
}
- if ( array_pop( $tr_history ) ) {
- $out .= "</tr>\n";
+
+ $r .= "\n<tr";
+ $r .= isset($t[$i]['attributes']) ? $t[$i]['attributes'] : '';
+ $r .= '>';
+ for($j = 0; isset($t[$i][$j]); $j++ ) {
+ $r .= "\n<" . $t[$i][$j]['type'];
+ $r .= isset($t[$i][$j]['attributes']) ? $t[$i][$j]['attributes'] : '';
+ $r .= '>';
+
+ $r .= $t[$i][$j]['content'];
+
+ $r .= '</' . $t[$i][$j]['type'] . '>';
+ unset($t[$i][$j]);
}
- if ( !array_pop( $has_opened_tr ) ) {
- $out .= "<tr><td></td></tr>\n" ;
+ $r .= "\n</tr>";
+
+ if( !isset($t[$i+1]) || ( isset($t[$i+1]) && ($t[$i]['type'] != $t[$i+1]['type'])) ) {
+ $r .= '</' . $t[$i]['type'] . '>';
}
-
- $out .= "</table>\n";
+ $last_section = $t[$i]['type'];
+ unset($t[$i]);
}
-
- # Remove trailing line-ending (b/c)
- if ( substr( $out, -1 ) === "\n" ) {
- $out = substr( $out, 0, -1 );
+ if ( $empty ) {
+ if ( isset($t['caption']) ) {
+ $r .= "\n<tr><td></td></tr>";
+ } else {
+ return '';
+ }
}
+ $r .= "\n</table>";
+ $r .= str_repeat( '</dd></dl>' , $t['indent'] );
- # special case: don't return empty table
- if ( $out === "<table>\n<tr><td></td></tr>\n</table>" ) {
- $out = '';
- }
+ return $r;
+ }
- wfProfileOut( __METHOD__ );
-
- return $out;
+ /**
+ * like end() but only works on the numeric array index and php's internal pointers
+ * returns a reference to the last element of an array much like "\$arr[-1]" in perl
+ * ignores associative elements and will create a 0 key will a NULL value if there were
+ * no numric elements and an array itself if not previously defined.
+ *
+ * @private
+ */
+ function &last (&$arr) {
+ for($i = count($arr); (!isset($arr[$i]) && $i > 0); $i--) { }
+ return $arr[$i];
}
/**
@@ -2242,7 +2322,7 @@
'<td|<th|<\\/?div|<hr|<\\/pre|<\\/p|'.$this->mUniqPrefix.'-pre|<\\/li|<\\/ul|<\\/ol|<\\/?center)/iS', $t );
if ( $openmatch or $closematch ) {
$paragraphStack = false;
- # TODO bug 5718: paragraph closed
+ # TODO bug 5718: paragraph closed
$output .= $this->closeParagraph();
if ( $preOpenMatch and !$preCloseMatch ) {
$this->mInPre = true;
Index: includes/Sanitizer.php
===================================================================
--- includes/Sanitizer.php (revision 78317)
+++ includes/Sanitizer.php (working copy)
@@ -369,7 +369,7 @@
'strike', 'strong', 'tt', 'var', 'div', 'center',
'blockquote', 'ol', 'ul', 'dl', 'table', 'caption', 'pre',
'ruby', 'rt' , 'rb' , 'rp', 'p', 'span', 'abbr', 'dfn',
- 'kbd', 'samp'
+ 'kbd', 'samp', 'thead', 'tbody', 'tfoot'
);
$htmlsingle = array(
'br', 'hr', 'li', 'dt', 'dd'
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2156
Default Alt Text
last.diff (14 KB)
Attached To
Mode
T6740: thead, tbody, tfoot for wikitable syntax
Attached
Detach File
Event Timeline
Log In to Comment