/** * parse the wiki syntax used to render tables * * @private * @return string */ function doTableStuff($text) { wfProfileIn(__METHOD__); $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 foreach ($lines as $outLine) { $line = trim($outLine); if ($line === '') { # empty line, go to next line $out .= $outLine . "\n"; continue; } $first_character = $line[0]; $matches = array(); if (preg_match('/^(:*)\\{\\|(.*)$/', $line, $matches)) { # First check if we are starting a new table $indent_level = 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 $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); if (!array_pop($has_opened_tr)) { $line = "<tr><td></td></tr>{$line}"; } if (array_pop($tr_history)) { $line = "</tr>{$line}"; } if (array_pop($td_history)) { $line = "</{$last_tag}>{$line}"; } 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 $attributes = $this->mStripState->unstripBoth($line); $attributes = Sanitizer::fixTagAttributes($attributes, 'tr'); array_pop($tr_attributes); array_push($tr_attributes, $attributes); $line = ''; $last_tag = array_pop($last_tag_history); array_pop($has_opened_tr); array_push($has_opened_tr, true); if (array_pop($tr_history)) { $line = '</tr>'; } if (array_pop($td_history)) { $line = "</{$last_tag}>{$line}"; } $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); } $line = substr($line, 1); if ($first_character === '!') { $line = str_replace('!!', '||', $line); } # 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); $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); } $last_tag = array_pop($last_tag_history); if (array_pop($td_history)) { $previous = "</{$last_tag}>\n{$previous}"; } if ($first_character === '|') { $last_tag = 'td'; } elseif ($first_character === '!') { $last_tag = 'th'; } elseif ($first_character === '+') { $last_tag = 'caption'; } else { $last_tag = ''; } array_push($last_tag_history, $last_tag); # 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]}"; } $outLine .= $cell; array_push($td_history, true); } } $out .= $outLine . "\n"; } # Closing open td, tr && table while (count($td_history) > 0) { if (array_pop($td_history)) { $out .= "</td>\n"; } if (array_pop($tr_history)) { $out .= "</tr>\n"; } if (!array_pop($has_opened_tr)) { $out .= "<tr><td></td></tr>\n"; } $out .= "</table>\n"; } # Remove trailing line-ending (b/c) if (substr($out, -1) === "\n") { $out = substr($out, 0, -1); } # special case: don't return empty table if ($out === "<table>\n<tr><td></td></tr>\n</table>") { $out = ''; } wfProfileOut(__METHOD__); return $out; }
/** * @deprecated use StringUtils::explodeMarkup */ function wfExplodeMarkup($separator, $text) { return StringUtils::explodeMarkup($separator, $text); }
/** * parse the wiki syntax used to render tables * * @private */ function doTableStuff($text) { wfProfileIn(__METHOD__); # RTE (Rich Text Editor) - begin # Used to determine whether the Parser running in RTE mode or not global $wgRTEParserEnabled; # RTE - end $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 foreach ($lines as $outLine) { $line = trim($outLine); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński # Initialize this variable regardless of the RTE mode being on/off, # then it can be used in next batch of code without checking RTE mode. $RTEcomment = null; if (!empty($wgRTEParserEnabled)) { # Check if there is a wikitext comment placholder at the beginning of given line, # then cut it off - to have proper MediaWiki table processing - and store in variable for later recovery $RTEdataIdx = RTEMarker::getDataIdx(RTEMarker::PLACEHOLDER, $line, false); if ($RTEdataIdx != null) { $RTEdata = RTEData::get('placeholder', $RTEdataIdx); if ($RTEdata && $RTEdata['type'] == 'comment') { $RTEcomment = substr($line, 0, 9); $line = substr($line, 9); } } } # RTE - end if ($line === '') { # empty line, go to next line $out .= $outLine . "\n"; continue; } $first_character = $line[0]; $matches = array(); if (preg_match('/^(:*)\\{\\|(.*)$/', $line, $matches)) { # First check if we are starting a new table $indent_level = strlen($matches[1]); $attributes = $this->mStripState->unstripBoth($matches[2]); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { # Throw an RTE edgacase if there is RTR marker (\x7f) in table attributes # Example: {| {{some template call}} if (strpos($attributes, "") !== false) { RTE::$edgeCases[] = 'COMPLEX.04'; } } # RTE - end $attributes = Sanitizer::fixTagAttributes($attributes, 'table'); $outLine = str_repeat('<dl><dd>', $indent_level) . "<table{$attributes}>"; # RTE (Rich Text Editor) - begin $outLine = $RTEcomment . $outLine; $RTEcomment = null; # RTE - end 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 $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); if (!array_pop($has_opened_tr)) { $line = "<tr><td></td></tr>{$line}"; } if (array_pop($tr_history)) { $line = "</tr>{$line}"; } if (array_pop($td_history)) { $line = "</{$last_tag}>{$line}"; } 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 $attributes = $this->mStripState->unstripBoth($line); # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { # Throw an RTE edgacase if there is RTE marker (\x7f) in row attributes if (strpos($attributes, "") !== false) { RTE::$edgeCases[] = 'COMPLEX.05'; } } # RTE - end $attributes = Sanitizer::fixTagAttributes($attributes, 'tr'); array_pop($tr_attributes); array_push($tr_attributes, $attributes); $line = ''; $last_tag = array_pop($last_tag_history); array_pop($has_opened_tr); array_push($has_opened_tr, true); if (array_pop($tr_history)) { $line = '</tr>'; } if (array_pop($td_history)) { $line = "</{$last_tag}>{$line}"; } $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); } $line = substr($line, 1); if ($first_character === '!') { $line = str_replace('!!', '||', $line); } # 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); $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); } $last_tag = array_pop($last_tag_history); if (array_pop($td_history)) { $previous = "</{$last_tag}>{$previous}"; } if ($first_character === '|') { $last_tag = 'td'; } elseif ($first_character === '!') { $last_tag = 'th'; } elseif ($first_character === '+') { $last_tag = 'caption'; } else { $last_tag = ''; } array_push($last_tag_history, $last_tag); # 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]}"; } $outLine .= $cell; array_push($td_history, true); } } else { # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($wgRTEParserEnabled)) { if (empty($td_history[0]) || $last_tag == 'caption') { if (strpos($outLine, "-comment-") !== false) { RTE::$edgeCases[] = 'COMPLEX.06'; } } } # RTE - end } # RTE (Rich Text Editor) - begin # @author: Inez Korczyński if (!empty($RTEcomment)) { # Throw an edgecase if $RTEcomment did not get flushed (nulled) yet RTE::$edgeCases[] = 'COMPLEX.10'; } # RTE - end $out .= $outLine . "\n"; } # Closing open td, tr && table while (count($td_history) > 0) { if (array_pop($td_history)) { $out .= "</td>\n"; } if (array_pop($tr_history)) { $out .= "</tr>\n"; } if (!array_pop($has_opened_tr)) { $out .= "<tr><td></td></tr>\n"; } $out .= "</table>\n"; } # Remove trailing line-ending (b/c) if (substr($out, -1) === "\n") { $out = substr($out, 0, -1); } # special case: don't return empty table if ($out === "<table>\n<tr><td></td></tr>\n</table>") { $out = ''; } wfProfileOut(__METHOD__); return $out; }
private function externalTableHelper($t) { $latexformat = ''; $t = trim($t); $t = explode("\n", $t); $ltd = array(); # Is current cell TD or TH? $tr = array(); # Is currently a tr tag open? $ltr = array(); # tr attributes $cellcount_max = array(); $cellcount_current = array(); $tableheader = array(); $thkr = array(); # table header index array $th = 0; $has_opened_tr = array(); # Did this table open a <tr> element? $anyCells = false; $firstCellOfRow = true; $ltx_caption = ''; $in_table = 0; foreach ($t as $k => $x) { $x = trim($x); if ($x == '') { // empty line, go to next line continue; } $fc = substr($x, 0, 1); //$matches = array(); if (preg_match('/^(:*)\\{\\|(.*)$/', $x, $matches)) { /* preg_match("/latexfmt=\"(.*?)\"/", $attributes, $latexformat); $latexwidth = '\linewidth'; if ( preg_match("/latexwidth=\"(.*?)\"/", $attributes, $latexwidth_a) ) { $latexwidth = $latexwidth_a[1]; $latexwidth = str_replace('\(\backslash{}\)', '\\', $latexwidth); } $latexformat = $latexformat[1]; $latexformat = str_replace("\\", "", $latexformat);*/ if ($in_table == 0) { /* new top-level table, initialise arrays */ $latexformat = ''; $cellcount_max = array(); $cellcount_current = array(); $tableheader = array(); $thkr = array(); # table header index array $th = 0; } $in_table++; array_push($ltd, ''); array_push($tr, false); array_push($ltr, ''); array_push($has_opened_tr, false); //Start of table: Extract LaTeX tips from attributes, make header. $attributes = $this->unstripForHTML($matches[2]); $this->debugMessage('Table: Attributes: ', $attributes); $attributes = str_replace($this->sc['backslash'], '\\', $attributes); $attributes_test = $this->parseAttrString($attributes); if (array_key_exists('latexfmt', $attributes_test)) { $latexformat = $attributes_test['latexfmt']; $latexformat = str_replace("\\", "", $latexformat); $this->debugMessage('Table: latexfmt: ', $latexformat); } if (array_key_exists('latexwidth', $attributes_test)) { $latexwidth = $attributes_test['latexwidth']; $latexwidth = str_replace('\\(\\backslash{}\\)', '\\', $latexwidth); $this->debugMessage('Table: latexwidth: ', $latexwidth); } else { $latexwidth = '\\linewidth'; } // start-of-table array_push($thkr, $k); $tableheader[$in_table]['width'] = $latexwidth; $tableheader[$in_table]['format'] = $latexformat; $cellcount_max[$in_table] = 0; // start-of-row $cellcount_current[$in_table] = 0; $this->addPackageDependency('tabularx'); $firstCellOfRow = true; } else { if ('|}' == substr($x, 0, 2) || '|\\}' == substr($x, 0, 3)) { //End of table. Pop stacks and print latex ending. $l = array_pop($ltd); if (!array_pop($has_opened_tr)) { $t[$k - 1] = $t[$k - 1] . "\\tabularnewline \\hline"; } if (array_pop($tr)) { $t[$k - 1] = $t[$k - 1] . '\\tabularnewline \\hline'; } array_pop($ltr); // end-of-row code $cellcount_max[$in_table] = max($cellcount_max[$in_table], $cellcount_current[$in_table]); // end-of-table $thk = array_pop($thkr); $latexwidth = $tableheader[$in_table]['width']; if ($tableheader[$in_table]['format'] == '') { $latexformat = array(); for ($i = 0; $i < $cellcount_max[$in_table]; $i++) { array_push($latexformat, 'Y'); } $latexformat = '|' . implode('|', $latexformat) . '|'; } else { $latexformat = $tableheader[$in_table]['format']; } if ($in_table > 1) { $t[$thk] = "{\\begin{tabularx}{{$latexwidth}}{{$latexformat}}\\hline"; $t[$k] = "\\end{tabularx}}" . trim($ltx_caption); } else { // This table is not nested $this->debugMessage('Table: inserted latexfmt: ', $latexformat); $this->debugMessage('Table: inserted latexwidth ', $latexwidth); wfRunHooks("w2lTableLaTeXAttributes", array(&$this, &$latexformat, &$latexwidth)); $table_head = "\\begin{tabularx}{{$latexwidth}}{{$latexformat}}\\hline"; $table_foot = "\\end{tabularx}\n" . trim($ltx_caption); wfRunHooks("w2lTableHead", array(&$this, &$table_head)); wfRunHooks("w2lTableFoot", array(&$this, &$table_foot)); $t[$thk] = $table_head; $t[$k] = $table_foot; unset($table_head, $table_foot); } $in_table--; $ltx_caption = ''; } else { if ('|-' == substr($x, 0, 2)) { # Allows for |--------------- if (strpos($x, '----') == 1) { $add_hline = '\\hline'; } else { $add_hline = ''; } $x = substr($x, 1); while ($x != '' && substr($x, 0, 1) == '-') { $x = substr($x, 1); } $z = ''; $l = array_pop($ltd); array_pop($has_opened_tr); array_push($has_opened_tr, true); if (array_pop($tr)) { $t[$k - 1] = $t[$k - 1] . '\\tabularnewline \\hline' . $add_hline; } array_pop($ltr); $t[$k] = $z; array_push($tr, false); array_push($ltd, ''); // end-of-row $cellcount_max[$in_table] = max($cellcount_max[$in_table], $cellcount_current[$in_table]); // start-of-row $cellcount_current[$in_table] = 0; $attributes = $this->unstripForHTML($x); array_push($ltr, Sanitizer::fixTagAttributes($attributes, 'tr')); $firstCellOfRow = true; $add_hline = ''; //$cellcounter[] = 0; } else { if (('|' === $fc || '!' === $fc || '|+' === substr($x, 0, 2)) && $in_table != 0) { # Caption # $x is a table row if ('|+' == substr($x, 0, 2)) { $fc = '+'; $x = substr($x, 1); } $after = substr($x, 1); if ($fc == '!') { $after = str_replace('!!', '||', $after); } // 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('||', $after); $t[$k] = ''; # Loop through each table cell foreach ($cells as $theline) { $z = ''; if ($fc != '+') { $tra = array_pop($ltr); if (!array_pop($tr)) { $z = "\n"; } // has been: "\n" array_push($tr, true); array_push($ltr, ''); // current-row-cell $cellcount_current[$in_table]++; array_pop($has_opened_tr); array_push($has_opened_tr, true); } $l = array_pop($ltd); //heading cells and normal cells are equal in LaTeX: if (($fc == '|' || $fc == '!') && !$firstCellOfRow) { $l = ' & '; } else { if ($fc == '+') { $ltx_caption .= $theline; continue; //Missing support for caption here! } else { $l = ''; } } //$firstCellOfRow = false; array_push($ltd, $l); # Cell parameters $y = explode('|', $theline, 2); # Note that a '|' inside an invalid link should not # be mistaken as delimiting cell parameters if (strpos($y[0], '[[') !== false) { $y = array($theline); } if (count($y) == 1) { $y[0] = $this->fixContentforTableCells($y[0]); if ($fc == '!') { //Heading cell highlighting $y = "{$z}{$l}" . "\\textbf{" . "{$y[0]}}"; } else { $y = "{$z}{$l}{$y[0]}"; } } else { $attributes = $this->unstripForHTML($y[0]); $multi_col = $this->checkColspan($attributes); //$y = "{$z}<{$l}".Sanitizer::fixTagAttributes($attributes, $l).">{$y[1]}" ; if ($firstCellOfRow == false) { $addSep = '&'; } else { $addSep = ''; } $y = "{$z}" . $addSep . '\\multicolumn{' . $multi_col['colspan'] . '}{' . $multi_col['latexfmt'] . '}{' . $y[1] . '}'; } $firstCellOfRow = false; // was some lines up... $t[$k] .= $y; $anyCells = true; } } } } } } $t = implode("\n", $t); # special case: don't return empty table //if(!$anyCells) $t = ''; //$t .= trim($ltx_caption); return $t; }