| 1 | <?php |
|---|
| 2 | /** |
|---|
| 3 | * @package HatenaSyntax |
|---|
| 4 | * @author anatoo<anatoo@nequal.jp> |
|---|
| 5 | * @license http://www.opensource.org/licenses/mit-license.php MIT License |
|---|
| 6 | * @version $Id: TOCRenderer.php 1163 2009-09-07 17:16:34Z anatoo $ |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | class HatenaSyntax_TOCRenderer |
|---|
| 10 | { |
|---|
| 11 | protected $headerCount; |
|---|
| 12 | |
|---|
| 13 | function render(HatenaSyntax_Node $rootnode, $id) |
|---|
| 14 | { |
|---|
| 15 | $treeroot = HatenaSyntax_Tree::make($this->filter($rootnode)); |
|---|
| 16 | $this->headerCount = 0; |
|---|
| 17 | $this->id = $id; |
|---|
| 18 | $renderer = new HatenaSyntax_TreeRenderer(array($this, 'renderHeader')); |
|---|
| 19 | return '<div class="toc">' . $renderer->render($treeroot) . '</div>'; |
|---|
| 20 | } |
|---|
| 21 | |
|---|
| 22 | protected function escape($str) |
|---|
| 23 | { |
|---|
| 24 | return htmlspecialchars($str, ENT_QUOTES); |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | function renderHeader($node) |
|---|
| 28 | { |
|---|
| 29 | $count = $this->headerCount++; |
|---|
| 30 | $buf = array(); |
|---|
| 31 | $data = $node->getData(); |
|---|
| 32 | foreach ($data['body'] as $leaf) { |
|---|
| 33 | if (is_string($leaf)) { |
|---|
| 34 | $buf[] = $leaf; |
|---|
| 35 | } |
|---|
| 36 | else { |
|---|
| 37 | $buf [] = $this->{'render' . $leaf->getType()}($lead->getData()); |
|---|
| 38 | } |
|---|
| 39 | } |
|---|
| 40 | return '<a href="#' . $this->id . '_header_' . $count . '">' . $this->escape(join('', $buf)) . '</a>'; |
|---|
| 41 | } |
|---|
| 42 | |
|---|
| 43 | protected function renderFootnote($data) |
|---|
| 44 | { |
|---|
| 45 | return ''; |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | function filter(HatenaSyntax_Node $rootnode) |
|---|
| 49 | { |
|---|
| 50 | if ($rootnode->getType() !== 'root') throw new Exception; |
|---|
| 51 | $header_arr = $this->fetchHeader($rootnode); |
|---|
| 52 | $ret = array(); |
|---|
| 53 | foreach ($header_arr as $header) { |
|---|
| 54 | $buf = $header->getData(); |
|---|
| 55 | $ret[] = array('level' => $buf['level'], 'value' => $header); |
|---|
| 56 | } |
|---|
| 57 | return $ret; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | protected function fetchHeader($node) |
|---|
| 61 | { |
|---|
| 62 | return $this->{'fetchHeaderIn' . $node->getType()}($node); |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | protected function fetchHeaderInRoot($node) |
|---|
| 66 | { |
|---|
| 67 | $buf = array(); |
|---|
| 68 | foreach ($node->getData() as $node) { |
|---|
| 69 | $buf[] = $this->fetchHeader($node); |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | return $this->concat($buf); |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | protected function fetchHeaderInHeader($node) |
|---|
| 76 | { |
|---|
| 77 | return array($node); |
|---|
| 78 | } |
|---|
| 79 | |
|---|
| 80 | protected function fetchHeaderInBlockQuote($node) |
|---|
| 81 | { |
|---|
| 82 | $buf = array(); |
|---|
| 83 | $data = $node->getData(); |
|---|
| 84 | foreach ($data['body'] as $node) { |
|---|
| 85 | $buf[] = $this->fetchHeader($node); |
|---|
| 86 | } |
|---|
| 87 | return $this->concat($buf); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | function __call($name, $args) |
|---|
| 91 | { |
|---|
| 92 | if (preg_match('#^fetchHeaderIn\w+$#i', $name)) return array(); |
|---|
| 93 | throw new Exception(sprintf('method(%s) not found', $name)); |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | protected function concat(Array $target) |
|---|
| 97 | { |
|---|
| 98 | if (!$target) return array(); |
|---|
| 99 | $target = array_reverse($target); |
|---|
| 100 | while (1 < count($target)) { |
|---|
| 101 | array_push($target, array_merge(array_pop($target), array_pop($target))); |
|---|
| 102 | } |
|---|
| 103 | return $target[0]; |
|---|
| 104 | } |
|---|
| 105 | } |
|---|