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