4 * Copyright 2004,2006,2007 $ThePhpWikiProgrammingTeam
6 * This file is part of PhpWiki.
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.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with PhpWiki; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * This is another replacement for MagicPhpWikiURL forms.
25 * Previously encoded with the "phpwiki:" syntax.
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=..
35 * - action, submit buttontext, optional cancel button (bool)
36 * - method=get or post, Default: post.
38 * Valid arguments for pulldown and editbox: autocomplete=1, Default: 0
39 * If autocomplete=1, additional arguments method and args may be used.
40 * If no method is given, value will be used to fill in the valid values.
41 * method="xmlrpc:server:name" or "url:http://server/wiki/method" or "array:jsvariable"
42 * or "plugin:pluginname"
43 * args are optional arguments, space seperated, for the method.
44 * A combobox is a pulldown with autocomplete=1.
46 * @Author: Reini Urban
48 * Values which are constants are evaluated.
49 * The cancel button must be supported by the action.
50 * (just some wikiadmin actions so far)
51 * improve layout by: nobr=1
52 * some allow values as list from from <!plugin-list !>
55 <?plugin WikiFormRich action=dumpserial method=get
56 checkbox[] name=include value="all"
57 editbox[] name=directory value=DEFAULT_DUMP_DIR
58 editbox[] name=pages value=*
59 editbox[] name=exclude value="" ?>
60 <?plugin WikiFormRich action=dumphtml method=get
61 editbox[] name=directory value=HTML_DUMP_DIR
62 editbox[] name=pages value="*"
63 editbox[] name=exclude value="" ?>
64 <?plugin WikiFormRich action=loadfile method=get
65 editbox[] name=source value=DEFAULT_WIKI_PGSRC
66 checkbox[] name=overwrite value=1
67 editbox[] name=exclude value="" ?>
68 <?plugin WikiFormRich action=TitleSearch method=get class=wikiadmin nobr=1
69 editbox[] name=s text=""
71 checkbox[] name=case_exact
72 checkbox[] name=regex ?>
73 <?plugin WikiFormRich action=FullTextSearch method=get class=wikiadmin nobr=1
74 editbox[] name=s text=""
76 checkbox[] name=case_exact
77 checkbox[] name=regex ?>
78 <?plugin WikiFormRich action=FuzzyPages method=get class=wikiadmin nobr=1
79 editbox[] name=s text=""
81 checkbox[] name=case_exact ?>
82 <?plugin WikiFormRich action=AppendText buttontext="AddPlugin"
83 radio[] name=s value=<!plugin-list BackLinks page=WikiPlugin limit=10 !>
85 <?plugin WikiFormRich action=AppendText buttontext="AddPlugin"
86 pulldown[] name=s text="Plugins: " value=<!plugin-list BackLinks page=WikiPlugin !>
88 <?plugin WikiFormRich action=AppendText buttontext="AddCategory"
89 pulldown[] name=s text="Categories: " value=<!plugin-list TitleSearch s=Category !>
91 <?plugin WikiFormRich action=SemanticSearch buttontext="AddRelation"
92 combobox[] name=relation text="Relation: " method=listRelations
94 <?plugin WikiFormRich action=AppendText buttontext="InsertTemplate"
95 combobox[] name=s text="Template: " method=titleSearch args="Template/"
99 class WikiPlugin_WikiFormRich
102 function getName () {
103 return "WikiFormRich";
105 function getDescription () {
106 return _("Provide generic WikiForm input buttons");
108 function getVersion() {
109 return preg_replace("/[Revision: $]/", '',
112 function getDefaultArguments() {
113 return array('action' => false, // required argument
114 'method' => 'post', // or get
115 'class' => 'wikiaction',
116 'buttontext' => false, // for the submit button. default: action
117 'cancel' => false, // boolean if the action supports cancel also
118 'nobr' => false, // "no break": linebreaks or not
122 /* TODO: support better block alignment: <br>, tables, indent
124 function handle_plugin_args_cruft($argstr, $args) {
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
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(); $j = count($this->inputbox) - 1;
136 $curargs = trim($m[2]);
137 // must match name=NAME and also value=<!plugin-list name !>
138 while (preg_match("/^(\w+?)=((?:\".*?\")|(?:\w+)|(?:\"?<!plugin-list.+?!>\"?))\s*/",
140 $attr = $m[1]; $value = $m[2];
141 $curargs = substr($curargs, strlen($m[0]));
142 if (preg_match("/^\"(.*)\"$/", $value, $m))
144 if (in_array($name, array("pulldown","checkbox","radio","radiobutton","combobox"))
145 and preg_match('/^<!plugin-list.+!>$/', $value, $m))
146 // like pulldown[] name=test value=<!plugin-list BackLinks page=HomePage!>
148 $loader = new WikiPluginLoader();
151 $plugin_str = preg_replace(array("/^<!/","/!>$/"),array("<?","?>"), $value);
152 // will return a pagelist object! pulldown,checkbox,radiobutton
153 $value = $loader->expandPI($plugin_str, $GLOBALS['request'], $markup, $basepage);
154 if (isa($value, 'PageList'))
155 $value = $value->pageNames(); // apply limit
156 elseif (!is_array($value))
157 trigger_error(sprintf("Invalid argument %s ignored", htmlentities($arg_array[$i])),
160 elseif (defined($value))
161 $value = constant($value);
162 $this->inputbox[$j][$name][$attr] = $value;
164 //trigger_error("not yet finished");
165 //eval('$this->inputbox[]["'.$m[1].'"]='.$m[2].';');
167 trigger_error(sprintf("Invalid argument %s ignored", htmlentities($arg_array[$i])),
174 function run($dbi, $argstr, &$request, $basepage) {
175 extract($this->getArgs($argstr, $request));
176 if (empty($action)) {
177 return $this->error(fmt("A required argument '%s' is missing.", "action"));
179 $form = HTML::form(array('action' => $request->getPostURL(),
180 'method' => strtolower($method),
181 'class' => 'wikiformrich',
182 'accept-charset' => $GLOBALS['charset']),
183 HiddenInputs(array('action' => $action)));
184 $nbsp = HTML::Raw(' ');
186 foreach ($this->inputbox as $inputbox) {
187 foreach ($inputbox as $inputtype => $input) {
188 if ($inputtype == 'radiobutton') $inputtype = 'radio'; // convert from older versions
189 $input['type'] = $inputtype;
191 if ($inputtype != 'submit') {
192 if (empty($input['name']))
193 return $this->error(fmt("A required argument '%s' is missing.",
194 $inputtype."[][name]"));
195 if (!isset($input['text'])) $input['text'] = gettext($input['name']);
196 $text = $input['text'];
197 unset($input['text']);
200 case 'checkbox': // text right
202 if (empty($input['value'])) $input['value'] = 1;
203 if (is_array($input['value'])) {
204 $div = HTML::div(array('class' => $class));
205 $values = $input['value'];
206 $name = $input['name'];
207 $input['name'] = $inputtype == 'checkbox' ? $name."[]" : $name;
208 foreach ($values as $val) {
209 $input['value'] = $val;
210 if ($request->getArg($name)) {
211 if ($request->getArg($name) == $val)
212 $input['checked'] = 'checked';
214 unset($input['checked']);
216 $div->pushContent(HTML::input($input), $nbsp, $val, $nbsp, "\n");
218 $div->pushContent(HTML::br());
220 $form->pushContent($div);
222 if (empty($input['checked'])) {
223 if ($request->getArg($input['name']))
224 $input['checked'] = 'checked';
226 $input['checked'] = 'checked';
229 $form->pushContent(HTML::input($input), $nbsp, $text, $nbsp);
231 $form->pushContent(HTML::div(array('class' => $class), HTML::input($input), $nbsp, $text));
234 case 'editbox': // text left
235 $input['type'] = 'text';
236 if (empty($input['value']) and ($s = $request->getArg($input['name'])))
237 $input['value'] = $s;
238 if (!empty($input['autocomplete']))
239 $this->_doautocomplete($form, $inputtype, $input, $input['value']);
241 $form->pushContent($text, $nbsp, HTML::input($input));
243 $form->pushContent(HTML::div(array('class' => $class), $text, $nbsp, HTML::input($input)));
245 case 'combobox': // text left
246 $input['autocomplete'] = 1;
248 $values = @$input['value'];
249 unset($input['value']);
250 unset($input['type']);
251 if (is_string($values)) $values = explode(",", $values);
252 if (!empty($input['autocomplete']))
253 $this->_doautocomplete($form, $inputtype, $input, $values);
254 $select = HTML::select($input);
255 if (empty($values) and ($s = $request->getArg($input['name']))) {
256 $select->pushContent(HTML::option(array('value'=> $s), $s));
257 } elseif (is_array($values)) {
258 $name = $input['name'];
259 unset($input['name']);
260 foreach ($values as $val) {
261 $input = array('value' => $val);
262 if ($request->getArg($name)) {
263 if ($request->getArg($name) == $val)
264 $input['selected'] = 'selected';
266 unset($input['selected']);
268 //TODO: filter uneeded attributes
269 $select->pushContent(HTML::option($input, $val));
271 } else { // force empty option
272 $select->pushContent(HTML::option(array(), ''));
274 $form->pushContent($text, $nbsp, $select);
278 $form->pushContent(HTML::input($input));
280 // change the order of inputs, by explicitly placing a submit button here.
281 case 'submit': // text right (?)
282 //$input['type'] = 'submit';
283 if (empty($input['value'])) $input['value'] = $buttontext ? $buttontext : $action;
284 unset($input['text']);
285 if (empty($input['class'])) $input['class'] = $class;
287 $form->pushContent(HTML::input($input), $nbsp, $text, $nbsp);
289 $form->pushContent(HTML::div(array('class' => $class), HTML::input($input), $text));
290 // unset the default submit button
296 if ($request->getArg('start_debug'))
297 $form->pushContent(HTML::input
298 (array('name' => 'start_debug',
299 'value' => $request->getArg('start_debug'),
300 'type' => 'hidden')));
302 $form->pushContent(HiddenInputs(array('pagename' => $basepage)));
303 if (!$already_submit) {
304 if (empty($buttontext)) $buttontext = $action;
305 $submit = Button('submit:', $buttontext, $class);
307 $form->pushContent(HTML::span
308 (array('class' => $class),
310 Button('submit:cancel', _("Cancel"), $class)));
312 $form->pushContent(HTML::span(array('class' => $class),
319 function _doautocomplete(&$form, $inputtype, &$input, &$values) {
321 $input['class'] = "dropdown";
322 $input['acdropdown'] = "true";
323 //$input['autocomplete'] = "OFF";
324 $input['autocomplete_complete'] = "true";
325 // only match begin: autocomplete_matchbegin, or
326 $input['autocomplete_matchsubstring'] = "true";
327 if (empty($values)) {
328 if ($input['method']) {
329 if (empty($input['args'])) {
330 if (preg_match("/^(.*?) (.*)$/",$input['method'],$m)) {
331 $input['method'] = $m[1];
332 $input['args'] = $m[2];
334 $input['args'] = null;
336 static $tmpArray = 'tmpArray00';
337 // deferred remote xmlrpc call
338 if (string_starts_with($input['method'], "dynxmlrpc:")) {
339 // how is server + method + args encoding parsed by acdropdown?
340 $input['autocomplete_list'] = substr($input['method'],3);
342 $input['autocomplete_list'] .= (" ".$input['args']);
343 // static xmlrpc call, local only
344 } elseif (string_starts_with($input['method'], "xmlrpc:")) {
345 include_once("lib/XmlRpcClient.php");
346 $values = wiki_xmlrpc_post(substr($input['method'],7), $input['args']);
347 } elseif (string_starts_with($input['method'], "url:")) {
348 include_once("lib/HttpClient.php");
349 $html = HttpClient::quickGet(substr($input['method'],4));
350 //TODO: how to parse the HTML result into a list?
351 } elseif (string_starts_with($input['method'], "dynurl:")) {
352 $input['autocomplete_list'] = substr($input['method'],3);
353 } elseif (string_starts_with($input['method'], "plugin:")) {
354 $dbi = $request->getDbh();
355 $pluginName = substr($input['method'],7);
357 require_once("lib/WikiPlugin.php");
358 $w = new WikiPluginLoader;
359 $p = $w->getPlugin($pluginName, false); // second arg?
361 trigger_error("invalid input['method'] ".$input['method'], E_USER_WARNING);
362 $pagelist = $p->run($dbi, @$input['args'], $request, $basepage);
364 if (is_object($pagelist) and isa($pagelist, 'PageList')) {
365 foreach ($pagelist->_pages as $page) {
366 if (is_object($page))
367 $values[] = $page->getName();
369 $values[] = (string)$page;
372 } elseif (string_starts_with($input['method'], "array:")) {
373 // some predefined values (e.g. in a template or themeinfo.php)
374 $input['autocomplete_list'] = $input['method'];
376 trigger_error("invalid input['method'] ".$input['method'], E_USER_WARNING);
378 if (empty($input['autocomplete_list']))
381 $input['autocomplete_list']="array:".$tmpArray;
382 $svalues = empty($values) ? "" : join("','", $values);
383 $form->pushContent(JavaScript("var $tmpArray = new Array('".$svalues."')"));
385 if (count($values) == 1)
386 $input['value'] = $values[0];
388 $input['value'] = "";
389 unset($input['method']);
390 unset($input['args']);
391 //unset($input['autocomplete']);
393 elseif ($s = $request->getArg($input['name']))
394 $input['value'] = $s;
405 // c-hanging-comment-ender-p: nil
406 // indent-tabs-mode: nil