]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/plugin/WikiFormRich.php
seperated --> separated
[SourceForge/phpwiki.git] / lib / plugin / WikiFormRich.php
1 <?php
2
3 /*
4  * Copyright 2004,2006,2007 $ThePhpWikiProgrammingTeam
5  *
6  * This file is part of PhpWiki.
7  *
8  * PhpWiki is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * PhpWiki is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with PhpWiki; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 /**
24  * This is another replacement for MagicPhpWikiURL forms.
25  * Previously encoded with the "phpwiki:" syntax.
26  *
27  * Enhanced WikiForm to be more generic:
28  * - editbox[]                 name=.. value=.. text=.. autocomplete=1
29  * - checkbox[]         name=.. value=0|1 checked text=..
30  * - radio[]                 name=.. value=.. text=..
31  * - pulldown[]                name=.. value=.. selected=.. text=.. autocomplete=1
32  * - combobox[]                name=.. value=.. text=.. method=.. args=..
33  * - hidden[]                name=.. value=..
34  * - submit[]
35  * - action, submit buttontext, optional cancel button (bool)
36  * - method=get or post, Default: post.
37  * Valid arguments for pulldown and editbox: autocomplete=1, Default: 0
38  * If autocomplete=1, additional arguments method and args may be used.
39  * If no method is given, value will be used to fill in the valid values.
40  * method="xmlrpc:server:name" or "url:http://server/wiki/method" or "array:jsvariable"
41  * or "plugin:pluginname"
42  * args are optional arguments, space separated, for the method.
43  * A combobox is a pulldown with autocomplete=1.
44  *
45  * @Author: Reini Urban
46  * Values which are constants are evaluated.
47  * The cancel button must be supported by the action.
48  *   (just some wikiadmin actions so far)
49  * improve layout by: nobr=1
50  * some allow values as list from from <!plugin-list !>
51
52 Samples:
53 <<WikiFormRich action=dumpserial method=get
54 checkbox[] name=include value="all"
55 editbox[] name=directory value=DEFAULT_DUMP_DIR
56 editbox[] name=pages value=*
57 editbox[] name=exclude value="" >>
58 <<WikiFormRich action=dumphtml method=get
59 editbox[] name=directory value=HTML_DUMP_DIR
60 editbox[] name=pages value="*"
61 editbox[] name=exclude value="" >>
62 <<WikiFormRich action=loadfile method=get
63 editbox[]  name=source value=DEFAULT_WIKI_PGSRC
64 checkbox[] name=overwrite value=1
65 editbox[]  name=exclude value="" >>
66 <<WikiFormRich action=TitleSearch method=get class=wikiadmin nobr=1
67 editbox[] name=s text=""
68 submit[]
69 checkbox[] name=case_exact
70 checkbox[] name=regex >>
71 <<WikiFormRich action=FullTextSearch method=get class=wikiadmin nobr=1
72 editbox[] name=s text=""
73 submit[]
74 checkbox[] name=case_exact
75 checkbox[] name=regex >>
76 <<WikiFormRich action=FuzzyPages method=get class=wikiadmin nobr=1
77 editbox[] name=s text=""
78 submit[]
79 checkbox[] name=case_exact ?>
80 <<WikiFormRich action=AppendText buttontext="AddPlugin"
81 radio[] name=s value=<!plugin-list BackLinks page=WikiPlugin limit=10 !>
82 ?>
83 <<WikiFormRich action=AppendText buttontext="AddPlugin"
84 pulldown[] name=s text="Plugins: " value=<!plugin-list BackLinks page=WikiPlugin !>
85 ?>
86 <<WikiFormRich action=AppendText buttontext="AddCategory"
87 pulldown[] name=s text="Categories: " value=<!plugin-list TitleSearch s=Category !>
88 ?>
89 <<WikiFormRich action=SemanticSearch buttontext="AddRelation"
90 combobox[] name=relation text="Relation: " method=listRelations
91 ?>
92 <<WikiFormRich action=AppendText buttontext="InsertTemplate"
93 combobox[] name=s text="Template: " method=titleSearch args="Template/"
94 ?>
95  */
96
97 class WikiPlugin_WikiFormRich
98     extends WikiPlugin
99 {
100     function getName()
101     {
102         return "WikiFormRich";
103     }
104
105     function getDescription()
106     {
107         return _("Provide generic WikiForm input buttons.");
108     }
109
110     function getDefaultArguments()
111     {
112         return array('action' => false, // required argument
113             'method' => 'post', // or get
114             'class' => 'wikiaction',
115             'buttontext' => false, // for the submit button. default: action
116             'cancel' => false, // boolean if the action supports cancel also
117             'nobr' => false, // "no break": linebreaks or not
118         );
119     }
120
121     /* TODO: support better block alignment: <br>, tables, indent
122      */
123     function handle_plugin_args_cruft($argstr, $args)
124     {
125         $allowed = array("editbox", "hidden", "checkbox", "radiobutton" /*deprecated*/,
126             "radio", "pulldown", "submit", "reset", "combobox");
127         // no editbox[] = array(...) allowed (space)
128         $arg_array = preg_split("/\n/", $argstr);
129         // for security we should check this better
130         $arg = '';
131         for ($i = 0; $i < count($arg_array); $i++) {
132             //TODO: we require an name=value pair here, but submit may go without also.
133             if (preg_match("/^\s*(" . join("|", $allowed) . ")\[\](.*)$/", $arg_array[$i], $m)) {
134                 $name = $m[1]; // one of the allowed input types
135                 $this->inputbox[][$name] = array();
136                 $j = count($this->inputbox) - 1;
137                 $curargs = trim($m[2]);
138                 // must match name=NAME and also value=<!plugin-list name !>
139                 while (preg_match("/^(\w+?)=((?:\".*?\")|(?:\w+)|(?:\"?<!plugin-list.+?!>\"?))\s*/",
140                     $curargs, $m)) {
141                     $attr = $m[1];
142                     $value = $m[2];
143                     $curargs = substr($curargs, strlen($m[0]));
144                     if (preg_match("/^\"(.*)\"$/", $value, $m))
145                         $value = $m[1];
146                     if (in_array($name, array("pulldown", "checkbox", "radio", "radiobutton", "combobox"))
147                         and preg_match('/^<!plugin-list.+!>$/', $value, $m)
148                     ) // like pulldown[] name=test value=<!plugin-list BackLinks page=HomePage!>
149                     {
150                         $loader = new WikiPluginLoader();
151                         $markup = null;
152                         $basepage = null;
153                         $plugin_str = preg_replace(array("/^<!/", "/!>$/"), array("<?", "?>"), $value);
154                         // will return a pagelist object! pulldown,checkbox,radiobutton
155                         $value = $loader->expandPI($plugin_str, $GLOBALS['request'], $markup, $basepage);
156                         if (isa($value, 'PageList'))
157                             $value = $value->pageNames(); // apply limit
158                         elseif (!is_array($value))
159                             trigger_error(sprintf("Invalid argument %s ignored", htmlentities($arg_array[$i])),
160                                 E_USER_WARNING);
161                     } elseif (defined($value))
162                         $value = constant($value);
163                     $this->inputbox[$j][$name][$attr] = $value;
164                 }
165                 //trigger_error("not yet finished");
166                 //eval('$this->inputbox[]["'.$m[1].'"]='.$m[2].';');
167             } else {
168                 trigger_error(sprintf("Invalid argument %s ignored", htmlentities($arg_array[$i])),
169                     E_USER_WARNING);
170             }
171         }
172         return;
173     }
174
175     function run($dbi, $argstr, &$request, $basepage)
176     {
177         extract($this->getArgs($argstr, $request));
178         if (empty($action)) {
179             return $this->error(fmt("A required argument ā€œ%sā€ is missing.", "action"));
180         }
181
182         $form = HTML::form(array('action' => $request->getPostURL(),
183                 'method' => strtolower($method),
184                 'class' => 'wikiformrich',
185                 'accept-charset' => $GLOBALS['charset']),
186             HiddenInputs(array('action' => $action)));
187         $nbsp = HTML::Raw('&nbsp;');
188         $already_submit = 0;
189         foreach ($this->inputbox as $inputbox) {
190             foreach ($inputbox as $inputtype => $input) {
191                 if ($inputtype == 'radiobutton') $inputtype = 'radio'; // convert from older versions
192                 $input['type'] = $inputtype;
193                 $text = '';
194                 if ($inputtype != 'submit') {
195                     if (empty($input['name']))
196                         return $this->error(fmt("A required argument ā€œ%sā€ is missing.",
197                             $inputtype . "[][name]"));
198                     if (!isset($input['text'])) $input['text'] = gettext($input['name']);
199                     $text = $input['text'];
200                     unset($input['text']);
201                 }
202                 switch ($inputtype) {
203                     case 'checkbox': // text right
204                     case 'radio':
205                         if (empty($input['value'])) $input['value'] = 1;
206                         if (is_array($input['value'])) {
207                             $div = HTML::div(array('class' => $class));
208                             $values = $input['value'];
209                             $name = $input['name'];
210                             $input['name'] = $inputtype == 'checkbox' ? $name . "[]" : $name;
211                             foreach ($values as $val) {
212                                 $input['value'] = $val;
213                                 if ($request->getArg($name)) {
214                                     if ($request->getArg($name) == $val)
215                                         $input['checked'] = 'checked';
216                                     else
217                                         unset($input['checked']);
218                                 }
219                                 $div->pushContent(HTML::input($input), $nbsp, $val, $nbsp, "\n");
220                                 if (!$nobr)
221                                     $div->pushContent(HTML::br());
222                             }
223                             $form->pushContent($div);
224                         } else {
225                             if (empty($input['checked'])) {
226                                 if ($request->getArg($input['name']))
227                                     $input['checked'] = 'checked';
228                             } else {
229                                 $input['checked'] = 'checked';
230                             }
231                             if ($nobr)
232                                 $form->pushContent(HTML::input($input), $nbsp, $text, $nbsp);
233                             else
234                                 $form->pushContent(HTML::div(array('class' => $class), HTML::input($input), $nbsp, $text));
235                         }
236                         break;
237                     case 'editbox': // text left
238                         $input['type'] = 'text';
239                         if (empty($input['value']) and ($s = $request->getArg($input['name'])))
240                             $input['value'] = $s;
241                         if (!empty($input['autocomplete']))
242                             $this->_doautocomplete($form, $inputtype, $input, $input['value']);
243                         if ($nobr)
244                             $form->pushContent($text, $nbsp, HTML::input($input));
245                         else
246                             $form->pushContent(HTML::div(array('class' => $class), $text, $nbsp, HTML::input($input)));
247                         break;
248                     case 'combobox': // text left
249                         $input['autocomplete'] = 1;
250                     case 'pulldown':
251                         $values = isset($input['value']) ? $input['value'] : '';
252                         unset($input['value']);
253                         unset($input['type']);
254                         if (is_string($values)) $values = explode(",", $values);
255                         if (!empty($input['autocomplete']))
256                             $this->_doautocomplete($form, $inputtype, $input, $values);
257                         $select = HTML::select($input);
258                         if (empty($values) and ($s = $request->getArg($input['name']))) {
259                             $select->pushContent(HTML::option(array('value' => $s), $s));
260                         } elseif (is_array($values)) {
261                             $name = $input['name'];
262                             unset($input['name']);
263                             foreach ($values as $val) {
264                                 $input = array('value' => $val);
265                                 if ($request->getArg($name)) {
266                                     if ($request->getArg($name) == $val)
267                                         $input['selected'] = 'selected';
268                                     else
269                                         unset($input['selected']);
270                                 }
271                                 //TODO: filter uneeded attributes
272                                 $select->pushContent(HTML::option($input, $val));
273                             }
274                         } else { // force empty option
275                             $select->pushContent(HTML::option(array(), ''));
276                         }
277                         $form->pushContent($text, $nbsp, $select);
278                         break;
279                     case 'reset':
280                     case 'hidden':
281                         $form->pushContent(HTML::input($input));
282                         break;
283                     // change the order of inputs, by explicitly placing a submit button here.
284                     case 'submit': // text right (?)
285                         //$input['type'] = 'submit';
286                         if (empty($input['value'])) $input['value'] = $buttontext ? $buttontext : $action;
287                         unset($input['text']);
288                         if (empty($input['class'])) $input['class'] = $class;
289                         if ($nobr)
290                             $form->pushContent(HTML::input($input), $nbsp, $text, $nbsp);
291                         else
292                             $form->pushContent(HTML::div(array('class' => $class), HTML::input($input), $text));
293                         // unset the default submit button
294                         $already_submit = 1;
295                         break;
296                 }
297             }
298         }
299         if ($request->getArg('start_debug'))
300             $form->pushContent(HTML::input
301             (array('name' => 'start_debug',
302                 'value' => $request->getArg('start_debug'),
303                 'type' => 'hidden')));
304         if (!USE_PATH_INFO)
305             $form->pushContent(HiddenInputs(array('pagename' => $basepage)));
306         if (!$already_submit) {
307             if (empty($buttontext)) $buttontext = $action;
308             $submit = Button('submit:', $buttontext, $class);
309             if ($cancel) {
310                 $form->pushContent(HTML::span
311                 (array('class' => $class),
312                     $submit,
313                     Button('submit:cancel', _("Cancel"), $class)));
314             } else {
315                 $form->pushContent(HTML::span(array('class' => $class),
316                     $submit));
317             }
318         }
319         return $form;
320     }
321
322     function _doautocomplete(&$form, $inputtype, &$input, &$values)
323     {
324         global $request;
325         $input['class'] = "dropdown";
326         $input['acdropdown'] = "true";
327         //$input['autocomplete'] = "OFF";
328         $input['autocomplete_complete'] = "true";
329         // only match begin: autocomplete_matchbegin, or
330         $input['autocomplete_matchsubstring'] = "true";
331         if (empty($values)) {
332             if (isset($input['method']) && $input['method']) {
333                 if (empty($input['args'])) {
334                     if (preg_match("/^(.*?) (.*)$/", $input['method'], $m)) {
335                         $input['method'] = $m[1];
336                         $input['args'] = $m[2];
337                     } else
338                         $input['args'] = null;
339                 }
340                 static $tmpArray = 'tmpArray00';
341                 // deferred remote xmlrpc call
342                 if (string_starts_with($input['method'], "dynxmlrpc:")) {
343                     // how is server + method + args encoding parsed by acdropdown?
344                     $input['autocomplete_list'] = substr($input['method'], 3);
345                     if ($input['args'])
346                         $input['autocomplete_list'] .= (" " . $input['args']);
347                     // static xmlrpc call, local only
348                 } elseif (string_starts_with($input['method'], "xmlrpc:")) {
349                     include_once 'lib/XmlRpcClient.php';
350                     $values = wiki_xmlrpc_post(substr($input['method'], 7), $input['args']);
351                 } elseif (string_starts_with($input['method'], "url:")) {
352                     include_once 'lib/HttpClient.php';
353                     $html = HttpClient::quickGet(substr($input['method'], 4));
354                     //TODO: how to parse the HTML result into a list?
355                 } elseif (string_starts_with($input['method'], "dynurl:")) {
356                     $input['autocomplete_list'] = substr($input['method'], 3);
357                 } elseif (string_starts_with($input['method'], "plugin:")) {
358                     $dbi = $request->getDbh();
359                     $pluginName = substr($input['method'], 7);
360                     $basepage = '';
361                     require_once 'lib/WikiPlugin.php';
362                     $w = new WikiPluginLoader;
363                     $p = $w->getPlugin($pluginName, false); // second arg?
364                     if (!is_object($p))
365                         trigger_error("invalid input['method'] " . $input['method'], E_USER_WARNING);
366                     $pagelist = $p->run($dbi, @$input['args'], $request, $basepage);
367                     $values = array();
368                     if (is_object($pagelist) and isa($pagelist, 'PageList')) {
369                         foreach ($pagelist->_pages as $page) {
370                             if (is_object($page))
371                                 $values[] = $page->getName();
372                             else
373                                 $values[] = (string)$page;
374                         }
375                     }
376                 } elseif (string_starts_with($input['method'], "array:")) {
377                     // some predefined values (e.g. in a template or themeinfo.php)
378                     $input['autocomplete_list'] = $input['method'];
379                 } else {
380                     trigger_error("invalid input['method'] " . $input['method'], E_USER_WARNING);
381                 }
382                 if (empty($input['autocomplete_list'])) {
383                     $tmpArray++;
384                     $input['autocomplete_list'] = "array:" . $tmpArray;
385                     $svalues = empty($values) ? "" : join("','", $values);
386                     $form->pushContent(JavaScript("var $tmpArray = new Array('" . $svalues . "')"));
387                 }
388                 if (count($values) == 1)
389                     $input['value'] = $values[0];
390                 else
391                     $input['value'] = "";
392                 unset($input['method']);
393                 unset($input['args']);
394                 //unset($input['autocomplete']);
395             } elseif ($s = $request->getArg($input['name']))
396                 $input['value'] = $s;
397         }
398         return true;
399     }
400 }
401
402 // Local Variables:
403 // mode: php
404 // tab-width: 8
405 // c-basic-offset: 4
406 // c-hanging-comment-ender-p: nil
407 // indent-tabs-mode: nil
408 // End: