1<?php
2/**
3 * Plugin asciidocjs - Use asciidoc inside dokuwiki
4 *
5 * To be run with Dokuwiki only
6 *
7 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
8 * @author     Rüdiger Kessel  <ruediger.kessel@gmail.com>
9 */
10if(!defined('DOKU_INC')) die();
11if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
12
13    /**
14     * All DokuWiki plugins to extend the parser/rendering mechanism
15     * need to inherit from this class
16     */
17    class syntax_plugin_asciidocjs extends DokuWiki_Syntax_Plugin {
18
19
20       public $scriptid = 0;
21       /**
22        * Get the type of syntax this plugin defines.
23        *
24        * @param none
25        * @return String <tt>'substition'</tt> (i.e. 'substitution').
26        * @public
27        * @static
28        */
29        function getType(){
30            return 'protected';
31        }
32
33       /**
34        * Where to sort in?
35        *
36        * @param none
37        * @return Integer <tt>6</tt>.
38        * @public
39        * @static
40        */
41        function getSort(){
42            return 1;
43        }
44
45
46       /**
47        * Connect lookup pattern to lexer.
48        *
49        * @param $aMode String The desired rendermode.
50        * @return none
51        * @public
52        * @see render()
53        */
54        function connectTo($mode) {
55          $this->Lexer->addEntryPattern('<asciidoc>',$mode,'plugin_asciidocjs');
56          $this->Lexer->addEntryPattern('//--asciidoc--//',$mode,'plugin_asciidocjs');
57        }
58
59       function postConnect() {
60          $this->Lexer->addExitPattern('</asciidoc>','plugin_asciidocjs');
61        }
62
63
64       /**
65        * Handler to prepare matched data for the rendering process.
66        *
67        * <p>
68        * The <tt>$aState</tt> parameter gives the type of pattern
69        * which triggered the call to this method:
70        * </p>
71        * @param $aAscdoc String The asciidoc text to convert.
72        */
73       function run_asciidoctor($node,$ascdoc,$save_mode) {
74           if ($node==''){
75               return '<!-- ascii-doc no node command -->';
76           }
77           $html = '';
78           $return_value = 1;
79           $descriptorspec = array(
80               0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
81               1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
82               2 => array("pipe", "w")   // stderr
83           );
84           $cwd = DOKU_PLUGIN.'asciidocjs';
85           $env = array();
86           $CMD=$node." asciidoc.js ".$save_mode;
87           $process = proc_open($CMD, $descriptorspec, $pipes, $cwd, $env);
88           if (is_resource($process)) {
89               // $pipes now looks like this:
90               // 0 => writeable handle connected to child stdin
91               // 1 => readable handle connected to child stdout
92               // Any error output will be appended to /tmp/error-output.txt
93
94               fwrite($pipes[0],$ascdoc);
95               fclose($pipes[0]);
96
97               $html=stream_get_contents($pipes[1]);
98               fclose($pipes[1]);
99
100               $error=stream_get_contents($pipes[2]);
101               fclose($pipes[2]);
102
103               // It is important that you close any pipes before calling
104               // proc_close in order to avoid a deadlock
105               $return_value = proc_close($process);
106           }
107           if ($return_value==0) {
108               return $html;
109           } else {
110               return "<!-- ascii-doc error $return_value: $error -->";
111           }
112       }
113       /**
114        * Handler to prepare matched data for the rendering process.
115        *
116        * <p>
117        * The <tt>$aState</tt> parameter gives the type of pattern
118        * which triggered the call to this method:
119        * </p>
120        * <dl>
121        * <dt>DOKU_LEXER_ENTER</dt>
122        * <dd>a pattern set by <tt>addEntryPattern()</tt></dd>
123        * <dt>DOKU_LEXER_MATCHED</dt>
124        * <dd>a pattern set by <tt>addPattern()</tt></dd>
125        * <dt>DOKU_LEXER_EXIT</dt>
126        * <dd> a pattern set by <tt>addExitPattern()</tt></dd>
127        * <dt>DOKU_LEXER_SPECIAL</dt>
128        * <dd>a pattern set by <tt>addSpecialPattern()</tt></dd>
129        * <dt>DOKU_LEXER_UNMATCHED</dt>
130        * <dd>ordinary text encountered within the plugin's syntax mode
131        * which doesn't match any pattern.</dd>
132        * </dl>
133        * @param $aMatch String The text matched by the patterns.
134        * @param $aState Integer The lexer state for the match.
135        * @param $aPos Integer The character position of the matched text.
136        * @param $aHandler Object Reference to the Doku_Handler object.
137        * @return Integer The current lexer state for the match.
138        * @public
139        * @see render()
140        * @static
141        */
142        function handle($match, $state, $pos, Doku_Handler $handler){
143            switch ($state) {
144              case DOKU_LEXER_ENTER :
145                $data ='';
146                if ($this->scriptid==0){
147                  $data .= '<script type="module" src="'.DOKU_BASE.'lib/plugins/asciidocjs/asciidoc.js'.'" defer></script>'.PHP_EOL;
148                  $data .= '<script type="text/javascript">'.PHP_EOL;
149                  $data .= 'save_mode="'.$this->getConf('save_mode').'";</script>'.PHP_EOL;
150                }
151                return array($state, $data, '');
152              case DOKU_LEXER_MATCHED :
153                break;
154              case DOKU_LEXER_UNMATCHED :
155                $data ='';
156                if ($this->getConf('save_mode')=='server'){
157                  $data.='<!-- ascii-doc start -->';
158                  $data.=$this->run_asciidoctor($this->getConf('exec_node'),$match,$this->getConf('save_mode'));
159                  $data.='<!-- ascii-doc end -->';
160                } else {
161                  $SID="asciidoc_c".strval($this->scriptid);
162                  $DID="asciidoc_t".strval($this->scriptid);
163                  $this->scriptid+=1;
164                  $data.='<div id="'.$DID.'"></div>'.PHP_EOL;
165                  $data.='<script type="text/javascript">if (typeof asciidocs === "undefined") asciidocs=[];'.PHP_EOL;
166                  $data.='asciidocs.push({"SID":"'.$SID.'","DID":"'.$DID.'"});</script>'.PHP_EOL;
167                  $data.='<script id="'.$SID.'" type="text/json">';
168                  $data.='{"text":'.json_encode($match).'}';
169                  $data.='</script>';
170                }
171                return array($state, $data, $match);
172              case DOKU_LEXER_EXIT :
173                return array($state, '', '');
174              case DOKU_LEXER_SPECIAL :
175                break;
176            }
177            return array();
178        }
179
180       /**
181        * Handle the actual output creation.
182        *
183        * <p>
184        * The method checks for the given <tt>$aFormat</tt> and returns
185        * <tt>FALSE</tt> when a format isn't supported. <tt>$aRenderer</tt>
186        * contains a reference to the renderer object which is currently
187        * handling the rendering. The contents of <tt>$aData</tt> is the
188        * return value of the <tt>handle()</tt> method.
189        * </p>
190        * @param $aFormat String The output format to generate.
191        * @param $aRenderer Object A reference to the renderer object.
192        * @param $aData Array The data created by the <tt>handle()</tt>
193        * method.
194        * @return Boolean <tt>TRUE</tt> if rendered successfully, or
195        * <tt>FALSE</tt> otherwise.
196        * @public
197        * @see handle()
198        */
199        function render($mode, Doku_Renderer $renderer, $data) {
200            if($mode == 'xhtml'){
201                if(is_a($renderer,'renderer_plugin_dw2pdf')){
202                  // this is the PDF export, render simple HTML here
203                  $renderer->doc .= $this->run_asciidoctor($this->getConf('exec_node'),$data[2],$this->getConf('save_mode'));
204                }else{
205                  // this is normal XHTML for Browsers, be fancy here
206                    $renderer->doc .= $data[1];
207                }
208                return true;
209            }
210            return false;
211        }
212    }
213
214?>
215
216