summaryrefslogtreecommitdiff
path: root/platform/www/lib/plugins/bureaucracy/helper
diff options
context:
space:
mode:
Diffstat (limited to 'platform/www/lib/plugins/bureaucracy/helper')
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/action.php136
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/actionmail.php212
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/actionscript.php62
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php459
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/field.php508
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php63
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fielddate.php42
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldemail.php30
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php114
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldfile.php75
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php47
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php35
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php62
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php119
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php16
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php29
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldradio.php82
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldselect.php61
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php60
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php37
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php89
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php29
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php34
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldtime.php42
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php62
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fielduser.php99
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldusers.php96
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php70
-rw-r--r--platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php98
29 files changed, 2868 insertions, 0 deletions
diff --git a/platform/www/lib/plugins/bureaucracy/helper/action.php b/platform/www/lib/plugins/bureaucracy/helper/action.php
new file mode 100644
index 0000000..5c6dd08
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/action.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Base class for bureaucracy actions.
+ *
+ * All bureaucracy actions have to inherit from this class.
+ *
+ * ATM this class is pretty empty but, in the future it could be used to add
+ * helper functions which can be utilized by the different actions.
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+class helper_plugin_bureaucracy_action extends syntax_plugin_bureaucracy {
+
+ /**
+ * Return false to prevent DokuWiki reusing instances of the plugin
+ *
+ * @return bool
+ */
+ public function isSingleton() {
+ return false;
+ }
+
+ /**
+ * Handle the user input [required]
+ *
+ * This function needs to be implemented to accept the user data collected
+ * from the form. Data has to be grabbed from $_POST['bureaucracy'] using
+ * the indicies in the 'idx' members of the $data items.
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields the list of fields in the form
+ * @param string $thanks the thank you message as defined in the form
+ * or default one. Might be modified by the action
+ * before returned
+ * @param array $argv additional arguments passed to the action
+ * @return bool|string false on error, $thanks on success
+ */
+ public function run($fields, $thanks, $argv){
+ msg('ERROR: called action %s did not implement a run() function');
+ return false;
+ }
+
+ /**
+ * Adds some language related replacement patterns
+ */
+ function prepareLanguagePlaceholder() {
+ global $ID;
+ global $conf;
+
+ $this->patterns['__lang__'] = '/@LANG@/';
+ $this->values['__lang__'] = $conf['lang'];
+
+ $this->patterns['__trans__'] = '/@TRANS@/';
+ $this->values['__trans__'] = '';
+
+ /** @var helper_plugin_translation $trans */
+ $trans = plugin_load('helper', 'translation');
+ if (!$trans) return;
+
+ $this->values['__trans__'] = $trans->getLangPart($ID);
+ $this->values['__lang__'] = $trans->realLC('');
+ }
+
+ /**
+ * Adds replacement pattern for fieldlabels (e.g @@Label@@)
+ *
+ * @param helper_plugin_bureaucracy_field $field
+ */
+ function prepareFieldReplacement($field) {
+ $label = $field->getParam('label');
+
+ if(!is_null($label)) {
+ $this->patterns[$label] = $field->getReplacementPattern();
+ $this->values[$label] = $field->getReplacementValue();
+ }
+ }
+
+ /**
+ * Adds <noinclude></noinclude> to replacement patterns
+ */
+ function prepareNoincludeReplacement() {
+ $this->patterns['__noinclude__'] = '/<noinclude>(.*?)<\/noinclude>/is';
+ $this->values['__noinclude__'] = '';
+ }
+
+ /**
+ * Generate field replacements
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields List of field objects
+ * @return array
+ */
+ function prepareFieldReplacements($fields) {
+ foreach ($fields as $field) {
+ //field replacements
+ $this->prepareFieldReplacement($field);
+ }
+ }
+
+ /**
+ * Returns ACL access level of the user or the (virtual) 'runas' user
+ *
+ * @param string $id pageid
+ * @return int
+ */
+ protected function aclcheck($id) {
+ $runas = $this->getConf('runas');
+
+ if($runas) {
+ $auth = auth_aclcheck($id, $runas, array());
+ } else {
+ $auth = auth_quickaclcheck($id);
+ }
+ return $auth;
+
+ }
+
+ /**
+ * Available methods
+ *
+ * @return array
+ */
+ public function getMethods() {
+ $result = array();
+ $result[] = array(
+ 'name' => 'run',
+ 'desc' => 'Handle the user input',
+ 'params' => array(
+ 'fields' => 'helper_plugin_bureaucracy_field[]',
+ 'thanks' => 'string',
+ 'argv' => 'array'
+ ),
+ 'return' => array('false on error, thanks message on success' => 'bool|string')
+ );
+ return $result;
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/actionmail.php b/platform/www/lib/plugins/bureaucracy/helper/actionmail.php
new file mode 100644
index 0000000..698e6c0
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/actionmail.php
@@ -0,0 +1,212 @@
+<?php
+/**
+ * Action sendemail for DokuWiki plugin bureaucracy
+ */
+
+class helper_plugin_bureaucracy_actionmail extends helper_plugin_bureaucracy_action {
+
+ protected $_mail_html = '';
+ protected $_mail_text = '';
+ protected $subject = '';
+ protected $replyto = array();
+ protected $mailtemplate = '';
+
+ /**
+ * Build a nice email from the submitted data and send it
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields
+ * @param string $thanks
+ * @param array $argv
+ * @return string thanks message
+ * @throws Exception mailing failed
+ */
+ public function run($fields, $thanks, $argv) {
+ global $ID;
+ global $conf;
+
+ $mail = new Mailer();
+
+ $this->prepareNamespacetemplateReplacements();
+ $this->prepareDateTimereplacements();
+ $this->prepareLanguagePlaceholder();
+ $this->prepareNoincludeReplacement();
+ $this->prepareFieldReplacements($fields);
+
+ $evdata = [
+ 'fields' => $fields,
+ 'values' => &$this->values
+ ];
+ $event = new Doku_Event('PLUGIN_BUREAUCRACY_EMAIL_SEND', $evdata);
+ if($event->advise_before()) {
+ //set default subject
+ $this->subject = sprintf($this->getLang('mailsubject'), $ID);
+
+ //build html&text table, collect replyto and subject
+ list($table_html, $table_text) = $this->processFieldsBuildTable($fields, $mail);
+
+ //Body
+ if($this->mailtemplate) {
+ //show template
+ $this->patterns['__tablehtml__'] = '/@TABLEHTML@/';
+ $this->patterns['__tabletext__'] = '/@TABLETEXT@/';
+ $this->values['__tablehtml__'] = $table_html;
+ $this->values['__tabletext__'] = $table_text;
+
+ list($this->_mail_html, $this->_mail_text) = $this->getContent();
+
+ } else {
+ //show simpel listing
+ $this->_mail_html .= sprintf($this->getLang('mailintro')."<br><br>", dformat());
+ $this->_mail_html .= $table_html;
+
+ $this->_mail_text .= sprintf($this->getLang('mailintro')."\n\n", dformat());
+ $this->_mail_text .= $table_text;
+ }
+ $mail->setBody($this->_mail_text,null,null,$this->_mail_html);
+
+ // Reply-to
+ if(!empty($this->replyto)) {
+ $replyto = $mail->cleanAddress($this->replyto);
+ $mail->setHeader('Reply-To', $replyto, false);
+ }
+
+ // To
+ $to = $this->replace(implode(',',$argv)); // get recipient address(es)
+ $to = $mail->cleanAddress($to);
+ $mail->to($to);
+
+ // From
+ $mail->from($conf['mailfrom']);
+
+ // Subject
+ $this->subject = $this->replace($this->subject);
+ $mail->subject($this->subject);
+
+ if(!$mail->send()) {
+ throw new Exception($this->getLang('e_mail'));
+ }
+ }
+ $event->advise_after();
+
+ return '<p>' . $thanks . '</p>';
+ }
+
+ /**
+ * Create html and plain table of the field
+ * and collect values for subject and replyto
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields
+ * @param Mailer $mail
+ * @return array of html and text table
+ */
+ protected function processFieldsBuildTable($fields, $mail) {
+ global $ID;
+
+ $table_html = '<table>';
+ $table_text = '';
+
+ foreach($fields as $field) {
+ $html = $text = '';
+ $value = $field->getParam('value');
+ $label = $field->getParam('label');
+
+ switch($field->getFieldType()) {
+ case 'fieldset':
+ if(!empty($field->depends_on)) {
+ //print fieldset only if depend condition is true
+ foreach($fields as $field_tmp) {
+ if($field_tmp->getParam('label') === $field->depends_on[0] && $field_tmp->getParam('value') === $field->depends_on[1] ) {
+ list($html, $text) = $this->mail_buildRow($label);
+ }
+ }
+ } else {
+ list($html, $text) = $this->mail_buildRow($label);
+ }
+ break;
+ case 'file':
+ if($value === null || $label === null) break; //print attachment only if field was visible
+ $file = $field->getParam('file');
+ if(!$file['size']) {
+ $message = $this->getLang('attachmentMailEmpty');
+ } else if($file['size'] > $this->getConf('maxEmailAttachmentSize')) {
+ $message = $file['name'] . ' ' . $this->getLang('attachmentMailToLarge');
+ msg(sprintf($this->getLang('attachmentMailToLarge_userinfo'), hsc($file['name']), filesize_h($this->getConf('maxEmailAttachmentSize'))), 2);
+ } else {
+ $message = $file['name'];
+ $mail->attachFile($file['tmp_name'], $file['type'], $file['name']);
+ }
+ list($html, $text) = $this->mail_buildRow($label, $message);
+ break;
+ case 'subject':
+ $this->subject = $label;
+ break;
+ case 'usemailtemplate':
+ if (!is_null($field->getParam('template')) ) {
+ $this->mailtemplate = $this->replace($field->getParam('template'));
+ resolve_pageid(getNS($ID), $this->mailtemplate, $ignored);
+ }
+ break;
+
+ default:
+ if($value === null || $label === null) break;
+ if(is_array($value)) $value = implode(', ', $value);
+ list($html, $text) = $this->mail_buildRow($label, $value);
+
+ if(!is_null($field->getParam('replyto'))) {
+ $this->replyto[] = $value;
+ }
+ }
+ $table_html .= $html;
+ $table_text .= $text;
+ }
+ $table_html .= '</table>';
+
+ return array($table_html, $table_text);
+ }
+
+ /**
+ * Build a row
+ *
+ * @param $column1
+ * @param null $column2
+ * @return array of html and text row
+ */
+ protected function mail_buildRow($column1,$column2=null) {
+ if($column2 === null) {
+ $html = '<tr><td colspan="2"><u>'.hsc($column1).'<u></td></tr>';
+ $text = "\n=====".$column1.'=====';
+ } else {
+ $html = '<tr><td><b>'.hsc($column1).'<b></td><td>'.hsc($column2).'</td></tr>';
+ $text = "\n $column1 \t\t $column2";
+ }
+ return array($html, $text);
+ }
+
+ /**
+ * Parse mail template in html and text, and perform replacements
+ *
+ * @return array html and text content
+ */
+ protected function getContent() {
+ $content = rawWiki($this->mailtemplate);
+ $html = '';
+ $text = '';
+
+ if(preg_match_all('#<code\b(.*?)>(.*?)</code>#is', $content, $matches)) {
+ foreach($matches[1] as $index => $codeoptions) {
+ list($syntax,) = explode(' ', trim($codeoptions), 2);
+ if($syntax == 'html') {
+ $html = $matches[2][$index];
+ }
+ if($syntax == 'text' || $syntax == '') {
+ $text = $matches[2][$index];
+ }
+ }
+ }
+ return array(
+ $this->replace($html),
+ $this->replace($text)
+ );
+ }
+}
+// vim:ts=4:sw=4:et:enc=utf-8:
diff --git a/platform/www/lib/plugins/bureaucracy/helper/actionscript.php b/platform/www/lib/plugins/bureaucracy/helper/actionscript.php
new file mode 100644
index 0000000..f308721
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/actionscript.php
@@ -0,0 +1,62 @@
+<?php
+
+class helper_plugin_bureaucracy_actionscript extends helper_plugin_bureaucracy_action {
+
+ protected $scriptNamePattern = '/^[_a-zA-Z0-9]+\.php$/';
+
+ /**
+ * @inheritDoc
+ * @throws \InvalidArgumentException
+ */
+ public function run($fields, $thanks, $argv) {
+ if (count($argv) < 1) {
+ throw new InvalidArgumentException('The "script"-action expects exactly 1 argument: the script name.');
+ }
+
+ $scriptName = $argv[0];
+
+ if (!$this->validateScriptName($scriptName)) {
+ $cleanedScriptName = hsc($scriptName);
+ throw new InvalidArgumentException("The supplied scriptname \"<code>$cleanedScriptName</code>\" is invalid! It must conform to <code>{hsc($this->scriptNamePattern)}</code>!");
+ }
+
+ $path = DOKU_CONF . 'plugin/bureaucracy/' . $scriptName;
+
+ if (!file_exists($path)) {
+ $shortPath = 'conf/plugin/bureaucracy/' . $scriptName;
+ throw new InvalidArgumentException("Script <code>$shortPath</code> doesn't exist!");
+ }
+
+ require $path;
+
+ $classFragment = substr($scriptName, 0, strpos($scriptName, '.'));
+ $className = 'helper_plugin_bureaucracy_handler_' . $classFragment;
+
+ $deprecatedClassName = 'bureaucracy_handler_' . $classFragment;
+ if (!class_exists($className) && class_exists($deprecatedClassName)) {
+ msg("Please change this script's class-name to <code>$className</code>.
+Your current scheme <code>$deprecatedClassName</code> is deprecated and will stop working in the future.", 2);
+ $className = $deprecatedClassName;
+ }
+
+ /** @var dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface $handler */
+ $handler = new $className;
+
+ if (!is_a($handler, dokuwiki\plugin\bureaucracy\interfaces\bureaucracy_handler_interface::class)) {
+ throw new InvalidArgumentException('The handler must implement the interface <code>dokuwiki\\plugin\\bureaucracy\\interfaces\\bureaucracy_handler_interface</code> !');
+ }
+
+ return $handler->handleData($fields, $thanks);
+ }
+
+ /**
+ * @param $scriptName
+ *
+ * @return bool
+ */
+ protected function validateScriptName($scriptName) {
+ $valid = preg_match($this->scriptNamePattern, $scriptName);
+ return $valid === 1;
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php b/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php
new file mode 100644
index 0000000..04714d8
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/actiontemplate.php
@@ -0,0 +1,459 @@
+<?php
+/**
+ * Simple template replacement action for the bureaucracy plugin
+ *
+ * @author Michael Klier <chi@chimeric.de>
+ */
+
+class helper_plugin_bureaucracy_actiontemplate extends helper_plugin_bureaucracy_action {
+
+ var $targetpages;
+ var $pagename;
+
+ /**
+ * Performs template action
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields array with form fields
+ * @param string $thanks thanks message
+ * @param array $argv array with entries: template, pagename, separator
+ * @return array|mixed
+ *
+ * @throws Exception
+ */
+ public function run($fields, $thanks, $argv) {
+ global $conf;
+
+ [$tpl, $this->pagename] = $argv;
+ $sep = $argv[2] ?? $conf['sepchar'];
+
+ $this->patterns = array();
+ $this->values = array();
+ $this->targetpages = array();
+
+ $this->prepareNamespacetemplateReplacements();
+ $this->prepareDateTimereplacements();
+ $this->prepareLanguagePlaceholder();
+ $this->prepareNoincludeReplacement();
+ $this->prepareFieldReplacements($fields);
+
+ $evdata = array(
+ 'patterns' => &$this->patterns,
+ 'values' => &$this->values,
+ 'fields' => $fields,
+ 'action' => $this
+ );
+
+ $event = new Doku_Event('PLUGIN_BUREAUCRACY_PAGENAME', $evdata);
+ if ($event->advise_before()) {
+ $this->buildTargetPagename($fields, $sep);
+ }
+ $event->advise_after();
+
+ //target&template(s) from addpage fields
+ $this->getAdditionalTargetpages($fields);
+ //target&template(s) from action field
+ $tpl = $this->getActionTargetpages($tpl);
+
+ if(empty($this->targetpages)) {
+ throw new Exception(sprintf($this->getLang('e_template'), $tpl));
+ }
+
+ $this->checkTargetPageNames();
+
+ $this->processUploads($fields);
+ $this->replaceAndSavePages($fields);
+
+ $ret = $this->buildThankYouPage($thanks);
+
+ return $ret;
+ }
+
+ /**
+ * Prepare and resolve target page
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields List of field objects
+ * @param string $sep Separator between fields for page id
+ * @throws Exception missing pagename
+ */
+ protected function buildTargetPagename($fields, $sep) {
+ global $ID;
+
+ foreach ($fields as $field) {
+ $pname = $field->getParam('pagename');
+ if (!is_null($pname)) {
+ if (is_array($pname)) $pname = implode($sep, $pname);
+ $this->pagename .= $sep . $pname;
+ }
+ }
+
+ $this->pagename = $this->replace($this->pagename);
+
+ $myns = getNS($ID);
+ resolve_pageid($myns, $this->pagename, $ignored); // resolve relatives
+
+ if ($this->pagename === '') {
+ throw new Exception($this->getLang('e_pagename'));
+ }
+ }
+
+ /**
+ * Handle templates from addpage field
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields List of field objects
+ * @return array
+ */
+ function getAdditionalTargetpages($fields) {
+ global $ID;
+ $ns = getNS($ID);
+
+ foreach ($fields as $field) {
+ if (!is_null($field->getParam('page_tpl')) && !is_null($field->getParam('page_tgt')) ) {
+ //template
+ $templatepage = $this->replace($field->getParam('page_tpl'));
+ resolve_pageid(getNS($ID), $templatepage, $ignored);
+
+ //target
+ $relativetargetpage = $field->getParam('page_tgt');
+ resolve_pageid($ns, $relativeTargetPageid, $ignored);
+ $targetpage = "$this->pagename:$relativetargetpage";
+
+ $auth = $this->aclcheck($templatepage); // runas
+ if ($auth >= AUTH_READ ) {
+ $this->addParsedTargetpage($targetpage, $templatepage);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns raw pagetemplate contents for the ID's namespace
+ *
+ * @param string $id the id of the page to be created
+ * @return string raw pagetemplate content
+ */
+ protected function rawPageTemplate($id) {
+ global $conf;
+
+ $path = dirname(wikiFN($id));
+ if(file_exists($path.'/_template.txt')) {
+ $tplfile = $path.'/_template.txt';
+ } else {
+ // search upper namespaces for templates
+ $len = strlen(rtrim($conf['datadir'], '/'));
+ while(strlen($path) >= $len) {
+ if(file_exists($path.'/__template.txt')) {
+ $tplfile = $path.'/__template.txt';
+ break;
+ }
+ $path = substr($path, 0, strrpos($path, '/'));
+ }
+ }
+
+ $tpl = io_readFile($tplfile);
+ return $tpl;
+ }
+
+ /**
+ * Load template(s) for targetpage as given via action field
+ *
+ * @param string $tpl template name as given in form
+ * @return string parsed templatename
+ */
+ protected function getActionTargetpages($tpl) {
+ global $USERINFO;
+ global $conf;
+ global $ID;
+ $runas = $this->getConf('runas');
+
+ if ($tpl == '_') {
+ // use namespace template
+ if (!isset($this->targetpages[$this->pagename])) {
+ $raw = $this->rawPageTemplate($this->pagename);
+ $this->noreplace_save($raw);
+ $this->targetpages[$this->pagename] = pageTemplate(array($this->pagename));
+ }
+ } elseif ($tpl !== '!') {
+ $tpl = $this->replace($tpl);
+
+ // resolve templates, but keep references to whole namespaces intact (ending in a colon)
+ if(substr($tpl, -1) == ':') {
+ $tpl = $tpl.'xxx'; // append a fake page name
+ resolve_pageid(getNS($ID), $tpl, $ignored);
+ $tpl = substr($tpl, 0, -3); // cut off fake page name again
+ } else {
+ resolve_pageid(getNS($ID), $tpl, $ignored);
+ }
+
+ $backup = array();
+ if ($runas) {
+ // Hack user credentials.
+ $backup = array($_SERVER['REMOTE_USER'], $USERINFO['grps']);
+ $_SERVER['REMOTE_USER'] = $runas;
+ $USERINFO['grps'] = array();
+ }
+
+ $template_pages = array();
+ //search checks acl (as runas)
+ $opts = array(
+ 'depth' => 0,
+ 'listfiles' => true,
+ 'showhidden' => true
+ );
+ search($template_pages, $conf['datadir'], 'search_universal', $opts, str_replace(':', '/', getNS($tpl)));
+
+ foreach ($template_pages as $template_page) {
+ $templatepageid = cleanID($template_page['id']);
+ // try to replace $tpl path with $this->pagename path in the founded $templatepageid
+ // - a single-page template will only match on itself and will be replaced,
+ // other newtargets are pages in same namespace, so aren't changed
+ // - a namespace as template will match at the namespaces-part of the path of pages in this namespace
+ // so these newtargets are changed
+ // if there exist a single-page and a namespace with name $tpl, both are selected
+ $newTargetpageid = preg_replace('/^' . preg_quote_cb(cleanID($tpl)) . '($|:)/', $this->pagename . '$1', $templatepageid);
+
+ if ($newTargetpageid === $templatepageid) {
+ // only a single-page template or page in the namespace template
+ // which matches the $tpl path are changed
+ continue;
+ }
+
+ if (!isset($this->targetpages[$newTargetpageid])) {
+ $this->addParsedTargetpage($newTargetpageid, $templatepageid);
+ }
+ }
+
+ if ($runas) {
+ /* Restore user credentials. */
+ list($_SERVER['REMOTE_USER'], $USERINFO['grps']) = $backup;
+ }
+ }
+ return $tpl;
+ }
+
+ /**
+ * Checks for existance and access of target pages
+ *
+ * @return mixed
+ * @throws Exception
+ */
+ protected function checkTargetPageNames() {
+ foreach (array_keys($this->targetpages) as $pname) {
+ // prevent overriding already existing pages
+ if (page_exists($pname)) {
+ throw new Exception(sprintf($this->getLang('e_pageexists'), html_wikilink($pname)));
+ }
+
+ $auth = $this->aclcheck($pname);
+ if ($auth < AUTH_CREATE) {
+ throw new Exception($this->getLang('e_denied'));
+ }
+ }
+ }
+
+ /**
+ * Perform replacements on the collected templates, and save the pages.
+ *
+ * Note: wrt runas, for changelog are used:
+ * - $INFO['userinfo']['name']
+ * - $INPUT->server->str('REMOTE_USER')
+ */
+ protected function replaceAndSavePages($fields) {
+ global $ID;
+ foreach ($this->targetpages as $pageName => $template) {
+ // set NSBASE var to make certain dataplugin constructs easier
+ $this->patterns['__nsbase__'] = '/@NSBASE@/';
+ $this->values['__nsbase__'] = noNS(getNS($pageName));
+
+ $evdata = array(
+ 'patterns' => &$this->patterns,
+ 'values' => &$this->values,
+ 'id' => $pageName,
+ 'template' => $template,
+ 'form' => $ID,
+ 'fields' => $fields
+ );
+
+ $event = new Doku_Event('PLUGIN_BUREAUCRACY_TEMPLATE_SAVE', $evdata);
+ if($event->advise_before()) {
+ // save page
+ saveWikiText(
+ $evdata['id'],
+ cleanText($this->replace($evdata['template'], false)),
+ sprintf($this->getLang('summary'), $ID)
+ );
+ }
+ $event->advise_after();
+ }
+ }
+
+ /**
+ * (Callback) Sorts first by namespace depth, next by page ids
+ *
+ * @param string $a
+ * @param string $b
+ * @return int positive if $b is in deeper namespace than $a, negative higher.
+ * further sorted by pageids
+ *
+ * return an integer less than, equal to, or
+ * greater than zero if the first argument is considered to be
+ * respectively less than, equal to, or greater than the second.
+ */
+ public function _sorttargetpages($a, $b) {
+ $ns_diff = substr_count($a, ':') - substr_count($b, ':');
+ return ($ns_diff === 0) ? strcmp($a, $b) : ($ns_diff > 0 ? -1 : 1);
+ }
+
+ /**
+ * (Callback) Build content of item
+ *
+ * @param array $item
+ * @return string
+ */
+ public function html_list_index($item){
+ $ret = '';
+ if($item['type']=='f'){
+ $ret .= html_wikilink(':'.$item['id']);
+ } else {
+ $ret .= '<strong>' . trim(substr($item['id'], strrpos($item['id'], ':', -2)), ':') . '</strong>';
+ }
+ return $ret;
+ }
+
+ /**
+ * Build thanks message, trigger indexing and rendering of new pages.
+ *
+ * @param string $thanks
+ * @return string html of thanks message or when redirect the first page id of created pages
+ */
+ protected function buildThankYouPage($thanks) {
+ global $ID;
+ $backupID = $ID;
+
+ $html = "<p>$thanks</p>";
+
+ // Build result tree
+ $pages = array_keys($this->targetpages);
+ usort($pages, array($this, '_sorttargetpages'));
+
+ $data = array();
+ $last_folder = array();
+ foreach ($pages as $ID) {
+ $lvl = substr_count($ID, ':');
+ for ($n = 0; $n < $lvl; ++$n) {
+ if (!isset($last_folder[$n]) || strpos($ID, $last_folder[$n]['id']) !== 0) {
+ $last_folder[$n] = array(
+ 'id' => substr($ID, 0, strpos($ID, ':', ($n > 0 ? strlen($last_folder[$n - 1]['id']) : 0) + 1) + 1),
+ 'level' => $n + 1,
+ 'open' => 1
+ );
+ $data[] = $last_folder[$n];
+ }
+ }
+ $data[] = array('id' => $ID, 'level' => 1 + substr_count($ID, ':'), 'type' => 'f');
+ }
+ $html .= html_buildlist($data, 'idx', array($this, 'html_list_index'), 'html_li_index');
+
+ // Add indexer bugs for every just-created page
+ $html .= '<div class="no">';
+ ob_start();
+ foreach ($pages as $ID) {
+ // indexerWebBug uses ID and INFO[exists], but the bureaucracy form
+ // page always exists, as does the just-saved page, so INFO[exists]
+ // is correct in any case
+ tpl_indexerWebBug();
+
+ // the iframe will trigger real rendering of the pages to make sure
+ // any used plugins are initialized (eg. the do plugin)
+ echo '<iframe src="' . wl($ID, array('do' => 'export_html')) . '" width="1" height="1" style="visibility:hidden"></iframe>';
+ }
+ $html .= ob_get_contents();
+ ob_end_clean();
+ $html .= '</div>';
+
+ $ID = $backupID;
+ return $html;
+ }
+
+ /**
+ * move the uploaded files to <pagename>:FILENAME
+ *
+ *
+ * @param helper_plugin_bureaucracy_field[] $fields
+ * @throws Exception
+ */
+ protected function processUploads($fields) {
+ foreach($fields as $field) {
+
+ if($field->getFieldType() !== 'file') continue;
+
+ $label = $field->getParam('label');
+ $file = $field->getParam('file');
+ $ns = $field->getParam('namespace');
+
+ //skip empty files
+ if(!$file['size']) {
+ $this->values[$label] = '';
+ continue;
+ }
+
+ $id = $ns.':'.$file['name'];
+ resolve_mediaid($this->pagename, $id, $ignored); // resolve relatives
+
+ $auth = $this->aclcheck($id); // runas
+ $move = 'copy_uploaded_file';
+ //prevent from is_uploaded_file() check
+ if(defined('DOKU_UNITTEST')) {
+ $move = 'copy';
+ }
+ $res = media_save(
+ array('name' => $file['tmp_name']),
+ $id,
+ false,
+ $auth,
+ $move);
+
+ if(is_array($res)) throw new Exception($res[0]);
+
+ $this->values[$label] = $res;
+
+ }
+ }
+
+ /**
+ * Load page data and do default pattern replacements like namespace templates do
+ * and add it to list of targetpages
+ *
+ * Note: for runas the values of the real user are used for the placeholders
+ * @NAME@ => $USERINFO['name']
+ * @MAIL@ => $USERINFO['mail']
+ * and the replaced value:
+ * @USER@ => $INPUT->server->str('REMOTE_USER')
+ *
+ * @param string $targetpageid pageid of destination
+ * @param string $templatepageid pageid of template for this targetpage
+ */
+ protected function addParsedTargetpage($targetpageid, $templatepageid) {
+ $tpl = rawWiki($templatepageid);
+ $this->noreplace_save($tpl);
+
+ $data = array(
+ 'id' => $targetpageid,
+ 'tpl' => $tpl,
+ 'doreplace' => true,
+ );
+ parsePageTemplate($data);
+
+ //collect and apply some other replacements
+ $patterns = array();
+ $values = array();
+ $keys = array('__lang__', '__trans__', '__year__', '__month__', '__day__', '__time__');
+ foreach($keys as $key) {
+ $patterns[$key] = $this->patterns[$key];
+ $values[$key] = $this->values[$key];
+ }
+
+ $this->targetpages[$targetpageid] = preg_replace($patterns, $values, $data['tpl']);
+ }
+
+}
+// vim:ts=4:sw=4:et:enc=utf-8:
diff --git a/platform/www/lib/plugins/bureaucracy/helper/field.php b/platform/www/lib/plugins/bureaucracy/helper/field.php
new file mode 100644
index 0000000..070e331
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/field.php
@@ -0,0 +1,508 @@
+<?php
+
+/**
+ * Base class for form fields
+ *
+ * This class provides basic functionality for many form fields. It supports
+ * labels, basic validation and template-based XHTML output.
+ *
+ * @author Adrian Lang <lang@cosmocode.de>
+ **/
+
+/**
+ * Class helper_plugin_bureaucracy_field
+ *
+ * base class for all the form fields
+ */
+class helper_plugin_bureaucracy_field extends syntax_plugin_bureaucracy {
+
+ protected $mandatory_args = 2;
+ public $opt = array();
+ /** @var string|array */
+ protected $tpl;
+ protected $checks = array();
+ public $hidden = false;
+ protected $error = false;
+ protected $checktypes = array(
+ '/' => 'match',
+ '<' => 'max',
+ '>' => 'min'
+ );
+
+ /**
+ * Construct a helper_plugin_bureaucracy_field object
+ *
+ * This constructor initializes a helper_plugin_bureaucracy_field object
+ * based on a given definition.
+ *
+ * The first two items represent:
+ * * the type of the field
+ * * and the label the field has been given.
+ * Additional arguments are type-specific mandatory extra arguments and optional arguments.
+ *
+ * The optional arguments may add constraints to the field value, provide a
+ * default value, mark the field as optional or define that the field is
+ * part of a pagename (when using the template action).
+ *
+ * Since the field objects are cached, this constructor may not reference
+ * request data.
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $this->init($args);
+ $this->standardArgs($args);
+ }
+
+ /**
+ * Return false to prevent DokuWiki reusing instances of the plugin
+ *
+ * @return bool
+ */
+ public function isSingleton() {
+ return false;
+ }
+
+ /**
+ * Checks number of arguments and store 'cmd', 'label' and 'display' values
+ *
+ * @param array $args array with the definition
+ */
+ protected function init(&$args) {
+ if(count($args) < $this->mandatory_args){
+ msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]),
+ hsc($args[1])), -1);
+ return;
+ }
+
+ // get standard arguments
+ $this->opt = array();
+ foreach (array('cmd', 'label') as $key) {
+ if (count($args) === 0) break;
+ $this->opt[$key] = array_shift($args);
+ }
+ $this->opt['display'] = $this->opt['label']; // allow to modify display value independently
+ }
+
+ /**
+ * Check for additional arguments and store their values
+ *
+ * @param array $args array with remaining definition arguments
+ */
+ protected function standardArgs($args) {
+ // parse additional arguments
+ foreach($args as $arg){
+ if ($arg[0] == '=') {
+ $this->setVal(substr($arg,1));
+ } elseif ($arg == '!') {
+ $this->opt['optional'] = true;
+ } elseif ($arg == '^') {
+ //only one field has focus
+ if (helper_plugin_bureaucracy_field::hasFocus()) {
+ $this->opt['id'] = 'focus__this';
+ }
+ } elseif($arg == '@') {
+ $this->opt['pagename'] = true;
+ } elseif($arg == '@@') {
+ $this->opt['replyto'] = true;
+ } elseif(preg_match('/x\d/', $arg)) {
+ $this->opt['rows'] = substr($arg,1);
+ } elseif($arg[0] == '.') {
+ $this->opt['class'] = substr($arg, 1);
+ } elseif(preg_match('/^0{2,}$/', $arg)) {
+ $this->opt['leadingzeros'] = strlen($arg);
+ } elseif($arg[0].$arg[1] == '**') {
+ $this->opt['matchexplanation'] = substr($arg,2);
+ } else {
+ $t = $arg[0];
+ $d = substr($arg,1);
+ if (in_array($t, array('>', '<')) && !is_numeric($d)) {
+ break;
+ }
+ if ($t == '/') {
+ if (substr($d, -1) !== '/') {
+ break;
+ }
+ $d = substr($d, 0, -1);
+ }
+ if (!isset($this->checktypes[$t]) || !method_exists($this, 'validate_' . $this->checktypes[$t])) {
+ msg(sprintf($this->getLang('e_unknownconstraint'), hsc($t).' ('.hsc($arg).')'), -1);
+ return;
+ }
+ $this->checks[] = array('t' => $t, 'd' => $d);
+ }
+ }
+ }
+
+ /**
+ * Add parsed element to Form which generates XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ * Additional parameters (CSS class & HTML name) are passed in $params.
+ * HTML output is created by passing the template $this->tpl to the simple
+ * template engine _parse_tpl.
+ *
+ * @param array $params Additional HTML specific parameters
+ * @param Doku_Form $form The target Doku_Form object
+ * @param int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ if(!$form->_infieldset){
+ $form->startFieldset('');
+ }
+ if ($this->error) {
+ $params['class'] = 'bureaucracy_error';
+ }
+
+ $params = array_merge($this->opt, $params);
+ $form->addElement($this->_parse_tpl($this->tpl, $params));
+ }
+
+ /**
+ * Only the first use get the focus, next calls not
+ *
+ * @return bool
+ */
+ protected static function hasFocus(){
+ static $focus = true;
+ if($focus) {
+ $focus = false;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Check for preload value in the request url
+ */
+ protected function _handlePreload() {
+ $preload_name = '@' . strtr($this->getParam('label'),' .','__') . '@';
+ if (isset($_GET[$preload_name])) {
+ $this->setVal($_GET[$preload_name]);
+ }
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * Accepts and validates a posted value.
+ *
+ * (Overridden by fieldset, which has as argument an array with the form array by reference)
+ *
+ * @param string $value The passed value or array or null if none given
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ return $this->hidden || $this->setVal($value);
+ }
+
+ /**
+ * Get the field type
+ *
+ * @return string
+ **/
+ public function getFieldType() {
+ return $this->opt['cmd'];
+ }
+
+ /**
+ * Get the replacement pattern used by action
+ *
+ * @return string
+ */
+ public function getReplacementPattern() {
+ $label = $this->getParam('label');
+ $value = $this->getParam('value');
+
+ if (is_array($value)) {
+ return '/(@@|##)' . preg_quote($label, '/') .
+ '(?:\((?P<delimiter>.*?)\))?' .//delimiter
+ '(?:\|(?P<default>.*?))' . (count($value) == 0 ? '' : '?') .
+ '\1/si';
+ }
+
+ return '/(@@|##)' . preg_quote($label, '/') .
+ '(?:\|(.*?))' . (is_null($value) ? '' : '?') .
+ '\1/si';
+ }
+
+ /**
+ * Used as an callback for preg_replace_callback
+ *
+ * @param $matches
+ * @return string
+ */
+ public function replacementMultiValueCallback($matches) {
+ $value = $this->opt['value'];
+
+ //default value
+ if (is_null($value) || $value === false) {
+ if (isset($matches['default']) && $matches['default'] != '') {
+ return $matches['default'];
+ }
+ return $matches[0];
+ }
+
+ //check if matched string containts a pair of brackets
+ $delimiter = preg_match('/\(.*\)/s', $matches[0]) ? $matches['delimiter'] : ', ';
+
+ return implode($delimiter, $value);
+ }
+
+ /**
+ * Get the value used by action
+ * If value is a callback preg_replace_callback is called instead preg_replace
+ *
+ * @return mixed|string
+ */
+ public function getReplacementValue() {
+ $value = $this->getParam('value');
+
+ if (is_array($value)) {
+ return array($this, 'replacementMultiValueCallback');
+ }
+
+ return is_null($value) || $value === false ? '$2' : $value;
+ }
+
+ /**
+ * Validate value and stores it
+ *
+ * @param mixed $value value entered into field
+ * @return bool whether the passed value is valid
+ */
+ protected function setVal($value) {
+ if ($value === '') {
+ $value = null;
+ }
+ $this->opt['value'] = $value;
+ try {
+ $this->_validate();
+ $this->error = false;
+ } catch (Exception $e) {
+ msg($e->getMessage(), -1);
+ $this->error = true;
+ }
+ return !$this->error;
+ }
+
+ /**
+ * Whether the field is true (used for depending fieldsets)
+ *
+ * @return bool whether field is set
+ */
+ public function isSet_() {
+ return !is_null($this->getParam('value'));
+ }
+
+ /**
+ * Validate value of field and throws exceptions for bad values.
+ *
+ * @throws Exception when field didn't validate.
+ */
+ protected function _validate() {
+ $value = $this->getParam('value');
+ if (is_null($value)) {
+ if(!isset($this->opt['optional'])) {
+ throw new Exception(sprintf($this->getLang('e_required'),hsc($this->opt['label'])));
+ }
+ return;
+ }
+
+ foreach ($this->checks as $check) {
+ $checktype = $this->checktypes[$check['t']];
+ if (!call_user_func(array($this, 'validate_' . $checktype), $check['d'], $value)) {
+ //replacement is custom explanation or just the regexp or the requested value
+ if(isset($this->opt['matchexplanation'])) {
+ $replacement = hsc($this->opt['matchexplanation']);
+ } elseif($checktype == 'match') {
+ $replacement = sprintf($this->getLang('checkagainst'), hsc($check['d']));
+ } else {
+ $replacement = hsc($check['d']);
+ }
+
+ throw new Exception(sprintf($this->getLang('e_' . $checktype), hsc($this->opt['label']), $replacement));
+ }
+ }
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ public function getParam($name) {
+ if (!isset($this->opt[$name]) || $name === 'value' && $this->hidden) {
+ return null;
+ }
+ if ($name === 'pagename') {
+ // If $this->opt['pagename'] is set, return the escaped value of the field.
+ $value = $this->getParam('value');
+ if (is_null($value)) {
+ return null;
+ }
+ global $conf;
+ if($conf['useslash']) $value = str_replace('/',' ',$value);
+ return str_replace(':',' ',$value);
+ }
+ return $this->opt[$name];
+ }
+
+ /**
+ * Parse a template with given parameters
+ *
+ * Replaces variables specified like @@VARNAME|default@@ using the passed
+ * value map.
+ *
+ * @param string|array $tpl The template as string or array
+ * @param array $params A hash mapping parameters to values
+ *
+ * @return string|array The parsed template
+ */
+ protected function _parse_tpl($tpl, $params) {
+ // addElement supports a special array format as well. In this case
+ // not all elements should be escaped.
+ $is_simple = !is_array($tpl);
+ if ($is_simple) $tpl = array($tpl);
+
+ foreach ($tpl as &$val) {
+ // Select box passes options as an array. We do not escape those.
+ if (is_array($val)) continue;
+
+ // find all variables and their defaults or param values
+ preg_match_all('/@@([A-Z]+)(?:\|((?:[^@]|@$|@[^@])*))?@@/', $val, $pregs);
+ for ($i = 0 ; $i < count($pregs[2]) ; ++$i) {
+ if (isset($params[strtolower($pregs[1][$i])])) {
+ $pregs[2][$i] = $params[strtolower($pregs[1][$i])];
+ }
+ }
+ // we now have placeholders in $pregs[0] and their values in $pregs[2]
+ $replacements = array(); // check if empty to prevent php 5.3 warning
+ if (!empty($pregs[0])) {
+ $replacements = array_combine($pregs[0], $pregs[2]);
+ }
+
+ if($is_simple){
+ // for simple string templates, we escape all replacements
+ $replacements = array_map('hsc', $replacements);
+ }else{
+ // for the array ones, we escape the label and display only
+ if(isset($replacements['@@LABEL@@'])) $replacements['@@LABEL@@'] = hsc($replacements['@@LABEL@@']);
+ if(isset($replacements['@@DISPLAY@@'])) $replacements['@@DISPLAY@@'] = hsc($replacements['@@DISPLAY@@']);
+ }
+
+ // we attach a mandatory marker to the display
+ if(isset($replacements['@@DISPLAY@@']) && !isset($params['optional'])){
+ $replacements['@@DISPLAY@@'] .= ' <sup>*</sup>';
+ }
+ $val = str_replace(array_keys($replacements), array_values($replacements), $val);
+ }
+ return $is_simple ? $tpl[0] : $tpl;
+ }
+
+ /**
+ * Executed after performing the action hooks
+ */
+ public function after_action() {
+ }
+
+ /**
+ * Constraint function: value of field should match this regexp
+ *
+ * @param string $d regexp
+ * @param mixed $value
+ * @return int|bool
+ */
+ protected function validate_match($d, $value) {
+ return @preg_match('/' . $d . '/i', $value);
+ }
+
+ /**
+ * Constraint function: value of field should be bigger
+ *
+ * @param int|number $d lower bound
+ * @param mixed $value of field
+ * @return bool
+ */
+ protected function validate_min($d, $value) {
+ return $value > $d;
+ }
+
+ /**
+ * Constraint function: value of field should be smaller
+ *
+ * @param int|number $d upper bound
+ * @param mixed $value of field
+ * @return bool
+ */
+ protected function validate_max($d, $value) {
+ return $value < $d;
+ }
+
+ /**
+ * Available methods
+ *
+ * @return array
+ */
+ public function getMethods() {
+ $result = array();
+ $result[] = array(
+ 'name' => 'initialize',
+ 'desc' => 'Initiate object, first parameters are at least cmd and label',
+ 'params' => array(
+ 'params' => 'array'
+ )
+ );
+ $result[] = array(
+ 'name' => 'renderfield',
+ 'desc' => 'Add parsed element to Form which generates XHTML',
+ 'params' => array(
+ 'params' => 'array',
+ 'form' => 'Doku_Form',
+ 'formid' => 'integer'
+ )
+ );
+ $result[] = array(
+ 'name' => 'handle_post',
+ 'desc' => 'Handle a post to the field',
+ 'params' => array(
+ 'value' => 'array',
+ 'fields' => 'helper_plugin_bureaucracy_field[]',
+ 'index' => 'Doku_Form',
+ 'formid' => 'integer'
+ ),
+ 'return' => array('isvalid' => 'bool')
+ );
+ $result[] = array(
+ 'name' => 'getFieldType',
+ 'desc' => 'Get the field type',
+ 'return' => array('fieldtype' => 'string')
+ );
+ $result[] = array(
+ 'name' => 'isSet_',
+ 'desc' => 'Whether the field is true (used for depending fieldsets) ',
+ 'return' => array('isset' => 'bool')
+ );
+ $result[] = array(
+ 'name' => 'getParam',
+ 'desc' => 'Get an arbitrary parameter',
+ 'params' => array(
+ 'name' => 'string'
+ ),
+ 'return' => array('Parameter value' => 'mixed|null')
+ );
+ $result[] = array(
+ 'name' => 'after_action',
+ 'desc' => 'Executed after performing the action hooks'
+ );
+ return $result;
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php b/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php
new file mode 100644
index 0000000..0c024fd
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldaddpage.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldaddpage
+ *
+ * Adds another page page_tgt based on a template page page_tpl only for use with the template action
+ */
+class helper_plugin_bureaucracy_fieldaddpage extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - page_tpl
+ * - page_tgt
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ if(count($args) < 3){
+ msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]),
+ hsc($args[1])), -1);
+ return;
+ }
+
+ // get standard arguments
+ $this->opt = array_combine(array('cmd', 'page_tpl', 'page_tgt'), $args);
+ }
+
+ /**
+ * Nothing displayed
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ function renderfield($params, Doku_Form $form, $formid) {
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * @param string $value null
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ function handle_post($value, &$fields, $index, $formid) {
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ function getParam($name) {
+ return ($name === 'value' ||
+ (in_array($name, array('page_tpl', 'page_tgt')) && $this->hidden)) ?
+ null :
+ parent::getParam($name);
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fielddate.php b/platform/www/lib/plugins/bureaucracy/helper/fielddate.php
new file mode 100644
index 0000000..6feae1c
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fielddate.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fielddate
+ *
+ * A date in the format YYYY-MM-DD, provides a date picker
+ */
+class helper_plugin_bureaucracy_fielddate extends helper_plugin_bureaucracy_fieldtextbox {
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ $attr = array(
+ 'class' => 'datepicker edit',
+ 'maxlength'=>'10'
+ );
+ if(!isset($this->opt['optional'])) {
+ $attr['required'] = 'required';
+ $attr['class'] .= ' required';
+ }
+ $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr);
+ }
+
+ /**
+ * Validate field input
+ *
+ * @throws Exception when empty or wrong date format
+ */
+ protected function _validate() {
+ parent::_validate();
+
+ $value = $this->getParam('value');
+ if (!is_null($value) && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
+ throw new Exception(sprintf($this->getLang('e_date'),hsc($this->getParam('display'))));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php b/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php
new file mode 100644
index 0000000..7857bd7
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldemail.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldemail
+ *
+ * Creates a single line input field where the input is validated to be a valid email address
+ */
+class helper_plugin_bureaucracy_fieldemail extends helper_plugin_bureaucracy_fieldtextbox {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - @@ (optional)
+ * - ^ (optional)
+ */
+
+ /**
+ * Validate field value
+ *
+ * @throws Exception when empty or not valid email address
+ */
+ function _validate() {
+ parent::_validate();
+
+ $value = $this->getParam('value');
+ if(!is_null($value) && $value !== '@MAIL@' && !mail_isvalid($value)){
+ throw new Exception(sprintf($this->getLang('e_email'),hsc($this->getParam('display'))));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php b/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php
new file mode 100644
index 0000000..ddce2b6
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldfieldset.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldfieldset
+ *
+ * Creates a new set of fields, which optional can be shown/hidden depending on the value of another field above it.
+ */
+class helper_plugin_bureaucracy_fieldfieldset extends helper_plugin_bureaucracy_field {
+ protected $mandatory_args = 1;
+ /** @var array with zero, one entry (fieldname) or two entries (fieldname and match value) */
+ public $depends_on = array();
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label (optional)
+ * - field name where switching depends on (optional)
+ * - match value (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ // get standard arguments
+ $this->opt = array('cmd' => array_shift($args));
+
+ if (count($args) > 0) {
+ $this->opt['label'] = array_shift($args);
+ $this->opt['display'] = $this->opt['label'];
+
+ $this->depends_on = $args;
+ }
+ }
+
+ /**
+ * Render the top of the fieldset as XHTML
+ *
+ * @param array $params Additional HTML specific parameters
+ * @param Doku_Form $form The target Doku_Form object
+ * @param int $formid unique identifier of the form which contains this field
+ */
+ function renderfield($params, Doku_Form $form, $formid) {
+ $form->startFieldset(hsc($this->getParam('display')));
+ if (!empty($this->depends_on)) {
+ $dependencies = array_map('hsc',(array) $this->depends_on);
+ if (count($this->depends_on) > 1) {
+ $msg = 'Only edit this fieldset if ' .
+ '“<span class="bureaucracy_depends_fname">%s</span>” '.
+ 'is set to “<span class="bureaucracy_depends_fvalue">%s</span>”.';
+ } else {
+ $msg = 'Only edit this fieldset if ' .
+ '“<span class="bureaucracy_depends_fname">%s</span>” is set.';
+ }
+
+ $form->addElement('<p class="bureaucracy_depends">' . vsprintf($msg, $dependencies) . '</p>');
+ }
+ }
+
+ /**
+ * Handle a post to the fieldset
+ *
+ * When fieldset is closed, set containing fields to hidden
+ *
+ * @param null $value field value of fieldset always empty
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ if(empty($this->depends_on)) {
+ return true;
+ }
+
+ // search the field where fieldset depends on in fields before fieldset
+ $hidden = false;
+ for ($n = 0 ; $n < $index; ++$n) {
+ $field = $fields[$n];
+ if ($field->getParam('label') != $this->depends_on[0]) {
+ continue;
+ }
+ if(count($this->depends_on) > 1) {
+ $hidden = $field->getParam('value') != $this->depends_on[1];
+ } else {
+ $hidden = !$field->isSet_();
+ }
+ break;
+ }
+ // mark fields after this fieldset as hidden
+ if ($hidden) {
+ $this->hidden = true;
+ for ($n = $index + 1 ; $n < count($fields) ; ++$n) {
+ $field = $fields[$n];
+ if ($field->getFieldType() === 'fieldset') {
+ break;
+ }
+ $field->hidden = true;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ function getParam($name) {
+ if($name === 'value') {
+ return null;
+ } else {
+ return parent::getParam($name);
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php b/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php
new file mode 100644
index 0000000..285308e
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldfile.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * File upload field
+ */
+class helper_plugin_bureaucracy_fieldfile extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ $this->init($args);
+
+ //default namespace for file upload (pagepath:file_name)
+ $this->opt['namespace'] = '.';
+
+ //check whenever the first argument is an upload namespace
+ if (isset($args[0]) && preg_match('/^[a-z.\-_:]+$/', $args[0])) {
+ $this->opt['namespace'] = array_shift($args);
+ }
+ $this->standardArgs($args);
+
+ $attr = array();
+ if(!isset($this->opt['optional'])) {
+ $attr['required'] = 'required';
+ }
+
+ $this->tpl = form_makeFileField('@@NAME@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr);
+
+ if(!isset($this->opt['optional'])){
+ $this->tpl['class'] .= ' required';
+ }
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * Accepts and validates a posted value.
+ *
+ * @param array $value The passed value or array or null if none given
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed filename is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ $this->opt['file'] = $value;
+
+ return parent::handle_post($value['name'], $fields, $index, $formid);
+ }
+
+ /**
+ * @throws Exception max size, required or upload error
+ */
+ protected function _validate() {
+ global $lang;
+ parent::_validate();
+
+ $file = $this->getParam('file');
+ if($file['error'] == 1 || $file['error'] == 2) {
+ throw new Exception(sprintf($lang['uploadsize'],filesize_h(php_to_byte(ini_get('upload_max_filesize')))));
+ } else if($file['error'] == 4) {
+ if(!isset($this->opt['optional'])) {
+ throw new Exception(sprintf($this->getLang('e_required'),hsc($this->opt['label'])));
+ }
+ } else if( $file['error'] || !is_uploaded_file($file['tmp_name'])) {
+ throw new Exception(hsc($this->opt['label']) .' '. $lang['uploadfail'] . ' (' .$file['error'] . ')' );
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php b/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php
new file mode 100644
index 0000000..dd63753
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldhidden.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldhidden
+ *
+ * Creates an invisible field with static data
+ */
+class helper_plugin_bureaucracy_fieldhidden extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - =default value
+ */
+
+ /**
+ * Render the field as XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ *
+ * @param array $params Additional HTML specific parameters
+ * @param Doku_Form $form The target Doku_Form object
+ * @param int $formid unique identifier of the form which contains this field
+ */
+ function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ $form->addHidden($params['name'], $this->getParam('value') . '');
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ function getParam($name) {
+ if (!isset($this->opt[$name]) || in_array($name, array('pagename', 'value')) && $this->hidden) {
+ return null;
+ }
+ if ($name === 'pagename') {
+ // If $this->opt['pagename'] is set, return the value of the field,
+ // UNESCAPED.
+ $name = 'value';
+ }
+ return $this->opt[$name];
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php b/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php
new file mode 100644
index 0000000..787e081
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldhiddenautoinc.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldhiddenautoinc
+ *
+ * Creates an invisible field with a number that increases by 1 on each form submit
+ */
+class helper_plugin_bureaucracy_fieldhiddenautoinc extends helper_plugin_bureaucracy_fieldnumber {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ $args[] = '++';
+ parent::initialize($args);
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ *
+ * @param array $params Additional HTML specific parameters
+ * @param Doku_Form $form The target Doku_Form object
+ * @param $formid
+ */
+ function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ $form->addHidden($params['name'], $this->getParam('value') . '');
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php b/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php
new file mode 100644
index 0000000..5311d90
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldmultiselect.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldmultiselect
+ *
+ * Creates a multiselect box
+ */
+class helper_plugin_bureaucracy_fieldmultiselect extends helper_plugin_bureaucracy_fieldselect {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - option1|option2|etc
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $this->init($args);
+ $this->opt['args'] = array_map('trim', explode('|',array_shift($args)));
+ $this->standardArgs($args);
+ if (isset($this->opt['value'])) {
+ $this->opt['value'] = array_map('trim', explode(',', $this->opt['value']));
+ } else {
+ $this->opt['value'] = array();
+ }
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ * Additional parameters (CSS class & HTML name) are passed in $params.
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ if(!$form->_infieldset){
+ $form->startFieldset('');
+ }
+ if ($this->error) {
+ $params['class'] = 'bureaucracy_error';
+ }
+ $params = array_merge($this->opt, $params);
+ $form->addElement(call_user_func_array('form_makeListboxField',
+ $this->_parse_tpl(
+ array(
+ '@@NAME@@[]',
+ $params['args'],
+ $this->opt['value'],
+ '@@DISPLAY@@',
+ '@@ID@@',
+ '@@CLASS@@',
+ array('multiple' => 'multiple')
+ ),
+ $params
+ )));
+ }
+} \ No newline at end of file
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php b/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php
new file mode 100644
index 0000000..93a2242
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldnumber.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldnumber
+ *
+ * Creates a single line input field, where input is validated to be numeric
+ */
+class helper_plugin_bureaucracy_fieldnumber extends helper_plugin_bureaucracy_fieldtextbox {
+
+ private $autoinc = false;
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ++ (optional)
+ * - 0000 (optional)
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $pp = array_search('++', $args, true);
+ if ($pp !== false) {
+ unset($args[$pp]);
+ $this->autoinc = true;
+ }
+
+ parent::initialize($args);
+
+ if ($this->autoinc) {
+ global $ID;
+ $key = $this->get_key();
+ $c_val = p_get_metadata($ID, 'bureaucracy ' . $key);
+ if (is_null($c_val)) {
+ if (!isset($this->opt['value'])) {
+ $this->opt['value'] = 0;
+ }
+ p_set_metadata($ID, array('bureaucracy' => array($key => $this->opt['value'])));
+ } else {
+ $this->opt['value'] = $c_val;
+ }
+ }
+ $this->opt['value'] = $this->addLeadingzeros($this->opt['value']);
+ }
+
+ /**
+ * Validate field value
+ *
+ * @throws Exception when not a number
+ */
+ protected function _validate() {
+ $value = $this->getParam('value');
+ if (!is_null($value) && !is_numeric($value)){
+ throw new Exception(sprintf($this->getLang('e_numeric'),hsc($this->getParam('display'))));
+ }
+
+ parent::_validate();
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * Accepts and validates a posted value.
+ *
+ * @param string $value The passed value or array or null if none given
+ * @param array $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ $value = $this->addLeadingzeros($value);
+
+ return parent::handle_post($value, $fields, $index, $formid);
+ }
+
+ /**
+ * Returns the cleaned key for this field required for metadata
+ *
+ * @return string key
+ */
+ private function get_key() {
+ return preg_replace('/\W/', '', $this->opt['label']) . '_autoinc';
+ }
+
+ /**
+ * Executed after performing the action hooks
+ *
+ * Increases counter and purge cache
+ */
+ public function after_action() {
+ if ($this->autoinc) {
+ global $ID;
+ p_set_metadata($ID, array('bureaucracy' => array($this->get_key() => $this->opt['value'] + 1)));
+ // Force rerendering by removing the instructions cache file
+ $cache_fn = getCacheName(wikiFN($ID).$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.'i');
+ if (file_exists($cache_fn)) {
+ unlink($cache_fn);
+ }
+ }
+ }
+
+ /**
+ * Add leading zeros, depending on the corresponding field option
+ *
+ * @param int|string $value number
+ * @return string
+ */
+ protected function addLeadingzeros(&$value) {
+ if (isset($this->opt['leadingzeros'])) {
+ $length = strlen($value);
+ for($i = $length; $i < $this->opt['leadingzeros']; $i++) {
+ $value = '0' . $value;
+ }
+ return $value;
+ }
+ return $value;
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php b/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php
new file mode 100644
index 0000000..d73177b
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldonoff.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldonoff
+ *
+ * Creates a checkbox
+ */
+class helper_plugin_bureaucracy_fieldonoff extends helper_plugin_bureaucracy_fieldyesno {
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - =yesvalue
+ * - !falsevalue
+ * - ^ (optional)
+ */
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php b/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php
new file mode 100644
index 0000000..e4e20f4
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldpassword.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldpassword
+ *
+ * Creates a single line password input field
+ */
+class helper_plugin_bureaucracy_fieldpassword extends helper_plugin_bureaucracy_field {
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ parent::initialize($args);
+
+ $attr = array();
+ if(!isset($this->opt['optional'])) {
+ $attr['required'] = 'required';
+ }
+ $this->tpl = form_makePasswordField('@@NAME@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr);
+
+ if(!isset($this->opt['optional'])){
+ $this->tpl['class'] .= ' required';
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php b/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php
new file mode 100644
index 0000000..e2b466d
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldradio.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldselect
+ *
+ * Creates a dropdown list
+ */
+class helper_plugin_bureaucracy_fieldradio extends helper_plugin_bureaucracy_field {
+
+ protected $mandatory_args = 3;
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - option1|option2|etc
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $this->init($args);
+ $this->opt['args'] = array_filter(array_map('trim', explode('|',array_shift($args))));
+ $this->standardArgs($args);
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ * Additional parameters (CSS class & HTML name) are passed in $params.
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ if(!$form->_infieldset){
+ $form->startFieldset('');
+ }
+ if ($this->error) {
+ $params['class'] = 'bureaucracy_error';
+ }
+ $params = array_merge($this->opt, $params);
+
+ list($name, $entries, $value, $label, $id, $class) = $this->_parse_tpl(
+ array(
+ '@@NAME@@',
+ $params['args'],
+ '@@VALUE@@',
+ '@@DISPLAY@@',
+ '@@ID@@',
+ '@@CLASS@@'
+ ),
+ $params
+ );
+
+ $value = (in_array($value, $entries) ? $value : null);
+ $valueoffieldwithid = ($value !== null ? $value : current($entries));
+ // label
+ $s = '<label';
+ $s .= ' class="radiolabel '.$class.'"';
+ $s .= '><span>' . $label . '</span>';
+ $s .= '</label>';
+ $form->addElement($s);
+
+ // radio fields
+ foreach($entries as $val) {
+ if($value === $val) {
+ $attrs = array('checked' => 'checked');
+ } else {
+ $attrs = array();
+ }
+ if($valueoffieldwithid === $val) {
+ $_id = $id; //e.g. autofocus with 'focus__this' id
+ } else {
+ $_id = '';
+ }
+ $form->addElement(form_makeRadioField($name, $val, $val, $_id, $class, $attrs));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php b/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php
new file mode 100644
index 0000000..391e562
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldselect.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldselect
+ *
+ * Creates a dropdown list
+ */
+class helper_plugin_bureaucracy_fieldselect extends helper_plugin_bureaucracy_field {
+
+ protected $mandatory_args = 3;
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - option1|option2|etc
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $this->init($args);
+ $this->opt['args'] = array_map('trim', explode('|',array_shift($args)));
+ $this->standardArgs($args);
+ if (!isset($this->opt['value']) && isset($this->opt['optional'])) {
+ array_unshift($this->opt['args'],' ');
+ }
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * Outputs the represented field using the passed Doku_Form object.
+ * Additional parameters (CSS class & HTML name) are passed in $params.
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ if(!$form->_infieldset){
+ $form->startFieldset('');
+ }
+ if ($this->error) {
+ $params['class'] = 'bureaucracy_error';
+ }
+ $params = array_merge($this->opt, $params);
+ $form->addElement(call_user_func_array('form_makeListboxField',
+ $this->_parse_tpl(
+ array(
+ '@@NAME@@',
+ $params['args'],
+ '@@VALUE|' . $params['args'][0] . '@@',
+ '@@DISPLAY@@',
+ '@@ID@@',
+ '@@CLASS@@'
+ ),
+ $params
+ )));
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php b/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php
new file mode 100644
index 0000000..191be72
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldstatic.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldstatic
+ *
+ * Adds some static text to the form
+ */
+class helper_plugin_bureaucracy_fieldstatic extends helper_plugin_bureaucracy_field {
+ protected $tpl = '<p>@@DISPLAY@@</p>';
+
+ /**
+ * Arguments:
+ * - cmd
+ * - text
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ // make always optional to prevent being marked as required
+ $this->opt['optional'] = true;
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * @param string $value The passed value
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ public function getParam($name) {
+ return ($name === 'value') ? null : parent::getParam($name);
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ if (!isset($this->opt['display'])) {
+ $this->opt['display'] = $this->opt['label'];
+ }
+ parent::renderfield($params, $form, $formid);
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php b/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php
new file mode 100644
index 0000000..f49c2b7
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldsubject.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldsubject
+ *
+ * Defines own subject for mail action from this form
+ */
+class helper_plugin_bureaucracy_fieldsubject extends helper_plugin_bureaucracy_field {
+ /**
+ * Arguments:
+ * - cmd
+ * - subjecttext
+ */
+
+ /**
+ * Render the field as XHTML
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $this->_handlePreload();
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * @param string $value null
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ function handle_post($value, &$fields, $index, $formid) {
+ return true;
+ }
+} \ No newline at end of file
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php b/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php
new file mode 100644
index 0000000..b9f2e45
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldsubmit.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldsubmit
+ *
+ * Creates a submit button
+ */
+class helper_plugin_bureaucracy_fieldsubmit extends helper_plugin_bureaucracy_field {
+ protected $mandatory_args = 1;
+ static $captcha_displayed = array();
+ static $captcha_checked = array();
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label (optional)
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ // make always optional to prevent being marked as required
+ $this->opt['optional'] = true;
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ if(!isset(helper_plugin_bureaucracy_fieldsubmit::$captcha_displayed[$formid])) {
+ helper_plugin_bureaucracy_fieldsubmit::$captcha_displayed[$formid] = true;
+ /** @var helper_plugin_captcha $helper */
+ $helper = null;
+ if(@is_dir(DOKU_PLUGIN.'captcha')) $helper = plugin_load('helper','captcha');
+ if(!is_null($helper) && $helper->isEnabled()){
+ $form->addElement($helper->getHTML());
+ }
+ }
+ $attr = array();
+ if(isset($this->opt['id'])) {
+ $attr['id'] = $this->opt['id'];
+ }
+ $this->tpl = form_makeButton('submit','', '@@DISPLAY|' . $this->getLang('submit') . '@@', $attr);
+ parent::renderfield($params, $form, $formid);
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * Accepts and validates a posted captcha value.
+ *
+ * @param string $value The passed value
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the posted form has a valid captcha
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ if ($this->hidden) {
+ return true;
+ }
+ if(!isset(helper_plugin_bureaucracy_fieldsubmit::$captcha_checked[$formid])) {
+ helper_plugin_bureaucracy_fieldsubmit::$captcha_checked[$formid] = true;
+ // check CAPTCHA
+ /** @var helper_plugin_captcha $helper */
+ $helper = null;
+ if(@is_dir(DOKU_PLUGIN.'captcha')) $helper = plugin_load('helper','captcha');
+ if(!is_null($helper) && $helper->isEnabled()){
+ return $helper->check();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ public function getParam($name) {
+ return ($name === 'value') ? null : parent::getParam($name);
+ }
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php
new file mode 100644
index 0000000..0dfcce2
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtextarea.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldtextarea
+ *
+ * Creates a multi-line input field
+ */
+class helper_plugin_bureaucracy_fieldtextarea extends helper_plugin_bureaucracy_field {
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - x123 (optional) as number of lines
+ * - ^ (optional)
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ if (!isset($this->opt['class'])) {
+ $this->opt['class'] = '';
+ }
+ $this->opt['class'] .= ' textareafield';
+ }
+
+ protected $tpl =
+'<label class="@@CLASS@@">
+ <span>@@DISPLAY@@</span>
+ <textarea name="@@NAME@@" id="@@ID@@" rows="@@ROWS|10@@" cols="10" class="edit @@OPTIONAL|required" required="required@@">@@VALUE@@</textarea>
+</label>';
+
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php
new file mode 100644
index 0000000..430cc2d
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtextbox.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldtextbox
+ *
+ * Creates a single line input field
+ */
+class helper_plugin_bureaucracy_fieldtextbox extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - =default (optional)
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ parent::initialize($args);
+
+ $attr = array();
+ if(!isset($this->opt['optional'])) {
+ $attr['required'] = 'required';
+ }
+
+ $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr);
+ if(isset($this->opt['class'])){
+ $this->tpl['class'] .= ' '.$this->opt['class'];
+ }
+ if(!isset($this->opt['optional'])){
+ $this->tpl['class'] .= ' required';
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php b/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php
new file mode 100644
index 0000000..164e71f
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldtime.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldtime
+ *
+ * A time in the format (h)h:mm(:ss)
+ */
+class helper_plugin_bureaucracy_fieldtime extends helper_plugin_bureaucracy_fieldtextbox {
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ $attr = array(
+ 'class' => 'timefield edit',
+ 'maxlength'=>'8'
+ );
+ if(!isset($this->opt['optional'])) {
+ $attr['required'] = 'required';
+ $attr['class'] .= ' required';
+ }
+ $this->tpl = form_makeTextField('@@NAME@@', '@@VALUE@@', '@@DISPLAY@@', '@@ID@@', '@@CLASS@@', $attr);
+ }
+
+ /**
+ * Validate field input
+ *
+ * @throws Exception when empty or wrong time format
+ */
+ protected function _validate() {
+ parent::_validate();
+
+ $value = $this->getParam('value');
+ if (!is_null($value) && !preg_match('/^\d{1,2}:\d{2}(?::\d{2})?$/', $value)) {
+ throw new Exception(sprintf($this->getLang('e_time'),hsc($this->getParam('display'))));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php b/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php
new file mode 100644
index 0000000..775f87b
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldusemailtemplate.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldusemailtemplate
+ *
+ * Adds a template only for use with the mail action
+ */
+class helper_plugin_bureaucracy_fieldusemailtemplate extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - template
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ function initialize($args) {
+ if(count($args) < 2){
+ msg(sprintf($this->getLang('e_missingargs'), hsc($args[0]),
+ hsc($args[1])), -1);
+ return;
+ }
+
+ // get standard arguments
+ $this->opt = array_combine(array('cmd', 'template'), $args);
+ }
+
+ /**
+ * Nothing displayed
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ function renderfield($params, Doku_Form $form, $formid) {
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * @param string $value null
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ function handle_post($value, &$fields, $index, $formid) {
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ function getParam($name) {
+ return ($name === 'value' ||
+ (in_array($name, array('template')) && $this->hidden)) ?
+ null :
+ parent::getParam($name);
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fielduser.php b/platform/www/lib/plugins/bureaucracy/helper/fielduser.php
new file mode 100644
index 0000000..49608e1
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fielduser.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fielduser
+ *
+ * Create single user input, with autocompletion
+ */
+class helper_plugin_bureaucracy_fielduser extends helper_plugin_bureaucracy_fieldtextbox {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ $this->tpl['class'] .= ' userpicker';
+ }
+
+ /**
+ * Allow receiving user attributes by ".". Ex. user.name
+ * You can pass an optional argument to user.grps enclosed in brackets, used as an groups delimiter Ex. user.grps(, )
+ *
+ * @return string
+ */
+ public function getReplacementPattern() {
+ $label = $this->opt['label'];
+
+ return '/(@@|##)' . preg_quote($label, '/') .
+ '(?:\.(.*?))?' . //match attribute after "."
+ '(?:\((.*?)\))?' . //match parameter enclosed in "()". Used for grps separator
+ '\1/si';
+ }
+
+ /**
+ * Used as an callback for preg_replace_callback
+ *
+ * @param $matches
+ * @return string
+ */
+ public function replacementValueCallback($matches) {
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+
+ $value = $this->opt['value'];
+ //attr doesn't exists
+ if (!isset($matches[2])) {
+ return is_null($value) || $value === false ? '' : $value;
+ }
+ $attr = $matches[2];
+
+ $udata = $auth->getUserData($value);
+ //no such user
+ if ($udata === false) {
+ return $matches[0];
+ }
+
+ switch($attr) {
+ case 'name':
+ case 'mail':
+ return $udata[$attr];
+ case 'grps':
+ $delitmiter = ', ';
+ if (isset($matches[3])) {
+ $delitmiter = $matches[3];
+ }
+ return implode($delitmiter, $udata['grps']);
+ default:
+ return $matches[0];
+ }
+ }
+
+ /**
+ * Return the callback for user replacement
+ *
+ * @return array
+ */
+ public function getReplacementValue() {
+ return array($this, 'replacementValueCallback');
+ }
+
+ /**
+ * Validate value of field
+ *
+ * @throws Exception when user not exists
+ */
+ protected function _validate() {
+ parent::_validate();
+
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+ $value = $this->getParam('value');
+ if (!is_null($value) && $auth->getUserData($value) === false) {
+ throw new Exception(sprintf($this->getLang('e_user'),hsc($this->getParam('display'))));
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php b/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php
new file mode 100644
index 0000000..bd5dce7
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldusers.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldusers
+ *
+ * Create multi-user input, with autocompletion
+ */
+class helper_plugin_bureaucracy_fieldusers extends helper_plugin_bureaucracy_fieldtextbox {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ $this->tpl['class'] .= ' userspicker';
+ }
+
+ /**
+ * Allow receiving user attributes by ".". Ex. user.name
+ * You can pass an optional argument to user.grps enclosed in brackets, used as an groups delimiter Ex. user.grps(, )
+ *
+ * @return string
+ */
+ public function getReplacementPattern() {
+ $label = $this->opt['label'];
+ return '/(@@|##)' . preg_quote($label, '/') .
+ '(?:\((?P<delimiter>.*?)\))?' .//delimiter
+ '(?:\.(?P<attribute>.*?))?' . //match attribute after "."
+ '\1/si';
+ }
+
+ /**
+ * Used as an callback for preg_replace_callback
+ *
+ * @param $matches
+ * @return string
+ */
+ public function replacementValueCallback($matches) {
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+
+ $value = $this->opt['value'];
+ //copy the value by default
+ if (isset($matches[2]) && is_array($matches[2]) && count($matches[2]) == 2) {
+ return is_null($value) || $value === false ? $matches[0] : $value;
+ }
+
+ $attribute = isset($matches['attribute']) ? $matches['attribute'] : '';
+ //check if matched string containts a pair of brackets
+ $delimiter = preg_match('/\(.*\)/s', $matches[0]) ? $matches['delimiter'] : ', ';
+ $users = array_map('trim', explode(',', $value));
+
+ switch($attribute) {
+ case '':
+ return implode($delimiter, $users);
+ case 'name':
+ case 'mail':
+ return implode($delimiter, array_map(function ($user) use ($auth, $attribute) {
+ return $auth->getUserData($user)[$attribute];
+ }, $users));
+ default:
+ return $matches[0];
+ }
+ }
+
+ /**
+ * Return the callback for user replacement
+ *
+ * @return array
+ */
+ public function getReplacementValue() {
+ return array($this, 'replacementValueCallback');
+ }
+
+ /**
+ * Validate value of field
+ *
+ * @throws Exception when user not exists
+ */
+ protected function _validate() {
+ parent::_validate();
+
+ /** @var DokuWiki_Auth_Plugin $auth */
+ global $auth;
+ $users = array_filter(preg_split('/\s*,\s*/', $this->getParam('value')));
+ foreach ($users as $user) {
+ if ($auth->getUserData($user) === false) {
+ throw new Exception(sprintf($this->getLang('e_users'), hsc($this->getParam('display'))));
+ }
+ }
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php b/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php
new file mode 100644
index 0000000..dada855
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldwiki.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldwiki
+ *
+ * Adds some static text to the form, but parses the input as Wiki syntax (computationally expensive)
+ */
+class helper_plugin_bureaucracy_fieldwiki extends helper_plugin_bureaucracy_field {
+
+ protected $tpl = '<p>@@LABEL@@</p>';
+
+ /**
+ * Arguments:
+ * - cmd
+ * - wiki text
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ parent::initialize($args);
+ // make always optional to prevent being marked as required
+ $this->opt['optional'] = true;
+ }
+
+ /**
+ * Handle a post to the field
+ *
+ * @param null $value empty
+ * @param helper_plugin_bureaucracy_field[] $fields (reference) form fields (POST handled upto $this field)
+ * @param int $index index number of field in form
+ * @param int $formid unique identifier of the form which contains this field
+ * @return bool Whether the passed value is valid
+ */
+ public function handle_post($value, &$fields, $index, $formid) {
+ return true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $name
+ * @return mixed|null
+ */
+ public function getParam($name) {
+ return ($name === 'value') ? null : parent::getParam($name);
+ }
+
+ /**
+ * Returns parsed wiki instructions
+ *
+ * @param string|array $tpl The template as string
+ * @param array $params A hash mapping parameters to values
+ *
+ * @return string The parsed template
+ */
+ protected function _parse_tpl($tpl, $params) {
+ $ins = p_get_instructions($params['display']);
+ // remove document and p instructions (opening and closing)
+ $start = 2;
+ $end = 2;
+ // check if struct instructions have to be removed as well from the beginning or end
+ if (isset($ins[1][1][0]) && $ins[1][1][0] === 'struct_output') {
+ $start = 3;
+ } elseif (isset($ins[count($ins) - 2][1][0]) && $ins[count($ins) - 2][1][0] === 'struct_output') {
+ $end = 3;
+ }
+ $ins = array_slice($ins, $start, -$end);
+ $tpl = p_render('xhtml', $ins, $byref_ignore);
+ return '<p>'.$tpl.'</p>';
+ }
+}
diff --git a/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php b/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php
new file mode 100644
index 0000000..77b83de
--- /dev/null
+++ b/platform/www/lib/plugins/bureaucracy/helper/fieldyesno.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Class helper_plugin_bureaucracy_fieldyesno
+ *
+ * Creates a checkbox
+ */
+class helper_plugin_bureaucracy_fieldyesno extends helper_plugin_bureaucracy_field {
+
+ /**
+ * Arguments:
+ * - cmd
+ * - label
+ * - =yesvalue
+ * - !falsevalue
+ * - ^ (optional)
+ *
+ * @param array $args The tokenized definition, only split at spaces
+ */
+ public function initialize($args) {
+ $this->init($args);
+ $newargs = array();
+ foreach ($args as $arg) {
+ switch ($arg[0]) {
+ case '=':
+ if($arg == '==1') {
+ $this->opt['value'] = '1';
+ }elseif($arg == '==0') {
+ $this->opt['value'] = '0';
+ }else{
+ $this->opt['true_value'] = substr($arg, 1);
+ }
+ break;
+ case '!':
+ $this->opt['false_value'] = substr($arg, 1);
+ break;
+ default:
+ $newargs[] = $arg;
+ }
+ }
+ $this->standardArgs($newargs);
+ $this->opt['optional'] = true;
+ }
+
+ /**
+ * Get an arbitrary parameter
+ *
+ * @param string $key
+ * @return mixed|null
+ */
+ public function getParam($key) {
+ if ($key === 'value') {
+ if ($this->opt['value'] === '1') {
+ return isset($this->opt['true_value']) ?
+ $this->opt['true_value'] :
+ null;
+ } elseif ($this->opt['value'] === '0') {
+ return isset($this->opt['false_value']) ?
+ $this->opt['false_value'] :
+ null;
+ }
+ }
+ return parent::getParam($key);
+ }
+
+ /**
+ * Whether the field is true (used for depending fieldsets)
+ *
+ * @return bool whether field is set
+ */
+ public function isSet_() {
+ return $this->opt['value'] === '1';
+ }
+
+ /**
+ * Render the field as XHTML
+ *
+ * @params array $params Additional HTML specific parameters
+ * @params Doku_Form $form The target Doku_Form object
+ * @params int $formid unique identifier of the form which contains this field
+ */
+ public function renderfield($params, Doku_Form $form, $formid) {
+ $id = 'bureaucracy__'.md5(rand());
+ if(isset($this->opt['id'])) {
+ $id = $this->opt['id'];
+ }
+ $params = array_merge(
+ array('value' => false),
+ $this->opt,
+ $params
+ );
+ $check = $params['value'] ? 'checked="checked"' : '';
+ $this->tpl = '<label class="@@CLASS@@" for="'.$id.'"><span>@@DISPLAY@@</span>'.
+ '<input type="hidden" name="@@NAME@@" value="0" />' .
+ '<input type="checkbox" name="@@NAME@@" value="1" id="'.$id.'" ' . $check . ' />' .
+ '</label>';
+ parent::renderfield($params, $form, $formid);
+ }
+}