1<?php
2/**
3 * DokuWiki Plugin survey (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  DRINGOT <ddonovan.ringot@hotmail.fr>
7 */
8
9// must be run within Dokuwiki
10if (!defined("DOKU_INC")) {
11    die();
12}
13
14if (!defined("DOKU_LF")) {
15    define("DOKU_LF", "\n");
16}
17if (!defined("DOKU_TAB")) {
18    define("DOKU_TAB", "\t");
19}
20if (!defined("DOKU_PLUGIN")) {
21    define("DOKU_PLUGIN", DOKU_INC . "lib/plugins/");
22}
23
24class helper_plugin_survey_survey extends DokuWiki_Plugin
25{
26    public function getMethods()
27    {
28        return [
29            [
30                "name" => "sanitizeSyntax",
31                "desc" => "Clean syntax before interpreting it",
32                "params" => [
33                    "The syntax to sanitize" => "string",
34                ],
35                "return" => [
36                    "Sanitized Syntaxstring" => "string",
37                ],
38            ],
39            [
40                "name" => "interpretSurvey",
41                "desc" =>
42                    "Interprets survey syntax text and returns " .
43                    "a survey configuration",
44                "params" => [
45                    "Syntax text for the survey" => "string",
46                    "Current line in the syntax" => "int",
47                    "Current level of survey" => "int",
48                ],
49                "return" => [
50                    "The survey configuration as a hash" => "array",
51                ],
52            ],
53        ];
54    }
55
56    /**
57     * Clean syntax before interpreting it
58     *
59     * @param String $surveySyntax The syntax to sanitize
60     *
61     * @return String Sanitized Syntaxstring
62     */
63
64    public function sanitizeSyntax($surveySyntax)
65    {
66        // Remove \r's from the syntax.
67
68        $surveySyntax = preg_replace("/\r/", "", $surveySyntax);
69
70        // Sanitize syntax. Remove empty lines and such
71
72        $tmp = [];
73
74        $surveyArray = explode("\n", $surveySyntax);
75
76        foreach ($surveyArray as $syntaxLine) {
77            // Only use good syntax, discard other lines
78
79            if (preg_match('/^ *  \* .*$/', $syntaxLine)) {
80                $tmp[] = $syntaxLine;
81            } else {
82                dbglog(
83                    "Discarded survey syntaxline: " . $syntaxLine,
84                    "Survey-Plugin SanitizeSyntax"
85                );
86            }
87        }
88
89        return implode("\n", $tmp);
90    }
91
92    public function renderText($lineText)
93    {
94        // Link
95
96        if (preg_match("/\[\[(.*)\]\]/", $lineText, $matches)) {
97            if (preg_match("/^([^|]*)\|(.*)$/", $matches[1], $titleMatches)) {
98                $link = $titleMatches[1];
99                $name = $titleMatches[2];
100            } else {
101                $link = $name = $matches[1];
102            }
103
104            if (preg_match("/^(http|ftp)/", $link)) {
105                // External link
106
107                $lineText = str_replace(
108                    $matches[0],
109                    '<a href="' . $link . '">' . $name . "</a>",
110                    $lineText
111                );
112            } else {
113                // Internal link
114
115                $lineText = str_replace(
116                    $matches[0],
117                    html_wikilink($link, $name),
118                    $lineText
119                );
120            }
121        } else {
122            $lineText = preg_replace(
123                "/\*\*([^\*]*)\*\*/",
124                "<b>$1</b>",
125                $lineText
126            );
127            $lineText = preg_replace("/_([^_]*)_/", "<u>$1</u>", $lineText);
128            $lineText = preg_replace(
129                "/\/\/([^\/]*)\/\//",
130                "<i>$1</i>",
131                $lineText
132            );
133        }
134
135        return $lineText;
136    }
137
138    /**
139     *
140     *
141     * As an example, it interprets the following source text into
142     * this survey configuration array:
143     *
144     *   * Question A
145     *      * Answer A-A
146     *      * Question A-B
147     *          * Answer A-B-A
148     *          * Answer A-B-B
149     *   * Question B
150     *      * Answer B-A
151     *      * Answer B-B
152     *
153     * array(
154     *     "_name": "root",
155     *     "_hasChildren": true,
156     *     "_children": array(
157     *         array(
158     *             "_name": "Question A",
159     *             "_hasChildren": true,
160     *             "_children": array(
161     *                 array(
162     *                     "_name": "Answer A-A",
163     *                     "_hasChildren": false
164     *                 ),
165     *                 array(
166     *                     "_name": "Question A-B",
167     *                     "_hasChildren": true,
168     *                     "_children": array(
169     *                         array(
170     *                             "_name": "Answer A-B-A",
171     *                             "_hasChildren": false
172     *                         ),
173     *                         array(
174     *                             "_name: "Answer A-B-B",
175     *                             "_hasChildren": false
176     *                         )
177     *                     )
178     *                 )
179     *             )
180     *         ),
181     *         array(
182     *             "_name:"Question B",
183     *             "_hasChildren": true,
184     *             "_children": array(
185     *                 array(
186     *                     "_name": "Answer B-A",
187     *                     "_hasChildren": false
188     *                 ),
189     *                 array(
190     *                     "_name": "Answer B-B",
191     *                     "_hasChildren": false
192     *                 )
193     *             )
194     *         )
195     *     )
196     * );
197     *
198     * @param String $syntaxText   Syntax text for the survey
199     * @param int    $currentLine  Current line in the syntax
200     * @param int    $currentLevel Current level of survey
201     *
202     * @return Array The survey configuration as a hash
203     */
204
205    public function interpretSurvey(
206        $syntaxText,
207        $currentLine = 0,
208        $currentLevel = -1
209    ) {
210        $syntaxArray = explode("\n", $syntaxText);
211
212        $returnArray = [];
213
214        if ($currentLevel == -1) {
215            $returnArray["_name"] = "root";
216            $returnArray["_children"] = [];
217        } else {
218            $workLine = $syntaxArray[$currentLine];
219
220            preg_match('/^( *)  \* (.*)$/', $workLine, $lineMatch);
221
222            $returnArray["_name"] = $this->renderText($lineMatch[2]);
223            $returnArray["_children"] = [];
224
225            $currentLine++;
226        }
227
228        while ($currentLine < count($syntaxArray)) {
229            $workLine = $syntaxArray[$currentLine];
230
231            preg_match('/^( *)  \* (.*)$/', $workLine, $lineMatch);
232
233            $nextLine = $syntaxArray[$currentLine + 1];
234
235            preg_match('/^( *)  \* (.*)$/', $nextLine, $nextLineMatch);
236
237            $lineLevel = strlen($lineMatch[1]) / 2;
238            $nextLineLevel = strlen($nextLineMatch[1]) / 2;
239
240            if ($lineLevel == $nextLineLevel) {
241                // Add a child
242
243                $returnArray["_children"][] = [
244                    "_name" => $this->renderText($lineMatch[2]),
245                    "_hasChildren" => false,
246                ];
247            } elseif ($lineLevel < $nextLineLevel) {
248                // Add a child with children
249
250                $subArray = $this->interpretSurvey(
251                    $syntaxText,
252                    $currentLine,
253                    $lineLevel
254                );
255
256                $returnArray["_children"][] = $subArray;
257
258                $currentLine = $subArray["_currentLine"];
259
260                $newNextLine = $syntaxArray[$currentLine + 1];
261
262                preg_match(
263                    '/^( *)  \* (.*)$/',
264                    $newNextLine,
265                    $newNextLineMatch
266                );
267
268                $newNextLineLevel = strlen($newNextLineMatch[1]) / 2;
269
270                if ($nextLineLevel > $newNextLineLevel + 1) {
271                    $returnArray["_hasChildren"] = true;
272                    $returnArray["_currentLine"] = $currentLine;
273
274                    return $returnArray;
275                }
276            } else {
277                // We're done here. Return.
278
279                // Add a child
280
281                $returnArray["_children"][] = [
282                    "_name" => $this->renderText($lineMatch[2]),
283                    "_hasChildren" => false,
284                ];
285
286                $returnArray["_hasChildren"] = true;
287                $returnArray["_currentLine"] = $currentLine;
288
289                return $returnArray;
290            }
291
292            $currentLine++;
293        }
294
295        // We're through
296
297        if (count($returnArray["_children"]) > 0) {
298            $returnArray["_hasChildren"] = true;
299        }
300
301        $returnArray["_currentLine"] = $currentLine;
302
303        return $returnArray;
304    }
305}
306