1<?php
2/**
3 * Div Syntax Component of the Wrap Plugin
4 *
5 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author     Anika Henke <anika@selfthinker.org>
7 */
8
9class syntax_plugin_wrap_div extends DokuWiki_Syntax_Plugin {
10    protected $special_pattern = '<div\b[^>\r\n]*?/>';
11    protected $entry_pattern   = '<div\b.*?>(?=.*?</div>)';
12    protected $exit_pattern    = '</div>';
13
14    function getType(){ return 'formatting';}
15    function getAllowedTypes() { return array('container', 'formatting', 'substition', 'protected', 'disabled', 'paragraphs'); }
16    function getPType(){ return 'stack';}
17    function getSort(){ return 195; }
18    // override default accepts() method to allow nesting - ie, to get the plugin accepts its own entry syntax
19    function accepts($mode) {
20        if ($mode == substr(get_class($this), 7)) return true;
21        return parent::accepts($mode);
22    }
23
24    /**
25     * Connect pattern to lexer
26     */
27    function connectTo($mode) {
28        $this->Lexer->addSpecialPattern($this->special_pattern,$mode,'plugin_wrap_'.$this->getPluginComponent());
29        $this->Lexer->addEntryPattern($this->entry_pattern,$mode,'plugin_wrap_'.$this->getPluginComponent());
30    }
31
32    function postConnect() {
33        $this->Lexer->addExitPattern($this->exit_pattern, 'plugin_wrap_'.$this->getPluginComponent());
34        $this->Lexer->addPattern('[ \t]*={2,}[^\n]+={2,}[ \t]*(?=\n)', 'plugin_wrap_'.$this->getPluginComponent());
35    }
36
37    /**
38     * Handle the match
39     */
40    function handle($match, $state, $pos, Doku_Handler $handler){
41        global $conf;
42        switch ($state) {
43            case DOKU_LEXER_ENTER:
44            case DOKU_LEXER_SPECIAL:
45                $data = strtolower(trim(substr($match,strpos($match,' '),-1)," \t\n/"));
46                return array($state, $data);
47
48            case DOKU_LEXER_UNMATCHED:
49                $handler->addCall('cdata', array($match), $pos);
50                break;
51
52            case DOKU_LEXER_MATCHED:
53                // we have a == header ==, use the core header() renderer
54                // (copied from core header() in inc/parser/handler.php)
55                $title = trim($match);
56                $level = 7 - strspn($title,'=');
57                if($level < 1) $level = 1;
58                $title = trim($title,'=');
59                $title = trim($title);
60
61                $handler->addCall('header',array($title,$level,$pos), $pos);
62                // close the section edit the header could open
63                if ($title && $level <= $conf['maxseclevel']) {
64                    $handler->addPluginCall('wrap_closesection', array(), DOKU_LEXER_SPECIAL, $pos, '');
65                }
66                break;
67
68            case DOKU_LEXER_EXIT:
69                return array($state, '');
70        }
71        return false;
72    }
73
74    /**
75     * Create output
76     */
77    function render($format, Doku_Renderer $renderer, $indata) {
78        static $type_stack = array ();
79
80        if (empty($indata)) return false;
81        list($state, $data) = $indata;
82
83        if($format == 'xhtml'){
84            /** @var Doku_Renderer_xhtml $renderer */
85            switch ($state) {
86                case DOKU_LEXER_ENTER:
87                    $sectionEditStartData = ['target' => 'plugin_wrap_start', 'hid' => ''];
88                    $sectionEditEndData = ['target' =>'plugin_wrap_end', 'hid' => ''];
89                    if (!defined('SEC_EDIT_PATTERN')) {
90                        // backwards-compatibility for Frusterick Manners (2017-02-19)
91                        $sectionEditStartData = 'plugin_wrap_start';
92                        $sectionEditEndData = 'plugin_wrap_end';
93                    }
94                    // add a section edit right at the beginning of the wrap output
95                    $renderer->startSectionEdit(0, $sectionEditStartData);
96                    $renderer->finishSectionEdit();
97                    // add a section edit for the end of the wrap output. This prevents the renderer
98                    // from closing the last section edit so the next section button after the wrap syntax will
99                    // include the whole wrap syntax
100                    $renderer->startSectionEdit(0,  $sectionEditEndData);
101
102                case DOKU_LEXER_SPECIAL:
103                    $wrap = $this->loadHelper('wrap');
104                    $attr = $wrap->buildAttributes($data, 'plugin_wrap');
105
106                    $renderer->doc .= '<div'.$attr.'>';
107                    if ($state == DOKU_LEXER_SPECIAL) $renderer->doc .= '</div>';
108                    break;
109
110                case DOKU_LEXER_EXIT:
111                    $renderer->doc .= '</div>';
112                    $renderer->finishSectionEdit();
113                    break;
114            }
115            return true;
116        }
117        if($format == 'odt'){
118            switch ($state) {
119                case DOKU_LEXER_ENTER:
120                    $wrap = plugin_load('helper', 'wrap');
121                    array_push ($type_stack, $wrap->renderODTElementOpen($renderer, 'div', $data));
122                    break;
123
124                case DOKU_LEXER_EXIT:
125                    $element = array_pop ($type_stack);
126                    $wrap = plugin_load('helper', 'wrap');
127                    $wrap->renderODTElementClose ($renderer, $element);
128                    break;
129            }
130            return true;
131        }
132        return false;
133    }
134}
135