/** * @param array $matches A set of results of the `transform` function * @return string */ protected function _url_callback($matches) { $url = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $matches[1]); Kernel::addConfig('urls', $url); $block = Kernel::get('OutputFormatBag')->buildTag('link', $url, array('href' => $url)); return parent::hashPart($block); }
/** * Build `<pre><code>` blocks. * * @param array $matches A set of results of the `transform()` function * @return string */ protected function _callback($matches) { $codeblock = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':Outdent', $matches[1]); $codeblock = Helper::escapeCodeContent($codeblock); # trim leading newlines and trailing newlines $codeblock = preg_replace('/\\A\\n+|\\n+\\z/', '', $codeblock); $codeblock = Kernel::get('OutputFormatBag')->buildTag('preformatted', $codeblock); return "\n\n" . parent::hashBlock($codeblock) . "\n\n"; }
/** * Build each blockquote block * * @param array $matches A set of results of the `transform()` function * @return string */ protected function _callback($matches) { $blockq = $matches[1]; $cite = isset($matches[2]) ? $matches[2] : null; // trim one level of quoting - trim whitespace-only lines $blockq = preg_replace('/^[ ]*>[ ]?(\\((.+?)\\))?|^[ ]+$/m', '', $blockq); $blockq = Lexer::runGamut('html_block_gamut', $blockq); # recurse $blockq = preg_replace('/^/m', " ", $blockq); // These leading spaces cause problem with <pre> content, // so we need to fix that: $blockq = preg_replace_callback('{(\\s*<pre>.+?</pre>)}sx', array($this, '_callback_spaces'), $blockq); $attributes = array(); if (!empty($cite)) { $attributes['cite'] = $cite; } $block = Kernel::get('OutputFormatBag')->buildTag('blockquote', $blockq, $attributes); return "\n" . parent::hashBlock($block) . "\n\n"; }
/** * Process ATX-style headers * * @param array $matches The results from the `transform()` function * @return string */ protected function _atx_callback($matches) { $level = strlen($matches[1]) + $this->_getRebasedHeaderLevel(); $domid = !empty($matches[3]) ? $matches[3] : Helper::header2Label($matches[2]); $domid = Kernel::get('DomId')->set($domid); $title = Lexer::runGamut('span_gamut', $matches[2]); Kernel::addConfig('menu', array('level' => $level, 'text' => parent::unhash($title)), $domid); $block = Kernel::get('OutputFormatBag')->buildTag('title', $title, array('level' => $level, 'id' => $domid)); $this->_setContentTitle($title); return "\n" . parent::hashBlock($block) . "\n\n"; }
/** * @param array $matches A set of results of the `transform` function * @return string */ protected function _inline_callback($matches) { $alt_text = $matches[2]; $url = $matches[3] == '' ? $matches[4] : $matches[3]; $title =& $matches[7]; $attributes = array(); $attributes['alt'] = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $alt_text); $attributes['src'] = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $url); if (!empty($title)) { $attributes['title'] = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $title); } $block = Kernel::get('OutputFormatBag')->buildTag('image', null, $attributes); return parent::hashPart($block); }
public function buildFootnoteStandardLink($text = null, array $attributes = array(), $note_type = Note::FOOTNOTE_DEFAULT) { $type_info = Note::getTypeInfo($note_type); if ($this->getConfig($type_info['prefix'] . '_link_class')) { $attributes['class'] = Helper::fillPlaceholders(Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $this->getConfig($type_info['prefix'] . '_link_class')), $text); } if ($this->getConfig($type_info['prefix'] . '_link_title_mask')) { $attributes['title'] = Helper::fillPlaceholders(Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $this->getConfig($type_info['prefix'] . '_link_title_mask')), $text); } $backlink_id = $attributes['backlink_id']; unset($attributes['backlink_id']); unset($attributes['counter']); $link = Kernel::get('OutputFormatBag')->buildTag('link', $text, $attributes); return Kernel::get('OutputFormatBag')->buildTag('sup', $link, array('id' => $backlink_id)); }
/** * Process the dd contents. * * @param array $matches * @return string */ protected function _item_callback_dd($matches) { $leading_line = $matches[1]; $marker_space = $matches[2]; $def = $matches[3]; if ($leading_line || preg_match('/\\n{2,}/', $def)) { // Replace marker with the appropriate whitespace indentation $def = str_repeat(' ', strlen($marker_space)) . $def; $def = Lexer::runGamut('html_block_gamut', Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':Outdent', $def . "\n\n")); // $def = "\n$def\n"; } else { $def = rtrim($def); $def = Lexer::runGamut('span_gamut', Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':Outdent', $def)); } return Kernel::get('OutputFormatBag')->buildTag('definition_list_item_definition', $def); }
/** * @param array $matches A set of results of the `transform()` function * @return string */ protected function _items_callback($matches) { $item = $matches[4]; $leading_line =& $matches[1]; $leading_space =& $matches[2]; $marker_space = $matches[3]; $trailing_blank_line =& $matches[5]; if ($leading_line || $trailing_blank_line || preg_match('/\\n{2,}/', $item)) { // Replace marker with the appropriate whitespace indentation $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item; $item = Lexer::runGamut('html_block_gamut', Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':Outdent', $item) . "\n"); } else { // Recursion for sub-lists: $item = self::transform(Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':Outdent', $item)); $item = preg_replace('/\\n+$/', '', $item); $item = Lexer::runGamut('span_gamut', $item); } return Kernel::get('OutputFormatBag')->buildTag('list_item', $item); }
/** * Do a footnote transformation * * @param string $note_id * @param string $note_content * @param int $type * @return void */ protected function _doTransformNote($note_id, $note_content, $type = self::FOOTNOTE_DEFAULT) { if (!empty($note_content)) { ++self::$notes_counter; $type_info = $this->getTypeInfo($type); $note_content .= "\n"; // Need to append newline before parsing. $note_content = Lexer::runGamut('html_block_gamut', $note_content . "\n"); $note_content = preg_replace_callback('{F\\x1Afn:(.*?)\\x1A:}', array($this, '_append_callback'), $note_content); $note_id = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $note_id); $backlink_id = Kernel::get('DomId')->get($type_info['prefix'] . 'ref:' . $note_id); $footlink_id = Kernel::get('DomId')->get($type_info['prefix'] . ':' . $note_id); $attributes = array(); $attributes['rev'] = $type_info['name']; $attributes['counter'] = self::$notes_counter; $attributes['href'] = '#' . $backlink_id; $note = array('count' => self::$notes_counter, 'type' => $type_info['name'], 'in-text-id' => $backlink_id, 'note-id' => $footlink_id, 'text' => Kernel::get('OutputFormatBag')->buildTag($type_info['outputformat_methods']['item'], $note_content, $attributes)); Kernel::get(Kernel::TYPE_CONTENT)->addNote($note, $note_id); } }
/** * Form HTML tables: parses table contents * * @param array $matches * @return string */ protected function _callback($matches) { $attributes = array(); //self::doDebug($matches); // The head string may have a begin slash $caption = count($matches) > 3 ? $matches[1] : null; $head = count($matches) > 3 ? preg_replace('/^ *[|]/m', '', $matches[2]) : preg_replace('/^ *[|]/m', '', $matches[1]); $underline = count($matches) > 3 ? $matches[3] : $matches[2]; $content = count($matches) > 3 ? preg_replace('/^ *[|]/m', '', $matches[4]) : preg_replace('/^ *[|]/m', '', $matches[3]); // Remove any tailing pipes for each line. $underline = preg_replace('/[|] *$/m', '', $underline); $content = preg_replace('/[|] *$/m', '', $content); // Reading alignement from header underline. $separators = preg_split('/ *[|] */', $underline); foreach ($separators as $n => $s) { $attributes[$n] = array(); if (preg_match('/^ *-+: *$/', $s)) { $attributes[$n]['style'] = 'text-align:right;'; } elseif (preg_match('/^ *:-+: *$/', $s)) { $attributes[$n]['style'] = 'text-align:center;'; } elseif (preg_match('/^ *:-+ *$/', $s)) { $attributes[$n]['style'] = 'text-align:left;'; } } // Split content by row. $headers = explode("\n", trim($head, "\n")); $text = ''; if (!empty($caption)) { $this->table_id = Helper::header2Label($caption); $text .= preg_replace_callback('/\\[(.*)\\]/', array($this, '_doCaption'), Lexer::runGamut('span_gamut', $caption)); } $lines = ''; foreach ($headers as $_header) { $line = ''; // Parsing span elements, including code spans, character escapes, // and inline HTML tags, so that pipes inside those gets ignored. $_header = Lexer::runGamut('filter:Span', $_header); // Split row by cell. $_header = preg_replace('/[|] *$/m', '', $_header); $_headers = preg_split('/[|]/', $_header); $col_count = count($_headers); // Write column headers. // we first loop for colspans $headspans = array(); foreach ($_headers as $_i => $_cell) { if ($_cell == '') { if ($_i == 0) { $headspans[1] = 2; } else { if (isset($headspans[$_i - 1])) { $headspans[$_i - 1]++; } else { $headspans[$_i - 1] = 2; } } } } foreach ($_headers as $n => $__header) { if ($__header != '') { $cell_attributes = $attributes[$n]; if (isset($headspans[$n])) { $cell_attributes['colspan'] = $headspans[$n]; } $line .= Kernel::get('OutputFormatBag')->buildTag('table_cell_head', Lexer::runGamut('span_gamut', trim($__header)), $cell_attributes) . "\n"; } } $lines .= Kernel::get('OutputFormatBag')->buildTag('table_line', $line) . "\n"; } $text .= Kernel::get('OutputFormatBag')->buildTag('table_header', $lines); // Split content by row. $rows = explode("\n", trim($content, "\n")); $lines = ''; foreach ($rows as $row) { $line = ''; // Parsing span elements, including code spans, character escapes, // and inline HTML tags, so that pipes inside those gets ignored. $row = Lexer::runGamut('filter:Span', $row); // Split row by cell. $row_cells = preg_split('/ *[|] */', $row, $col_count); $row_cells = array_pad($row_cells, $col_count, ''); // we first loop for colspans $colspans = array(); foreach ($row_cells as $_i => $_cell) { if ($_cell == '') { if ($_i == 0) { $colspans[1] = 2; } else { if (isset($colspans[$_i - 1])) { $colspans[$_i - 1]++; } else { $colspans[$_i - 1] = 2; } } } } foreach ($row_cells as $n => $cell) { if ($cell != '') { $cell_attributes = $attributes[$n]; if (isset($colspans[$n])) { $cell_attributes['colspan'] = $colspans[$n]; } $line .= Kernel::get('OutputFormatBag')->buildTag('table_cell', Lexer::runGamut('span_gamut', trim($cell)), $cell_attributes) . "\n"; } } $lines .= Kernel::get('OutputFormatBag')->buildTag('table_line', $line) . "\n"; } $text .= Kernel::get('OutputFormatBag')->buildTag('table_body', $lines); $table = Kernel::get('OutputFormatBag')->buildTag('table', $text); return parent::hashBlock($table) . "\n"; }
/** * Handle $token provided by parseSpan by determining its nature and * returning the corresponding value that should replace it. * * @param string $token * @param string $str * @return string */ public function handleSpanToken($token, &$str) { switch ($token[0]) { case "\\": if ($token[1] == "(") { $texend = strpos($str, '\\)'); if ($texend) { $eqn = substr($str, 0, $texend); $str = substr($str, $texend + 2); $texspan = Lexer::runGamut('filter:Maths:span', $eqn); return parent::hashPart($texspan); } else { return $str; } } else { return parent::hashPart("&#" . ord($token[1]) . ";"); } case "`": // Search for end marker in remaining text. if (preg_match('/^(.*?[^`])' . preg_quote($token) . '(?!`)(.*)$/sm', $str, $matches)) { $str = $matches[2]; $codespan = Lexer::runGamut('filter:CodeBlock:span', $matches[1], true); return parent::hashPart($codespan); } return $token; // return as text since no ending marker found. // return as text since no ending marker found. default: return parent::hashPart($token); } }
/** * Process paragraphs * * @param string $text The text to parse * * @return string The text parsed */ public function RebuildParagraph($text) { // Strip leading and trailing lines: $text = preg_replace('/\\A\\n+|\\n+\\z/', '', $text); $grafs = preg_split('/\\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); // Wrap <p> tags and unhashify HTML blocks foreach ($grafs as $key => $value) { $value = trim(Lexer::runGamut('span_gamut', $value)); // Check if this should be enclosed in a paragraph. // Clean tag hashes & block tag hashes are left alone. $is_p = !preg_match('/^B\\x1A[0-9]+B|^C\\x1A[0-9]+C$/', $value); if ($is_p) { $value = Kernel::get('OutputFormatBag')->buildTag('paragraph', $value); } $grafs[$key] = $value; } // Join grafs in one text, then unhash HTML tags. // $text = implode("\n\n", $grafs); $text = implode('', $grafs); // Finish by removing any tag hashes still present in $text. $text = Lexer::runGamut('filter:HTML:unhash', $text, true); return $text; }
/** * @param string $text * @return string */ public function transform($text) { $token_stack = array(''); $text_stack = array(''); $italic = ''; $strong = ''; $tree_char_em = false; while (1) { // Get prepared regular expression for seraching emphasis tokens in current context. $token_re = self::$em_strong_prepared["{$italic}{$strong}"]; // Each loop iteration search for the next emphasis token. // Each token is then passed to handleSpanToken. $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); $text_stack[0] .= $parts[0]; $token =& $parts[1]; $text =& $parts[2]; if (empty($token)) { // Reached end of text span: empty stack without emitting any more emphasis. while ($token_stack[0]) { $text_stack[1] .= array_shift($token_stack); $text_stack[0] .= array_shift($text_stack); } break; } $token_len = strlen($token); if ($tree_char_em) { // Reached closing marker while inside a three-char emphasis. if ($token_len == 3) { // Three-char closing marker, close em and strong. array_shift($token_stack); $span = Lexer::runGamut('span_gamut', array_shift($text_stack)); $span = Kernel::get('OutputFormatBag')->buildTag('italic', $span); $span = Kernel::get('OutputFormatBag')->buildTag('bold', $span); $text_stack[0] .= parent::hashPart($span); $italic = ''; $strong = ''; } else { // Other closing marker: close one em or strong and // change current token state to match the other $token_stack[0] = str_repeat($token[0], 3 - $token_len); $tag = $token_len == 2 ? "bold" : "italic"; $span = Lexer::runGamut('span_gamut', $text_stack[0]); $span = Kernel::get('OutputFormatBag')->buildTag($tag, $span); $text_stack[0] = parent::hashPart($span); ${$tag} = ''; // $$tag stands for $italic or $strong } $tree_char_em = false; } elseif ($token_len == 3) { if ($italic) { // Reached closing marker for both em and strong. // Closing strong marker: for ($i = 0; $i < 2; ++$i) { $shifted_token = array_shift($token_stack); $tag = strlen($shifted_token) == 2 ? "bold" : "italic"; $span = Lexer::runGamut('span_gamut', array_shift($text_stack)); $span = Kernel::get('OutputFormatBag')->buildTag($tag, $span); $text_stack[0] .= parent::hashPart($span); ${$tag} = ''; // $$tag stands for $italic or $strong } } else { // Reached opening three-char emphasis marker. Push on token // stack; will be handled by the special condition above. $italic = $token[0]; $strong = "{$italic}{$italic}"; array_unshift($token_stack, $token); array_unshift($text_stack, ''); $tree_char_em = true; } } elseif ($token_len == 2) { if ($strong) { // Unwind any dangling emphasis marker: if (strlen($token_stack[0]) == 1) { $text_stack[1] .= array_shift($token_stack); $text_stack[0] .= array_shift($text_stack); } // Closing strong marker: array_shift($token_stack); $span = Lexer::runGamut('span_gamut', array_shift($text_stack)); $span = Kernel::get('OutputFormatBag')->buildTag('bold', $span); $text_stack[0] .= parent::hashPart($span); $strong = ''; } else { array_unshift($token_stack, $token); array_unshift($text_stack, ''); $strong = $token; } } else { // Here $token_len == 1 if ($italic) { if (strlen($token_stack[0]) == 1) { // Closing emphasis marker: array_shift($token_stack); $span = Lexer::runGamut('span_gamut', array_shift($text_stack)); $span = Kernel::get('OutputFormatBag')->buildTag('italic', $span); $text_stack[0] .= parent::hashPart($span); $italic = ''; } else { $text_stack[0] .= $token; } } else { array_unshift($token_stack, $token); array_unshift($text_stack, ''); $italic = $token; } } } return $text_stack[0]; }
/** * Process each abbreviation * * @param array $matches One set of results form the `transform()` function * @return string */ protected function _callback($matches) { $abbr = $matches[0]; $abbr_desciptions = Kernel::getConfig('abbr_desciptions'); if (isset($abbr_desciptions[$abbr])) { $attributes = array(); $desc = trim($abbr_desciptions[$abbr]); if (!empty($desc)) { $attributes['title'] = Lexer::runGamut(GamutLoader::TOOL_ALIAS . ':EncodeAttribute', $desc); } $abbr = Kernel::get('OutputFormatBag')->buildTag('abbreviation', $abbr, $attributes); return parent::hashBlock($abbr); } else { return $abbr; } }