1<?php
2/**
3 * PHP Markdown Extra plugin for DokuWiki.
4 *
5 * @license GPL 3 (http://www.gnu.org/licenses/gpl.html) - NOTE: PHP Markdown
6 * Extra is licensed under the BSD license. See License.text for details.
7 * @version 1.03 - 24.11.2012 - PHP Markdown Extra 1.2.5 included.
8 * @author Joonas Pulakka <joonas.pulakka@iki.fi>, Jiang Le <smartynaoki@gmail.com>
9 */
10
11if (!defined('DOKU_INC')) die();
12if (!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
13require_once (DOKU_PLUGIN . 'syntax.php');
14require_once (DOKU_PLUGIN . 'markdownextra/markdown.php');
15
16class syntax_plugin_markdownextra extends DokuWiki_Syntax_Plugin {
17
18    function getType() {
19        return 'protected';
20    }
21
22    function getPType() {
23        return 'block';
24    }
25
26    function getSort() {
27        return 69;
28    }
29
30    function connectTo($mode) {
31        $this->Lexer->addEntryPattern('<markdown>(?=.*</markdown>)', $mode, 'plugin_markdownextra');
32    }
33
34    function postConnect() {
35        $this->Lexer->addExitPattern('</markdown>', 'plugin_markdownextra');
36    }
37
38    function handle($match, $state, $pos, Doku_Handler $handler) {
39        switch ($state) {
40            case DOKU_LEXER_ENTER :      return array($state, '');
41            case DOKU_LEXER_UNMATCHED :  return array($state, Markdown($match));
42            case DOKU_LEXER_EXIT :       return array($state, '');
43        }
44        return array($state,'');
45    }
46
47    function render($mode, Doku_Renderer $renderer, $data) {
48        //dbg('function render($mode, &$renderer, $data)-->'.' mode = '.$mode.' data = '.$data);
49        //dbg($data);
50        if ($mode == 'xhtml') {
51            list($state,$match) = $data;
52            switch ($state) {
53                case DOKU_LEXER_ENTER :      break;
54                case DOKU_LEXER_UNMATCHED :
55                    $match = $this->_toc($renderer, $match);
56                    $renderer->doc .= $match;
57                    break;
58                case DOKU_LEXER_EXIT :       break;
59            }
60            return true;
61        }else if ($mode == 'metadata') {
62            //dbg('function render($mode, &$renderer, $data)-->'.' mode = '.$mode.' data = '.$data);
63            //dbg($data);
64            list($state,$match) = $data;
65            switch ($state) {
66                case DOKU_LEXER_ENTER :      break;
67                case DOKU_LEXER_UNMATCHED :
68                    if (!$renderer->meta['title']){
69                        $renderer->meta['title'] = $this->_markdown_header($match);
70                    }
71                    $this->_toc($renderer, $match);
72                    $internallinks = $this->_internallinks($match);
73                    #dbg($internallinks);
74                    if (count($internallinks)>0){
75                        foreach($internallinks as $internallink)
76                        {
77                            $renderer->internallink($internallink);
78                        }
79                    }
80                    break;
81                case DOKU_LEXER_EXIT :       break;
82            }
83            return true;
84        } else {
85            return false;
86        }
87    }
88
89    function _markdown_header($text)
90    {
91        $doc = new DOMDocument('1.0','UTF-8');
92        //dbg($doc);
93        $meta = '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>';
94        $doc->loadHTML($meta.$text);
95        //dbg($doc->saveHTML());
96        if ($nodes = $doc->getElementsByTagName('h1')){
97            return $nodes->item(0)->nodeValue;
98        }
99        return false;
100    }
101
102    function _internallinks($text)
103    {
104        $links = array();
105        if ( ! $text ) return $links;
106        $doc = new DOMDocument('1.0', 'UTF-8');
107        $doc->loadHTML($text);
108        if ($nodes = $doc->getElementsByTagName('a')){
109            foreach($nodes as $atag)
110            {
111                $href = $atag->getAttribute('href');
112                if (!preg_match('/^(https{0,1}:\/\/|ftp:\/\/|mailto:)/i',$href)){
113                    $links[] = $href;
114                }
115            }
116        }
117        return $links;
118    }
119
120    function _toc(&$renderer, $text)
121    {
122        $doc = new DOMDocument('1.0','UTF-8');
123        //dbg($doc);
124        $meta = '<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head>';
125        $doc->loadHTML($meta.$text);
126        if ($nodes = $doc->getElementsByTagName("*")){
127            foreach($nodes as $node)
128            {
129                if (preg_match('/h([1-7])/',$node->tagName,$match))
130                {
131                    #dbg($node);
132                    $node->setAttribute('class', 'sectionedit'.$match[1]);
133                    $hid = $renderer->_headerToLink($node->nodeValue,'true');
134                    $node->setAttribute('id',$hid);
135                    $renderer->toc_additem($hid, $node->nodeValue, $match[1]);
136                }
137
138            }
139        }
140        //remove outer tags of content
141        $html = $doc->saveHTML();
142        $html = str_replace('<!DOCTYPE html>','',$html);
143        $html = preg_replace('/.+<body>/', '', $html);
144        $html = preg_replace('@</body>.*</html>@','', $html);
145        return $html;
146    }
147
148}